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 43  
44 44 def __bind_events(self):
45 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 49 self.coord = asarray(position)
50 50  
51 51 def stop(self):
... ...
invesalius/data/styles.py
... ... @@ -473,18 +473,6 @@ class CrossInteractorStyle(DefaultInteractorStyle):
473 473 self.slice_actor = viewer.slice_data.actor
474 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 476 self.picker = vtk.vtkWorldPointPicker()
489 477  
490 478 self.AddObserver("MouseMoveEvent", self.OnCrossMove)
... ... @@ -514,48 +502,18 @@ class CrossInteractorStyle(DefaultInteractorStyle):
514 502  
515 503 def ChangeCrossPosition(self, iren):
516 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 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 511 def OnScrollBar(self, *args, **kwargs):
554 512 # Update other slice's cross according to the new focal point from
555 513 # the actual orientation.
556 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 517 Publisher.sendMessage('Update slice viewer')
560 518  
561 519  
... ...
invesalius/data/viewer_slice.py
... ... @@ -565,17 +565,31 @@ class Viewer(wx.Panel):
565 565 if self.slice_data.cursor:
566 566 self.slice_data.cursor.SetColour(colour_vtk)
567 567  
568   - def UpdateSlicesNavigation(self, arg, position):
  568 + def UpdateSlicesPosition(self, position):
569 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 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 583 self.ScrollSlice(coord)
576 584  
577 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 594 def ScrollSlice(self, coord):
581 595 if self.orientation == "AXIAL":
... ... @@ -818,12 +832,12 @@ class Viewer(wx.Panel):
818 832 Publisher.subscribe(self.ChangeSliceNumber,
819 833 ('Set scroll position',
820 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 839 Publisher.subscribe(self.SetCrossFocalPoint, 'Set cross focal point')
826   - # Publisher.subscribe(self.UpdateSlicesNavigation,
  840 + # Publisher.subscribe(self.UpdateSlicesPosition,
827 841 # 'Co-registered points')
828 842 ###
829 843 # Publisher.subscribe(self.ChangeBrushColour,
... ... @@ -1141,9 +1155,9 @@ class Viewer(wx.Panel):
1141 1155  
1142 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 1162 def _set_cross_visibility(self, visibility):
1149 1163 self.cross_actor.SetVisibility(visibility)
... ... @@ -1300,12 +1314,16 @@ class Viewer(wx.Panel):
1300 1314 if update3D:
1301 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 1322 try:
1304 1323 self.style.OnScrollBar()
1305 1324 except AttributeError:
1306 1325 print("Do not have OnScrollBar")
1307 1326  
1308   - self.interactor.Render()
1309 1327 if evt:
1310 1328 if self._flush_buffer:
1311 1329 self.slice_.apply_slice_buffer_to_mask(self.orientation)
... ...
invesalius/data/viewer_volume.py
... ... @@ -270,9 +270,9 @@ class Viewer(wx.Panel):
270 270  
271 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 276 Publisher.subscribe(self._check_ball_reference, 'Enable style')
277 277 Publisher.subscribe(self._uncheck_ball_reference, 'Disable style')
278 278  
... ... @@ -1191,10 +1191,10 @@ class Viewer(wx.Panel):
1191 1191  
1192 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 1198 coord_flip = list(position[:3])
1199 1199 coord_flip[1] = -coord_flip[1]
1200 1200 self.ball_actor.SetPosition(coord_flip)
... ...
invesalius/gui/task_navigator.py
... ... @@ -446,7 +446,7 @@ class NeuronavigationPanel(wx.Panel):
446 446 Publisher.subscribe(self.LoadImageFiducials, 'Load image fiducials')
447 447 Publisher.subscribe(self.UpdateTriggerState, 'Update trigger state')
448 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 450 Publisher.subscribe(self.OnDisconnectTracker, 'Disconnect tracker')
451 451 Publisher.subscribe(self.UpdateObjectRegistration, 'Update object registration')
452 452 Publisher.subscribe(self.OnCloseProject, 'Close project data')
... ... @@ -506,7 +506,7 @@ class NeuronavigationPanel(wx.Panel):
506 506 def EnableACT(self, data):
507 507 self.enable_act = data
508 508  
509   - def UpdateImageCoordinates(self, arg, position):
  509 + def UpdateImageCoordinates(self, position):
510 510 # TODO: Change from world coordinates to matrix coordinates. They are better for multi software communication.
511 511 self.current_coord = position
512 512 for m in [0, 1, 2]:
... ... @@ -1213,15 +1213,15 @@ class MarkersPanel(wx.Panel):
1213 1213  
1214 1214 def __bind_events(self):
1215 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 1217 Publisher.subscribe(self.OnDeleteSingleMarker, 'Delete fiducial marker')
1218 1218 Publisher.subscribe(self.OnDeleteAllMarkers, 'Delete all markers')
1219 1219 Publisher.subscribe(self.OnCreateMarker, 'Create marker')
1220 1220 Publisher.subscribe(self.UpdateNavigationStatus, 'Navigation status')
1221 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 1225 #self.current_angle = pubsub_evt.data[1][3:]
1226 1226  
1227 1227 def UpdateNavigationStatus(self, nav_status, vis_status):
... ... @@ -1747,7 +1747,7 @@ class TractographyPanel(wx.Panel):
1747 1747  
1748 1748 def __bind_events(self):
1749 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 1751 Publisher.subscribe(self.UpdateNavigationStatus, 'Navigation status')
1752 1752  
1753 1753 def OnSelectPeelingDepth(self, evt, ctrl):
... ... @@ -1941,7 +1941,7 @@ class TractographyPanel(wx.Panel):
1941 1941 wx.MessageBox(_("File incompatible, using default configuration."), _("InVesalius 3"))
1942 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 1946 Minimal working version of tract computation. Updates when cross sends Pubsub message to update.
1947 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 2055  
2056 2056 #TODO: If using the view_tracts substitute the raw coord from the offset coordinate, so the user
2057 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 2061 if view_obj:
2061 2062 wx.CallAfter(Publisher.sendMessage, 'Update object matrix', m_img=m_img, coord=coord)
... ...