Commit 6d41707629230a8aef06bc33568a79da6e0f4ec5

Authored by Thiago Franco de Moraes
1 parent 03ed982b
Exists in fill_holes_auto

2d and 3d holes filling

invesalius/data/mask.py
@@ -342,13 +342,34 @@ class Mask(): @@ -342,13 +342,34 @@ class Mask():
342 def clear_history(self): 342 def clear_history(self):
343 self.history.clear_history() 343 self.history.clear_history()
344 344
345 - def fill_holes_auto(self, idx):  
346 - matrix = self.matrix[idx+1, 1:, 1:]  
347 - matrix = matrix.reshape(1, matrix.shape[0], matrix.shape[1])  
348 - imask = (~(matrix > 127))  
349 - labels, nlabels = ndimage.label(imask, output=np.uint16) 345 + def fill_holes_auto(self, target, conn, orientation, index, size):
  346 + CON2D = {4: 1, 8: 2}
  347 + CON3D = {6: 1, 18: 2, 26: 3}
350 348
351 - floodfill.fill_holes_automatically(matrix, labels, nlabels, 100000) 349 + if target == '3D':
  350 + matrix = self.matrix[1:, 1:, 1:]
  351 + bstruct = ndimage.generate_binary_structure(3, CON3D[conn])
  352 +
  353 + imask = (~(matrix > 127))
  354 + labels, nlabels = ndimage.label(imask, bstruct, output=np.uint16)
  355 + else:
  356 + bstruct = ndimage.generate_binary_structure(2, CON2D[conn])
  357 +
  358 + if orientation == 'AXIAL':
  359 + matrix = self.matrix[index+1, 1:, 1:]
  360 + elif orientation == 'CORONAL':
  361 + matrix = self.matrix[1:, index+1, 1:]
  362 + elif orientation == 'SAGITAL':
  363 + matrix = self.matrix[1:, 1:, index+1]
  364 +
  365 + imask = (~(matrix > 127))
  366 + labels, nlabels = ndimage.label(imask, bstruct, output=np.uint16)
  367 +
  368 + labels = labels.reshape(1, labels.shape[0], labels.shape[1])
  369 + matrix = matrix.reshape(1, matrix.shape[0], matrix.shape[1])
  370 +
  371 +
  372 + floodfill.fill_holes_automatically(matrix, labels, nlabels, size)
352 373
353 # for l in xrange(nlabels): 374 # for l in xrange(nlabels):
354 # trues = (labels == l) 375 # trues = (labels == l)
invesalius/data/slice_.py
@@ -1486,8 +1486,19 @@ class Slice(object): @@ -1486,8 +1486,19 @@ class Slice(object):
1486 #iu.Export(imagedata, filename) 1486 #iu.Export(imagedata, filename)
1487 1487
1488 def _fill_holes_auto(self, pubsub_evt): 1488 def _fill_holes_auto(self, pubsub_evt):
1489 - self.do_threshold_to_all_slices()  
1490 - self.current_mask.fill_holes_auto(self.buffer_slices['AXIAL'].index) 1489 + data = pubsub_evt.data
  1490 + target = data['target']
  1491 + conn = data['conn']
  1492 + orientation = data['orientation']
  1493 + size = data['size']
  1494 +
  1495 + if target == '2D':
  1496 + index = self.buffer_slices[orientation].index
  1497 + else:
  1498 + index = 0
  1499 + self.do_threshold_to_all_slices()
  1500 +
  1501 + self.current_mask.fill_holes_auto(target, conn, orientation, index, size)
