Commit 6da76721b2f2ffe54fee27b149f838a8aa9bd185

Authored by Thiago Franco de Moraes
Committed by GitHub
1 parent c79f0659

Created methods to get pixel and voxel position given the x,y screen position (#51)

invesalius/data/slice_.py
... ... @@ -434,7 +434,7 @@ class Slice(object):
434 434 thresh_min, thresh_max = self.current_mask.edition_threshold_range
435 435  
436 436 if hasattr(position, '__iter__'):
437   - py, px = position
  437 + px, py = position
438 438 if orientation == 'AXIAL':
439 439 sx = self.spacing[0]
440 440 sy = self.spacing[1]
... ...
invesalius/data/styles.py
... ... @@ -76,6 +76,7 @@ def get_LUT_value(data, window, level):
76 76 data.shape = shape
77 77 return data
78 78  
  79 +
79 80 class BaseImageInteractorStyle(vtk.vtkInteractorStyleImage):
80 81 def __init__(self, viewer):
81 82 self.right_pressed = False
... ... @@ -213,52 +214,18 @@ class CrossInteractorStyle(DefaultInteractorStyle):
213 214  
214 215 def ChangeCrossPosition(self, iren):
215 216 mouse_x, mouse_y = iren.GetEventPosition()
216   - ren = iren.GetRenderWindow().GetRenderers().GetFirstRenderer()
217   - self.picker.Pick(mouse_x, mouse_y, 0, ren)
218   -
219   - # Get in what slice data the click occurred
220   - # pick to get click position in the 3d world
221   - coord_cross = self.get_coordinate_cursor()
222   - position = self.slice_actor.GetInput().FindPoint(coord_cross)
223   - # Forcing focal point to be setted in the center of the pixel.
224   - coord_cross = self.slice_actor.GetInput().GetPoint(position)
225   -
226   - coord = self.calcultate_scroll_position(position)
227   - Publisher.sendMessage('Update cross position', coord_cross)
  217 + wx, wy, wz = self.viewer.get_coordinate_cursor(mouse_x, mouse_y, self.picker)
  218 + px, py = self.viewer.get_slice_pixel_coord_by_world_pos(wx, wy, wz)
  219 + coord = self.viewer.calcultate_scroll_position(px, py)
  220 + Publisher.sendMessage('Update cross position', (wx, wy, wz))
228 221 self.ScrollSlice(coord)
229 222 Publisher.sendMessage('Set ball reference position based on bound',
230   - coord_cross)
231   - Publisher.sendMessage('Set camera in volume', coord_cross)
  223 + (wx, wy, wz))
  224 + Publisher.sendMessage('Set camera in volume', (wx, wy, wz))
