diff --git a/TPTBox/core/nii_poi_abstract.py b/TPTBox/core/nii_poi_abstract.py index d086180..0205dcd 100755 --- a/TPTBox/core/nii_poi_abstract.py +++ b/TPTBox/core/nii_poi_abstract.py @@ -1,7 +1,6 @@ from __future__ import annotations import sys -import warnings from dataclasses import dataclass from typing import TYPE_CHECKING, Any @@ -495,6 +494,7 @@ def local_to_global(self, x: COORDINATE) -> tuple: Returns: tuple: World-space coordinate rounded to 7 decimal places. """ + # TODO ITK version a = self.rotation @ (np.array(x) * np.array(self.zoom)) + self.origin return tuple(round(float(v), 7) for v in a) diff --git a/TPTBox/core/nii_wrapper.py b/TPTBox/core/nii_wrapper.py index 18c3710..041f4d5 100755 --- a/TPTBox/core/nii_wrapper.py +++ b/TPTBox/core/nii_wrapper.py @@ -1202,8 +1202,7 @@ def resample_from_to(self, to_vox_map:Image_Reference|Has_Grid|tuple[SHAPE,AFFIN pad = tuple((int(b), int(a)) for b, a in zip(pad_before, pad_after)) ret = s.apply_pad(pad, mode=mode,inplace=inplace,verbose=verbose) - #TODO SET raise_error=False before committing - valid = ret.assert_affine(mapping,raise_error=True,origin_tolerance=0.0001,error_tolerance=0.0001,shape_tolerance=0) + valid = ret.assert_affine(mapping,raise_error=False,origin_tolerance=0.0001,error_tolerance=0.0001,shape_tolerance=0) if valid: log.print(f"resample_from_to only needs padding/cropping {pad}",verbose=verbose) ret.affine = mapping.affine #remove floating point error @@ -2446,7 +2445,7 @@ def to_stls( def to_stl( self: NII, - label: int, + label: int|Enum|Sequence[int]|Sequence[Enum], out_path: Path | dict[int, Path] | None = None, bb: tuple | None = None, to_world: bool = True, @@ -2499,7 +2498,6 @@ def to_stl( not support per-vertex attributes such as scalar values from marching cubes. """ from stl import mesh - seg = self.extract_label(label) # Prepare binary mask seg_arr = np.pad(seg.clamp(0, 1).get_array(), 1) diff --git a/TPTBox/core/poi_fun/poi_abstract.py b/TPTBox/core/poi_fun/poi_abstract.py index d8c558b..d74dfee 100755 --- a/TPTBox/core/poi_fun/poi_abstract.py +++ b/TPTBox/core/poi_fun/poi_abstract.py @@ -1030,12 +1030,16 @@ def join_left(self, pois: Self, inplace=False, _right_join=False) -> Self: Self: The combined set of centroids, either in-place or as a new set, depending on the 'inplace' parameter. """ ctd_list = self.centroids + if "label_name" in pois.info and "label_name" not in self.info: + self.info["label_name"] = {} if not inplace: ctd_list = ctd_list.copy() for x, y, c in pois.items(): if (x, y) in self and not _right_join: continue ctd_list[x, y] = c + if "label_name" in pois.info and f"({x}, {y})" in pois.info["label_name"]: + self.info["label_name"][f"({x}, {y})"] = pois.info["label_name"][f"({x}, {y})"] if inplace: return self return self.copy(ctd_list) diff --git a/TPTBox/core/poi_fun/save_load.py b/TPTBox/core/poi_fun/save_load.py index 6dd9cff..966d991 100644 --- a/TPTBox/core/poi_fun/save_load.py +++ b/TPTBox/core/poi_fun/save_load.py @@ -135,8 +135,12 @@ def convert(o): return str(o.absolute()) raise TypeError(type(o)) - with open(out_path, "w") as f: - json.dump(json_object, f, default=convert, indent=4) + try: + with open(out_path, "w") as f: + json.dump(json_object, f, default=convert, indent=4) + except TypeError: + Path(out_path).unlink(missing_ok=True) + raise log.print("POIs saved:", out_path, print_add, ltype=Log_Type.SAVE, verbose=verbose) diff --git a/TPTBox/core/vert_constants.py b/TPTBox/core/vert_constants.py index c5603c0..d7ef0e8 100755 --- a/TPTBox/core/vert_constants.py +++ b/TPTBox/core/vert_constants.py @@ -1223,8 +1223,15 @@ def save_as_name(cls) -> bool: Rib_Left = 63 Rib_Right = 64 # 66-80 Free + # Sacrum Subregions + Sacrum_Sacral_Ala_Left = 70 + Sacrum_Sacral_Ala_Right = 71 + Sacrum_Posterior_Sacral_Elements = 72 + Sacrum_Body = 73 + Sacrum_Endplate = 74 # Muscle inserts # https://www.frontiersin.org/articles/10.3389/fbioe.2022.862804/full + Metal = 80 # 81-91 Muscle_Inserts_Spinosus_Process = 81 Muscle_Inserts_Transverse_Process_Left = 83 diff --git a/TPTBox/registration/_deformable/multilabel_segmentation.py b/TPTBox/registration/_deformable/multilabel_segmentation.py index adb8861..33cadce 100644 --- a/TPTBox/registration/_deformable/multilabel_segmentation.py +++ b/TPTBox/registration/_deformable/multilabel_segmentation.py @@ -325,7 +325,7 @@ def transform_nii(self, nii_atlas: NII, allow_only_same_grid_as_moving: bool = T nii_reg = self.reg_deform.transform_nii(nii_atlas) if nii_reg.seg: nii_reg.set_dtype_("smallest_uint") - out = nii_reg.resample_from_to(self.target_grid_org) + out = nii_reg.resample_from_to(self.target_grid_org, mode="constant") if self.same_side: return out axis = out.get_axis("R") diff --git a/unit_tests/test_testsamples.py b/unit_tests/test_testsamples.py index e8d9545..28a38c2 100644 --- a/unit_tests/test_testsamples.py +++ b/unit_tests/test_testsamples.py @@ -113,6 +113,12 @@ def test_POIs_CT(self): Location.Vertebral_Body_Endplate_Inferior, Location.Rib_Left, Location.Rib_Right, + Location.Sacrum_Sacral_Ala_Left, + Location.Sacrum_Sacral_Ala_Right, + Location.Sacrum_Posterior_Sacral_Elements, + Location.Sacrum_Body, + Location.Sacrum_Endplate, + Location.Metal, ] self.make_POIs(vert_nii, subreg_nii, label, ignore_list) @@ -134,6 +140,12 @@ def test_POIs_MR(self): Location.Vertebral_Body_Endplate_Inferior, Location.Rib_Left, Location.Rib_Right, + Location.Sacrum_Sacral_Ala_Left, + Location.Sacrum_Sacral_Ala_Right, + Location.Sacrum_Posterior_Sacral_Elements, + Location.Sacrum_Body, + Location.Sacrum_Endplate, + Location.Metal, ] self.make_POIs(vert_nii, subreg_nii, label, ignore_list)