1491 1502
1492 self.buffer_slices['AXIAL'].discard_mask() 1503 self.buffer_slices['AXIAL'].discard_mask()
1493 self.buffer_slices['CORONAL'].discard_mask() 1504 self.buffer_slices['CORONAL'].discard_mask()
invesalius/gui/dialogs.py
@@ -1891,6 +1891,21 @@ class Panel2DConnectivity(wx.Panel): @@ -1891,6 +1891,21 @@ class Panel2DConnectivity(wx.Panel):
1891 sizer.Fit(self) 1891 sizer.Fit(self)
1892 self.Layout() 1892 self.Layout()
1893 1893
  1894 + def GetConnSelected(self):
  1895 + if self.conect2D_4.GetValue():
  1896 + return 4
  1897 + else:
  1898 + return 8
  1899 +
  1900 + def GetOrientation(self):
  1901 + dic_ori = {
  1902 + _(u"Axial"): 'AXIAL',
  1903 + _(u"Coronal"): 'CORONAL',
  1904 + _(u"Sagital"): 'SAGITAL'
  1905 + }
  1906 +
  1907 + return dic_ori[self.cmb_orientation.GetStringSelection()]
  1908 +
1894 1909
1895 class Panel3DConnectivity(wx.Panel): 1910 class Panel3DConnectivity(wx.Panel):
1896 def __init__(self, parent, ID=-1, style=wx.TAB_TRAVERSAL|wx.NO_BORDER): 1911 def __init__(self, parent, ID=-1, style=wx.TAB_TRAVERSAL|wx.NO_BORDER):
@@ -1915,6 +1930,14 @@ class Panel3DConnectivity(wx.Panel): @@ -1915,6 +1930,14 @@ class Panel3DConnectivity(wx.Panel):
1915 sizer.Fit(self) 1930 sizer.Fit(self)
1916 self.Layout() 1931 self.Layout()
1917 1932
  1933 + def GetConnSelected(self):
  1934 + if self.conect3D_6.GetValue():
  1935 + return 6
  1936 + elif self.conect3D_18.GetValue():
  1937 + return 18
  1938 + else:
  1939 + return 26
  1940 +
1918 1941
1919 class PanelFFillThreshold(wx.Panel): 1942 class PanelFFillThreshold(wx.Panel):
1920 def __init__(self, parent, config, ID=-1, style=wx.TAB_TRAVERSAL|wx.NO_BORDER): 1943 def __init__(self, parent, config, ID=-1, style=wx.TAB_TRAVERSAL|wx.NO_BORDER):
@@ -2484,7 +2507,7 @@ class CropOptionsDialog(wx.Dialog): @@ -2484,7 +2507,7 @@ class CropOptionsDialog(wx.Dialog):
2484 2507
2485 2508
2486 class FillHolesAutoDialog(wx.Dialog): 2509 class FillHolesAutoDialog(wx.Dialog):
2487 - def __init__(self, title, config): 2510 + def __init__(self, title):
2488 pre = wx.PreDialog() 2511 pre = wx.PreDialog()
2489 pre.Create(wx.GetApp().GetTopWindow(), -1, title, style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT) 2512 pre.Create(wx.GetApp().GetTopWindow(), -1, title, style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT)
2490 self.PostCreate(pre) 2513 self.PostCreate(pre)
@@ -2522,49 +2545,52 @@ class FillHolesAutoDialog(wx.Dialog): @@ -2522,49 +2545,52 @@ class FillHolesAutoDialog(wx.Dialog):
2522 sizer.AddSpacer(5) 2545 sizer.AddSpacer(5)
2523 sizer.Add(self.panel3dcon, flag=wx.LEFT|wx.RIGHT|wx.EXPAND, border=7) 2546 sizer.Add(self.panel3dcon, flag=wx.LEFT|wx.RIGHT|wx.EXPAND, border=7)
2524 sizer.AddSpacer(5) 2547 sizer.AddSpacer(5)
2525 - sizer.Add(self.apply_btn, 0, flag=wx.ALIGN_RIGHT|wx.RIGHT, border=7)  
2526 - sizer.Add(self.close_btn, 0, flag=wx.ALIGN_RIGHT|wx.RIGHT, border=7) 2548 +
  2549 + btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
  2550 + btn_sizer.Add(self.apply_btn, 0, flag=wx.ALIGN_RIGHT, border=5)
  2551 + btn_sizer.Add(self.close_btn, 0, flag=wx.LEFT|wx.ALIGN_RIGHT, border=5)
  2552 +
  2553 + sizer.AddSizer(btn_sizer, 0, flag=wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT, border=5)
  2554 +
