Skip to content
Snippets Groups Projects
Commit 9477aeca authored by Paul McCarthy's avatar Paul McCarthy
Browse files

Simplified ortho orientation labelling, and made it less inaccurate.

parent 9634fc9f
No related branches found
No related tags found
No related merge requests found
...@@ -333,9 +333,14 @@ class Image(props.HasProperties): ...@@ -333,9 +333,14 @@ class Image(props.HasProperties):
return int(code) return int(code)
def getWorldOrientation(self, axis, code=None): def getOrientation(self, axis, xform):
"""Returns a code representing the orientation of the specified axis """Returns a code representing the orientation of the specified data
in world space. axis in the coordinate system defined by the given transformation
matrix.
:arg xform: A transformation matrix which is assumed to transform
coordinates from the image world coordinate system to
some other coordinate system.
This method returns one of the following values, indicating the This method returns one of the following values, indicating the
direction in which coordinates along the specified axis increase: direction in which coordinates along the specified axis increase:
...@@ -357,45 +362,16 @@ class Image(props.HasProperties): ...@@ -357,45 +362,16 @@ class Image(props.HasProperties):
increases from inferior to superior). increases from inferior to superior).
""" """
if self.getXFormCode(code) == constants.NIFTI_XFORM_UNKNOWN: if self.getXFormCode() == constants.NIFTI_XFORM_UNKNOWN:
return constants.ORIENT_UNKNOWN return constants.ORIENT_UNKNOWN
if axis == 0: return constants.ORIENT_L2R
elif axis == 1: return constants.ORIENT_P2A
elif axis == 2: return constants.ORIENT_I2S
else: return constants.ORIENT_UNKNOWN
def getVoxelOrientation(self, axis, code=None):
"""Returns a code representing the (estimated) orientation of the
specified data axis.
:arg code: May be either ``qform`` or ``sform``, specifying which
transformation to use.
See the :meth:`getWorldOrientation` method for a description
of the return value.
"""
if self.getXFormCode(code) == constants.NIFTI_XFORM_UNKNOWN:
return constants.ORIENT_UNKNOWN
if code is None: xform = self.nibImage.get_affine()
elif code == 'sform': xform = self.nibImage.get_sform()
elif code == 'qform': xform = self.nibImage.get_qform()
else: raise ValueError('code must be None, qform, or sform')
# the aff2axcodes returns one code for each
# axis in the image array (i.e. in voxel space),
# which denotes the real world direction
import nibabel as nib import nibabel as nib
code = nib.orientations.aff2axcodes( code = nib.orientations.aff2axcodes(
xform, xform,
((constants.ORIENT_R2L, constants.ORIENT_L2R), ((constants.ORIENT_R2L, constants.ORIENT_L2R),
(constants.ORIENT_A2P, constants.ORIENT_P2A), (constants.ORIENT_A2P, constants.ORIENT_P2A),
(constants.ORIENT_S2I, constants.ORIENT_I2S)))[axis] (constants.ORIENT_S2I, constants.ORIENT_I2S)))[axis]
return code return code
......
...@@ -616,12 +616,9 @@ nifti = TypeDict({ ...@@ -616,12 +616,9 @@ nifti = TypeDict({
'voxOrient.0' : 'X voxel orientation', 'voxOrient.0' : 'X voxel orientation',
'voxOrient.1' : 'Y voxel orientation', 'voxOrient.1' : 'Y voxel orientation',
'voxOrient.2' : 'Z voxel orientation', 'voxOrient.2' : 'Z voxel orientation',
'sformOrient.0' : 'X sform orientation', 'worldOrient.0' : 'X world orientation',
'sformOrient.1' : 'Y sform orientation', 'worldOrient.1' : 'Y world orientation',
'sformOrient.2' : 'Z sform orientation', 'worldOrient.2' : 'Z world orientation',
'qformOrient.0' : 'X qform orientation',
'qformOrient.1' : 'Y qform orientation',
'qformOrient.2' : 'Z qform orientation',
'qform' : 'QForm matrix', 'qform' : 'QForm matrix',
'sform' : 'SForm matrix', 'sform' : 'SForm matrix',
......
...@@ -14,9 +14,11 @@ import collections ...@@ -14,9 +14,11 @@ import collections
import wx import wx
import wx.html as wxhtml import wx.html as wxhtml
import fsl.data.strings as strings import numpy as np
import fsl.data.constants as constants
import fsl.fsleyes.panel as fslpanel import fsl.data.strings as strings
import fsl.data.constants as constants
import fsl.fsleyes.panel as fslpanel
class OverlayInfoPanel(fslpanel.FSLEyesPanel): class OverlayInfoPanel(fslpanel.FSLEyesPanel):
...@@ -178,8 +180,10 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel): ...@@ -178,8 +180,10 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
info = OverlayInfo('{} - {}'.format( info = OverlayInfo('{} - {}'.format(
display.name, strings.labels[self, overlay])) display.name, strings.labels[self, overlay]))
img = overlay.nibImage img = overlay.nibImage
hdr = img.get_header() hdr = img.get_header()
opts = display.getDisplayOpts()
voxUnits, timeUnits = hdr.get_xyzt_units() voxUnits, timeUnits = hdr.get_xyzt_units()
qformCode = int(hdr['qform_code']) qformCode = int(hdr['qform_code'])
...@@ -240,7 +244,8 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel): ...@@ -240,7 +244,8 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
section=xformSect) section=xformSect)
for i in range(3): for i in range(3):
orient = overlay.getVoxelOrientation(i) xform = opts.getTransform('world', 'id')
orient = overlay.getOrientation(i, xform)
orient = '{} - {}'.format( orient = '{} - {}'.format(
strings.anatomy['Image', 'lowlong', orient], strings.anatomy['Image', 'lowlong', orient],
strings.anatomy['Image', 'highlong', orient]) strings.anatomy['Image', 'highlong', orient])
...@@ -249,23 +254,15 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel): ...@@ -249,23 +254,15 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
section=orientSect) section=orientSect)
for i in range(3): for i in range(3):
orient = overlay.getWorldOrientation(i, code='sform') xform = np.eye(4)
orient = overlay.getOrientation(i, xform)
orient = '{} - {}'.format( orient = '{} - {}'.format(
strings.anatomy['Image', 'lowlong', orient], strings.anatomy['Image', 'lowlong', orient],
strings.anatomy['Image', 'highlong', orient]) strings.anatomy['Image', 'highlong', orient])
info.addInfo(strings.nifti['sformOrient.{}'.format(i)], info.addInfo(strings.nifti['worldOrient.{}'.format(i)],
orient, orient,
section=orientSect) section=orientSect)
for i in range(3):
orient = overlay.getWorldOrientation(i, code='qform')
orient = '{} - {}'.format(
strings.anatomy['Image', 'lowlong', orient],
strings.anatomy['Image', 'highlong', orient])
info.addInfo(strings.nifti['qformOrient.{}'.format(i)],
orient,
section=orientSect)
return info return info
......
...@@ -309,7 +309,7 @@ class OrthoViewProfile(profiles.Profile): ...@@ -309,7 +309,7 @@ class OrthoViewProfile(profiles.Profile):
if zoom == 0: if zoom == 0:
return return
self._zoomModeMouseWheel(canvas, zoom) self._zoomModeMouseWheel(None, canvas, zoom)
def _zoomModeLeftMouseDrag(self, ev, canvas, mousePos, canvasPos): def _zoomModeLeftMouseDrag(self, ev, canvas, mousePos, canvasPos):
......
...@@ -359,16 +359,12 @@ class OrthoPanel(canvaspanel.CanvasPanel): ...@@ -359,16 +359,12 @@ class OrthoPanel(canvaspanel.CanvasPanel):
self.__zLabels.values() self.__zLabels.values()
if overlay is not None: if overlay is not None:
opts = self._displayCtx.getOpts(overlay) opts = self._displayCtx.getOpts(overlay)
xform = opts.getTransform('world', 'display')
if opts.transform in ('pixdim', 'id'): xorient = overlay.getOrientation(0, xform)
xorient = overlay.getVoxelOrientation(0) yorient = overlay.getOrientation(1, xform)
yorient = overlay.getVoxelOrientation(1) zorient = overlay.getOrientation(2, xform)
zorient = overlay.getVoxelOrientation(2)
else:
xorient = overlay.getWorldOrientation(0)
yorient = overlay.getWorldOrientation(1)
zorient = overlay.getWorldOrientation(2)
if constants.ORIENT_UNKNOWN in (xorient, yorient, zorient): if constants.ORIENT_UNKNOWN in (xorient, yorient, zorient):
...@@ -429,13 +425,10 @@ class OrthoPanel(canvaspanel.CanvasPanel): ...@@ -429,13 +425,10 @@ class OrthoPanel(canvaspanel.CanvasPanel):
# Update anatomy labels when # Update anatomy labels when
# overlay bounds change # overlay bounds change
if i == self._displayCtx.selectedOverlay: opts.addListener('bounds',
opts.addListener('bounds', self._name,
self._name, self.__refreshLabels,
self.__refreshLabels, overwrite=True)
overwrite=True)
else:
opts.removeListener('bounds', self._name)
# anatomical orientation may have changed with an image change # anatomical orientation may have changed with an image change
self.__refreshLabels() self.__refreshLabels()
...@@ -480,23 +473,17 @@ class OrthoPanel(canvaspanel.CanvasPanel): ...@@ -480,23 +473,17 @@ class OrthoPanel(canvaspanel.CanvasPanel):
self.PostSizeEvent() self.PostSizeEvent()
return return
opts = self._displayCtx.getOpts(overlay)
# The image is being displayed as it is stored on log.debug('Refreshing orientation labels '
# disk - the image.getOrientation method calculates 'according to {}'.format(overlay.name))
# and returns labels for each voxelwise axis.
if opts.transform in ('pixdim', 'id'):
xorient = overlay.getVoxelOrientation(0)
yorient = overlay.getVoxelOrientation(1)
zorient = overlay.getVoxelOrientation(2)
# The overlay is being displayed in 'real world' space - # Figure out the orientation of the
# the definition of this space may be present in the # image in the display coordinate system
# overlay meta data opts = self._displayCtx.getOpts(overlay)
else: xform = opts.getTransform('world', 'display')
xorient = overlay.getWorldOrientation(0) xorient = overlay.getOrientation(0, xform)
yorient = overlay.getWorldOrientation(1) yorient = overlay.getOrientation(1, xform)
zorient = overlay.getWorldOrientation(2) zorient = overlay.getOrientation(2, xform)
xlo = strings.anatomy['Image', 'lowshort', xorient] xlo = strings.anatomy['Image', 'lowshort', xorient]
ylo = strings.anatomy['Image', 'lowshort', yorient] ylo = strings.anatomy['Image', 'lowshort', yorient]
...@@ -505,6 +492,10 @@ class OrthoPanel(canvaspanel.CanvasPanel): ...@@ -505,6 +492,10 @@ class OrthoPanel(canvaspanel.CanvasPanel):
yhi = strings.anatomy['Image', 'highshort', yorient] yhi = strings.anatomy['Image', 'highshort', yorient]
zhi = strings.anatomy['Image', 'highshort', zorient] zhi = strings.anatomy['Image', 'highshort', zorient]
log.debug('X orientation: {} - {}'.format(xlo, xhi))
log.debug('Y orientation: {} - {}'.format(ylo, yhi))
log.debug('Z orientation: {} - {}'.format(zlo, zhi))
bg = sceneOpts.bgColour bg = sceneOpts.bgColour
fg = colourmaps.complementaryColour(bg) fg = colourmaps.complementaryColour(bg)
bg = [int(round(c * 255)) for c in bg] bg = [int(round(c * 255)) for c in bg]
...@@ -514,16 +505,16 @@ class OrthoPanel(canvaspanel.CanvasPanel): ...@@ -514,16 +505,16 @@ class OrthoPanel(canvaspanel.CanvasPanel):
self.__xLabels['left'] .SetLabel(ylo) self.__xLabels['left'] .SetLabel(ylo)
self.__xLabels['right'] .SetLabel(yhi) self.__xLabels['right'] .SetLabel(yhi)
self.__xLabels['top'] .SetLabel(zlo) self.__xLabels['bottom'].SetLabel(zlo)
self.__xLabels['bottom'].SetLabel(zhi) self.__xLabels['top'] .SetLabel(zhi)
self.__yLabels['left'] .SetLabel(xlo) self.__yLabels['left'] .SetLabel(xlo)
self.__yLabels['right'] .SetLabel(xhi) self.__yLabels['right'] .SetLabel(xhi)
self.__yLabels['top'] .SetLabel(zlo) self.__yLabels['bottom'].SetLabel(zlo)
self.__yLabels['bottom'].SetLabel(zhi) self.__yLabels['top'] .SetLabel(zhi)
self.__zLabels['left'] .SetLabel(xlo) self.__zLabels['left'] .SetLabel(xlo)
self.__zLabels['right'] .SetLabel(xhi) self.__zLabels['right'] .SetLabel(xhi)
self.__zLabels['top'] .SetLabel(ylo) self.__zLabels['bottom'].SetLabel(ylo)
self.__zLabels['bottom'].SetLabel(yhi) self.__zLabels['top'] .SetLabel(yhi)
self.PostSizeEvent() self.PostSizeEvent()
......
...@@ -77,22 +77,10 @@ def buildLabelBitmaps(overlayList, ...@@ -77,22 +77,10 @@ def buildLabelBitmaps(overlayList,
display = displayCtx.getDisplay(overlay) display = displayCtx.getDisplay(overlay)
opts = display.getDisplayOpts() opts = display.getDisplayOpts()
xform = opts.getTransform('world', 'display')
# The overlay is being displayed as it is stored on xorient = overlay.getOrientation(0, xform)
# disk - the image.getOrientation method calculates yorient = overlay.getOrientation(1, xform)
# and returns labels for each voxelwise axis. zorient = overlay.getOrientation(2, xform)
if opts.transform in ('pixdim', 'id'):
xorient = overlay.getVoxelOrientation(0)
yorient = overlay.getVoxelOrientation(1)
zorient = overlay.getVoxelOrientation(2)
# The overlay is being displayed in 'real world' space -
# the definition of this space may be present in the
# overlay meta data
else:
xorient = overlay.getWorldOrientation(0)
yorient = overlay.getWorldOrientation(1)
zorient = overlay.getWorldOrientation(2)
if constants.ORIENT_UNKNOWN in [xorient, yorient, zorient]: if constants.ORIENT_UNKNOWN in [xorient, yorient, zorient]:
fgColour = 'red' fgColour = 'red'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment