Skip to content

Commit

Permalink
Merge pull request #3 from ibs-lab/test-image-recon
Browse files Browse the repository at this point in the history
TwoSurfaceHeadModel: make landmarks optional
  • Loading branch information
emiddell authored Mar 18, 2024
2 parents 67389a7 + 7ee4d9b commit 8b3423b
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 9 deletions.
7 changes: 6 additions & 1 deletion src/cedalion/dataclasses/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand Down
23 changes: 15 additions & 8 deletions src/cedalion/imagereco/forward_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -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)
Expand Down

0 comments on commit 8b3423b

Please sign in to comment.