Commit 50cad05c75d947d97239c0ec408666cdd1924890

Authored by Victor Hugo Souza
Committed by GitHub
1 parent 27f1cd9f
Exists in master

FIX: Failed to fetch image coordinates from cross move (#257)

* FIX: Failed to fetch image coordinates from cross move
- Previous changes to the cross style disrupted the navigation
- Enhanced how image coordinates are communicated through pubsub

* WIP: Fix scroll and cross focal point difference in coordinate

* FIX: Scroll and cross coordinates did not match
- Removed debugging prints
- Commented and removed unnecessary calls and function
- Tested on niftis with 1.0 and 0.488 pixel spacings

* Rename UpdateSlices
invesalius/data/record_coords.py
@@ -43,9 +43,9 @@ class Record(threading.Thread): @@ -43,9 +43,9 @@ class Record(threading.Thread):
43 43
44 def __bind_events(self): 44 def __bind_events(self):
45 # Publisher.subscribe(self.UpdateCurrentCoords, 'Co-registered points') 45 # Publisher.subscribe(self.UpdateCurrentCoords, 'Co-registered points')
46 - Publisher.subscribe(self.UpdateCurrentCoords, 'Update cross position') 46 + Publisher.subscribe(self.UpdateCurrentCoords, 'Set cross focal point')
47 47
48 - def UpdateCurrentCoords(self, arg, position): 48 + def UpdateCurrentCoords(self, position):
49 self.coord = asarray(position) 49 self.coord = asarray(position)
50 50
51 def stop(self): 51 def stop(self):
invesalius/data/styles.py
@@ -473,18 +473,6 @@ class CrossInteractorStyle(DefaultInteractorStyle): @@ -473,18 +473,6 @@ class CrossInteractorStyle(DefaultInteractorStyle):
473 self.slice_actor = viewer.slice_data.actor 473 self.slice_actor = viewer.slice_data.actor
474 self.slice_data = viewer.slice_data 474 self.slice_data = viewer.slice_data
475 475
476 - # tracts  
477 - # self.seed = [0., 0., 0.]  
478 - # slic = sl.Slice()  
479 - # self.affine = slic.affine  
480 - # self.tracker = slic.tracker  
481 - #  
482 - # self.affine_vtk = vtk.vtkMatrix4x4()  
483 - # for row in range(0, 4):  
484 - # for col in range(0, 4):  
485 - # self.affine_vtk.SetElement(row, col, self.affine[row, col])  
486 - # ---  
487 -  
488 self.picker = vtk.vtkWorldPointPicker() 476 self.picker = vtk.vtkWorldPointPicker()
489 477
490 self.AddObserver("MouseMoveEvent", self.OnCrossMove) 478 self.AddObserver("MouseMoveEvent", self.OnCrossMove)
@@ -514,48 +502,18 @@ class CrossInteractorStyle(DefaultInteractorStyle): @@ -514,48 +502,18 @@ class CrossInteractorStyle(DefaultInteractorStyle):
514 502
515 def ChangeCrossPosition(self, iren): 503 def ChangeCrossPosition(self, iren):
516 mouse_x, mouse_y = iren.GetEventPosition() 504 mouse_x, mouse_y = iren.GetEventPosition()
517 - wx, wy, wz = self.viewer.get_coordinate_cursor(mouse_x, mouse_y, self.picker)  
518 - px, py = self.viewer.get_slice_pixel_coord_by_world_pos(wx, wy, wz)  
519 - coord = self.viewer.calcultate_scroll_position(px, py)  
520 -  
521 - # Tracts  
522 - # pos_world_aux = np.ones([4, 1])  
523 - # pos_world_aux[:3, -1] = bases.flip_x((wx, wy, wz))[:3]  
524 - # pos_world = np.linalg.inv(self.affine) @ pos_world_aux  
525 - # seed_aux = pos_world.reshape([1, 4])[0, :3]  
526 - # self.seed = seed_aux[np.newaxis, :]  
527 - # print("Check the seed: ", self.seed)  
528 - #  
529 - self.viewer.UpdateSlicesNavigation(None, (wx, wy, wz, 0.0, 0.0, 0.0))  
530 - Publisher.sendMessage('Set cross focal point', position=(wx, wy, wz)) 505 + x, y, z = self.viewer.get_coordinate_cursor(mouse_x, mouse_y, self.picker)
  506 + self.viewer.UpdateSlicesPosition([x, y, z])
  507 + # This "Set cross" message is needed to update the cross in the other slices
  508 + Publisher.sendMessage('Set cross focal point', position=[x, y, z, 0., 0., 0.])
531 Publisher.sendMessage('Update slice viewer') 509 Publisher.sendMessage('Update slice viewer')
532 - # self.ScrollSlice(coord)  
533 -  
534 - # iren.Render()  
535 -  
536 - def ScrollSlice(self, coord):  
537 - if self.orientation == "AXIAL":  
538 - Publisher.sendMessage(('Set scroll position', 'SAGITAL'),  
539 - index=coord[0])  
540 - Publisher.sendMessage(('Set scroll position', 'CORONAL'),  
541 - index=coord[1])  
542 - elif self.orientation == "SAGITAL":  
543 - Publisher.sendMessage(('Set scroll position', 'AXIAL'),  
544 - index=coord[2])  
545 - Publisher.sendMessage(('Set scroll position', 'CORONAL'),  
546 - index=coord[1])  
547 - elif self.orientation == "CORONAL":  
548 - Publisher.sendMessage(('Set scroll position', 'AXIAL'),  
549 - index=coord[2])  
550 - Publisher.sendMessage(('Set scroll position', 'SAGITAL'),  
551 - index=coord[0])  
552 510
553 def OnScrollBar(self, *args, **kwargs): 511 def OnScrollBar(self, *args, **kwargs):
554 # Update other slice's cross according to the new focal point from 512 # Update other slice's cross according to the new focal point from
555 # the actual orientation. 513 # the actual orientation.
556 x, y, z = self.viewer.cross.GetFocalPoint() 514 x, y, z = self.viewer.cross.GetFocalPoint()
557 - self.viewer.UpdateSlicesNavigation(None, (x, y, z, 0.0, 0.0, 0.0))  
558 - Publisher.sendMessage('Set cross focal point', position=(x, y, z)) 515 + self.viewer.UpdateSlicesPosition([x, y, z])
  516 + Publisher.sendMessage('Set cross focal point', position=[x, y, z, 0., 0., 0.])
559 Publisher.sendMessage('Update slice viewer') 517 Publisher.sendMessage('Update slice viewer')
560 518
561 519
invesalius/data/viewer_slice.py
@@ -565,17 +565,31 @@ class Viewer(wx.Panel): @@ -565,17 +565,31 @@ class Viewer(wx.Panel):
565 if self.slice_data.cursor: 565 if self.slice_data.cursor:
566 self.slice_data.cursor.SetColour(colour_vtk) 566 self.slice_data.cursor.SetColour(colour_vtk)
567 567
568 - def UpdateSlicesNavigation(self, arg, position): 568 + def UpdateSlicesPosition(self, position):
569 # Get point from base change 569 # Get point from base change
570 - ux, uy, uz = position[:3]  
571 - px, py = self.get_slice_pixel_coord_by_world_pos(ux, uy, uz) 570 + px, py = self.get_slice_pixel_coord_by_world_pos(*position)
572 coord = self.calcultate_scroll_position(px, py) 571 coord = self.calcultate_scroll_position(px, py)
  572 + # Debugging coordinates. For a 1.0 spacing axis the coord and position is the same,
  573 + # but for a spacing dimension =! 1, the coord and position are different
  574 + # print("\nPosition: {}".format(position))
  575 + # print("Scroll position: {}".format(coord))
  576 + # print("Slice actor bounds: {}".format(self.slice_data.actor.GetBounds()))
  577 + # print("Scroll from int of position: {}\n".format([round(s) for s in position]))
573 578
574 - self.cross.SetFocalPoint((ux, uy, uz)) 579 + # this call did not affect the working code
  580 + # self.cross.SetFocalPoint(coord)
  581 +
  582 + # update the image slices in all three orientations
575 self.ScrollSlice(coord) 583 self.ScrollSlice(coord)
576 584
577 def SetCrossFocalPoint(self, position): 585 def SetCrossFocalPoint(self, position):
578 - self.cross.SetFocalPoint(position) 586 + """
  587 + Sets the cross focal point for all slice panels (axial, coronal, sagittal). This function is also called via
  588 + pubsub messaging and may receive a list of 6 coordinates. Thus, limiting the number of list elements in the
  589 + SetFocalPoint call is required.
  590 + :param position: list of 6 coordinates in vtk world coordinate system wx, wy, wz
  591 + """
  592 + self.cross.SetFocalPoint(position[:3])
579 593
580 def ScrollSlice(self, coord): 594 def ScrollSlice(self, coord):
581 if self.orientation == "AXIAL": 595 if self.orientation == "AXIAL":
@@ -818,12 +832,12 @@ class Viewer(wx.Panel): @@ -818,12 +832,12 @@ class Viewer(wx.Panel):
818 Publisher.subscribe(self.ChangeSliceNumber, 832 Publisher.subscribe(self.ChangeSliceNumber,
819 ('Set scroll position', 833 ('Set scroll position',
820 self.orientation)) 834 self.orientation))
821 - Publisher.subscribe(self.__update_cross_position,  
822 - 'Update cross position')  
823 - Publisher.subscribe(self.__update_cross_position,  
824 - 'Update cross position %s' % self.orientation) 835 + # Publisher.subscribe(self.__update_cross_position,
  836 + # 'Update cross position')
  837 + # Publisher.subscribe(self.__update_cross_position,
  838 + # 'Update cross position %s' % self.orientation)
825 Publisher.subscribe(self.SetCrossFocalPoint, 'Set cross focal point') 839 Publisher.subscribe(self.SetCrossFocalPoint, 'Set cross focal point')
826 - # Publisher.subscribe(self.UpdateSlicesNavigation, 840 + # Publisher.subscribe(self.UpdateSlicesPosition,
827 # 'Co-registered points') 841 # 'Co-registered points')
828 ### 842 ###
829 # Publisher.subscribe(self.ChangeBrushColour, 843 # Publisher.subscribe(self.ChangeBrushColour,
@@ -1141,9 +1155,9 @@ class Viewer(wx.Panel): @@ -1141,9 +1155,9 @@ class Viewer(wx.Panel):
1141 1155
1142 renderer.AddActor(cross_actor) 1156 renderer.AddActor(cross_actor)
1143 1157
1144 - def __update_cross_position(self, arg, position):  
1145 - # self.cross.SetFocalPoint(position[:3])  
1146 - self.UpdateSlicesNavigation(None, position) 1158 + # def __update_cross_position(self, arg, position):
  1159 + # # self.cross.SetFocalPoint(position[:3])
  1160 + # self.UpdateSlicesPosition(None, position)
1147 1161
1148 def _set_cross_visibility(self, visibility): 1162 def _set_cross_visibility(self, visibility):
1149 self.cross_actor.SetVisibility(visibility) 1163 self.cross_actor.SetVisibility(visibility)
@@ -1300,12 +1314,16 @@ class Viewer(wx.Panel): @@ -1300,12 +1314,16 @@ class Viewer(wx.Panel):
1300 if update3D: 1314 if update3D:
1301 self.UpdateSlice3D(pos) 1315 self.UpdateSlice3D(pos)
1302 1316
  1317 + # This Render needs to come before the self.style.OnScrollBar, otherwise the GetFocalPoint will sometimes
  1318 + # provide the non-updated coordinate and the cross focal point will lag one pixel behind the actual
  1319 + # scroll position
  1320 + self.interactor.Render()
  1321 +
1303 try: 1322 try:
1304 self.style.OnScrollBar() 1323 self.style.OnScrollBar()
1305 except AttributeError: 1324 except AttributeError:
1306 print("Do not have OnScrollBar") 1325 print("Do not have OnScrollBar")
1307 1326
1308 - self.interactor.Render()  
1309 if evt: 1327 if evt:
1310 if self._flush_buffer: 1328 if self._flush_buffer:
1311 self.slice_.apply_slice_buffer_to_mask(self.orientation) 1329 self.slice_.apply_slice_buffer_to_mask(self.orientation)
invesalius/data/viewer_volume.py
@@ -270,9 +270,9 @@ class Viewer(wx.Panel): @@ -270,9 +270,9 @@ class Viewer(wx.Panel):
270 270
271 Publisher.subscribe(self.RemoveVolume, 'Remove Volume') 271 Publisher.subscribe(self.RemoveVolume, 'Remove Volume')
272 272
273 - Publisher.subscribe(self.UpdateCameraBallPosition,  
274 - 'Update cross position')  
275 - Publisher.subscribe(self.SetCrossFocalPoint, 'Set cross focal point') 273 + # Publisher.subscribe(self.UpdateCameraBallPosition,
  274 + # 'Update cross position')
  275 + Publisher.subscribe(self.UpdateCameraBallPosition, 'Set cross focal point')
276 Publisher.subscribe(self._check_ball_reference, 'Enable style') 276 Publisher.subscribe(self._check_ball_reference, 'Enable style')
277 Publisher.subscribe(self._uncheck_ball_reference, 'Disable style') 277 Publisher.subscribe(self._uncheck_ball_reference, 'Disable style')
278 278
@@ -1191,10 +1191,10 @@ class Viewer(wx.Panel): @@ -1191,10 +1191,10 @@ class Viewer(wx.Panel):
1191 1191
1192 self.ren.AddActor(self.ball_actor) 1192 self.ren.AddActor(self.ball_actor)
1193 1193
1194 - def SetCrossFocalPoint(self, position):  
1195 - self.UpdateCameraBallPosition(None, position) 1194 + # def SetCrossFocalPoint(self, position):
  1195 + # self.UpdateCameraBallPosition(None, position)
1196 1196
1197 - def UpdateCameraBallPosition(self, arg, position): 1197 + def UpdateCameraBallPosition(self, position):
1198 coord_flip = list(position[:3]) 1198 coord_flip = list(position[:3])
1199 coord_flip[1] = -coord_flip[1] 1199 coord_flip[1] = -coord_flip[1]
1200 self.ball_actor.SetPosition(coord_flip) 1200 self.ball_actor.SetPosition(coord_flip)
invesalius/gui/task_navigator.py
@@ -446,7 +446,7 @@ class NeuronavigationPanel(wx.Panel): @@ -446,7 +446,7 @@ class NeuronavigationPanel(wx.Panel):
446 Publisher.subscribe(self.LoadImageFiducials, 'Load image fiducials') 446 Publisher.subscribe(self.LoadImageFiducials, 'Load image fiducials')
447 Publisher.subscribe(self.UpdateTriggerState, 'Update trigger state') 447 Publisher.subscribe(self.UpdateTriggerState, 'Update trigger state')
448 Publisher.subscribe(self.UpdateTrackObjectState, 'Update track object state') 448 Publisher.subscribe(self.UpdateTrackObjectState, 'Update track object state')
449 - Publisher.subscribe(self.UpdateImageCoordinates, 'Update cross position') 449 + Publisher.subscribe(self.UpdateImageCoordinates, 'Set cross focal point')
450 Publisher.subscribe(self.OnDisconnectTracker, 'Disconnect tracker') 450 Publisher.subscribe(self.OnDisconnectTracker, 'Disconnect tracker')
451 Publisher.subscribe(self.UpdateObjectRegistration, 'Update object registration') 451 Publisher.subscribe(self.UpdateObjectRegistration, 'Update object registration')
452 Publisher.subscribe(self.OnCloseProject, 'Close project data') 452 Publisher.subscribe(self.OnCloseProject, 'Close project data')
@@ -506,7 +506,7 @@ class NeuronavigationPanel(wx.Panel): @@ -506,7 +506,7 @@ class NeuronavigationPanel(wx.Panel):
506 def EnableACT(self, data): 506 def EnableACT(self, data):
507 self.enable_act = data 507 self.enable_act = data
508 508
509 - def UpdateImageCoordinates(self, arg, position): 509 + def UpdateImageCoordinates(self, position):
510 # TODO: Change from world coordinates to matrix coordinates. They are better for multi software communication. 510 # TODO: Change from world coordinates to matrix coordinates. They are better for multi software communication.
511 self.current_coord = position 511 self.current_coord = position
512 for m in [0, 1, 2]: 512 for m in [0, 1, 2]:
@@ -1213,15 +1213,15 @@ class MarkersPanel(wx.Panel): @@ -1213,15 +1213,15 @@ class MarkersPanel(wx.Panel):
1213 1213
1214 def __bind_events(self): 1214 def __bind_events(self):
1215 # Publisher.subscribe(self.UpdateCurrentCoord, 'Co-registered points') 1215 # Publisher.subscribe(self.UpdateCurrentCoord, 'Co-registered points')
1216 - Publisher.subscribe(self.UpdateCurrentCoord, 'Update cross position') 1216 + Publisher.subscribe(self.UpdateCurrentCoord, 'Set cross focal point')
1217 Publisher.subscribe(self.OnDeleteSingleMarker, 'Delete fiducial marker') 1217 Publisher.subscribe(self.OnDeleteSingleMarker, 'Delete fiducial marker')
1218 Publisher.subscribe(self.OnDeleteAllMarkers, 'Delete all markers') 1218 Publisher.subscribe(self.OnDeleteAllMarkers, 'Delete all markers')
1219 Publisher.subscribe(self.OnCreateMarker, 'Create marker') 1219 Publisher.subscribe(self.OnCreateMarker, 'Create marker')
1220 Publisher.subscribe(self.UpdateNavigationStatus, 'Navigation status') 1220 Publisher.subscribe(self.UpdateNavigationStatus, 'Navigation status')
1221 Publisher.subscribe(self.UpdateSeedCoordinates, 'Update tracts') 1221 Publisher.subscribe(self.UpdateSeedCoordinates, 'Update tracts')
1222 1222
1223 - def UpdateCurrentCoord(self, arg, position):  
1224 - self.current_coord = position[:] 1223 + def UpdateCurrentCoord(self, position):
  1224 + self.current_coord = position
1225 #self.current_angle = pubsub_evt.data[1][3:] 1225 #self.current_angle = pubsub_evt.data[1][3:]
1226 1226
1227 def UpdateNavigationStatus(self, nav_status, vis_status): 1227 def UpdateNavigationStatus(self, nav_status, vis_status):
@@ -1747,7 +1747,7 @@ class TractographyPanel(wx.Panel): @@ -1747,7 +1747,7 @@ class TractographyPanel(wx.Panel):
1747 1747
1748 def __bind_events(self): 1748 def __bind_events(self):
1749 Publisher.subscribe(self.OnCloseProject, 'Close project data') 1749 Publisher.subscribe(self.OnCloseProject, 'Close project data')
1750 - Publisher.subscribe(self.OnUpdateTracts, 'Update cross position') 1750 + Publisher.subscribe(self.OnUpdateTracts, 'Set cross focal point')
1751 Publisher.subscribe(self.UpdateNavigationStatus, 'Navigation status') 1751 Publisher.subscribe(self.UpdateNavigationStatus, 'Navigation status')
1752 1752
1753 def OnSelectPeelingDepth(self, evt, ctrl): 1753 def OnSelectPeelingDepth(self, evt, ctrl):
@@ -1941,7 +1941,7 @@ class TractographyPanel(wx.Panel): @@ -1941,7 +1941,7 @@ class TractographyPanel(wx.Panel):
1941 wx.MessageBox(_("File incompatible, using default configuration."), _("InVesalius 3")) 1941 wx.MessageBox(_("File incompatible, using default configuration."), _("InVesalius 3"))
1942 Publisher.sendMessage('Update status text in GUI', label="") 1942 Publisher.sendMessage('Update status text in GUI', label="")
1943 1943
1944 - def OnUpdateTracts(self, arg, position): 1944 + def OnUpdateTracts(self, position):
1945 """ 1945 """
1946 Minimal working version of tract computation. Updates when cross sends Pubsub message to update. 1946 Minimal working version of tract computation. Updates when cross sends Pubsub message to update.
1947 Position refers to the coordinates in InVesalius 2D space. To represent the same coordinates in the 3D space, 1947 Position refers to the coordinates in InVesalius 2D space. To represent the same coordinates in the 3D space,
@@ -2055,7 +2055,8 @@ class UpdateNavigationScene(threading.Thread): @@ -2055,7 +2055,8 @@ class UpdateNavigationScene(threading.Thread):
2055 2055
2056 #TODO: If using the view_tracts substitute the raw coord from the offset coordinate, so the user 2056 #TODO: If using the view_tracts substitute the raw coord from the offset coordinate, so the user
2057 # see the red cross in the position of the offset marker 2057 # see the red cross in the position of the offset marker
2058 - wx.CallAfter(Publisher.sendMessage, 'Update cross position', arg=m_img, position=coord) 2058 + wx.CallAfter(Publisher.sendMessage, 'Set cross focal point', position=coord)
  2059 + wx.CallAfter(Publisher.sendMessage, 'Update slice viewer')
2059 2060
2060 if view_obj: 2061 if view_obj:
2061 wx.CallAfter(Publisher.sendMessage, 'Update object matrix', m_img=m_img, coord=coord) 2062 wx.CallAfter(Publisher.sendMessage, 'Update object matrix', m_img=m_img, coord=coord)