Commit d54e05ee97b91d31a931b4ceb6ec2b7ea6face14
1 parent
a25e8aeb
Exists in
ffill_segmentation
Segmenting using floodfill
Showing
5 changed files
with
256 additions
and
3 deletions
Show diff stats
invesalius/constants.py
| @@ -484,6 +484,7 @@ ID_REORIENT_IMG = wx.NewId() | @@ -484,6 +484,7 @@ ID_REORIENT_IMG = wx.NewId() | ||
| 484 | ID_FLOODFILL_MASK = wx.NewId() | 484 | ID_FLOODFILL_MASK = wx.NewId() |
| 485 | ID_REMOVE_MASK_PART = wx.NewId() | 485 | ID_REMOVE_MASK_PART = wx.NewId() |
| 486 | ID_SELECT_MASK_PART = wx.NewId() | 486 | ID_SELECT_MASK_PART = wx.NewId() |
| 487 | +ID_FLOODFILL_SEGMENTATION = wx.NewId() | ||
| 487 | 488 | ||
| 488 | #--------------------------------------------------------- | 489 | #--------------------------------------------------------- |
| 489 | STATE_DEFAULT = 1000 | 490 | STATE_DEFAULT = 1000 |
| @@ -504,6 +505,7 @@ SLICE_STATE_REORIENT = 3010 | @@ -504,6 +505,7 @@ SLICE_STATE_REORIENT = 3010 | ||
| 504 | SLICE_STATE_MASK_FFILL = 3011 | 505 | SLICE_STATE_MASK_FFILL = 3011 |
| 505 | SLICE_STATE_REMOVE_MASK_PARTS = 3012 | 506 | SLICE_STATE_REMOVE_MASK_PARTS = 3012 |
| 506 | SLICE_STATE_SELECT_MASK_PARTS = 3013 | 507 | SLICE_STATE_SELECT_MASK_PARTS = 3013 |
| 508 | +SLICE_STATE_FFILL_SEGMENTATION = 3014 | ||
| 507 | 509 | ||
| 508 | VOLUME_STATE_SEED = 2001 | 510 | VOLUME_STATE_SEED = 2001 |
| 509 | # STATE_LINEAR_MEASURE = 3001 | 511 | # STATE_LINEAR_MEASURE = 3001 |
| @@ -524,6 +526,7 @@ SLICE_STYLES.append(SLICE_STATE_WATERSHED) | @@ -524,6 +526,7 @@ SLICE_STYLES.append(SLICE_STATE_WATERSHED) | ||
| 524 | SLICE_STYLES.append(SLICE_STATE_MASK_FFILL) | 526 | SLICE_STYLES.append(SLICE_STATE_MASK_FFILL) |
| 525 | SLICE_STYLES.append(SLICE_STATE_REMOVE_MASK_PARTS) | 527 | SLICE_STYLES.append(SLICE_STATE_REMOVE_MASK_PARTS) |
| 526 | SLICE_STYLES.append(SLICE_STATE_SELECT_MASK_PARTS) | 528 | SLICE_STYLES.append(SLICE_STATE_SELECT_MASK_PARTS) |
| 529 | +SLICE_STYLES.append(SLICE_STATE_FFILL_SEGMENTATION) | ||
| 527 | 530 | ||
| 528 | VOLUME_STYLES = TOOL_STATES + [VOLUME_STATE_SEED, STATE_MEASURE_DISTANCE, | 531 | VOLUME_STYLES = TOOL_STATES + [VOLUME_STATE_SEED, STATE_MEASURE_DISTANCE, |
| 529 | STATE_MEASURE_ANGLE] | 532 | STATE_MEASURE_ANGLE] |
| @@ -535,6 +538,7 @@ STYLE_LEVEL = {SLICE_STATE_EDITOR: 1, | @@ -535,6 +538,7 @@ STYLE_LEVEL = {SLICE_STATE_EDITOR: 1, | ||
| 535 | SLICE_STATE_MASK_FFILL: 2, | 538 | SLICE_STATE_MASK_FFILL: 2, |
| 536 | SLICE_STATE_REMOVE_MASK_PARTS: 2, | 539 | SLICE_STATE_REMOVE_MASK_PARTS: 2, |
| 537 | SLICE_STATE_SELECT_MASK_PARTS: 2, | 540 | SLICE_STATE_SELECT_MASK_PARTS: 2, |
| 541 | + SLICE_STATE_FFILL_SEGMENTATION: 2, | ||
| 538 | SLICE_STATE_CROSS: 2, | 542 | SLICE_STATE_CROSS: 2, |
| 539 | SLICE_STATE_SCROLL: 2, | 543 | SLICE_STATE_SCROLL: 2, |
| 540 | SLICE_STATE_REORIENT: 2, | 544 | SLICE_STATE_REORIENT: 2, |
invesalius/data/styles.py
| @@ -1841,6 +1841,120 @@ class SelectMaskPartsInteractorStyle(DefaultInteractorStyle): | @@ -1841,6 +1841,120 @@ class SelectMaskPartsInteractorStyle(DefaultInteractorStyle): | ||
| 1841 | self.config.mask = mask | 1841 | self.config.mask = mask |
| 1842 | 1842 | ||
| 1843 | 1843 | ||
| 1844 | +class FFillSegmentationConfig(object): | ||
| 1845 | + __metaclass__= utils.Singleton | ||
| 1846 | + def __init__(self): | ||
| 1847 | + self.dlg_visible = False | ||
| 1848 | + self.target = "2D" | ||
| 1849 | + self.con_2d = 4 | ||
| 1850 | + self.con_3d = 6 | ||
| 1851 | + | ||
| 1852 | + self.t0 = 0 | ||
| 1853 | + self.t1 = 100 | ||
| 1854 | + | ||
| 1855 | + self.fill_value = 254 | ||
| 1856 | + | ||
| 1857 | + | ||
| 1858 | +class FloodFillSegmentInteractorStyle(DefaultInteractorStyle): | ||
| 1859 | + def __init__(self, viewer): | ||
| 1860 | + DefaultInteractorStyle.__init__(self, viewer) | ||
| 1861 | + | ||
| 1862 | + self.viewer = viewer | ||
| 1863 | + self.orientation = self.viewer.orientation | ||
| 1864 | + | ||
| 1865 | + self.picker = vtk.vtkWorldPointPicker() | ||
| 1866 | + self.slice_actor = viewer.slice_data.actor | ||
| 1867 | + self.slice_data = viewer.slice_data | ||
| 1868 | + | ||
| 1869 | + self.config = FFillSegmentationConfig() | ||
| 1870 | + self.dlg_ffill = None | ||
| 1871 | + | ||
| 1872 | + self._progr_title = _(u"Fill hole") | ||
| 1873 | + self._progr_msg = _(u"Filling hole ...") | ||
| 1874 | + | ||
| 1875 | + self.AddObserver("LeftButtonPressEvent", self.OnFFClick) | ||
| 1876 | + | ||
| 1877 | + def SetUp(self): | ||
| 1878 | + if not self.config.dlg_visible: | ||
| 1879 | + self.config.dlg_visible = True | ||
| 1880 | + self.dlg_ffill = dialogs.FFillSegmentationOptionsDialog(self.config) | ||
| 1881 | + self.dlg_ffill.Show() | ||
| 1882 | + | ||
| 1883 | + def CleanUp(self): | ||
| 1884 | + if (self.dlg_ffill is not None) and (self.config.dlg_visible): | ||
| 1885 | + self.config.dlg_visible = False | ||
| 1886 | + self.dlg_ffill.Destroy() | ||
| 1887 | + self.dlg_ffill = None | ||
| 1888 | + | ||
| 1889 | + def OnFFClick(self, obj, evt): | ||
| 1890 | + if (self.viewer.slice_.buffer_slices[self.orientation].mask is None): | ||
| 1891 | + return | ||
| 1892 | + | ||
| 1893 | + viewer = self.viewer | ||
| 1894 | + iren = viewer.interactor | ||
| 1895 | + mouse_x, mouse_y = iren.GetEventPosition() | ||
| 1896 | + x, y, z = self.viewer.get_voxel_coord_by_screen_pos(mouse_x, mouse_y, self.picker) | ||
| 1897 | + | ||
| 1898 | + mask = self.viewer.slice_.current_mask.matrix[1:, 1:, 1:] | ||
| 1899 | + image = self.viewer.slice_.matrix | ||
| 1900 | + | ||
| 1901 | + if mask[z, y, x] < self.config.t0 or mask[z, y, x] > self.config.t1: | ||
| 1902 | + return | ||
| 1903 | + | ||
| 1904 | + if self.config.target == "3D": | ||
| 1905 | + bstruct = np.array(generate_binary_structure(3, CON3D[self.config.con_3d]), dtype='uint8') | ||
| 1906 | + self.viewer.slice_.do_threshold_to_all_slices() | ||
| 1907 | + cp_mask = self.viewer.slice_.current_mask.matrix.copy() | ||
| 1908 | + else: | ||
| 1909 | + _bstruct = generate_binary_structure(2, CON2D[self.config.con_2d]) | ||
| 1910 | + if self.orientation == 'AXIAL': | ||
| 1911 | + bstruct = np.zeros((1, 3, 3), dtype='uint8') | ||
| 1912 | + bstruct[0] = _bstruct | ||
| 1913 | + elif self.orientation == 'CORONAL': | ||
| 1914 | + bstruct = np.zeros((3, 1, 3), dtype='uint8') | ||
| 1915 | + bstruct[:, 0, :] = _bstruct | ||
| 1916 | + elif self.orientation == 'SAGITAL': | ||
| 1917 | + bstruct = np.zeros((3, 3, 1), dtype='uint8') | ||
| 1918 | + bstruct[:, :, 0] = _bstruct | ||
| 1919 | + | ||
| 1920 | + if self.config.target == '2D': | ||
| 1921 | + floodfill.floodfill_threshold(image, [[x, y, z]], self.config.t0, self.config.t1, self.config.fill_value, bstruct, mask) | ||
| 1922 | + b_mask = self.viewer.slice_.buffer_slices[self.orientation].mask | ||
| 1923 | + index = self.viewer.slice_.buffer_slices[self.orientation].index | ||
| 1924 | + | ||
| 1925 | + if self.orientation == 'AXIAL': | ||
| 1926 | + p_mask = mask[index,:,:].copy() | ||
| 1927 | + elif self.orientation == 'CORONAL': | ||
| 1928 | + p_mask = mask[:, index, :].copy() | ||
| 1929 | + elif self.orientation == 'SAGITAL': | ||
| 1930 | + p_mask = mask[:, :, index].copy() | ||
| 1931 | + | ||
| 1932 | + self.viewer.slice_.current_mask.save_history(index, self.orientation, p_mask, b_mask) | ||
| 1933 | + else: | ||
| 1934 | + with futures.ThreadPoolExecutor(max_workers=1) as executor: | ||
| 1935 | + future = executor.submit(floodfill.floodfill_threshold, image, [[x, y, z]], self.config.t0, self.config.t1, self.config.fill_value, bstruct, mask) | ||
| 1936 | + | ||
| 1937 | + dlg = wx.ProgressDialog(self._progr_title, self._progr_msg, parent=None, style=wx.PD_APP_MODAL) | ||
| 1938 | + while not future.done(): | ||
| 1939 | + dlg.Pulse() | ||
| 1940 | + time.sleep(0.1) | ||
| 1941 | + | ||
| 1942 | + dlg.Destroy() | ||
| 1943 | + | ||
| 1944 | + self.viewer.slice_.current_mask.save_history(0, 'VOLUME', self.viewer.slice_.current_mask.matrix.copy(), cp_mask) | ||
| 1945 | + | ||
| 1946 | + self.viewer.slice_.buffer_slices['AXIAL'].discard_mask() | ||
| 1947 | + self.viewer.slice_.buffer_slices['CORONAL'].discard_mask() | ||
| 1948 | + self.viewer.slice_.buffer_slices['SAGITAL'].discard_mask() | ||
| 1949 | + | ||
| 1950 | + self.viewer.slice_.buffer_slices['AXIAL'].discard_vtk_mask() | ||
| 1951 | + self.viewer.slice_.buffer_slices['CORONAL'].discard_vtk_mask() | ||
| 1952 | + self.viewer.slice_.buffer_slices['SAGITAL'].discard_vtk_mask() | ||
| 1953 | + | ||
| 1954 | + self.viewer.slice_.current_mask.was_edited = True | ||
| 1955 | + Publisher.sendMessage('Reload actual slice') | ||
| 1956 | + | ||
| 1957 | + | ||
| 1844 | def get_style(style): | 1958 | def get_style(style): |
| 1845 | STYLES = { | 1959 | STYLES = { |
| 1846 | const.STATE_DEFAULT: DefaultInteractorStyle, | 1960 | const.STATE_DEFAULT: DefaultInteractorStyle, |
| @@ -1859,6 +1973,7 @@ def get_style(style): | @@ -1859,6 +1973,7 @@ def get_style(style): | ||
| 1859 | const.SLICE_STATE_MASK_FFILL: FloodFillMaskInteractorStyle, | 1973 | const.SLICE_STATE_MASK_FFILL: FloodFillMaskInteractorStyle, |
| 1860 | const.SLICE_STATE_REMOVE_MASK_PARTS: RemoveMaskPartsInteractorStyle, | 1974 | const.SLICE_STATE_REMOVE_MASK_PARTS: RemoveMaskPartsInteractorStyle, |
| 1861 | const.SLICE_STATE_SELECT_MASK_PARTS: SelectMaskPartsInteractorStyle, | 1975 | const.SLICE_STATE_SELECT_MASK_PARTS: SelectMaskPartsInteractorStyle, |
| 1976 | + const.SLICE_STATE_FFILL_SEGMENTATION: FloodFillSegmentInteractorStyle, | ||
| 1862 | } | 1977 | } |
| 1863 | return STYLES[style] | 1978 | return STYLES[style] |
| 1864 | 1979 |
invesalius/gui/dialogs.py
| @@ -2031,3 +2031,124 @@ class SelectPartsOptionsDialog(wx.Dialog): | @@ -2031,3 +2031,124 @@ class SelectPartsOptionsDialog(wx.Dialog): | ||
| 2031 | Publisher.sendMessage('Disable style', const.SLICE_STATE_SELECT_MASK_PARTS) | 2031 | Publisher.sendMessage('Disable style', const.SLICE_STATE_SELECT_MASK_PARTS) |
| 2032 | evt.Skip() | 2032 | evt.Skip() |
| 2033 | self.Destroy() | 2033 | self.Destroy() |
| 2034 | + | ||
| 2035 | + | ||
| 2036 | +class FFillSegmentationOptionsDialog(wx.Dialog): | ||
| 2037 | + def __init__(self, config): | ||
| 2038 | + pre = wx.PreDialog() | ||
| 2039 | + pre.Create(wx.GetApp().GetTopWindow(), -1, _(u"Floodfill Segmentation"), style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT) | ||
| 2040 | + self.PostCreate(pre) | ||
| 2041 | + | ||
| 2042 | + self.config = config | ||
| 2043 | + | ||
| 2044 | + self._init_gui() | ||
| 2045 | + | ||
| 2046 | + def _init_gui(self): | ||
| 2047 | + """ | ||
| 2048 | + Create the widgets. | ||
| 2049 | + """ | ||
| 2050 | + import project as prj | ||
| 2051 | + # Target | ||
| 2052 | + self.target_2d = wx.RadioButton(self, -1, _(u"2D - Actual slice"), style=wx.RB_GROUP) | ||
| 2053 | + self.target_3d = wx.RadioButton(self, -1, _(u"3D - All slices")) | ||
| 2054 | + | ||
| 2055 | + if self.config.target == "2D": | ||
| 2056 | + self.target_2d.SetValue(1) | ||
| 2057 | + else: | ||
| 2058 | + self.target_3d.SetValue(1) | ||
| 2059 | + | ||
| 2060 | + # Connectivity 2D | ||
| 2061 | + self.conect2D_4 = wx.RadioButton(self, -1, "4", style=wx.RB_GROUP) | ||
| 2062 | + self.conect2D_8 = wx.RadioButton(self, -1, "8") | ||
| 2063 | + | ||
| 2064 | + if self.config.con_2d == 8: | ||
| 2065 | + self.conect2D_8.SetValue(1) | ||
| 2066 | + else: | ||
| 2067 | + self.conect2D_4.SetValue(1) | ||
| 2068 | + self.config.con_2d = 4 | ||
| 2069 | + | ||
| 2070 | + # Connectivity 3D | ||
| 2071 | + self.conect3D_6 = wx.RadioButton(self, -1, "6", style=wx.RB_GROUP) | ||
| 2072 | + self.conect3D_18 = wx.RadioButton(self, -1, "18") | ||
| 2073 | + self.conect3D_26 = wx.RadioButton(self, -1, "26") | ||
| 2074 | + | ||
| 2075 | + if self.config.con_3d == 18: | ||
| 2076 | + self.conect3D_18.SetValue(1) | ||
| 2077 | + elif self.config.con_3d == 26: | ||
| 2078 | + self.conect3D_26.SetValue(1) | ||
| 2079 | + else: | ||
| 2080 | + self.conect3D_6.SetValue(1) | ||
| 2081 | + | ||
| 2082 | + project = prj.Project() | ||
| 2083 | + bound_min, bound_max = project.threshold_range | ||
| 2084 | + colour = [i*255 for i in const.MASK_COLOUR[0]] | ||
| 2085 | + colour.append(100) | ||
| 2086 | + self.threshold = grad.GradientCtrl(self, -1, int(bound_min), | ||
| 2087 | + int(bound_max), self.config.t0, | ||
| 2088 | + self.config.t1, colour) | ||
| 2089 | + | ||
| 2090 | + # Sizer | ||
| 2091 | + sizer = wx.GridBagSizer(15, 6) | ||
| 2092 | + sizer.AddStretchSpacer((0, 0)) | ||
| 2093 | + | ||
| 2094 | + sizer.Add(wx.StaticText(self, -1, _(u"Parameters")), (1, 0), (1, 6), flag=wx.LEFT, border=7) | ||
| 2095 | + sizer.Add(self.target_2d, (2, 0), (1, 6), flag=wx.LEFT, border=9) | ||
| 2096 | + sizer.Add(self.target_3d, (3, 0), (1, 6), flag=wx.LEFT, border=9) | ||
| 2097 | + | ||
| 2098 | + sizer.AddStretchSpacer((4, 0)) | ||
| 2099 | + | ||
| 2100 | + sizer.Add(wx.StaticText(self, -1, _(u"2D Connectivity")), (5, 0), (1, 6), flag=wx.LEFT, border=9) | ||
| 2101 | + sizer.Add(self.conect2D_4, (6, 0), flag=wx.LEFT, border=9) | ||
| 2102 | + sizer.Add(self.conect2D_8, (6, 1), flag=wx.LEFT, border=9) | ||
| 2103 | + | ||
| 2104 | + sizer.AddStretchSpacer((7, 0)) | ||
| 2105 | + | ||
| 2106 | + sizer.Add(wx.StaticText(self, -1, _(u"3D Connectivity")), (8, 0), (1, 6), flag=wx.LEFT, border=9) | ||
| 2107 | + sizer.Add(self.conect3D_6, (9, 0), flag=wx.LEFT, border=9) | ||
| 2108 | + sizer.Add(self.conect3D_18, (9, 1), flag=wx.LEFT, border=9) | ||
| 2109 | + sizer.Add(self.conect3D_26, (9, 2), flag=wx.LEFT, border=9) | ||
| 2110 | + sizer.AddStretchSpacer((10, 0)) | ||
| 2111 | + | ||
| 2112 | + sizer.Add(wx.StaticText(self, -1, _(u"Threshold")), (11, 0), (1, 6), flag=wx.LEFT, border=9) | ||
| 2113 | + sizer.Add(self.threshold, (12, 0), (1, 6), flag=wx.LEFT|wx.RIGHT|wx.EXPAND, border=9) | ||
| 2114 | + sizer.AddStretchSpacer((13, 0)) | ||
| 2115 | + | ||
| 2116 | + self.SetSizer(sizer) | ||
| 2117 | + sizer.Fit(self) | ||
| 2118 | + self.Layout() | ||
| 2119 | + | ||
| 2120 | + self.Bind(wx.EVT_RADIOBUTTON, self.OnSetRadio) | ||
| 2121 | + self.Bind(grad.EVT_THRESHOLD_CHANGING, self.OnSlideChanged, self.threshold) | ||
| 2122 | + self.Bind(wx.EVT_CLOSE, self.OnClose) | ||
| 2123 | + | ||
| 2124 | + def OnSetRadio(self, evt): | ||
| 2125 | + # Target | ||
| 2126 | + if self.target_2d.GetValue(): | ||
| 2127 | + self.config.target = "2D" | ||
| 2128 | + else: | ||
| 2129 | + self.config.target = "3D" | ||
| 2130 | + | ||
| 2131 | + # 2D | ||
| 2132 | + if self.conect2D_4.GetValue(): | ||
| 2133 | + self.config.con_2d = 4 | ||
| 2134 | + elif self.conect2D_8.GetValue(): | ||
| 2135 | + self.config.con_2d = 8 | ||
| 2136 | + | ||
| 2137 | + # 3D | ||
| 2138 | + if self.conect3D_6.GetValue(): | ||
| 2139 | + self.config.con_3d = 6 | ||
| 2140 | + elif self.conect3D_18.GetValue(): | ||
| 2141 | + self.config.con_3d = 18 | ||
| 2142 | + elif self.conect3D_26.GetValue(): | ||
| 2143 | + self.config.con_3d = 26 | ||
| 2144 | + | ||
| 2145 | + def OnSlideChanged(self, evt): | ||
| 2146 | + self.config.t0 = self.threshold.GetMinValue() | ||
| 2147 | + self.config.t1 = self.threshold.GetMaxValue() | ||
| 2148 | + print self.config.t0, self.config.t1 | ||
| 2149 | + | ||
| 2150 | + def OnClose(self, evt): | ||
| 2151 | + if self.config.dlg_visible: | ||
| 2152 | + Publisher.sendMessage('Disable style', const.SLICE_STATE_MASK_FFILL) | ||
| 2153 | + evt.Skip() | ||
| 2154 | + self.Destroy() |
invesalius/gui/frame.py
| @@ -454,6 +454,9 @@ class Frame(wx.Frame): | @@ -454,6 +454,9 @@ class Frame(wx.Frame): | ||
| 454 | elif id == const.ID_SELECT_MASK_PART: | 454 | elif id == const.ID_SELECT_MASK_PART: |
| 455 | self.OnSelectMaskParts() | 455 | self.OnSelectMaskParts() |
| 456 | 456 | ||
| 457 | + elif id == const.ID_FLOODFILL_SEGMENTATION: | ||
| 458 | + self.OnFFillSegmentation() | ||
| 459 | + | ||
| 457 | elif id == const.ID_VIEW_INTERPOLATED: | 460 | elif id == const.ID_VIEW_INTERPOLATED: |
| 458 | st = self.actived_interpolated_slices.IsChecked(const.ID_VIEW_INTERPOLATED) | 461 | st = self.actived_interpolated_slices.IsChecked(const.ID_VIEW_INTERPOLATED) |
| 459 | if st: | 462 | if st: |
| @@ -593,6 +596,9 @@ class Frame(wx.Frame): | @@ -593,6 +596,9 @@ class Frame(wx.Frame): | ||
| 593 | def OnSelectMaskParts(self): | 596 | def OnSelectMaskParts(self): |
| 594 | Publisher.sendMessage('Enable style', const.SLICE_STATE_SELECT_MASK_PARTS) | 597 | Publisher.sendMessage('Enable style', const.SLICE_STATE_SELECT_MASK_PARTS) |
| 595 | 598 | ||
| 599 | + def OnFFillSegmentation(self): | ||
| 600 | + Publisher.sendMessage('Enable style', const.SLICE_STATE_FFILL_SEGMENTATION) | ||
| 601 | + | ||
| 596 | def OnInterpolatedSlices(self, status): | 602 | def OnInterpolatedSlices(self, status): |
| 597 | Publisher.sendMessage('Set interpolated slices', status) | 603 | Publisher.sendMessage('Set interpolated slices', status) |
| 598 | 604 | ||
| @@ -618,7 +624,8 @@ class MenuBar(wx.MenuBar): | @@ -618,7 +624,8 @@ class MenuBar(wx.MenuBar): | ||
| 618 | const.ID_REORIENT_IMG, | 624 | const.ID_REORIENT_IMG, |
| 619 | const.ID_FLOODFILL_MASK, | 625 | const.ID_FLOODFILL_MASK, |
| 620 | const.ID_REMOVE_MASK_PART, | 626 | const.ID_REMOVE_MASK_PART, |
| 621 | - const.ID_SELECT_MASK_PART,] | 627 | + const.ID_SELECT_MASK_PART, |
| 628 | + const.ID_FLOODFILL_SEGMENTATION,] | ||
| 622 | self.__init_items() | 629 | self.__init_items() |
| 623 | self.__bind_events() | 630 | self.__bind_events() |
| 624 | 631 | ||
| @@ -741,6 +748,13 @@ class MenuBar(wx.MenuBar): | @@ -741,6 +748,13 @@ class MenuBar(wx.MenuBar): | ||
| 741 | 748 | ||
| 742 | tools_menu.AppendMenu(-1, _(u"Mask"), mask_menu) | 749 | tools_menu.AppendMenu(-1, _(u"Mask"), mask_menu) |
| 743 | 750 | ||
| 751 | + # Segmentation Menu | ||
| 752 | + segmentation_menu = wx.Menu() | ||
| 753 | + self.ffill_segmentation = segmentation_menu.Append(const.ID_FLOODFILL_SEGMENTATION, _(u"Floodfill")) | ||
| 754 | + self.ffill_segmentation.Enable(False) | ||
| 755 | + | ||
| 756 | + tools_menu.AppendMenu(-1, _("Segmentation"), segmentation_menu) | ||
| 757 | + | ||
| 744 | # Image menu | 758 | # Image menu |
| 745 | image_menu = wx.Menu() | 759 | image_menu = wx.Menu() |
| 746 | reorient_menu = image_menu.Append(const.ID_REORIENT_IMG, _(u'Reorient image\tCtrl+Shift+R')) | 760 | reorient_menu = image_menu.Append(const.ID_REORIENT_IMG, _(u'Reorient image\tCtrl+Shift+R')) |
| @@ -758,8 +772,6 @@ class MenuBar(wx.MenuBar): | @@ -758,8 +772,6 @@ class MenuBar(wx.MenuBar): | ||
| 758 | self.view_menu.Check(const.ID_VIEW_INTERPOLATED, v) | 772 | self.view_menu.Check(const.ID_VIEW_INTERPOLATED, v) |
| 759 | 773 | ||
| 760 | self.actived_interpolated_slices = self.view_menu | 774 | self.actived_interpolated_slices = self.view_menu |
| 761 | - | ||
| 762 | - | ||
| 763 | 775 | ||
| 764 | #view_tool_menu = wx.Menu() | 776 | #view_tool_menu = wx.Menu() |
| 765 | #app = view_tool_menu.Append | 777 | #app = view_tool_menu.Append |
invesalius/gui/widgets/gradient.py
| @@ -493,6 +493,7 @@ class GradientCtrl(wx.Panel): | @@ -493,6 +493,7 @@ class GradientCtrl(wx.Panel): | ||
| 493 | return self.minimun | 493 | return self.minimun |
| 494 | 494 | ||
| 495 | def _GenerateEvent(self, event): | 495 | def _GenerateEvent(self, event): |
| 496 | + print "GEN" | ||
| 496 | if event == myEVT_THRESHOLD_CHANGING: | 497 | if event == myEVT_THRESHOLD_CHANGING: |
| 497 | self.changed = True | 498 | self.changed = True |
| 498 | elif event == myEVT_THRESHOLD_CHANGED : | 499 | elif event == myEVT_THRESHOLD_CHANGED : |