Commit 9a0892f4162350e15e09ef5729ade3fb3c8c915c

Authored by Thiago Franco de Moraes
1 parent f7f83def
Exists in watershed

Added suport to erase a mark

Showing 1 changed file with 68 additions and 15 deletions   Show diff stats
invesalius/data/styles.py
@@ -30,6 +30,7 @@ import converters @@ -30,6 +30,7 @@ import converters
30 import numpy as np 30 import numpy as np
31 31
32 from scipy import ndimage 32 from scipy import ndimage
  33 +from skimage.morphology import watershed
33 34
34 ORIENTATIONS = { 35 ORIENTATIONS = {
35 "AXIAL": const.AXIAL, 36 "AXIAL": const.AXIAL,
@@ -37,6 +38,16 @@ ORIENTATIONS = { @@ -37,6 +38,16 @@ ORIENTATIONS = {
37 "SAGITAL": const.SAGITAL, 38 "SAGITAL": const.SAGITAL,
38 } 39 }
39 40
  41 +BRUSH_FOREGROUND=1
  42 +BRUSH_BACKGROUND=2
  43 +BRUSH_ERASE=3
  44 +
  45 +def get_LUT_value(data, window, level):
  46 + return np.piecewise(data,
  47 + [data <= (level - 0.5 - (window-1)/2),
  48 + data > (level - 0.5 + (window-1)/2)],
  49 + [0, 255, lambda data: ((data - (level - 0.5))/(window-1) + 0.5)*(255-0)])
  50 +
40 class BaseImageInteractorStyle(vtk.vtkInteractorStyleImage): 51 class BaseImageInteractorStyle(vtk.vtkInteractorStyleImage):
41 def __init__(self, viewer): 52 def __init__(self, viewer):
42 self.right_pressed = False 53 self.right_pressed = False
@@ -668,6 +679,10 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -668,6 +679,10 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
668 self.AddObserver("MouseMoveEvent", self.OnBrushMove) 679 self.AddObserver("MouseMoveEvent", self.OnBrushMove)
669 680
670 def SetUp(self): 681 def SetUp(self):
  682 + mask = self.viewer.slice_.current_mask.matrix
  683 + mask[0] = 1
  684 + mask[:, 0, :] = 1
  685 + mask[:, :, 0] = 1
671 self._create_mask() 686 self._create_mask()
672 687
673 def CleanUp(self): 688 def CleanUp(self):
@@ -723,17 +738,40 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -723,17 +738,40 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
723 coord = slice_data.actor.GetInput().GetPoint(position) 738 coord = slice_data.actor.GetInput().GetPoint(position)
724 739
725 slice_data.cursor.SetPosition(coord) 740 slice_data.cursor.SetPosition(coord)
  741 +
726 cursor = slice_data.cursor 742 cursor = slice_data.cursor
  743 + position = slice_data.actor.GetInput().FindPoint(coord)
727 radius = cursor.radius 744 radius = cursor.radius
728 745
729 if position < 0: 746 if position < 0:
730 position = viewer.calculate_matrix_position(coord) 747 position = viewer.calculate_matrix_position(coord)
731 748
732 - n = self.viewer.slice_data.number  
733 - self.edit_mask_pixel(viewer._brush_cursor_op, n, cursor.GetPixels(),  
734 - position, radius, viewer.orientation)  
735 - viewer._flush_buffer = True 749 + if iren.GetControlKey():
  750 + operation = BRUSH_BACKGROUND
  751 + elif iren.GetShiftKey():
  752 + operation = BRUSH_ERASE
  753 + else:
  754 + operation = BRUSH_FOREGROUND
736 755
  756 + if operation == const.BRUSH_DRAW:
  757 + self.foreground = True
  758 +
  759 + elif operation == const.BRUSH_ERASE:
  760 + self.foreground = True
  761 +
  762 + n = self.viewer.slice_data.number
  763 + self.edit_mask_pixel(operation, n, cursor.GetPixels(),
  764 + position, radius, self.orientation)
  765 + if self.orientation == 'AXIAL':
  766 + mask = self.matrix[n, :, :]
  767 + elif self.orientation == 'CORONAL':
  768 + mask = self.matrix[:, n, :]
  769 + elif self.orientation == 'SAGITAL':
  770 + mask = self.matrix[:, :, n]
  771 + spacing = self.viewer.slice_.spacing
  772 + vmask = converters.to_vtk(mask, spacing, n, self.orientation)
  773 + cvmask = do_colour_mask(vmask)
  774 + self.viewer.slice_.qblend[self.orientation][n] = cvmask
737 # TODO: To create a new function to reload images to viewer. 775 # TODO: To create a new function to reload images to viewer.
738 viewer.OnScrollBar() 776 viewer.OnScrollBar()
739 777
@@ -763,14 +801,6 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -763,14 +801,6 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
763 801
764 coord = self.get_coordinate_cursor() 802 coord = self.get_coordinate_cursor()
765 position = viewer.slice_data.actor.GetInput().FindPoint(coord) 803 position = viewer.slice_data.actor.GetInput().FindPoint(coord)
766 - operations = [const.BRUSH_DRAW, const.BRUSH_ERASE]  
767 - operation = operations[iren.GetControlKey()]  
768 -  
769 - if operation == const.BRUSH_DRAW:  
770 - self.foreground = True  
771 -  
772 - elif operation == const.BRUSH_ERASE:  
773 - self.foreground = True  
774 804
775 # when position == -1 the cursos is not over the image, so is not 805 # when position == -1 the cursos is not over the image, so is not
776 # necessary to set the cursor position to world coordinate center of 806 # necessary to set the cursor position to world coordinate center of
@@ -787,6 +817,19 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -787,6 +817,19 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
787 817
788 if position < 0: 818 if position < 0:
789 position = viewer.calculate_matrix_position(coord) 819 position = viewer.calculate_matrix_position(coord)
  820 +
  821 + if iren.GetControlKey():
  822 + operation = BRUSH_BACKGROUND
  823 + elif iren.GetShiftKey():
  824 + operation = BRUSH_ERASE
  825 + else:
  826 + operation = BRUSH_FOREGROUND
  827 +
  828 + if operation == const.BRUSH_DRAW:
  829 + self.foreground = True
  830 +
  831 + elif operation == const.BRUSH_ERASE:
  832 + self.foreground = True
790 833
791 n = self.viewer.slice_data.number 834 n = self.viewer.slice_data.number
792 self.edit_mask_pixel(operation, n, cursor.GetPixels(), 835 self.edit_mask_pixel(operation, n, cursor.GetPixels(),
@@ -825,9 +868,17 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -825,9 +868,17 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
825 mask = self.viewer.slice_.current_mask.matrix[1: , 1:, n+1] 868 mask = self.viewer.slice_.current_mask.matrix[1: , 1:, n+1]
826 markers = self.matrix[:, :, n] 869 markers = self.matrix[:, :, n]
827 870
828 - tmp_mask = ndimage.watershed_ift((image - image.min()).astype('uint16'), markers) 871 +
  872 + ww = self.viewer.slice_.window_width
  873 + wl = self.viewer.slice_.window_level
  874 +
  875 + #tmp_image = get_LUT_value(image, ww, wl).astype('uint16')
  876 + tmp_image = ndimage.morphological_gradient((image - image.min()).astype('uint16'), 5)
  877 + print tmp_image.dtype, tmp_image.min(), tmp_image.max()
  878 + tmp_mask = watershed(tmp_image, markers)
829 mask[:] = 0 879 mask[:] = 0
830 mask[tmp_mask == 1] = 255 880 mask[tmp_mask == 1] = 255
  881 + self.viewer._flush_buffer = True
831 self.viewer.OnScrollBar(update3D=False) 882 self.viewer.OnScrollBar(update3D=False)
832 883
833 def get_coordinate_cursor(self): 884 def get_coordinate_cursor(self):
@@ -910,10 +961,12 @@ class WaterShedInteractorStyle(DefaultInteractorStyle): @@ -910,10 +961,12 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
910 961
911 # Checking if roi_i has at least one element. 962 # Checking if roi_i has at least one element.
912 if roi_m.size: 963 if roi_m.size:
913 - if operation == const.BRUSH_DRAW: 964 + if operation == BRUSH_FOREGROUND:
914 roi_m[index] = 1 965 roi_m[index] = 1
915 - elif operation == const.BRUSH_ERASE: 966 + elif operation == BRUSH_BACKGROUND:
916 roi_m[index] = 2 967 roi_m[index] = 2
  968 + elif operation == BRUSH_ERASE:
  969 + roi_m[index] = 0
917 970
918 971
919 def do_colour_mask(imagedata): 972 def do_colour_mask(imagedata):