Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,18 @@ jobs:
python -m pip install --upgrade pip
pip install .

- name: Swap in vtk-osmesa (Linux, Python 3.11/3.12 — no wheel for 3.13 yet)
# Software-rendered VTK build; lets tests/test_canvas3d.py run its
# live-render-window tests safely with no display. The regular vtk
# wheel here can hard-crash the whole process (uncatchable native
# abort) instead of a clean test failure, so this MUST be the
# matching osmesa build, not just "some vtk". pyvista/pyvistaqt
# import vtk by name at runtime, not by pinned file hash, so they
# don't need reinstalling after the swap.
if: runner.os == 'Linux' && matrix.python-version != '3.13'
run: |
pip uninstall -y vtk
pip install --index-url https://wheels.vtk.org vtk-osmesa --no-deps

- name: Run unit tests
run: python -m unittest discover -s tests -v
15 changes: 15 additions & 0 deletions anylabeling/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import os

from PyQt6.QtCore import QObject, pyqtSignal, pyqtSlot

# Common polygonal-mesh formats pyvista.read() supports. Deliberately a
# curated subset, not pyvista's full reader list — that list also includes
# non-mesh formats (images, volumes, CFD data) that must not be routed
# through the 3D mesh-loading path.
MESH_EXTENSIONS = [".obj", ".stl", ".ply", ".vtk", ".vtp", ".vtu", ".glb", ".gltf"]


def is_mesh_file(filename):
"""Check if the filename is a mesh file"""
if not filename:
return False
return os.path.splitext(filename)[1].lower() in MESH_EXTENSIONS


class GenericWorker(QObject):
finished = pyqtSignal()
Expand Down
40 changes: 27 additions & 13 deletions anylabeling/views/labeling/label_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import PIL.Image

from anylabeling.utils import is_mesh_file

from ...app_info import __version__
from . import utils
from .logger import logger
Expand All @@ -31,12 +33,17 @@ def __init__(self, filename=None):
self.shapes = []
self.image_path = None
self.image_data = None
self.flags = {}
self.other_data = {}
if filename is not None:
self.load(filename)
self.filename = filename

@staticmethod
def load_image_file(filename):
if is_mesh_file(filename):
return None

try:
image_pil = PIL.Image.open(filename)
except OSError:
Expand Down Expand Up @@ -74,6 +81,7 @@ def load(self, filename):
"group_id",
"shape_type",
"flags",
"vertex_indices",
]
try:
with io_open(filename, "r") as f:
Expand All @@ -82,30 +90,36 @@ def load(self, filename):
if version is None:
logger.warning("Loading JSON file (%s) of unknown version", filename)

if data["imageData"] is not None:
image_path = data.get("imagePath", "")
if is_mesh_file(image_path):
image_data = None
elif data.get("imageData") is not None:
image_data = base64.b64decode(data["imageData"])
else:
elif image_path:
# relative path from label file to relative path from cwd
image_path = osp.join(osp.dirname(filename), data["imagePath"])
image_data = self.load_image_file(image_path)
abs_image_path = osp.join(osp.dirname(filename), image_path)
image_data = self.load_image_file(abs_image_path)
else:
image_data = None
flags = data.get("flags") or {}
image_path = data["imagePath"]
self._check_image_height_and_width(
base64.b64encode(image_data).decode("utf-8"),
data.get("imageHeight"),
data.get("imageWidth"),
)
if image_data:
self._check_image_height_and_width(
base64.b64encode(image_data).decode("utf-8"),
data.get("imageHeight"),
data.get("imageWidth"),
)
shapes = [
{
"label": s["label"],
"label": s.get("label", ""),
"text": s.get("text", ""),
"points": s["points"],
"points": s.get("points", []),
"shape_type": s.get("shape_type", "polygon"),
"vertex_indices": s.get("vertex_indices", []),
"flags": s.get("flags", {}),
"group_id": s.get("group_id"),
"other_data": {k: v for k, v in s.items() if k not in shape_keys},
}
for s in data["shapes"]
for s in data.get("shapes", [])
]
except Exception as e: # noqa
raise LabelFileError(e) from e
Expand Down
Loading
Loading