11from __future__ import annotations
22
3+ import json
34from copy import deepcopy
45from pathlib import Path
56
1011from TPTBox .core .poi_fun .poi_abstract import Abstract_POI , POI_Descriptor
1112from TPTBox .core .poi_fun .save_load import FORMAT_GLOBAL , load_poi , save_poi
1213from TPTBox .core .vert_constants import Abstract_lvl , logging
14+ from TPTBox .logger .log_file import log
1315
1416###### GLOBAL POI #####
1517
@@ -138,7 +140,7 @@ def to_other(self, msk: Has_Grid, verbose=False) -> poi.POI:
138140 v = (- v [0 ], - v [1 ], v [2 ]) # noqa: PLW2901
139141 v_out = msk .global_to_local (v )
140142 if verbose :
141- print (v , "-->" , v_out )
143+ log . print (v , "-->" , v_out )
142144 out [k1 , k2 ] = tuple (v_out )
143145
144146 return poi .POI (centroids = out , ** msk ._extract_affine (), info = self .info , format = self .format )
@@ -155,8 +157,8 @@ def copy(self, centroids: POI_Descriptor | None = None) -> Self:
155157 @classmethod
156158 def load (cls , poi : poi .POI_Reference , itk_coords : bool | None = None ) -> Self :
157159 poi_obj = load_poi (poi )
158- if not isinstance ( poi_obj , POI_Global ) :
159- poi_obj = poi_obj .to_global (itk_coords if itk_coords is not None else False )
160+ if not poi_obj . is_global :
161+ poi_obj = poi_obj .to_global (itk_coords if itk_coords is not None else False ) # type: ignore
160162 if itk_coords is not None :
161163 assert itk_coords == poi_obj .itk_coords , "not implemented swichting to/from itk_coords to nii "
162164 return poi_obj # type: ignore
@@ -173,3 +175,79 @@ def save(
173175 return save_poi (
174176 self , out_path , make_parents , additional_info , save_hint = save_hint , resample_reference = resample_reference , verbose = verbose
175177 )
178+
179+ def save_mrk (self , filepath : str | Path , color = None , split_by_region = True , split_by_subregion = False ):
180+ """
181+ Save the POI data to a .mrk.json file in Slicer Markups format.
182+ Automatically sets coordinate system based on itk_coords.
183+ Includes level_one_info and level_two_info in the description.
184+ Preserves metadata from `info` dictionary.
185+ """
186+ if color is None :
187+ color = self .info .get ("color" , [1.0 , 0.0 , 0.0 ])
188+ filepath = Path (filepath )
189+ if not filepath .name .endswith (".mrk.json" ):
190+ filepath = filepath .parent / (filepath .stem + ".mrk.json" )
191+ coordinate_system = "LPS" if self .itk_coords else "RAS"
192+
193+ # Create list of control points
194+ from TPTBox import NII
195+ from TPTBox .mesh3D .mesh_colors import get_color_by_label
196+
197+ list_markups = {}
198+ for region , subregion , coords in self .centroids .items ():
199+ try :
200+ name = self .level_two_info (subregion ).name
201+ except Exception :
202+ name = subregion
203+ try :
204+ name2 = self .level_one_info (region ).name
205+ except Exception :
206+ name2 = region
207+ key = "P"
208+ color2 = color
209+ if split_by_region :
210+ key += str (region ) + "_"
211+ color2 = get_color_by_label (region ).rgb .tolist ()
212+ if split_by_subregion :
213+ key += str (subregion )
214+ color2 = get_color_by_label (region ).rgb .tolist ()
215+ if key not in list_markups :
216+ list_markups [key ] = {
217+ "type" : "Fiducial" ,
218+ "coordinateSystem" : coordinate_system ,
219+ "locked" : False ,
220+ "labelFormat" : "%N-%d" ,
221+ "controlPoints" : [],
222+ "display" : {
223+ "visibility" : True ,
224+ "opacity" : 1.0 ,
225+ "color" : color2 .copy (),
226+ "propertiesLabelVisibility" : False ,
227+ },
228+ "description" : "" , # self.info,
229+ }
230+
231+ list_markups [key ]["controlPoints" ].append (
232+ {
233+ "id" : f"{ region } -{ subregion } " ,
234+ "label" : f"{ region } -{ subregion } " ,
235+ "description" : name ,
236+ "associatedNodeID" : name2 ,
237+ "position" : list (coords ),
238+ "orientation" : [1.0 , 0.0 , 0.0 , 0.0 , 1.0 , 0.0 , 0.0 , 0.0 , 1.0 ],
239+ "selected" : False ,
240+ "locked" : False ,
241+ "visibility" : True ,
242+ "positionStatus" : "defined" ,
243+ }
244+ )
245+ mrk_data = {
246+ "markups" : list (list_markups .values ()),
247+ "schema" : "https://raw.githubusercontent.com/slicer/slicer/master/Modules/Loadable/Markups/Resources/Schema/markups-schema-v1.0.3.json#" ,
248+ # "coordinateSystem": coordinate_system,
249+ }
250+
251+ with open (filepath , "w" ) as f :
252+ json .dump (mrk_data , f , indent = 2 )
253+ log .on_save (f"Saved .mrk.json to { filepath } " )
0 commit comments