Commit 9a0892f4162350e15e09ef5729ade3fb3c8c915c
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): |