From 92f1f1a7a51b402386f88fa4d23a850a5d4ddece Mon Sep 17 00:00:00 2001 From: Thiago Franco de Moraes Date: Wed, 2 Jul 2014 16:07:42 -0300 Subject: [PATCH] Added a gui to set some configs from watershed --- invesalius/data/styles.py | 54 ++++++++++++++++++++++++++++++++++++++++++++---------- invesalius/gui/dialogs.py | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ invesalius/gui/task_slice.py | 11 ++++++++++- 3 files changed, 139 insertions(+), 11 deletions(-) diff --git a/invesalius/data/styles.py b/invesalius/data/styles.py index 84a6e36..b70532f 100644 --- a/invesalius/data/styles.py +++ b/invesalius/data/styles.py @@ -32,6 +32,7 @@ import numpy as np from scipy import ndimage from scipy.misc import imsave +from scipy.ndimage import watershed_ift, generate_binary_structure from skimage.morphology import watershed from skimage import filter @@ -740,20 +741,45 @@ class EditorInteractorStyle(DefaultInteractorStyle): class WatershedConfig(object): __metaclass__= utils.Singleton def __init__(self): - self.operation = BRUSH_FOREGROUND + self.algorithm = "Watershed" + self.con_2d = 4 + self.con_3d = 18 + self.mg_size = 3 self.use_ww_wl = True + self.operation = BRUSH_FOREGROUND self.cursor_type = const.BRUSH_CIRCLE self.cursor_size = const.BRUSH_SIZE Publisher.subscribe(self.set_operation, 'Set watershed operation') Publisher.subscribe(self.set_use_ww_wl, 'Set use ww wl') + Publisher.subscribe(self.set_algorithm, "Set watershed algorithm") + Publisher.subscribe(self.set_2dcon, "Set watershed 2d con") + Publisher.subscribe(self.set_3dcon, "Set watershed 3d con") + Publisher.subscribe(self.set_gaussian_size, "Set watershed gaussian size") + def set_operation(self, pubsub_evt): self.operation = WATERSHED_OPERATIONS[pubsub_evt.data] def set_use_ww_wl(self, pubsub_evt): self.use_ww_wl = pubsub_evt.data + def set_algorithm(self, pubsub_evt): + self.algorithm = pubsub_evt.data + + def set_2dcon(self, pubsub_evt): + self.con_2d = pubsub_evt.data + + def set_3dcon(self, pubsub_evt): + self.con_3d = pubsub_evt.data + + def set_gaussian_size(self, pubsub_evt): + self.mg_size = pubsub_evt.data + +WALGORITHM = {"Watershed": watershed, + "Watershed IFT": watershed_ift} +CON2D = {4: 1, 8: 2} +CON3D = {6: 1, 18: 2, 26: 3} class WaterShedInteractorStyle(DefaultInteractorStyle): def __init__(self, viewer): @@ -765,7 +791,6 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): self.operation = BRUSH_FOREGROUND - self.mg_size = 3 self.config = WatershedConfig() self.picker = vtk.vtkWorldPointPicker() @@ -1047,12 +1072,17 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): wl = self.viewer.slice_.window_level if BRUSH_BACKGROUND in markers and BRUSH_FOREGROUND in markers: + w_algorithm = WALGORITHM[self.config.algorithm] + bstruct = generate_binary_structure(2, CON2D[self.config.con_2d]) if self.config.use_ww_wl: - tmp_image = ndimage.morphological_gradient(get_LUT_value(image, ww, wl).astype('uint16'), self.mg_size) - tmp_mask = watershed(tmp_image, markers) + tmp_image = ndimage.morphological_gradient( + get_LUT_value(image, ww, wl).astype('uint16'), + self.config.mg_size) + + tmp_mask = w_algorithm(tmp_image, markers.astype('int16'), bstruct) else: - tmp_image = ndimage.morphological_gradient(image, self.mg_size) - tmp_mask = watershed(tmp_image, markers) + tmp_image = ndimage.morphological_gradient(image, self.config.mg_size) + tmp_mask = w_algorithm(tmp_image, markers.astype('int16'), bstruct) if self.viewer.overwrite_mask: mask[:] = 0 @@ -1158,12 +1188,16 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): ww = self.viewer.slice_.window_width wl = self.viewer.slice_.window_level if BRUSH_BACKGROUND in markers and BRUSH_FOREGROUND in markers: + w_algorithm = WALGORITHM[self.config.algorithm] + bstruct = generate_binary_structure(3, CON3D[self.config.con_3d]) if self.config.use_ww_wl: - tmp_image = ndimage.morphological_gradient(get_LUT_value(image, ww, wl).astype('uint16'), self.mg_size) - tmp_mask = watershed(tmp_image, markers) + tmp_image = ndimage.morphological_gradient( + get_LUT_value(image, ww, wl).astype('uint16'), + self.config.mg_size) + tmp_mask = w_algorithm(tmp_image, markers.astype('int16'), bstruct) else: - tmp_image = ndimage.morphological_gradient(image, self.mg_size) - tmp_mask = watershed(tmp_image, markers) + tmp_image = ndimage.morphological_gradient(image, self.config.mg_size) + tmp_mask = w_algorithm(tmp_image, markers.astype('int16'), bstruct) if self.viewer.overwrite_mask: mask[:] = 0 diff --git a/invesalius/gui/dialogs.py b/invesalius/gui/dialogs.py index c6d7271..949d35b 100644 --- a/invesalius/gui/dialogs.py +++ b/invesalius/gui/dialogs.py @@ -1384,3 +1384,88 @@ class ClutImagedataDialog(wx.Dialog): super(wx.Dialog, self).Show(show) if gen_evt: self.clut_widget._generate_event() + + +class WatershedOptions(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent) + + self.algorithms = ("Watershed", "Watershed IFT") + self.con2d_choices = (4, 8) + self.con3d_choices = (6, 18, 26) + + self._init_gui() + self._bind_events() + + def _init_gui(self): + self.choice_algorithm = wx.RadioBox(self, -1, "Algorithm", + choices=("Watershed", "Watershed IFT"), + style=wx.NO_BORDER | wx.HORIZONTAL) + + self.choice_2dcon = wx.RadioBox(self, -1, "2D", + choices=[str(i) for i in self.con2d_choices], + style=wx.NO_BORDER | wx.HORIZONTAL) + + self.choice_3dcon = wx.RadioBox(self, -1, "3D", + choices=[str(i) for i in self.con3d_choices], + style=wx.NO_BORDER | wx.HORIZONTAL) + + self.gaussian_size = wx.SpinCtrl(self, -1, "", min=1, max=10) + + box_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Conectivity"), wx.VERTICAL) + box_sizer.Add(self.choice_2dcon, 0, wx.ALIGN_CENTER_VERTICAL,2) + box_sizer.Add(self.choice_3dcon, 0, wx.ALIGN_CENTER_VERTICAL,2) + + g_sizer = wx.BoxSizer(wx.HORIZONTAL) + g_sizer.Add(wx.StaticText(self, -1, "Gaussian size"), 0, wx.ALIGN_RIGHT | wx.ALL, 5) + g_sizer.Add(self.gaussian_size, 0, wx.ALIGN_LEFT | wx.ALL, 5) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.choice_algorithm, 0, wx.ALIGN_CENTER_VERTICAL,2) + sizer.Add(box_sizer, 1, wx.EXPAND,2) + sizer.Add(g_sizer, 0, wx.ALIGN_LEFT, 2) + + self.SetSizer(sizer) + sizer.Fit(self) + self.Layout() + + def _bind_events(self): + self.choice_algorithm.Bind(wx.EVT_RADIOBOX, self.OnSetAlgorithm) + self.gaussian_size.Bind(wx.EVT_SPINCTRL, self.OnSetGaussianSize) + self.choice_2dcon.Bind(wx.EVT_RADIOBOX, self.OnSetCon2D) + self.choice_3dcon.Bind(wx.EVT_RADIOBOX, self.OnSetCon3D) + + def OnSetAlgorithm(self, evt): + v = self.algorithms[evt.GetInt()] + Publisher.sendMessage("Set watershed algorithm", v) + + def OnSetGaussianSize(self, evt): + v = self.gaussian_size.GetValue() + Publisher.sendMessage("Set watershed gaussian size", v) + + def OnSetCon2D(self, evt): + v = self.con2d_choices[evt.GetInt()] + Publisher.sendMessage("Set watershed 2d con", v) + + def OnSetCon3D(self, evt): + v = self.con3d_choices[evt.GetInt()] + Publisher.sendMessage("Set watershed 3d con", v) + + +class WatershedOptionsDialog(wx.Dialog): + def __init__(self): + pre = wx.PreDialog() + pre.Create(wx.GetApp().GetTopWindow(), -1, style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT) + self.PostCreate(pre) + + self._init_gui() + + def _init_gui(self): + wop = WatershedOptions(self) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(wop, 0, wx.EXPAND) + + self.SetSizer(sizer) + sizer.Fit(self) + self.Layout() diff --git a/invesalius/gui/task_slice.py b/invesalius/gui/task_slice.py index d346467..8e10752 100644 --- a/invesalius/gui/task_slice.py +++ b/invesalius/gui/task_slice.py @@ -779,15 +779,20 @@ class WatershedTool(EditionTools): self.ww_wl_cbox = ww_wl_cbox # Line 6 + self.btn_wconfig = wx.Button(self, -1, "C", size=(48, -1)) self.btn_exp_watershed = wx.Button(self, -1, _('Expand watershed to 3D')) + sizer_btns = wx.BoxSizer(wx.HORIZONTAL) + sizer_btns.Add(self.btn_wconfig, 0, wx.ALIGN_LEFT | wx.LEFT | wx.TOP | wx.DOWN, 5) + sizer_btns.Add(self.btn_exp_watershed, 0, wx.GROW|wx.EXPAND| wx.ALL, 5) + # Add lines into main sizer sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(text1, 0, wx.GROW|wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 5) sizer.Add(line2, 0, wx.GROW|wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 5) sizer.Add(check_box, 0, wx.GROW|wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 5) sizer.Add(ww_wl_cbox, 0, wx.GROW|wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 5) - sizer.Add(self.btn_exp_watershed, 0, wx.GROW|wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 5) + sizer.Add(sizer_btns, 0, wx.EXPAND) sizer.Fit(self) self.SetSizer(sizer) @@ -803,6 +808,7 @@ class WatershedTool(EditionTools): self.check_box.Bind(wx.EVT_CHECKBOX, self.OnCheckOverwriteMask) self.ww_wl_cbox.Bind(wx.EVT_CHECKBOX, self.OnCheckWWWL) self.btn_exp_watershed.Bind(wx.EVT_BUTTON, self.OnExpandWatershed) + self.btn_wconfig.Bind(wx.EVT_BUTTON, self.OnConfig) def ChangeMaskColour(self, pubsub_evt): colour = pubsub_evt.data @@ -860,5 +866,8 @@ class WatershedTool(EditionTools): value = self.ww_wl_cbox.GetValue() Publisher.sendMessage('Set use ww wl', value) + def OnConfig(self, evt): + dlg.WatershedOptionsDialog().Show() + def OnExpandWatershed(self, evt): Publisher.sendMessage('Expand watershed to 3D AXIAL') -- libgit2 0.21.2