From 6d41707629230a8aef06bc33568a79da6e0f4ec5 Mon Sep 17 00:00:00 2001 From: Thiago Franco de Moraes Date: Thu, 22 Sep 2016 10:44:31 -0300 Subject: [PATCH] 2d and 3d holes filling --- invesalius/data/mask.py | 33 +++++++++++++++++++++++++++------ invesalius/data/slice_.py | 15 +++++++++++++-- invesalius/gui/dialogs.py | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------- invesalius/gui/frame.py | 2 +- 4 files changed, 94 insertions(+), 36 deletions(-) diff --git a/invesalius/data/mask.py b/invesalius/data/mask.py index 30b6b78..6275f30 100644 --- a/invesalius/data/mask.py +++ b/invesalius/data/mask.py @@ -342,13 +342,34 @@ class Mask(): def clear_history(self): self.history.clear_history() - def fill_holes_auto(self, idx): - matrix = self.matrix[idx+1, 1:, 1:] - matrix = matrix.reshape(1, matrix.shape[0], matrix.shape[1]) - imask = (~(matrix > 127)) - labels, nlabels = ndimage.label(imask, output=np.uint16) + def fill_holes_auto(self, target, conn, orientation, index, size): + CON2D = {4: 1, 8: 2} + CON3D = {6: 1, 18: 2, 26: 3} - floodfill.fill_holes_automatically(matrix, labels, nlabels, 100000) + if target == '3D': + matrix = self.matrix[1:, 1:, 1:] + bstruct = ndimage.generate_binary_structure(3, CON3D[conn]) + + imask = (~(matrix > 127)) + labels, nlabels = ndimage.label(imask, bstruct, output=np.uint16) + else: + bstruct = ndimage.generate_binary_structure(2, CON2D[conn]) + + if orientation == 'AXIAL': + matrix = self.matrix[index+1, 1:, 1:] + elif orientation == 'CORONAL': + matrix = self.matrix[1:, index+1, 1:] + elif orientation == 'SAGITAL': + matrix = self.matrix[1:, 1:, index+1] + + imask = (~(matrix > 127)) + labels, nlabels = ndimage.label(imask, bstruct, output=np.uint16) + + labels = labels.reshape(1, labels.shape[0], labels.shape[1]) + matrix = matrix.reshape(1, matrix.shape[0], matrix.shape[1]) + + + floodfill.fill_holes_automatically(matrix, labels, nlabels, size) # for l in xrange(nlabels): # trues = (labels == l) diff --git a/invesalius/data/slice_.py b/invesalius/data/slice_.py index 1673ad6..65433bb 100644 --- a/invesalius/data/slice_.py +++ b/invesalius/data/slice_.py @@ -1486,8 +1486,19 @@ class Slice(object): #iu.Export(imagedata, filename) def _fill_holes_auto(self, pubsub_evt): - self.do_threshold_to_all_slices() - self.current_mask.fill_holes_auto(self.buffer_slices['AXIAL'].index) + data = pubsub_evt.data + target = data['target'] + conn = data['conn'] + orientation = data['orientation'] + size = data['size'] + + if target == '2D': + index = self.buffer_slices[orientation].index + else: + index = 0 + self.do_threshold_to_all_slices() + + self.current_mask.fill_holes_auto(target, conn, orientation, index, size) self.buffer_slices['AXIAL'].discard_mask() self.buffer_slices['CORONAL'].discard_mask() diff --git a/invesalius/gui/dialogs.py b/invesalius/gui/dialogs.py index 3f1640e..97d3ebf 100644 --- a/invesalius/gui/dialogs.py +++ b/invesalius/gui/dialogs.py @@ -1891,6 +1891,21 @@ class Panel2DConnectivity(wx.Panel): sizer.Fit(self) self.Layout() + def GetConnSelected(self): + if self.conect2D_4.GetValue(): + return 4 + else: + return 8 + + def GetOrientation(self): + dic_ori = { + _(u"Axial"): 'AXIAL', + _(u"Coronal"): 'CORONAL', + _(u"Sagital"): 'SAGITAL' + } + + return dic_ori[self.cmb_orientation.GetStringSelection()] + class Panel3DConnectivity(wx.Panel): def __init__(self, parent, ID=-1, style=wx.TAB_TRAVERSAL|wx.NO_BORDER): @@ -1915,6 +1930,14 @@ class Panel3DConnectivity(wx.Panel): sizer.Fit(self) self.Layout() + def GetConnSelected(self): + if self.conect3D_6.GetValue(): + return 6 + elif self.conect3D_18.GetValue(): + return 18 + else: + return 26 + class PanelFFillThreshold(wx.Panel): def __init__(self, parent, config, ID=-1, style=wx.TAB_TRAVERSAL|wx.NO_BORDER): @@ -2484,7 +2507,7 @@ class CropOptionsDialog(wx.Dialog): class FillHolesAutoDialog(wx.Dialog): - def __init__(self, title, config): + def __init__(self, title): pre = wx.PreDialog() pre.Create(wx.GetApp().GetTopWindow(), -1, title, style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT) self.PostCreate(pre) @@ -2522,49 +2545,52 @@ class FillHolesAutoDialog(wx.Dialog): sizer.AddSpacer(5) sizer.Add(self.panel3dcon, flag=wx.LEFT|wx.RIGHT|wx.EXPAND, border=7) sizer.AddSpacer(5) - sizer.Add(self.apply_btn, 0, flag=wx.ALIGN_RIGHT|wx.RIGHT, border=7) - sizer.Add(self.close_btn, 0, flag=wx.ALIGN_RIGHT|wx.RIGHT, border=7) + + btn_sizer = wx.BoxSizer(wx.HORIZONTAL) + btn_sizer.Add(self.apply_btn, 0, flag=wx.ALIGN_RIGHT, border=5) + btn_sizer.Add(self.close_btn, 0, flag=wx.LEFT|wx.ALIGN_RIGHT, border=5) + + sizer.AddSizer(btn_sizer, 0, flag=wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT, border=5) + sizer.AddSpacer(5) self.SetSizer(sizer) sizer.Fit(self) self.Layout() + self.apply_btn.Bind(wx.EVT_BUTTON, self.OnApply) self.close_btn.Bind(wx.EVT_BUTTON, self.OnBtnClose) self.Bind(wx.EVT_RADIOBUTTON, self.OnSetRadio) - self.Bind(wx.EVT_CLOSE, self.OnClose) + + def OnApply(self, evt): + if self.panel_target.target_2d.GetValue(): + target = "2D" + conn = self.panel2dcon.GetConnSelected() + orientation = self.panel2dcon.GetOrientation() + else: + target = "3D" + conn = self.panel3dcon.GetConnSelected() + orientation = '' + + data = { + 'target': target, + 'conn': conn, + 'orientation': orientation, + 'size': 1000, + } + + Publisher.sendMessage("Fill holes automatically", data) + def OnBtnClose(self, evt): self.Close() + self.Destroy() def OnSetRadio(self, evt): # Target if self.panel_target.target_2d.GetValue(): - self.config.target = "2D" self.panel2dcon.Enable(1) self.panel3dcon.Enable(0) else: - self.config.target = "3D" self.panel3dcon.Enable(1) self.panel2dcon.Enable(0) - - # 2D - if self.panel2dcon.conect2D_4.GetValue(): - self.config.con_2d = 4 - elif self.panel2dcon.conect2D_8.GetValue(): - self.config.con_2d = 8 - - # 3D - if self.panel3dcon.conect3D_6.GetValue(): - self.config.con_3d = 6 - elif self.panel3dcon.conect3D_18.GetValue(): - self.config.con_3d = 18 - elif self.panel3dcon.conect3D_26.GetValue(): - self.config.con_3d = 26 - - def OnClose(self, evt): - print "ONCLOSE" - if self.config.dlg_visible: - Publisher.sendMessage('Disable style', const.SLICE_STATE_MASK_FFILL) - evt.Skip() - self.Destroy() diff --git a/invesalius/gui/frame.py b/invesalius/gui/frame.py index 925cc43..1c97e67 100644 --- a/invesalius/gui/frame.py +++ b/invesalius/gui/frame.py @@ -597,7 +597,7 @@ class Frame(wx.Frame): def OnFillHolesAutomatically(self): # Publisher.sendMessage('Fill holes automatically') - fdlg = dlg.FillHolesAutoDialog() + fdlg = dlg.FillHolesAutoDialog(_(u"Fill holes automatically")) fdlg.Show() def OnRemoveMaskParts(self): -- libgit2 0.21.2