Commit 3749eea2ab80ccbef0693c465311bd973c4551e6

Authored by Thiago Franco de Moraes
1 parent ad7294a7
Exists in select_part

Starting to select part to new mask

invesalius/constants.py
... ... @@ -483,6 +483,7 @@ ID_CLEAN_MASK = wx.NewId()
483 483 ID_REORIENT_IMG = wx.NewId()
484 484 ID_FLOODFILL_MASK = wx.NewId()
485 485 ID_REMOVE_MASK_PART = wx.NewId()
  486 +ID_SELECT_MASK_PART = wx.NewId()
486 487  
487 488 #---------------------------------------------------------
488 489 STATE_DEFAULT = 1000
... ... @@ -502,6 +503,7 @@ SLICE_STATE_WATERSHED = 3009
502 503 SLICE_STATE_REORIENT = 3010
503 504 SLICE_STATE_MASK_FFILL = 3011
504 505 SLICE_STATE_REMOVE_MASK_PARTS = 3012
  506 +SLICE_STATE_SELECT_MASK_PARTS = 3013
505 507  
506 508 VOLUME_STATE_SEED = 2001
507 509 # STATE_LINEAR_MEASURE = 3001
... ... @@ -521,6 +523,7 @@ SLICE_STYLES.append(SLICE_STATE_EDITOR)
521 523 SLICE_STYLES.append(SLICE_STATE_WATERSHED)
522 524 SLICE_STYLES.append(SLICE_STATE_MASK_FFILL)
523 525 SLICE_STYLES.append(SLICE_STATE_REMOVE_MASK_PARTS)
  526 +SLICE_STYLES.append(SLICE_STATE_SELECT_MASK_PARTS)
