Commit 32a72e8b400238d37779453dcf05084a5402256d
1 parent
7853c073
Exists in
master
and in
6 other branches
ENH: Cursor actor is being shown over slice. Not working when cursor is moved.
Showing
1 changed file
with
75 additions
and
60 deletions
Show diff stats
invesalius/data/viewer_slice.py
... | ... | @@ -29,34 +29,34 @@ import project |
29 | 29 | import cursor_actors as ca |
30 | 30 | |
31 | 31 | class Viewer(wx.Panel): |
32 | - | |
32 | + | |
33 | 33 | def __init__(self, prnt, orientation='AXIAL'): |
34 | 34 | wx.Panel.__init__(self, prnt, size=wx.Size(320, 300)) |
35 | - | |
35 | + | |
36 | 36 | colour = [255*c for c in const.ORIENTATION_COLOUR[orientation]] |
37 | 37 | self.SetBackgroundColour(colour) |
38 | - | |
38 | + | |
39 | 39 | # Interactor aditional style |
40 | 40 | self.modes = ['DEFAULT'] |
41 | 41 | self.mouse_pressed = 0 |
42 | - | |
42 | + | |
43 | 43 | self.__init_gui() |
44 | 44 | |
45 | 45 | self.orientation = orientation |
46 | 46 | self.slice_number = 0 |
47 | - | |
47 | + | |
48 | 48 | self._brush_cursor_op = 'Draw' |
49 | 49 | self.brush_cursor_size = 30 |
50 | - | |
50 | + self.cursor = None | |
51 | 51 | # VTK pipeline and actors |
52 | 52 | self.__config_interactor() |
53 | 53 | self.pick = vtk.vtkCellPicker() |
54 | - | |
54 | + | |
55 | 55 | self.__bind_events() |
56 | 56 | self.__bind_events_wx() |
57 | 57 | |
58 | 58 | def __init_gui(self): |
59 | - | |
59 | + | |
60 | 60 | interactor = wxVTKRenderWindowInteractor(self, -1, size=self.GetSize()) |
61 | 61 | |
62 | 62 | scroll = wx.ScrollBar(self, -1, style=wx.SB_VERTICAL) |
... | ... | @@ -78,7 +78,7 @@ class Viewer(wx.Panel): |
78 | 78 | self.interactor = interactor |
79 | 79 | |
80 | 80 | def __config_interactor(self): |
81 | - | |
81 | + | |
82 | 82 | ren = vtk.vtkRenderer() |
83 | 83 | |
84 | 84 | interactor = self.interactor |
... | ... | @@ -86,14 +86,13 @@ class Viewer(wx.Panel): |
86 | 86 | |
87 | 87 | self.cam = ren.GetActiveCamera() |
88 | 88 | self.ren = ren |
89 | - | |
90 | - self.AppendMode('EDITOR') | |
91 | - | |
89 | + | |
90 | + | |
92 | 91 | def AppendMode(self, mode): |
93 | - | |
92 | + | |
94 | 93 | # Retrieve currently set modes |
95 | 94 | self.modes.append(mode) |
96 | - | |
95 | + | |
97 | 96 | # All modes and bindings |
98 | 97 | action = {'DEFAULT': { |
99 | 98 | "MouseMoveEvent": self.OnCrossMove, |
... | ... | @@ -111,7 +110,7 @@ class Viewer(wx.Panel): |
111 | 110 | style = vtk.vtkInteractorStyleImage() |
112 | 111 | self.style = style |
113 | 112 | self.interactor.SetInteractorStyle(style) |
114 | - | |
113 | + | |
115 | 114 | # Check all modes set by user |
116 | 115 | for mode in self.modes: |
117 | 116 | # Check each event available for each mode |
... | ... | @@ -120,17 +119,7 @@ class Viewer(wx.Panel): |
120 | 119 | style.AddObserver(event, |
121 | 120 | action[mode][event]) |
122 | 121 | |
123 | - # Insert cursor | |
124 | - cursor = ca.CursorCircle() | |
125 | - cursor.SetOrientation(self.orientation) | |
126 | - coordinates = {"SAGITAL": [self.slice_number, 0, 0], | |
127 | - "CORONAL": [0, self.slice_number, 0], | |
128 | - "AXIAL": [0, 0, self.slice_number]} | |
129 | - cursor.SetPosition(coordinates[self.orientation]) | |
130 | - self.ren.AddActor(cursor.actor) | |
131 | - self.ren.Render() | |
132 | - | |
133 | - self.cursor = cursor | |
122 | + | |
134 | 123 | |
135 | 124 | def ChangeBrushSize(self, pubsub_evt): |
136 | 125 | size = pubsub_evt.data |
... | ... | @@ -140,23 +129,24 @@ class Viewer(wx.Panel): |
140 | 129 | self.interactor.Render() |
141 | 130 | |
142 | 131 | def ChangeBrushColour(self, pubsub_evt): |
143 | - vtk_colour = pubsub_evt.data[3] | |
144 | - self.cursor.SetColour(vtk_colour) | |
145 | - self._brush_cursor_colour = vtk_colour | |
146 | - self.ren.Render() | |
147 | - self.interactor.Render() | |
148 | - | |
132 | + if (self.cursor): | |
133 | + vtk_colour = pubsub_evt.data[3] | |
134 | + self.cursor.SetColour(vtk_colour) | |
135 | + self._brush_cursor_colour = vtk_colour | |
136 | + self.ren.Render() | |
137 | + self.interactor.Render() | |
138 | + | |
149 | 139 | |
150 | 140 | def ChangeBrushActor(self, pubsub_evt): |
151 | 141 | brush_type = pubsub_evt.data |
152 | 142 | self.ren.RemoveActor(self.cursor.actor) |
153 | - | |
143 | + | |
154 | 144 | if brush_type == 'square': |
155 | 145 | cursor = ca.CursorRectangle() |
156 | 146 | elif brush_type == 'circle': |
157 | 147 | cursor = ca.CursorCircle() |
158 | 148 | self.cursor = cursor |
159 | - | |
149 | + | |
160 | 150 | cursor.SetOrientation(self.orientation) |
161 | 151 | coordinates = {"SAGITAL": [self.slice_number, 0, 0], |
162 | 152 | "CORONAL": [0, self.slice_number, 0], |
... | ... | @@ -187,21 +177,21 @@ class Viewer(wx.Panel): |
187 | 177 | self.cursor.SetPosition(coord) |
188 | 178 | self.cursor.SetEditionPosition(self.GetCoordinateCursorEdition()) |
189 | 179 | self.ren.Render() |
190 | - | |
180 | + | |
191 | 181 | if self._brush_cursor_op == 'Erase': |
192 | 182 | evt_msg = 'Erase mask pixel' |
193 | 183 | elif self._brush_cursor_op == 'Draw': |
194 | 184 | evt_msg = 'Add mask pixel' |
195 | 185 | elif self._brush_cursor_op == 'Threshold': |
196 | 186 | evt_msg = 'Edit mask pixel' |
197 | - | |
187 | + | |
198 | 188 | if self.mouse_pressed: |
199 | 189 | print "Edit pixel region based on origin:", coord |
200 | 190 | pixels = self.cursor.GetPixels() |
201 | 191 | for coord in pixels: |
202 | 192 | ps.Publisher().sendMessage(evt_msg, coord) |
203 | 193 | self.interactor.Render() |
204 | - | |
194 | + | |
205 | 195 | def OnCrossMove(self, obj, evt_vtk): |
206 | 196 | coord = self.GetCoordinate() |
207 | 197 | # Update position in other slices |
... | ... | @@ -214,34 +204,34 @@ class Viewer(wx.Panel): |
214 | 204 | coord[1]) |
215 | 205 | ps.Publisher().sendMessage(('Set scroll position', 'AXIAL'), |
216 | 206 | coord[2]) |
217 | - | |
218 | - | |
207 | + | |
208 | + | |
219 | 209 | def GetCoordinate(self): |
220 | - | |
210 | + | |
221 | 211 | # Find position |
222 | 212 | mouse_x, mouse_y = self.interactor.GetEventPosition() |
223 | 213 | self.pick.Pick(mouse_x, mouse_y, 0, self.ren) |
224 | 214 | x, y, z = self.pick.GetPickPosition() |
225 | - | |
215 | + | |
226 | 216 | # First we fix the position origin, based on vtkActor bounds |
227 | 217 | bounds = self.actor.GetBounds() |
228 | 218 | bound_xi, bound_xf, bound_yi, bound_yf, bound_zi, bound_zf = bounds |
229 | 219 | x = float(x - bound_xi) |
230 | 220 | y = float(y - bound_yi) |
231 | 221 | z = float(z - bound_zi) |
232 | - | |
222 | + | |
233 | 223 | # Then we fix the porpotion, based on vtkImageData spacing |
234 | 224 | spacing_x, spacing_y, spacing_z = self.imagedata.GetSpacing() |
235 | 225 | x = x/spacing_x |
236 | 226 | y = y/spacing_y |
237 | 227 | z = z/spacing_z |
238 | - | |
228 | + | |
239 | 229 | # Based on the current orientation, we define 3D position |
240 | 230 | coordinates = {"SAGITAL": [self.slice_number, y, z], |
241 | 231 | "CORONAL": [x, self.slice_number, z], |
242 | 232 | "AXIAL": [x, y, self.slice_number]} |
243 | 233 | coord = [int(coord) for coord in coordinates[self.orientation]] |
244 | - | |
234 | + | |
245 | 235 | # According to vtkImageData extent, we limit min and max value |
246 | 236 | # If this is not done, a VTK Error occurs when mouse is pressed outside |
247 | 237 | # vtkImageData extent |
... | ... | @@ -254,24 +244,24 @@ class Viewer(wx.Panel): |
254 | 244 | elif coord[index] < extent_min[index]: |
255 | 245 | coord[index] = extent_min[index] |
256 | 246 | #print "New coordinate: ", coord |
257 | - | |
247 | + | |
258 | 248 | return coord |
259 | - | |
249 | + | |
260 | 250 | def GetCoordinateCursor(self): |
261 | - | |
251 | + | |
262 | 252 | # Find position |
263 | 253 | mouse_x, mouse_y = self.interactor.GetEventPosition() |
264 | 254 | self.pick.Pick(mouse_x, mouse_y, 0, self.ren) |
265 | 255 | x, y, z = self.pick.GetPickPosition() |
266 | 256 | return x, y, z |
267 | - | |
257 | + | |
268 | 258 | def GetCoordinateCursorEdition(self): |
269 | - | |
259 | + | |
270 | 260 | # Find position |
271 | 261 | mouse_x, mouse_y = self.interactor.GetEventPosition() |
272 | 262 | self.pick.Pick(mouse_x, mouse_y, 0, self.ren) |
273 | 263 | x, y, z = self.pick.GetPickPosition() |
274 | - | |
264 | + | |
275 | 265 | # First we fix the position origin, based on vtkActor bounds |
276 | 266 | bounds = self.actor.GetBounds() |
277 | 267 | bound_xi, bound_xf, bound_yi, bound_yf, bound_zi, bound_zf = bounds |
... | ... | @@ -299,21 +289,21 @@ class Viewer(wx.Panel): |
299 | 289 | z = self.slice_number |
300 | 290 | |
301 | 291 | return x,y,z |
302 | - | |
292 | + | |
303 | 293 | def __bind_events(self): |
304 | 294 | ps.Publisher().subscribe(self.LoadImagedata, 'Load slice to viewer') |
305 | 295 | ps.Publisher().subscribe(self.SetColour, 'Change mask colour') |
306 | 296 | ps.Publisher().subscribe(self.UpdateRender, 'Update slice viewer') |
307 | - ps.Publisher().subscribe(self.ChangeSliceNumber, ('Set scroll position', | |
297 | + ps.Publisher().subscribe(self.ChangeSliceNumber, ('Set scroll position', | |
308 | 298 | self.orientation)) |
309 | - | |
299 | + | |
310 | 300 | ### |
311 | 301 | ps.Publisher().subscribe(self.ChangeBrushSize,'Set edition brush size') |
312 | 302 | ps.Publisher().subscribe(self.ChangeBrushColour, 'Add mask') |
313 | 303 | ps.Publisher().subscribe(self.ChangeBrushActor, 'Set brush format') |
314 | 304 | ps.Publisher().subscribe(self.ChangeBrushOperation, 'Set edition operation') |
315 | - | |
316 | - | |
305 | + | |
306 | + | |
317 | 307 | def ChangeBrushOperation(self, pubsub_evt): |
318 | 308 | print pubsub_evt.data |
319 | 309 | self._brush_cursor_op = pubsub_evt.data |
... | ... | @@ -339,6 +329,7 @@ class Viewer(wx.Panel): |
339 | 329 | |
340 | 330 | actor = vtk.vtkImageActor() |
341 | 331 | actor.SetInput(slice_.GetOutput()) |
332 | + actor_bound = actor.GetBounds() | |
342 | 333 | self.actor = actor |
343 | 334 | |
344 | 335 | colour = const.ORIENTATION_COLOUR[self.orientation] |
... | ... | @@ -363,7 +354,30 @@ class Viewer(wx.Panel): |
363 | 354 | self.scroll.SetScrollbar(wx.SB_VERTICAL, 1, max_slice_number, |
364 | 355 | max_slice_number) |
365 | 356 | self.SetScrollPosition(0) |
366 | - self.cursor.SetSpacing(imagedata.GetSpacing()) | |
357 | + | |
358 | + actor_bound = actor.GetBounds() | |
359 | + | |
360 | + # Insert cursor | |
361 | + cursor = ca.CursorCircle() | |
362 | + cursor.SetOrientation(self.orientation) | |
363 | + self.__update_cursor_position() | |
364 | + cursor.SetSpacing(imagedata.GetSpacing()) | |
365 | + self.ren.AddActor(cursor.actor) | |
366 | + self.ren.Render() | |
367 | + | |
368 | + self.cursor = cursor | |
369 | + | |
370 | + self.AppendMode('EDITOR') | |
371 | + | |
372 | + def __update_cursor_position(self, position = None): | |
373 | + | |
374 | + if (self.cursor): | |
375 | + slice_number = self.slice_number | |
376 | + actor_bound = self.actor.GetBounds() | |
377 | + coordinates = {"SAGITAL": [actor_bound[1] + 1 + slice_number, actor_bound[3], actor_bound[5]], | |
378 | + "CORONAL": [actor_bound[1], actor_bound[3] + 1 + slice_number, actor_bound[5]], | |
379 | + "AXIAL": [actor_bound[1], actor_bound[3], actor_bound[5] + 1 + slice_number]} | |
380 | + self.cursor.SetPosition(coordinates[self.orientation]) | |
367 | 381 | |
368 | 382 | def SetOrientation(self, orientation): |
369 | 383 | self.orientation = orientation |
... | ... | @@ -378,10 +392,10 @@ class Viewer(wx.Panel): |
378 | 392 | cam.SetViewUp(const.CAM_VIEW_UP[self.orientation]) |
379 | 393 | cam.ComputeViewPlaneNormal() |
380 | 394 | cam.OrthogonalizeViewUp() |
381 | - cam.ParallelProjectionOn() | |
395 | + cam.ParallelProjectionOn() | |
382 | 396 | |
383 | 397 | self.__update_display_extent() |
384 | - | |
398 | + | |
385 | 399 | self.ren.ResetCamera() |
386 | 400 | self.ren.Render() |
387 | 401 | |
... | ... | @@ -389,11 +403,11 @@ class Viewer(wx.Panel): |
389 | 403 | |
390 | 404 | pos = self.slice_number |
391 | 405 | e = self.imagedata.GetWholeExtent() |
392 | - | |
406 | + | |
393 | 407 | new_extent = {"SAGITAL": (pos, pos, e[2], e[3], e[4], e[5]), |
394 | 408 | "CORONAL": (e[0], e[1], pos, pos, e[4], e[5]), |
395 | 409 | "AXIAL": (e[0], e[1], e[2], e[3], pos, pos)} |
396 | - | |
410 | + | |
397 | 411 | self.actor.SetDisplayExtent(new_extent[self.orientation]) |
398 | 412 | self.ren.ResetCameraClippingRange() |
399 | 413 | self.ren.Render() |
... | ... | @@ -416,6 +430,7 @@ class Viewer(wx.Panel): |
416 | 430 | self.text_actor.SetInput(str(index)) |
417 | 431 | self.slice_number = index |
418 | 432 | self.__update_display_extent() |
433 | + self.__update_cursor_position() | |
419 | 434 | |
420 | 435 | def ChangeSliceNumber(self, pubsub_evt): |
421 | 436 | index = pubsub_evt.data | ... | ... |