From e3086c43c33475e4df8613e67df28ae8b0fc9f95 Mon Sep 17 00:00:00 2001 From: Paulo Henrique Junqueira Amorim Date: Mon, 23 Sep 2024 23:37:30 -0300 Subject: [PATCH] Command line for automatic export of skull and implant by command line. (#850) --- app.py | 35 ++++++++++++++++++++++-- invesalius/data/slice_.py | 1 + invesalius/data/surface.py | 56 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/app.py b/app.py index 0b22ba047..33db1413a 100644 --- a/app.py +++ b/app.py @@ -361,7 +361,7 @@ def use_cmd_optargs(args): Publisher.sendMessage("Save project", filepath=os.path.abspath(args.save)) exit(0) - check_for_segmentation(args) + check_for_cranioplasty(args) check_for_export(args) return True @@ -411,10 +411,41 @@ def use_cmd_optargs(args): return False -def check_for_segmentation(args): +def check_for_cranioplasty(args): + import invesalius.constants as const + from invesalius.i18n import tr as _ + + surface_options = { + "method": { + "algorithm": "Default", + "options": {}, + }, + "options": { + "index": 0, + "name": "", + "quality": _("Optimal *"), + "fill": False, + "keep_largest": False, + "overwrite": False, + }, + } + if args.cranioplasty: + from invesalius.data import slice_ + from invesalius.project import Project + + # create cranium mask + Publisher.sendMessage("Update threshold limits", threshold_range=(226, 3071)) + Publisher.sendMessage("Appy threshold all slices") + + # create implant mask Publisher.sendMessage("Create implant for cranioplasty") + # convert masks to surfaces and exports them. + Publisher.sendMessage( + "Export all surfaces separately", folder="./", filetype=const.FILETYPE_STL + ) + def sanitize(text): text = str(text).strip().replace(" ", "_") diff --git a/invesalius/data/slice_.py b/invesalius/data/slice_.py index bcf9fa4ea..eeea274ef 100644 --- a/invesalius/data/slice_.py +++ b/invesalius/data/slice_.py @@ -254,6 +254,7 @@ def __bind_events(self) -> None: Publisher.subscribe(self._fill_holes_auto, "Fill holes automatically") Publisher.subscribe(self._set_interpolation_method, "Set interpolation method") + Publisher.subscribe(self.do_threshold_to_all_slices, "Appy threshold all slices") def GetMaxSliceNumber(self, orientation: str) -> int: shape: Tuple[int, int, int] = self.matrix.shape diff --git a/invesalius/data/surface.py b/invesalius/data/surface.py index a3670ff52..d6a0ec7f7 100644 --- a/invesalius/data/surface.py +++ b/invesalius/data/surface.py @@ -228,6 +228,7 @@ def __bind_events(self): Publisher.subscribe(self.UpdateConvertToInvFlag, "Update convert_to_inv flag") Publisher.subscribe(self.CreateSurfaceFromPolydata, "Create surface from polydata") + Publisher.subscribe(self.export_all_surfaces_separately, "Export all surfaces separately") def OnDuplicate(self, surface_indexes): proj = prj.Project() @@ -1206,6 +1207,61 @@ def OnExportSurface(self, filename, filetype, convert_to_world=False): dlg.Destroy() os.remove(temp_file) + def export_all_surfaces_separately(self, folder, filetype): + import invesalius.data.slice_ as slc + + if filetype in ( + const.FILETYPE_STL, + const.FILETYPE_VTP, + const.FILETYPE_PLY, + const.FILETYPE_STL_ASCII, + ): + proj = prj.Project() + + for index in list(proj.mask_dict.keys()): + if index == 1: + algorithm = "Context aware smoothing" + else: + algorithm = "Default" + surface_parameters = { + "method": { + "algorithm": algorithm, + "options": {}, + }, + "options": { + "index": index, + "name": "", + "quality": _("Optimal *"), + "fill": False, + "keep_largest": True, + "overwrite": False, + }, + } + + mask = proj.mask_dict[index] + print(mask.matrix.min(), mask.matrix.max(), mask.name) + slice_ = slc.Slice() + + Publisher.sendMessage( + "Create surface", + slice_=slice_, + mask=mask, + surface_parameters=surface_parameters, + ) + + # hide all surfaces + for index in proj.surface_dict: + proj.surface_dict[index].is_shown = False + + # Displays one surface at a time and export + for index in proj.surface_dict.keys(): + print(proj.surface_dict[index].name) + proj.surface_dict[index].is_shown = True + self._export_surface( + os.path.join(folder, str(index) + ".stl"), const.FILETYPE_STL, False + ) + proj.surface_dict[index].is_shown = False + def _export_surface(self, filename, filetype, convert_to_world): if filetype in ( const.FILETYPE_STL,