From a2be4d98b0fd159de5f1a9726ab7e64d35bee9e3 Mon Sep 17 00:00:00 2001 From: tatiana Date: Mon, 25 Jan 2010 19:05:59 +0000 Subject: [PATCH] ADD: New surface dialog (fix #127) --- invesalius/constants.py | 1 + invesalius/data/surface.py | 66 +++++++++++++++++++++++++++++++++++++++++++----------------------- invesalius/data/surface_process.py | 30 ++++++++++++++++++++++-------- invesalius/gui/dialogs.py | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------- invesalius/gui/task_surface.py | 23 ++++++++++++++++++++++- invesalius/project.py | 2 -- 6 files changed, 163 insertions(+), 68 deletions(-) diff --git a/invesalius/constants.py b/invesalius/constants.py index 976c9dc..156c029 100644 --- a/invesalius/constants.py +++ b/invesalius/constants.py @@ -202,6 +202,7 @@ SURFACE_QUALITY = { _("High"): (0, 1, 0.3000, 0.1), _("Optimal *"): (0, 2, 0.3000, 0.4)} DEFAULT_SURFACE_QUALITY = _("Optimal *") +SURFACE_QUALITY_LIST = [_("Low"),_("Medium"),_("High"),_("Optimal *")] # Surface properties diff --git a/invesalius/data/surface.py b/invesalius/data/surface.py index caccefa..aac7278 100644 --- a/invesalius/data/surface.py +++ b/invesalius/data/surface.py @@ -39,7 +39,7 @@ class Surface(): Represent both vtkPolyData and associated properties. """ general_index = -1 - def __init__(self, index=None): + def __init__(self, index=None, name=""): Surface.general_index += 1 if index is None: self.index = Surface.general_index @@ -51,7 +51,10 @@ class Surface(): self.transparency = const.SURFACE_TRANSPARENCY self.volume = 0 self.is_shown = 1 - self.name = const.SURFACE_NAME_PATTERN %(self.index+1) + if not name: + self.name = const.SURFACE_NAME_PATTERN %(self.index+1) + else: + self.name = name def SavePlist(self, filename): surface = {} @@ -186,17 +189,31 @@ class SurfaceManager(): (surface.index, surface.name, surface.colour, surface.volume, surface.transparency)) + + #### + #(mask_index, surface_name, quality, fill_holes, keep_largest) + def AddNewActor(self, pubsub_evt): """ Create surface actor, save into project and send it to viewer. """ - imagedata, colour, [min_value, max_value], \ - edited_points, overwrite = pubsub_evt.data - + surface_data = pubsub_evt.data + + if len(surface_data) == 5: + imagedata, colour, [min_value, max_value], \ + edited_points, overwrite = pubsub_evt.data + quality=_('Optimal *') + surface_name = "" + fill_holes = True + keep_largest = False + else: + imagedata, colour, [min_value, max_value],\ + edited_points, overwrite, surface_name,\ + quality, fill_holes, keep_largest =\ + pubsub_evt.data - print "---------------- OVERWRITE:",overwrite - quality=_('Optimal *') mode = 'CONTOUR' # 'GRAYSCALE' + ps.Publisher().sendMessage('Begin busy cursor') imagedata_tmp = None if (edited_points): @@ -214,11 +231,15 @@ class SurfaceManager(): if imagedata_resolution: imagedata = iu.ResampleImage3D(imagedata, imagedata_resolution) - pipeline_size = 4 + pipeline_size = 3 if decimate_reduction: pipeline_size += 1 if (smooth_iterations and smooth_relaxation_factor): pipeline_size += 1 + if fill_holes: + pipeline_size += 1 + if keep_largest: + pipeline_size += 1 # Update progress value in GUI UpdateProgress = vu.ShowProgress(pipeline_size) @@ -236,7 +257,7 @@ class SurfaceManager(): pipe_in, pipe_out = multiprocessing.Pipe() sp = surface_process.SurfaceProcess(pipe_in, filename_img, mode, min_value, max_value, decimate_reduction, smooth_relaxation_factor, - smooth_iterations, language) + smooth_iterations, language, fill_holes, keep_largest) sp.start() while 1: @@ -282,28 +303,27 @@ class SurfaceManager(): if overwrite: surface = Surface(index = self.last_surface_index) else: - surface = Surface() + surface = Surface(name=surface_name) surface.colour = colour surface.polydata = polydata - # Set actor colour and transparency actor.GetProperty().SetColor(colour) actor.GetProperty().SetOpacity(1-surface.transparency) # Remove temporary files - if sys.platform == "win32": - try: - os.remove(filename_img) - os.remove(filename_polydata) - except (WindowsError): - print "Error while removing surface temporary file" - else: # sys.platform == "linux2" or sys.platform == "darwin" - try: - os.remove(filename_img) - os.remove(filename_polydata) - except (OSError): - print "Error while removing surface temporary file" + #if sys.platform == "win32": + # try: + # os.remove(filename_img) + # os.remove(filename_polydata) + # except (WindowsError): + # print "Error while removing surface temporary file" + #else: # sys.platform == "linux2" or sys.platform == "darwin" + # try: + # os.remove(filename_img) + # os.remove(filename_polydata) + # except (OSError): + # print "Error while removing surface temporary file" # Append surface into Project.surface_dict proj = prj.Project() diff --git a/invesalius/data/surface_process.py b/invesalius/data/surface_process.py index aeb7465..2dbd6fc 100644 --- a/invesalius/data/surface_process.py +++ b/invesalius/data/surface_process.py @@ -8,7 +8,7 @@ class SurfaceProcess(multiprocessing.Process): def __init__(self, pipe, filename, mode, min_value, max_value, decimate_reduction, smooth_relaxation_factor, - smooth_iterations, language): + smooth_iterations, language, fill_holes, keep_largest): multiprocessing.Process.__init__(self) self.pipe = pipe @@ -20,6 +20,9 @@ class SurfaceProcess(multiprocessing.Process): self.smooth_relaxation_factor = smooth_relaxation_factor self.smooth_iterations = smooth_iterations self.language = language + self.fill_holes = fill_holes + self.keep_largest = keep_largest + def run(self): self.CreateSurface() @@ -86,15 +89,26 @@ class SurfaceProcess(multiprocessing.Process): self.SendProgress(obj, _("Generating 3D surface..."))) polydata = smoother.GetOutput() + + if self.keep_largest: + conn = vtk.vtkPolyDataConnectivityFilter() + conn.SetInput(polydata) + conn.SetExtractionModeToLargestRegion() + conn.AddObserver("ProgressEvent", lambda obj,evt: + self.SendProgress(obj, _("Generating 3D surface..."))) + polydata = conn.GetOutput() + # Filter used to detect and fill holes. Only fill boundary edges holes. #TODO: Hey! This piece of code is the same from # polydata_utils.FillSurfaceHole, we need to review this. - filled_polydata = vtk.vtkFillHolesFilter() - filled_polydata.SetInput(polydata) - filled_polydata.SetHoleSize(500) - filled_polydata.AddObserver("ProgressEvent", lambda obj,evt: - self.SendProgress(obj, _("Generating 3D surface..."))) - polydata = filled_polydata.GetOutput() + if self.fill_holes: + filled_polydata = vtk.vtkFillHolesFilter() + filled_polydata.SetInput(polydata) + filled_polydata.SetHoleSize(300) + filled_polydata.AddObserver("ProgressEvent", lambda obj,evt: + self.SendProgress(obj, _("Generating 3D surface..."))) + polydata = filled_polydata.GetOutput() + filename = tempfile.mktemp() @@ -104,4 +118,4 @@ class SurfaceProcess(multiprocessing.Process): writer.Write() self.pipe.send(None) - self.pipe.send(filename) \ No newline at end of file + self.pipe.send(filename) diff --git a/invesalius/gui/dialogs.py b/invesalius/gui/dialogs.py index c22f9ec..9981e6b 100644 --- a/invesalius/gui/dialogs.py +++ b/invesalius/gui/dialogs.py @@ -393,13 +393,13 @@ def ShowSavePresetDialog(default_filename="raycasting"): return filename -MASK_LIST = [] class NewSurfaceDialog(wx.Dialog): def __init__(self, parent, ID, title, size=wx.DefaultSize, pos=wx.DefaultPosition, style=wx.DEFAULT_DIALOG_STYLE, useMetal=False): - import data.surface as surface import constants as const + import data.surface as surface + import project as prj # Instead of calling wx.Dialog.__init__ we precreate the dialog # so we can set an extra style that must be set before @@ -420,57 +420,98 @@ class NewSurfaceDialog(wx.Dialog): self.CenterOnScreen() - # Now continue with the normal construction of the dialog - # contents + # LINE 1: Surface name + + label_surface = wx.StaticText(self, -1, _("New surface name:")) + + default_name = const.SURFACE_NAME_PATTERN %(surface.Surface.general_index+2) + text = wx.TextCtrl(self, -1, "", size=(80,-1)) + text.SetHelpText(_("Name the surface to be created")) + text.SetValue(default_name) + self.text = text - # Label related to mask name - label_mask = wx.StaticText(self, -1, _("Select mask to be used for creating 3D surface:")) + # LINE 2: Mask of reference - # Combo related to mask name - combo_surface_name = wx.ComboBox(self, -1, "", choices= MASK_LIST, + # Informative label + label_mask = wx.StaticText(self, -1, _("Mask of reference:")) + + # Retrieve existing masks + project = prj.Project() + index_list = project.mask_dict.keys() + index_list.sort() + self.mask_list = [project.mask_dict[index].name for index in index_list] + + + # Mask selection combo + combo_mask = wx.ComboBox(self, -1, "", choices= self.mask_list, style=wx.CB_DROPDOWN|wx.CB_READONLY) - combo_surface_name.SetSelection(0) + combo_mask.SetSelection(len(self.mask_list)-1) if sys.platform != 'win32': - combo_surface_name.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) - self.combo_surface_name = combo_surface_name + combo_mask.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) + self.combo_mask = combo_mask + # LINE 3: Surface quality + label_quality = wx.StaticText(self, -1, _("Surface quality:")) - label_surface = wx.StaticText(self, -1, _("Set new surface name:")) + combo_quality = wx.ComboBox(self, -1, "", choices= const.SURFACE_QUALITY_LIST, + style=wx.CB_DROPDOWN|wx.CB_READONLY) + combo_quality.SetSelection(3) + if sys.platform != 'win32': + combo_quality.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) + self.combo_quality = combo_quality - text = wx.TextCtrl(self, -1, "", size=(80,-1)) - text.SetHelpText(_("Name of the new surface to be created")) - default_name = const.SURFACE_NAME_PATTERN %(surface.Surface.general_index+2) - text.SetValue(default_name) - self.text = text + # OVERVIEW + # Sizer that joins content above + flag_link = wx.EXPAND|wx.GROW|wx.ALL + flag_button = wx.ALL | wx.EXPAND| wx.GROW - sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(label_mask, 0, wx.ALL|wx.GROW|wx.EXPAND, 5) - sizer.Add(combo_surface_name, 1, wx.GROW|wx.EXPAND|wx.LEFT|wx.RIGHT, 10) - sizer.Add(label_surface, 0, wx.ALL|wx.GROW|wx.EXPAND, 5) - sizer.Add(text, 0, wx.GROW|wx.EXPAND|wx.RIGHT|wx.LEFT, 10) + fixed_sizer = wx.FlexGridSizer(rows=2, cols=2, hgap=10, vgap=0) + fixed_sizer.AddGrowableCol(0, 1) + fixed_sizer.AddMany([ (label_surface, 1, flag_link, 5), + (text, 1, flag_button, 2), + (label_mask, 1, flag_link, 5), + (combo_mask, 0, flag_button, 1), + (label_quality, 1, flag_link, 5), + (combo_quality, 0, flag_button, 1)]) - btnsizer = wx.StdDialogButtonSizer() - #if wx.Platform != "__WXMSW__": - # btn = wx.ContextHelpButton(self) - # btnsizer.AddButton(btn) + # LINES 4 and 5: Checkboxes + check_box_holes = wx.CheckBox(self, -1, _("Fill holes")) + check_box_holes.SetValue(True) + self.check_box_holes = check_box_holes + check_box_largest = wx.CheckBox(self, -1, _("Keep largest region")) + self.check_box_largest = check_box_largest - btn = wx.Button(self, wx.ID_OK) - btn.SetDefault() - btnsizer.AddButton(btn) + # LINE 6: Buttons - btn = wx.Button(self, wx.ID_CANCEL) - btnsizer.AddButton(btn) + btn_ok = wx.Button(self, wx.ID_OK) + btn_ok.SetDefault() + btn_cancel = wx.Button(self, wx.ID_CANCEL) + + btnsizer = wx.StdDialogButtonSizer() + btnsizer.AddButton(btn_ok) + btnsizer.AddButton(btn_cancel) btnsizer.Realize() - sizer.Add(btnsizer, 0, wx.ALIGN_RIGHT|wx.ALL, 5) + # OVERVIEW + # Merge all sizers and checkboxes + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(fixed_sizer, 0, wx.TOP|wx.RIGHT|wx.LEFT|wx.GROW|wx.EXPAND, 20) + sizer.Add(check_box_holes, 0, wx.RIGHT|wx.LEFT, 30) + sizer.Add(check_box_largest, 0, wx.RIGHT|wx.LEFT, 30) + sizer.Add(btnsizer, 0, wx.ALIGN_RIGHT|wx.ALL, 10) self.SetSizer(sizer) sizer.Fit(self) - #def GetValue(self): - # return self.text.GetValue() + _("| mask: ") + MASK_LIST[self.combo_surface_name.GetSelection()] + def GetValue(self): + mask_index = self.combo_mask.GetSelection() + surface_name = self.text.GetValue() + quality = const.SURFACE_QUALITY_LIST[self.combo_quality.GetSelection()] + fill_holes = self.check_box_holes.GetValue() + keep_largest = self.check_box_largest.GetValue() + return (mask_index, surface_name, quality, fill_holes, keep_largest) INDEX_TO_EXTENSION = {0: "bmp", 1: "jpg", 2: "png", 3: "ps", 4:"povray", 5:"tiff"} WILDCARD_SAVE_PICTURE = _("BMP image")+" (*.bmp)|*.bmp|"+\ diff --git a/invesalius/gui/task_surface.py b/invesalius/gui/task_surface.py index 5809a90..c41f2ca 100644 --- a/invesalius/gui/task_surface.py +++ b/invesalius/gui/task_surface.py @@ -26,6 +26,7 @@ import wx.lib.pubsub as ps import gui.dialogs as dlg import gui.widgets.foldpanelbar as fpb import gui.widgets.colourselect as csel +import project as prj import utils as utl #INTERPOLATION_MODE_LIST = ["Cubic", "Linear", "NearestNeighbor"] @@ -130,7 +131,27 @@ class InnerTaskPanel(wx.Panel): #import gui.dialogs as dlg dialog = dlg.NewSurfaceDialog(self, -1, _('InVesalius 3 - New surface')) if dialog.ShowModal() == wx.ID_OK: - print "TODO: Send Signal - Create 3d surface %s \n" % dialog.GetValue() + # Retrieve information from dialog + (mask_index, surface_name, surface_quality, fill_holes,\ + keep_largest) = dialog.GetValue() + + # Retrieve information from mask + proj = prj.Project() + mask = proj.mask_dict[mask_index] + + # Send all information so surface can be created + surface_data = [proj.imagedata, + mask.colour, + mask.threshold_range, + mask.edited_points, + False, # overwrite + surface_name, + surface_quality, + fill_holes, + keep_largest] + + ps.Publisher().sendMessage('Create surface', surface_data) + print "TODO: Send Signal - Create 3d surface %s \n" % surface_data dialog.Destroy() if evt: evt.Skip() diff --git a/invesalius/project.py b/invesalius/project.py index 014cee0..c0e394a 100755 --- a/invesalius/project.py +++ b/invesalius/project.py @@ -266,8 +266,6 @@ class Project(object): self.surface_dict[s.index] = s else: setattr(self, key, project[key]) - #print "depois", self.__dict__ - def Compress(folder, filename): -- libgit2 0.21.2