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 342 def clear_history(self):
343 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 374 # for l in xrange(nlabels):
354 375 # trues = (labels == l)
... ...
invesalius/data/slice_.py
... ... @@ -1486,8 +1486,19 @@ class Slice(object):
1486 1486 #iu.Export(imagedata, filename)
1487 1487  
1488 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 1503 self.buffer_slices['AXIAL'].discard_mask()
1493 1504 self.buffer_slices['CORONAL'].discard_mask()
... ...
invesalius/gui/dialogs.py
... ... @@ -1891,6 +1891,21 @@ class Panel2DConnectivity(wx.Panel):
1891 1891 sizer.Fit(self)
1892 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 1910 class Panel3DConnectivity(wx.Panel):
1896 1911 def __init__(self, parent, ID=-1, style=wx.TAB_TRAVERSAL|wx.NO_BORDER):
... ... @@ -1915,6 +1930,14 @@ class Panel3DConnectivity(wx.Panel):
1915 1930 sizer.Fit(self)
1916 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 1942 class PanelFFillThreshold(wx.Panel):
1920 1943 def __init__(self, parent, config, ID=-1, style=wx.TAB_TRAVERSAL|wx.NO_BORDER):
... ... @@ -2484,7 +2507,7 @@ class CropOptionsDialog(wx.Dialog):
2484 2507  
2485 2508  
2486 2509 class FillHolesAutoDialog(wx.Dialog):
2487   - def __init__(self, title, config):
  2510 + def __init__(self, title):
2488 2511 pre = wx.PreDialog()
2489 2512 pre.Create(wx.GetApp().GetTopWindow(), -1, title, style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT)
2490 2513 self.PostCreate(pre)
... ... @@ -2522,49 +2545,52 @@ class FillHolesAutoDialog(wx.Dialog):
2522 2545 sizer.AddSpacer(5)
2523 2546 sizer.Add(self.panel3dcon, flag=wx.LEFT|wx.RIGHT|wx.EXPAND, border=7)
2524 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 2555 sizer.AddSpacer(5)
2528 2556  
2529 2557 self.SetSizer(sizer)
2530 2558 sizer.Fit(self)
2531 2559 self.Layout()
2532 2560  
  2561 + self.apply_btn.Bind(wx.EVT_BUTTON, self.OnApply)
2533 2562 self.close_btn.Bind(wx.EVT_BUTTON, self.OnBtnClose)
2534 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 2585 def OnBtnClose(self, evt):
2538 2586 self.Close()
  2587 + self.Destroy()
2539 2588  
2540 2589 def OnSetRadio(self, evt):
2541 2590 # Target
2542 2591 if self.panel_target.target_2d.GetValue():
2543   - self.config.target = "2D"
2544 2592 self.panel2dcon.Enable(1)
2545 2593 self.panel3dcon.Enable(0)
2546 2594 else:
2547   - self.config.target = "3D"
2548 2595 self.panel3dcon.Enable(1)
2549 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 597  
598 598 def OnFillHolesAutomatically(self):
599 599 # Publisher.sendMessage('Fill holes automatically')
600   - fdlg = dlg.FillHolesAutoDialog()
  600 + fdlg = dlg.FillHolesAutoDialog(_(u"Fill holes automatically"))
601 601 fdlg.Show()
602 602  
603 603 def OnRemoveMaskParts(self):
... ...