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):
return int(code)
def getWorldOrientation(self, axis, code=None):
"""Returns a code representing the orientation of the specified axis
in world space.
def getOrientation(self, axis, xform):
"""Returns a code representing the orientation of the specified data
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
direction in which coordinates along the specified axis increase:
......@@ -357,45 +362,16 @@ class Image(props.HasProperties):
increases from inferior to superior).
"""
if self.getXFormCode(code) == constants.NIFTI_XFORM_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')
if self.getXFormCode() == constants.NIFTI_XFORM_UNKNOWN:
return constants.ORIENT_UNKNOWN
# 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
code = nib.orientations.aff2axcodes(
xform,
((constants.ORIENT_R2L, constants.ORIENT_L2R),
(constants.ORIENT_A2P, constants.ORIENT_P2A),
(constants.ORIENT_S2I, constants.ORIENT_I2S)))[axis]
return code
......
......@@ -616,12 +616,9 @@ nifti = TypeDict({
'voxOrient.0' : 'X voxel orientation',
'voxOrient.1' : 'Y voxel orientation',
'voxOrient.2' : 'Z voxel orientation',
'sformOrient.0' : 'X sform orientation',
'sformOrient.1' : 'Y sform orientation',
'sformOrient.2' : 'Z sform orientation',
'qformOrient.0' : 'X qform orientation',
'qformOrient.1' : 'Y qform orientation',
'qformOrient.2' : 'Z qform orientation',
'worldOrient.0' : 'X world orientation',
'worldOrient.1' : 'Y world orientation',
'worldOrient.2' : 'Z world orientation',
'qform' : 'QForm matrix',
'sform' : 'SForm matrix',
......
......@@ -14,9 +14,11 @@ import collections
import wx
import wx.html as wxhtml
import fsl.data.strings as strings
import fsl.data.constants as constants
import fsl.fsleyes.panel as fslpanel
import numpy as np
import fsl.data.strings as strings
import fsl.data.constants as constants
import fsl.fsleyes.panel as fslpanel
class OverlayInfoPanel(fslpanel.FSLEyesPanel):
......@@ -178,8 +180,10 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
info = OverlayInfo('{} - {}'.format(
display.name, strings.labels[self, overlay]))
img = overlay.nibImage
hdr = img.get_header()
opts = display.getDisplayOpts()
voxUnits, timeUnits = hdr.get_xyzt_units()
qformCode = int(hdr['qform_code'])
......@@ -240,7 +244,8 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
section=xformSect)
for i in range(3):
orient = overlay.getVoxelOrientation(i)
xform = opts.getTransform('world', 'id')
orient = overlay.getOrientation(i, xform)
orient = '{} - {}'.format(
strings.anatomy['Image', 'lowlong', orient],
strings.anatomy['Image', 'highlong', orient])
......@@ -249,23 +254,15 @@ class OverlayInfoPanel(fslpanel.FSLEyesPanel):
section=orientSect)
for i in range(3):
orient = overlay.getWorldOrientation(i, code='sform')
xform = np.eye(4)
orient = overlay.getOrientation(i, xform)
orient = '{} - {}'.format(
strings.anatomy['Image', 'lowlong', orient],
strings.anatomy['Image', 'highlong', orient])
info.addInfo(strings.nifti['sformOrient.{}'.format(i)],
info.addInfo(strings.nifti['worldOrient.{}'.format(i)],
orient,
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
......
......@@ -309,7 +309,7 @@ class OrthoViewProfile(profiles.Profile):
if zoom == 0:
return
self._zoomModeMouseWheel(canvas, zoom)
self._zoomModeMouseWheel(None, canvas, zoom)
def _zoomModeLeftMouseDrag(self, ev, canvas, mousePos, canvasPos):
......
......@@ -359,16 +359,12 @@ class OrthoPanel(canvaspanel.CanvasPanel):
self.__zLabels.values()
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.getVoxelOrientation(0)
yorient = overlay.getVoxelOrientation(1)
zorient = overlay.getVoxelOrientation(2)
else:
xorient = overlay.getWorldOrientation(0)
yorient = overlay.getWorldOrientation(1)
zorient = overlay.getWorldOrientation(2)
xorient = overlay.getOrientation(0, xform)
yorient = overlay.getOrientation(1, xform)
zorient = overlay.getOrientation(2, xform)
if constants.ORIENT_UNKNOWN in (xorient, yorient, zorient):
......@@ -429,13 +425,10 @@ class OrthoPanel(canvaspanel.CanvasPanel):
# Update anatomy labels when
# overlay bounds change
if i == self._displayCtx.selectedOverlay:
opts.addListener('bounds',
self._name,
self.__refreshLabels,
overwrite=True)
else:
opts.removeListener('bounds', self._name)
opts.addListener('bounds',
self._name,
self.__refreshLabels,
overwrite=True)
# anatomical orientation may have changed with an image change
self.__refreshLabels()
......@@ -480,23 +473,17 @@ class OrthoPanel(canvaspanel.CanvasPanel):
self.PostSizeEvent()
return
opts = self._displayCtx.getOpts(overlay)
# The image is being displayed as it is stored on
# disk - the image.getOrientation method calculates
# 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)
log.debug('Refreshing orientation labels '
'according to {}'.format(overlay.name))
# 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)
# Figure out the orientation of the
# image in the display coordinate system
opts = self._displayCtx.getOpts(overlay)
xform = opts.getTransform('world', 'display')
xorient = overlay.getOrientation(0, xform)
yorient = overlay.getOrientation(1, xform)
zorient = overlay.getOrientation(2, xform)
xlo = strings.anatomy['Image', 'lowshort', xorient]
ylo = strings.anatomy['Image', 'lowshort', yorient]
......@@ -505,6 +492,10 @@ class OrthoPanel(canvaspanel.CanvasPanel):
yhi = strings.anatomy['Image', 'highshort', yorient]
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
fg = colourmaps.complementaryColour(bg)
bg = [int(round(c * 255)) for c in bg]
......@@ -514,16 +505,16 @@ class OrthoPanel(canvaspanel.CanvasPanel):
self.__xLabels['left'] .SetLabel(ylo)
self.__xLabels['right'] .SetLabel(yhi)
self.__xLabels['top'] .SetLabel(zlo)
self.__xLabels['bottom'].SetLabel(zhi)
self.__xLabels['bottom'].SetLabel(zlo)
self.__xLabels['top'] .SetLabel(zhi)
self.__yLabels['left'] .SetLabel(xlo)
self.__yLabels['right'] .SetLabel(xhi)
self.__yLabels['top'] .SetLabel(zlo)
self.__yLabels['bottom'].SetLabel(zhi)
self.__yLabels['bottom'].SetLabel(zlo)
self.__yLabels['top'] .SetLabel(zhi)
self.__zLabels['left'] .SetLabel(xlo)
self.__zLabels['right'] .SetLabel(xhi)
self.__zLabels['top'] .SetLabel(ylo)
self.__zLabels['bottom'].SetLabel(yhi)
self.__zLabels['bottom'].SetLabel(ylo)
self.__zLabels['top'] .SetLabel(yhi)
self.PostSizeEvent()
......
......@@ -77,22 +77,10 @@ def buildLabelBitmaps(overlayList,
display = displayCtx.getDisplay(overlay)
opts = display.getDisplayOpts()
# The overlay is being displayed as it is stored on
# disk - the image.getOrientation method calculates
# 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 -
# 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)
xform = opts.getTransform('world', 'display')
xorient = overlay.getOrientation(0, xform)
yorient = overlay.getOrientation(1, xform)
zorient = overlay.getOrientation(2, xform)
if constants.ORIENT_UNKNOWN in [xorient, yorient, zorient]:
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