232 225 Publisher.sendMessage('Render volume viewer')
233 226  
234 227 iren.Render()
235 228  
236   -
237   - def calcultate_scroll_position(self, position):
238   - # Based in the given coord (x, y, z), returns a list with the scroll positions for each
239   - # orientation, being the first position the sagital, second the coronal
240   - # and the last, axial.
241   -
242   - if self.orientation == 'AXIAL':
243   - image_width = self.slice_actor.GetInput().GetDimensions()[0]
244   - axial = self.slice_data.number
245   - coronal = position / image_width
246   - sagital = position % image_width
247   -
248   - elif self.orientation == 'CORONAL':
249   - image_width = self.slice_actor.GetInput().GetDimensions()[0]
250   - axial = position / image_width
251   - coronal = self.slice_data.number
252   - sagital = position % image_width
253   -
254   - elif self.orientation == 'SAGITAL':
255   - image_width = self.slice_actor.GetInput().GetDimensions()[1]
256   - axial = position / image_width
257   - coronal = position % image_width
258   - sagital = self.slice_data.number
259   -
260   - return sagital, coronal, axial
261   -
262 229 def ScrollSlice(self, coord):
263 230 if self.orientation == "AXIAL":
264 231 Publisher.sendMessage(('Set scroll position', 'SAGITAL'),
... ... @@ -276,18 +243,6 @@ class CrossInteractorStyle(DefaultInteractorStyle):
276 243 Publisher.sendMessage(('Set scroll position', 'SAGITAL'),
277 244 coord[0])
278 245  
279   - def get_coordinate_cursor(self):
280   - # Find position
281   - x, y, z = self.picker.GetPickPosition()
282   - bounds = self.viewer.slice_data.actor.GetBounds()
283   - if bounds[0] == bounds[1]:
284   - x = bounds[0]
285   - elif bounds[2] == bounds[3]:
286   - y = bounds[2]
287   - elif bounds[4] == bounds[5]:
288   - z = bounds[4]
289   - return x, y, z
290   -
291 246  
292 247 class WWWLInteractorStyle(DefaultInteractorStyle):
293 248 """
... ... @@ -791,21 +746,13 @@ class EditorInteractorStyle(DefaultInteractorStyle):
791 746 #i.cursor.Show(0)
792 747 slice_data.cursor.Show()
793 748  
794   - self.picker.Pick(mouse_x, mouse_y, 0, render)
795   -
796   - coord = self.get_coordinate_cursor()
797   - position = slice_data.actor.GetInput().FindPoint(coord)
  749 + wx, wy, wz = viewer.get_coordinate_cursor(mouse_x, mouse_y, self.picker)
  750 + position = viewer.get_slice_pixel_coord_by_world_pos(wx, wy, wz)
798 751  
799   - if position != -1:
800   - coord = slice_data.actor.GetInput().GetPoint(position)
801   -
802   - slice_data.cursor.SetPosition(coord)
803 752 cursor = slice_data.cursor
804 753 radius = cursor.radius
805 754  
806   - if position < 0:
807   - position = viewer.calculate_matrix_position(coord)
808   -
  755 + slice_data.cursor.SetPosition((wx, wy, wz))
809 756 viewer.slice_.edit_mask_pixel(operation, cursor.GetPixels(),
810 757 position, radius, viewer.orientation)
811 758 #viewer._flush_buffer = True
... ... @@ -842,39 +789,19 @@ class EditorInteractorStyle(DefaultInteractorStyle):
842 789 elif operation == const.BRUSH_DRAW and iren.GetControlKey():
843 790 operation = const.BRUSH_ERASE
844 791  
845   - # TODO: Improve!
846   - #for i in self.slice_data_list:
847   - #i.cursor.Show(0)
848   -
849   - self.picker.Pick(mouse_x, mouse_y, 0, render)
850   -
851   - #if (self.pick.GetViewProp()):
852   - #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
853   - #else:
854   - #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
855   -
856   - coord = self.get_coordinate_cursor()
857   - position = viewer.slice_data.actor.GetInput().FindPoint(coord)
858   -
859   - # when position == -1 the cursos is not over the image, so is not
860   - # necessary to set the cursor position to world coordinate center of
861   - # pixel from slice image.
862   - if position != -1:
863   - coord = slice_data.actor.GetInput().GetPoint(position)
864   - slice_data.cursor.SetPosition(coord)
865   - #self.__update_cursor_position(slice_data, coord)
  792 + wx, wy, wz = viewer.get_coordinate_cursor(mouse_x, mouse_y, self.picker)
  793 + slice_data.cursor.SetPosition((wx, wy, wz))
866 794  
867 795 if (self.left_pressed):
868 796 cursor = slice_data.cursor
869   - position = slice_data.actor.GetInput().FindPoint(coord)
870 797 radius = cursor.radius
871 798  
872   - if position < 0:
873   - position = viewer.calculate_matrix_position(coord)
  799 + position = viewer.get_slice_pixel_coord_by_world_pos(wx, wy, wz)
874 800  
  801 + slice_data.cursor.SetPosition((wx, wy, wz))
875 802 viewer.slice_.edit_mask_pixel(operation, cursor.GetPixels(),
876   - position, radius, self.orientation)
877   - # TODO: To create a new function to reload images to viewer.
  803 + position, radius, viewer.orientation)
  804 +
878 805 viewer.OnScrollBar(update3D=False)
879 806  
880 807 else:
... ... @@ -924,18 +851,6 @@ class EditorInteractorStyle(DefaultInteractorStyle):
924 851 else:
925 852 self.OnScrollBackward(obj, evt)
926 853  
927   - def get_coordinate_cursor(self):
928   - # Find position
929   - x, y, z = self.picker.GetPickPosition()
930   - bounds = self.viewer.slice_data.actor.GetBounds()
931   - if bounds[0] == bounds[1]:
932   - x = bounds[0]
933   - elif bounds[2] == bounds[3]:
934   - y = bounds[2]
935   - elif bounds[4] == bounds[5]:
936   - z = bounds[4]
937   - return x, y, z
938   -
939 854  
940 855 class WatershedProgressWindow(object):
941 856 def __init__(self, process):
... ... @@ -1153,28 +1068,15 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
1153 1068 render = iren.FindPokedRenderer(mouse_x, mouse_y)
1154 1069 slice_data = viewer.get_slice_data(render)
1155 1070  
1156   - # TODO: Improve!
1157   - #for i in self.slice_data_list:
1158   - #i.cursor.Show(0)
1159   - slice_data.cursor.Show()
1160   -
1161   - self.picker.Pick(mouse_x, mouse_y, 0, render)
1162   -
1163   - coord = self.get_coordinate_cursor()
1164   - position = slice_data.actor.GetInput().FindPoint(coord)
1165   -
1166   - if position != -1:
1167   - coord = slice_data.actor.GetInput().GetPoint(position)
  1071 + coord = self.viewer.get_coordinate_cursor(mouse_x, mouse_y, picker=None)
  1072 + position = self.viewer.get_slice_pixel_coord_by_screen_pos(mouse_x, mouse_y, self.picker)
1168 1073  
  1074 + slice_data.cursor.Show()
1169 1075 slice_data.cursor.SetPosition(coord)
1170 1076  
1171 1077 cursor = slice_data.cursor
1172   - position = slice_data.actor.GetInput().FindPoint(coord)
1173 1078 radius = cursor.radius
1174 1079  
1175   - if position < 0:
1176   - position = viewer.calculate_matrix_position(coord)
1177   -
1178 1080 operation = self.config.operation
1179 1081  
1180 1082 if operation == BRUSH_FOREGROUND:
... ... @@ -1213,31 +1115,13 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
1213 1115 render = iren.FindPokedRenderer(mouse_x, mouse_y)
1214 1116 slice_data = viewer.get_slice_data(render)
1215 1117  
1216   - # TODO: Improve!
1217   - #for i in self.slice_data_list:
1218   - #i.cursor.Show(0)
1219   -
1220   - self.picker.Pick(mouse_x, mouse_y, 0, render)
1221   -
1222   - #if (self.pick.GetViewProp()):
1223   - #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
1224   - #else:
1225   - #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
1226   -
1227   - coord = self.get_coordinate_cursor()
1228   - position = viewer.slice_data.actor.GetInput().FindPoint(coord)
1229   -
1230   - # when position == -1 the cursos is not over the image, so is not
1231   - # necessary to set the cursor position to world coordinate center of
1232   - # pixel from slice image.
1233   - if position != -1:
1234   - coord = slice_data.actor.GetInput().GetPoint(position)
  1118 + coord = self.viewer.get_coordinate_cursor(mouse_x, mouse_y, self.picker)
1235 1119 slice_data.cursor.SetPosition(coord)
1236   - #self.__update_cursor_position(slice_data, coord)
1237 1120  
1238 1121 if (self.left_pressed):
1239 1122 cursor = slice_data.cursor
1240   - position = slice_data.actor.GetInput().FindPoint(coord)
  1123 + position = self.viewer.get_slice_pixel_coord_by_world_pos(*coord)
  1124 + print ">>>", position
1241 1125 radius = cursor.radius
1242 1126  
1243 1127 if position < 0:
... ... @@ -1344,18 +1228,6 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
1344 1228  
1345 1229 Publisher.sendMessage('Reload actual slice')
1346 1230  
1347   - def get_coordinate_cursor(self):
1348   - # Find position
1349   - x, y, z = self.picker.GetPickPosition()
1350   - bounds = self.viewer.slice_data.actor.GetBounds()
1351   - if bounds[0] == bounds[1]:
1352   - x = bounds[0]
1353   - elif bounds[2] == bounds[3]:
1354   - y = bounds[2]
1355   - elif bounds[4] == bounds[5]:
1356   - z = bounds[4]
1357   - return x, y, z
1358   -
1359 1231 def edit_mask_pixel(self, operation, n, index, position, radius, orientation):
1360 1232 if orientation == 'AXIAL':
1361 1233 mask = self.matrix[n, :, :]
... ... @@ -1366,7 +1238,7 @@ class WaterShedInteractorStyle(DefaultInteractorStyle):
1366 1238  
1367 1239 spacing = self.viewer.slice_.spacing
1368 1240 if hasattr(position, '__iter__'):
1369   - py, px = position
  1241 + px, py = position
1370 1242 if orientation == 'AXIAL':
1371 1243 sx = spacing[0]
1372 1244 sy = spacing[1]
... ... @@ -1804,24 +1676,10 @@ class FloodFillMaskInteractorStyle(DefaultInteractorStyle):
1804 1676  
1805 1677 viewer = self.viewer
1806 1678 iren = viewer.interactor
1807   -
1808 1679 mouse_x, mouse_y = iren.GetEventPosition()
1809   - render = iren.FindPokedRenderer(mouse_x, mouse_y)
1810   - slice_data = viewer.get_slice_data(render)
1811   -
1812   - self.picker.Pick(mouse_x, mouse_y, 0, render)
1813   -
1814   - coord = self.get_coordinate_cursor()
1815   - position = slice_data.actor.GetInput().FindPoint(coord)
1816   -
1817   - if position != -1:
1818   - coord = slice_data.actor.GetInput().GetPoint(position)
1819   -
1820   - if position < 0:
1821   - position = viewer.calculate_matrix_position(coord)
  1680 + x, y, z = self.viewer.get_voxel_coord_by_screen_pos(mouse_x, mouse_y, self.picker)
1822 1681  
1823 1682 mask = self.viewer.slice_.current_mask.matrix[1:, 1:, 1:]
1824   - x, y, z = self.calcultate_scroll_position(position)
1825 1683 if mask[z, y, x] < self.t0 or mask[z, y, x] > self.t1:
1826 1684 return
1827 1685  
... ... @@ -1878,43 +1736,6 @@ class FloodFillMaskInteractorStyle(DefaultInteractorStyle):
1878 1736 self.viewer.slice_.current_mask.was_edited = True
1879 1737 Publisher.sendMessage('Reload actual slice')
1880 1738  
1881   - def get_coordinate_cursor(self):
1882   - # Find position
1883   - x, y, z = self.picker.GetPickPosition()
1884   - bounds = self.viewer.slice_data.actor.GetBounds()
1885   - if bounds[0] == bounds[1]:
1886   - x = bounds[0]
1887   - elif bounds[2] == bounds[3]:
1888   - y = bounds[2]
1889   - elif bounds[4] == bounds[5]:
1890   - z = bounds[4]
1891   - return x, y, z
1892   -
1893   - def calcultate_scroll_position(self, position):
1894   - # Based in the given coord (x, y, z), returns a list with the scroll positions for each
1895   - # orientation, being the first position the sagital, second the coronal
1896   - # and the last, axial.
1897   -
1898   - if self.orientation == 'AXIAL':
1899   - image_width = self.slice_actor.GetInput().GetDimensions()[0]
1900   - axial = self.slice_data.number
1901   - coronal = position / image_width
1902   - sagital = position % image_width
1903   -
1904   - elif self.orientation == 'CORONAL':
1905   - image_width = self.slice_actor.GetInput().GetDimensions()[0]
1906   - axial = position / image_width
1907   - coronal = self.slice_data.number
1908   - sagital = position % image_width
1909   -
1910   - elif self.orientation == 'SAGITAL':
1911   - image_width = self.slice_actor.GetInput().GetDimensions()[1]
1912   - axial = position / image_width
1913   - coronal = position % image_width
1914   - sagital = self.slice_data.number
1915   -
1916   - return sagital, coronal, axial
1917   -
1918 1739  
1919 1740 class RemoveMaskPartsInteractorStyle(FloodFillMaskInteractorStyle):
1920 1741 def __init__(self, viewer):
... ... @@ -1989,7 +1810,7 @@ class SelectMaskPartsInteractorStyle(DefaultInteractorStyle):
1989 1810  
1990 1811 iren = self.viewer.interactor
1991 1812 mouse_x, mouse_y = iren.GetEventPosition()
1992   - x, y, z = self.viewer.get_voxel_clicked(mouse_x, mouse_y, self.picker)
  1813 + x, y, z = self.viewer.get_voxel_coord_by_screen_pos(mouse_x, mouse_y, self.picker)
1993 1814  
1994 1815 mask = self.viewer.slice_.current_mask.matrix[1:, 1:, 1:]
1995 1816  
... ...
invesalius/data/viewer_slice.py
... ... @@ -940,25 +940,23 @@ class Viewer(wx.Panel):
940 940 # WARN: Return the only slice_data used in this slice_viewer.
941 941 return self.slice_data
942 942  
943   - def calcultate_scroll_position(self, position):
944   - # Based in the given coord (x, y, z), returns a list with the scroll positions for each
  943 + def calcultate_scroll_position(self, x, y):
  944 + # Based in the given coord (x, y), returns a list with the scroll positions for each
945 945 # orientation, being the first position the sagital, second the coronal
946 946 # and the last, axial.
947   - image_width = self.slice_.buffer_slices[self.orientation].image.shape[1]
948   -
949 947 if self.orientation == 'AXIAL':
950 948 axial = self.slice_data.number
951   - coronal = position / image_width
952   - sagital = position % image_width
  949 + coronal = y
  950 + sagital = x
953 951  
954 952 elif self.orientation == 'CORONAL':
955   - axial = position / image_width
  953 + axial = y
956 954 coronal = self.slice_data.number
957   - sagital = position % image_width
  955 + sagital = x
958 956  
959 957 elif self.orientation == 'SAGITAL':
960   - axial = position / image_width
961   - coronal = position % image_width
  958 + axial = y
  959 + coronal = x
962 960 sagital = self.slice_data.number
963 961  
964 962 return sagital, coronal, axial
... ... @@ -975,13 +973,28 @@ class Viewer(wx.Panel):
975 973 elif self.orientation == 'SAGITAL':
976 974 mx = round((y - yi)/self.slice_.spacing[1], 0)
977 975 my = round((z - zi)/self.slice_.spacing[2], 0)
978   - return my, mx
  976 + return mx, my
979 977  
980   - def get_coordinate_cursor(self, picker=None):
981   - # Find position
  978 + def get_coordinate_cursor(self, mx, my, picker=None):
  979 + """
  980 + Given the mx, my screen position returns the x, y, z position in world
  981 + coordinates.
  982 +
  983 + Parameters
  984 + mx (int): x position.
  985 + my (int): y position
  986 + picker: the picker used to get calculate the voxel coordinate.
  987 +
  988 + Returns:
  989 + world coordinate (x, y, z)
  990 + """
982 991 if picker is None:
983 992 picker = self.pick
984 993  
  994 + slice_data = self.slice_data
  995 + renderer = slice_data.renderer
  996 +
  997 + picker.Pick(mx, my, 0, renderer)
985 998 x, y, z = picker.GetPickPosition()
986 999 bounds = self.slice_data.actor.GetBounds()
987 1000 if bounds[0] == bounds[1]:
... ... @@ -1029,10 +1042,10 @@ class Viewer(wx.Panel):
1029 1042  
1030 1043 return x, y, z
1031 1044  
1032   - def get_voxel_clicked(self, mx, my, picker=None):
  1045 + def get_voxel_coord_by_screen_pos(self, mx, my, picker=None):
1033 1046 """
1034   - Given the (mx, my) mouse clicked position returns the voxel coordinate
1035   - of the voxel at (that mx, my) position.
  1047 + Given the (mx, my) screen position returns the voxel coordinate
  1048 + of the volume at (that mx, my) position.
1036 1049  
1037 1050 Parameters:
1038 1051 mx (int): x position.
... ... @@ -1046,23 +1059,86 @@ class Viewer(wx.Panel):
1046 1059 if picker is None:
1047 1060 picker = self.pick
1048 1061  
  1062 + wx, wy, wz = self.get_coordinate_cursor(mx, my, picker)
  1063 + x, y, z = self.get_voxel_coord_by_world_pos(wx, wy, wz)
  1064 +
  1065 + return (x, y, z)
  1066 +
  1067 + def get_voxel_coord_by_world_pos(self, wx, wy, wz):
  1068 + """
  1069 + Given the (x, my) screen position returns the voxel coordinate
  1070 + of the volume at (that mx, my) position.
  1071 +
  1072 + Parameters:
  1073 + wx (float): x position.
  1074 + wy (float): y position
  1075 + wz (float): z position
  1076 +
  1077 + Returns:
  1078 + voxel_coordinate (x, y, z): voxel coordinate inside the matrix. Can
  1079 + be used to access the voxel value inside the matrix.
  1080 + """
  1081 + px, py = self.get_slice_pixel_coord_by_world_pos(wx, wy, wz)
  1082 + x, y, z = self.calcultate_scroll_position(px, py)
  1083 +
  1084 + return (x, y, z)
  1085 +
  1086 +
  1087 + def get_slice_pixel_coord_by_screen_pos(self, mx, my, picker=None):
  1088 + """
  1089 + Given the (mx, my) screen position returns the pixel coordinate
  1090 + of the slice at (that mx, my) position.
  1091 +
  1092 + Parameters:
  1093 + mx (int): x position.
  1094 + my (int): y position
  1095 + picker: the picker used to get calculate the pixel coordinate.
  1096 +
  1097 + Returns:
  1098 + voxel_coordinate (x, y): voxel coordinate inside the matrix. Can
  1099 + be used to access the voxel value inside the matrix.
  1100 + """
  1101 + if picker is None:
  1102 + picker = self.pick
  1103 +
  1104 + wx, wy, wz = self.get_coordinate_cursor(mx, my, picker)
  1105 + return self.get_slice_pixel_coord_by_world_pos(wx, wy, wz)
  1106 +
  1107 + return px, py
  1108 +
  1109 + def get_slice_pixel_coord_by_world_pos(self, wx, wy, wz):
  1110 + """
  1111 + Given the (wx, wy, wz) world position returns the pixel coordinate
  1112 + of the slice at (that mx, my) position.
  1113 +
  1114 + Parameters:
  1115 + mx (int): x position.
  1116 + my (int): y position
  1117 + picker: the picker used to get calculate the pixel coordinate.
  1118 +
  1119 + Returns:
  1120 + voxel_coordinate (x, y): voxel coordinate inside the matrix. Can
  1121 + be used to access the voxel value inside the matrix.
  1122 + """
  1123 + coord = wx, wy, wz
  1124 + px, py = self.calculate_matrix_position(coord)
  1125 +
  1126 + return px, py
  1127 +
  1128 + def get_coord_inside_volume(self, mx, my, picker=None):
  1129 + if picker is None:
  1130 + picker = self.pick
  1131 +
1049 1132 slice_data = self.slice_data
1050 1133 renderer = slice_data.renderer
1051 1134  
1052   - picker.Pick(mx, my, 0, renderer)
1053   -
1054 1135 coord = self.get_coordinate_cursor(picker)
1055 1136 position = slice_data.actor.GetInput().FindPoint(coord)
1056 1137  
1057 1138 if position != -1:
1058 1139 coord = slice_data.actor.GetInput().GetPoint(position)
1059 1140  
1060   - if position < 0:
1061   - position = viewer.calculate_matrix_position(coord)
1062   -
1063   - x, y, z = self.calcultate_scroll_position(position)
1064   -
1065   - return (x, y, z)
  1141 + return coord
1066 1142  
1067 1143 def __bind_events(self):
1068 1144 Publisher.subscribe(self.LoadImagedata,
... ...