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 | 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): | ... | ... |