524 527  
525 528 VOLUME_STYLES = TOOL_STATES + [VOLUME_STATE_SEED, STATE_MEASURE_DISTANCE,
526 529 STATE_MEASURE_ANGLE]
... ... @@ -531,6 +534,7 @@ STYLE_LEVEL = {SLICE_STATE_EDITOR: 1,
531 534 SLICE_STATE_WATERSHED: 1,
532 535 SLICE_STATE_MASK_FFILL: 2,
533 536 SLICE_STATE_REMOVE_MASK_PARTS: 2,
  537 + SLICE_STATE_SELECT_MASK_PARTS: 2,
534 538 SLICE_STATE_CROSS: 2,
535 539 SLICE_STATE_SCROLL: 2,
536 540 SLICE_STATE_REORIENT: 2,
... ...
invesalius/data/slice_.py
... ... @@ -1282,6 +1282,22 @@ class Slice(object):
1282 1282 op, m1, m2 = pubsub_evt.data
1283 1283 self.do_boolean_op(op, m1, m2)
1284 1284  
  1285 + def create_new_mask(self, show=True):
  1286 + last_name = self.current_mask.name
  1287 +
  1288 + proj = Project()
  1289 + mask_dict = proj.mask_dict
  1290 + names_list = [mask_dict[i].name for i in mask_dict.keys()]
  1291 + new_name = utils.next_copy_name(last_name, names_list)
  1292 +
  1293 + future_mask = Mask()
  1294 + future_mask.create_mask(self.matrix.shape)
  1295 + future_mask.name = new_name
  1296 +
  1297 + self._add_mask_into_proj(future_mask, show=show)
  1298 +
  1299 + return future_mask
  1300 +
1285 1301 def do_boolean_op(self, op, m1, m2):
1286 1302 name_ops = {const.BOOLEAN_UNION: _(u"Union"),
1287 1303 const.BOOLEAN_DIFF: _(u"Diff"),
... ...
invesalius/data/styles.py
... ... @@ -1928,6 +1928,115 @@ class RemoveMaskPartsInteractorStyle(FloodFillMaskInteractorStyle):
1928 1928 self._progr_msg = _(u"Removing part ...")
1929 1929  
1930 1930  
  1931 +class SelectPartConfig(object):
  1932 + __metaclass__= utils.Singleton
  1933 + def __init__(self):
  1934 + self.matrix = None
  1935 + self.con_3d = 6
  1936 +
  1937 +
  1938 +class SelectMaskPartsInteractorStyle(DefaultInteractorStyle):
  1939 + def __init__(self, viewer):
  1940 + DefaultInteractorStyle.__init__(self, viewer)
  1941 +
  1942 + self.viewer = viewer
  1943 + self.orientation = self.viewer.orientation
  1944 +
  1945 + self.picker = vtk.vtkWorldPointPicker()
  1946 + self.slice_actor = viewer.slice_data.actor
  1947 + self.slice_data = viewer.slice_data
  1948 +
  1949 + self.config = SelectPartConfig()
  1950 + self.dlg_ffill = None
  1951 +
  1952 + self.t0 = 254
  1953 + self.t1 = 255
  1954 + self.fill_value = 254
  1955 +
  1956 + self.AddObserver("LeftButtonPressEvent", self.OnSelect)
  1957 +
  1958 + def CleanUp(self):
  1959 + self.config.matrix = None
  1960 +
  1961 + def OnSelect(self, obj, evt):
  1962 + if (self.viewer.slice_.buffer_slices[self.orientation].mask is None):
  1963 + return
  1964 +
  1965 + viewer = self.viewer
  1966 + iren = viewer.interactor
  1967 +
  1968 + mouse_x, mouse_y = iren.GetEventPosition()
  1969 + render = iren.FindPokedRenderer(mouse_x, mouse_y)
  1970 + slice_data = viewer.get_slice_data(render)
  1971 +
  1972 + self.picker.Pick(mouse_x, mouse_y, 0, render)
  1973 +
  1974 + coord = self.get_coordinate_cursor()
  1975 + position = slice_data.actor.GetInput().FindPoint(coord)
  1976 +
  1977 + if position != -1:
  1978 + coord = slice_data.actor.GetInput().GetPoint(position)
  1979 +
  1980 + if position < 0:
  1981 + position = viewer.calculate_matrix_position(coord)
  1982 +
  1983 + mask = self.viewer.slice_.current_mask.matrix[1:, 1:, 1:]
  1984 + x, y, z = self.calcultate_scroll_position(position)
  1985 +
  1986 + bstruct = np.array(generate_binary_structure(3, CON3D[self.config.con_3d]), dtype='uint8')
  1987 + self.viewer.slice_.do_threshold_to_all_slices()
  1988 +
  1989 + if self.config.matrix is None:
  1990 + self._create_new_mask()
  1991 +
  1992 + floodfill.floodfill_threshold(mask, [[x, y, z]], self.t0, self.t1, self.fill_value, bstruct, self.config.matrix[1:, 1:, 1:])
  1993 +
  1994 + def _create_new_mask(self):
  1995 + mask = self.viewer.slice_.create_new_mask(show=False)
  1996 + mask.was_edited = True
  1997 + mask.matrix[0, :, :] = 1
  1998 + mask.matrix[:, 0, :] = 1
  1999 + mask.matrix[:, :, 0] = 1
  2000 +
  2001 + self.config.matrix = mask.matrix
  2002 +
  2003 + def get_coordinate_cursor(self):
  2004 + # Find position
  2005 + x, y, z = self.picker.GetPickPosition()
  2006 + bounds = self.viewer.slice_data.actor.GetBounds()
  2007 + if bounds[0] == bounds[1]:
  2008 + x = bounds[0]
  2009 + elif bounds[2] == bounds[3]:
  2010 + y = bounds[2]
  2011 + elif bounds[4] == bounds[5]:
  2012 + z = bounds[4]
  2013 + return x, y, z
  2014 +
  2015 + def calcultate_scroll_position(self, position):
  2016 + # Based in the given coord (x, y, z), returns a list with the scroll positions for each
  2017 + # orientation, being the first position the sagital, second the coronal
  2018 + # and the last, axial.
  2019 +
  2020 + if self.orientation == 'AXIAL':
  2021 + image_width = self.slice_actor.GetInput().GetDimensions()[0]
  2022 + axial = self.slice_data.number
  2023 + coronal = position / image_width
  2024 + sagital = position % image_width
  2025 +
  2026 + elif self.orientation == 'CORONAL':
  2027 + image_width = self.slice_actor.GetInput().GetDimensions()[0]
  2028 + axial = position / image_width
  2029 + coronal = self.slice_data.number
  2030 + sagital = position % image_width
  2031 +
  2032 + elif self.orientation == 'SAGITAL':
  2033 + image_width = self.slice_actor.GetInput().GetDimensions()[1]
  2034 + axial = position / image_width
  2035 + coronal = position % image_width
  2036 + sagital = self.slice_data.number
  2037 +
  2038 + return sagital, coronal, axial
  2039 +
1931 2040 def get_style(style):
1932 2041 STYLES = {
1933 2042 const.STATE_DEFAULT: DefaultInteractorStyle,
... ... @@ -1945,6 +2054,7 @@ def get_style(style):
1945 2054 const.SLICE_STATE_REORIENT: ReorientImageInteractorStyle,
1946 2055 const.SLICE_STATE_MASK_FFILL: FloodFillMaskInteractorStyle,
1947 2056 const.SLICE_STATE_REMOVE_MASK_PARTS: RemoveMaskPartsInteractorStyle,
  2057 + const.SLICE_STATE_SELECT_MASK_PARTS: SelectMaskPartsInteractorStyle,
1948 2058 }
1949 2059 return STYLES[style]
1950 2060  
... ...
invesalius/gui/data_notebook.py
... ... @@ -512,11 +512,11 @@ class MasksListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin):
512 512 self.SetStringItem(index, 1, label,
513 513 imageId=self.mask_list_index[index])
514 514 self.SetStringItem(index, 2, threshold)
515   - self.SetItemImage(index, 1)
516   - for key in self.mask_list_index.keys():
517   - if key != index:
518   - self.SetItemImage(key, 0)
519   - self.current_index = index
  515 + # self.SetItemImage(index, 1)
  516 + # for key in self.mask_list_index.keys():
  517 + # if key != index:
  518 + # self.SetItemImage(key, 0)
  519 + # self.current_index = index
520 520  
521 521 def AddMask(self, pubsub_evt):
522 522 index, mask_name, threshold_range, colour = pubsub_evt.data
... ...
invesalius/gui/frame.py
... ... @@ -451,20 +451,16 @@ class Frame(wx.Frame):
451 451 elif id == const.ID_REMOVE_MASK_PART:
452 452 self.OnRemoveMaskParts()
453 453  
  454 + elif id == const.ID_SELECT_MASK_PART:
  455 + self.OnSelectMaskParts()
  456 +
454 457 elif id == const.ID_VIEW_INTERPOLATED:
455   -
456 458 st = self.actived_interpolated_slices.IsChecked(const.ID_VIEW_INTERPOLATED)
457   -
458 459 if st:
459 460 self.OnInterpolatedSlices(True)
460 461 else:
461 462 self.OnInterpolatedSlices(False)
462 463  
463   - def OnInterpolatedSlices(self, status):
464   -
465   - Publisher.sendMessage('Set interpolated slices', status)
466   -
467   -
468 464 def OnSize(self, evt):
469 465 """
470 466 Refresh GUI when frame is resized.
... ... @@ -594,6 +590,12 @@ class Frame(wx.Frame):
594 590 def OnRemoveMaskParts(self):
595 591 Publisher.sendMessage('Enable style', const.SLICE_STATE_REMOVE_MASK_PARTS)
596 592  
  593 + def OnSelectMaskParts(self):
  594 + Publisher.sendMessage('Enable style', const.SLICE_STATE_SELECT_MASK_PARTS)
  595 +
  596 + def OnInterpolatedSlices(self, status):
  597 + Publisher.sendMessage('Set interpolated slices', status)
  598 +
597 599 # ------------------------------------------------------------------
598 600 # ------------------------------------------------------------------
599 601 # ------------------------------------------------------------------
... ... @@ -615,7 +617,8 @@ class MenuBar(wx.MenuBar):
615 617 const.ID_PROJECT_CLOSE,
616 618 const.ID_REORIENT_IMG,
617 619 const.ID_FLOODFILL_MASK,
618   - const.ID_REMOVE_MASK_PART,]
  620 + const.ID_REMOVE_MASK_PART,
  621 + const.ID_SELECT_MASK_PART,]
619 622 self.__init_items()
620 623 self.__bind_events()
621 624  
... ... @@ -733,6 +736,9 @@ class MenuBar(wx.MenuBar):
733 736 self.remove_mask_part_menu = mask_menu.Append(const.ID_REMOVE_MASK_PART, _(u"Remove parts"))
734 737 self.remove_mask_part_menu.Enable(False)
735 738  
  739 + self.select_mask_part_menu = mask_menu.Append(const.ID_SELECT_MASK_PART, _(u"Select parts"))
  740 + self.select_mask_part_menu.Enable(False)
  741 +
736 742 tools_menu.AppendMenu(-1, _(u"Mask"), mask_menu)
737 743  
738 744 # Image menu
... ...