2527 sizer.AddSpacer(5) 2555 sizer.AddSpacer(5)
2528 2556
2529 self.SetSizer(sizer) 2557 self.SetSizer(sizer)
2530 sizer.Fit(self) 2558 sizer.Fit(self)
2531 self.Layout() 2559 self.Layout()
2532 2560
  2561 + self.apply_btn.Bind(wx.EVT_BUTTON, self.OnApply)
2533 self.close_btn.Bind(wx.EVT_BUTTON, self.OnBtnClose) 2562 self.close_btn.Bind(wx.EVT_BUTTON, self.OnBtnClose)
2534 self.Bind(wx.EVT_RADIOBUTTON, self.OnSetRadio) 2563 self.Bind(wx.EVT_RADIOBUTTON, self.OnSetRadio)
2535 - self.Bind(wx.EVT_CLOSE, self.OnClose) 2564 +
  2565 + def OnApply(self, evt):
  2566 + if self.panel_target.target_2d.GetValue():
  2567 + target = "2D"
  2568 + conn = self.panel2dcon.GetConnSelected()
  2569 + orientation = self.panel2dcon.GetOrientation()
  2570 + else:
  2571 + target = "3D"
  2572 + conn = self.panel3dcon.GetConnSelected()
  2573 + orientation = ''
  2574 +
  2575 + data = {
  2576 + 'target': target,
  2577 + 'conn': conn,
  2578 + 'orientation': orientation,
  2579 + 'size': 1000,
  2580 + }
  2581 +
  2582 + Publisher.sendMessage("Fill holes automatically", data)
  2583 +
2536 2584
2537 def OnBtnClose(self, evt): 2585 def OnBtnClose(self, evt):
2538 self.Close() 2586 self.Close()
  2587 + self.Destroy()
2539 2588
2540 def OnSetRadio(self, evt): 2589 def OnSetRadio(self, evt):
2541 # Target 2590 # Target
2542 if self.panel_target.target_2d.GetValue(): 2591 if self.panel_target.target_2d.GetValue():
2543 - self.config.target = "2D"  
2544 self.panel2dcon.Enable(1) 2592 self.panel2dcon.Enable(1)
2545 self.panel3dcon.Enable(0) 2593 self.panel3dcon.Enable(0)
2546 else: 2594 else:
2547 - self.config.target = "3D"  
2548 self.panel3dcon.Enable(1) 2595 self.panel3dcon.Enable(1)
2549 self.panel2dcon.Enable(0) 2596 self.panel2dcon.Enable(0)
2550 -  
2551 - # 2D  
2552 - if self.panel2dcon.conect2D_4.GetValue():  
2553 - self.config.con_2d = 4  
2554 - elif self.panel2dcon.conect2D_8.GetValue():  
2555 - self.config.con_2d = 8  
2556 -  
2557 - # 3D  
2558 - if self.panel3dcon.conect3D_6.GetValue():  
2559 - self.config.con_3d = 6  
2560 - elif self.panel3dcon.conect3D_18.GetValue():  
2561 - self.config.con_3d = 18  
2562 - elif self.panel3dcon.conect3D_26.GetValue():  
2563 - self.config.con_3d = 26  
2564 -  
2565 - def OnClose(self, evt):  
2566 - print "ONCLOSE"  
2567 - if self.config.dlg_visible:  
2568 - Publisher.sendMessage('Disable style', const.SLICE_STATE_MASK_FFILL)  
2569 - evt.Skip()  
2570 - self.Destroy()  
invesalius/gui/frame.py
@@ -597,7 +597,7 @@ class Frame(wx.Frame): @@ -597,7 +597,7 @@ class Frame(wx.Frame):
597 597
598 def OnFillHolesAutomatically(self): 598 def OnFillHolesAutomatically(self):
599 # Publisher.sendMessage('Fill holes automatically') 599 # Publisher.sendMessage('Fill holes automatically')
600 - fdlg = dlg.FillHolesAutoDialog() 600 + fdlg = dlg.FillHolesAutoDialog(_(u"Fill holes automatically"))
601 fdlg.Show() 601 fdlg.Show()
602 602
603 def OnRemoveMaskParts(self): 603 def OnRemoveMaskParts(self):