From b844b7a2d57787a4a339d71a2d9262ced761145e Mon Sep 17 00:00:00 2001 From: harmening Date: Fri, 15 Mar 2024 07:43:27 +0100 Subject: [PATCH 1/2] TwoSurfaceHeadModel: make landmarks optional --- src/cedalion/dataclasses/geometry.py | 7 ++++++- src/cedalion/imagereco/forward_model.py | 21 ++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/cedalion/dataclasses/geometry.py b/src/cedalion/dataclasses/geometry.py index c7fd488..364fd78 100644 --- a/src/cedalion/dataclasses/geometry.py +++ b/src/cedalion/dataclasses/geometry.py @@ -129,7 +129,12 @@ def decimate(self, face_count: int) -> "TrimeshSurface": The surface with a decimated mesh """ - decimated = self.mesh.simplify_quadric_decimation(face_count) + try: + decimated = self.mesh.simplify_quadric_decimation(face_count) + except: + # deprecated trimesh function, please update trimesh! + decimated = self.mesh.simplify_quadratic_decimation(face_count) + return TrimeshSurface(decimated, self.crs, self.units) def smooth(self, lamb: float) -> "TrimeshSurface": diff --git a/src/cedalion/imagereco/forward_model.py b/src/cedalion/imagereco/forward_model.py index c30cca6..5f4397d 100644 --- a/src/cedalion/imagereco/forward_model.py +++ b/src/cedalion/imagereco/forward_model.py @@ -46,7 +46,7 @@ def from_segmentation( "skull": "skull.nii", "wm": "wm.nii", }, - landmarks_ras_file: str = "landmarks.mrk.json", + landmarks_ras_file: Optional[str] = None, brain_seg_types: list[str] = ["gm", "wm"], scalp_seg_types: list[str] = ["scalp"], smoothing: float = 0.5, @@ -71,11 +71,14 @@ def from_segmentation( # load landmarks. Other than the segmentation masks which are in voxel (ijk) # space, these are already in RAS space. - if not os.path.isabs(landmarks_ras_file): - landmarks_ras_file = os.path.join(segmentation_dir, landmarks_ras_file) + if landmarks_ras_file is not None: + if not os.path.isabs(landmarks_ras_file): + landmarks_ras_file = os.path.join(segmentation_dir, landmarks_ras_file) - landmarks_ras = cedalion.io.read_mrk_json(landmarks_ras_file, crs=crs_ras) - landmarks_ijk = landmarks_ras.points.apply_transform(t_ras2ijk) + landmarks_ras = cedalion.io.read_mrk_json(landmarks_ras_file, crs=crs_ras) + landmarks_ijk = landmarks_ras.points.apply_transform(t_ras2ijk) + else: + landmarks_ijk = None # derive surfaces from segmentation masks brain_ijk = surface_from_segmentation(segmentation_masks, brain_seg_types) @@ -127,13 +130,15 @@ def from_segmentation( @property def crs(self): assert self.brain.crs == self.scalp.crs - assert self.scalp.crs == self.landmarks.points.crs + if self.landmarks is not None: + assert self.scalp.crs == self.landmarks.points.crs return self.brain.crs def apply_transform(self, transform: cdt.AffineTransform) -> "TwoSurfaceHeadModel": brain = self.brain.apply_transform(transform) scalp = self.scalp.apply_transform(transform) - landmarks = self.landmarks.points.apply_transform(transform) + landmarks = self.landmarks.points.apply_transform(transform) \ + if self.landmarks is not None else None return TwoSurfaceHeadModel( segmentation_masks=self.segmentation_masks, @@ -152,6 +157,8 @@ def apply_transform(self, transform: cdt.AffineTransform) -> "TwoSurfaceHeadMode def align_and_snap_to_scalp( self, points: cdt.LabeledPointCloud ) -> cdt.LabeledPointCloud: + assert self.landmarks is not None, "Please add landmarks in RAS to head \ + instance." t = register_trans_rot_isoscale(self.landmarks, points) transformed = points.points.apply_transform(t) snapped = self.scalp.snap(transformed) From 7ee4d9bd82aea53e0fc3a9f389be09ea4e2ff4c9 Mon Sep 17 00:00:00 2001 From: harmening Date: Mon, 18 Mar 2024 13:53:05 +0100 Subject: [PATCH 2/2] make landmarks an optional member of TwoSurfaceHeadModel --- src/cedalion/imagereco/forward_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cedalion/imagereco/forward_model.py b/src/cedalion/imagereco/forward_model.py index 5f4397d..b01b759 100644 --- a/src/cedalion/imagereco/forward_model.py +++ b/src/cedalion/imagereco/forward_model.py @@ -27,7 +27,7 @@ class TwoSurfaceHeadModel: segmentation_masks: xr.DataArray brain: cdc.Surface scalp: cdc.Surface - landmarks: cdt.LabeledPointCloud + landmarks: Optional[cdt.LabledPointCloud] t_ijk2ras: cdt.AffineTransform t_ras2ijk: cdt.AffineTransform voxel_to_vertex_brain: scipy.sparse.spmatrix