Commit 6d41707629230a8aef06bc33568a79da6e0f4ec5
1 parent
03ed982b
Exists in
fill_holes_auto
2d and 3d holes filling
Showing
4 changed files
with
94 additions
and
36 deletions
Show diff stats
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): |