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

Merge branch 'display_world_location_stuff'. Haven't thoroughly tested

the merge yet ..
parents 8ed6bbf2 81f49290
No related branches found
No related tags found
No related merge requests found
...@@ -17,6 +17,7 @@ from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas ...@@ -17,6 +17,7 @@ from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
from mpl_toolkits.mplot3d import Axes3D from mpl_toolkits.mplot3d import Axes3D
import fsl.fslview.viewpanel as viewpanel import fsl.fslview.viewpanel as viewpanel
import fsl.utils.transform as transform
class SpacePanel(viewpanel.ViewPanel): class SpacePanel(viewpanel.ViewPanel):
...@@ -60,7 +61,7 @@ class SpacePanel(viewpanel.ViewPanel): ...@@ -60,7 +61,7 @@ class SpacePanel(viewpanel.ViewPanel):
def _onDestroy(self, ev): def _onDestroy(self, ev):
ev.Skip() ev.Skip()
self._iamgeList.removeListener('images', self._name) self._imageList.removeListener('images', self._name)
self._iamgeList.removeListener('selectedImage', self._name) self._iamgeList.removeListener('selectedImage', self._name)
...@@ -74,12 +75,13 @@ class SpacePanel(viewpanel.ViewPanel): ...@@ -74,12 +75,13 @@ class SpacePanel(viewpanel.ViewPanel):
self._canvas.draw() self._canvas.draw()
return return
image = self._imageList[self._displayCtx.selectedImage] image = self._imageList[self._displayCtx.selectedImage]
display = image.getAttribute('display')
image.addListener('transform', display.addListener('transform',
self._name, self._name,
self._selectedImageChanged, self._selectedImageChanged,
overwrite=True) overwrite=True)
self._axis.set_title(image.name) self._axis.set_title(image.name)
self._axis.set_xlabel('X') self._axis.set_xlabel('X')
...@@ -97,11 +99,13 @@ class SpacePanel(viewpanel.ViewPanel): ...@@ -97,11 +99,13 @@ class SpacePanel(viewpanel.ViewPanel):
def _plotImageBounds(self): def _plotImageBounds(self):
image = self._imageList[self._displayCtx.selectedImage] image = self._imageList[self._displayCtx.selectedImage]
display = image.getAttribute('display')
v2DMat = display.voxToDisplayMat
xlo, xhi = image.imageBounds(0) xlo, xhi = transform.axisBounds(image.shape, v2DMat, 0)
ylo, yhi = image.imageBounds(1) ylo, yhi = transform.axisBounds(image.shape, v2DMat, 1)
zlo, zhi = image.imageBounds(2) zlo, zhi = transform.axisBounds(image.shape, v2DMat, 2)
points = np.zeros((8, 3), dtype=np.float32) points = np.zeros((8, 3), dtype=np.float32)
points[0, :] = [xlo, ylo, zlo] points[0, :] = [xlo, ylo, zlo]
...@@ -122,7 +126,8 @@ class SpacePanel(viewpanel.ViewPanel): ...@@ -122,7 +126,8 @@ class SpacePanel(viewpanel.ViewPanel):
# Imported here to avoid circular import issues # Imported here to avoid circular import issues
import fsl.fslview.strings as strings import fsl.fslview.strings as strings
image = self._imageList[self._displayCtx.selectedImage] image = self._imageList[self._displayCtx.selectedImage]
display = image.getAttribute('display')
centre = np.array(image.shape) / 2.0 centre = np.array(image.shape) / 2.0
...@@ -138,7 +143,7 @@ class SpacePanel(viewpanel.ViewPanel): ...@@ -138,7 +143,7 @@ class SpacePanel(viewpanel.ViewPanel):
lblLo = strings.imageAxisLowShortLabels[ orient] lblLo = strings.imageAxisLowShortLabels[ orient]
lblHi = strings.imageAxisHighShortLabels[orient] lblHi = strings.imageAxisHighShortLabels[orient]
wldSpan = image.voxToWorld(voxSpan) wldSpan = transform.transform(voxSpan, display.voxToDisplayMat)
self._axis.plot(wldSpan[:, 0], self._axis.plot(wldSpan[:, 0],
wldSpan[:, 1], wldSpan[:, 1],
...@@ -152,7 +157,8 @@ class SpacePanel(viewpanel.ViewPanel): ...@@ -152,7 +157,8 @@ class SpacePanel(viewpanel.ViewPanel):
def _plotAxisLengths(self): def _plotAxisLengths(self):
image = self._imageList[self._displayCtx.selectedImage] image = self._imageList[self._displayCtx.selectedImage]
display = image.getAttribute('display')
for ax, colour, label in zip(range(3), for ax, colour, label in zip(range(3),
['r', 'g', 'b'], ['r', 'g', 'b'],
...@@ -162,7 +168,11 @@ class SpacePanel(viewpanel.ViewPanel): ...@@ -162,7 +168,11 @@ class SpacePanel(viewpanel.ViewPanel):
points[:] = [-0.5, -0.5, -0.5] points[:] = [-0.5, -0.5, -0.5]
points[1, ax] = image.shape[ax] - 0.5 points[1, ax] = image.shape[ax] - 0.5
tx = image.voxToWorld(points) tx = transform.transform(points, display.voxToDisplayMat)
axlen = transform.axisLength(image.shape,
display.voxToDisplayMat,
ax)
self._axis.plot(tx[:, 0], self._axis.plot(tx[:, 0],
tx[:, 1], tx[:, 1],
...@@ -170,13 +180,14 @@ class SpacePanel(viewpanel.ViewPanel): ...@@ -170,13 +180,14 @@ class SpacePanel(viewpanel.ViewPanel):
lw=1, lw=1,
color=colour, color=colour,
alpha=0.5, alpha=0.5,
label='Axis {} (length {:0.2f})'.format( label='Axis {} (length {:0.2f})'.format(label,
label, image.axisLength(ax))) axlen))
def _plotImageCorners(self): def _plotImageCorners(self):
image = self._imageList[self._displayCtx.selectedImage] image = self._imageList[self._displayCtx.selectedImage]
display = image.getAttribute('display')
x, y, z = image.shape[:3] x, y, z = image.shape[:3]
...@@ -195,7 +206,7 @@ class SpacePanel(viewpanel.ViewPanel): ...@@ -195,7 +206,7 @@ class SpacePanel(viewpanel.ViewPanel):
points[6, :] = [x, y, -0.5] points[6, :] = [x, y, -0.5]
points[7, :] = [x, y, z] points[7, :] = [x, y, z]
points = image.voxToWorld(points) points = transform.transform(points, display.voxToDisplayMat)
self._axis.scatter(points[:, 0], points[:, 1], points[:, 2], self._axis.scatter(points[:, 0], points[:, 1], points[:, 2],
color='b', s=40) color='b', s=40)
......
...@@ -25,6 +25,7 @@ import matplotlib.pyplot as plt ...@@ -25,6 +25,7 @@ import matplotlib.pyplot as plt
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
import fsl.fslview.viewpanel as viewpanel import fsl.fslview.viewpanel as viewpanel
import fsl.utils.transform as transform
class TimeSeriesPanel(viewpanel.ViewPanel): class TimeSeriesPanel(viewpanel.ViewPanel):
...@@ -125,7 +126,10 @@ class TimeSeriesPanel(viewpanel.ViewPanel): ...@@ -125,7 +126,10 @@ class TimeSeriesPanel(viewpanel.ViewPanel):
for image in self._imageList: for image in self._imageList:
ix, iy, iz = image.worldToVox([[x, y, z]])[0] display = image.getAttribute('display')
xform = display.displayToVoxMat
ix, iy, iz = transform.transform([[x, y, z]], xform)[0]
ix = round(ix) ix = round(ix)
iy = round(iy) iy = round(iy)
......
...@@ -11,6 +11,7 @@ import props ...@@ -11,6 +11,7 @@ import props
import fsl.data.imagefile as imagefile import fsl.data.imagefile as imagefile
import fsl.data.image as fslimage import fsl.data.image as fslimage
import fsl.utils.transform as transform
import fsl.fslview.displaycontext as displaycontext import fsl.fslview.displaycontext as displaycontext
runChoices = OrderedDict(( runChoices = OrderedDict((
...@@ -189,6 +190,7 @@ def selectHeadCentre(opts, button): ...@@ -189,6 +190,7 @@ def selectHeadCentre(opts, button):
image = fslimage.Image(opts.inputImage) image = fslimage.Image(opts.inputImage)
imageList = fslimage.ImageList([image]) imageList = fslimage.ImageList([image])
displayCtx = displaycontext.DisplayContext(imageList) displayCtx = displaycontext.DisplayContext(imageList)
display = image.getAttribute('display')
parent = button.GetTopLevelParent() parent = button.GetTopLevelParent()
frame = orthopanel.OrthoDialog(parent, frame = orthopanel.OrthoDialog(parent,
imageList, imageList,
...@@ -196,11 +198,13 @@ def selectHeadCentre(opts, button): ...@@ -196,11 +198,13 @@ def selectHeadCentre(opts, button):
opts.inputImage, opts.inputImage,
style=wx.RESIZE_BORDER) style=wx.RESIZE_BORDER)
panel = frame.panel panel = frame.panel
v2dMat = display.voxToDisplayMat
d2vMat = display.displayToVoxMat
# Whenever the x/y/z coordinates change on # Whenever the x/y/z coordinates change on
# the ortho panel, update the option values. # the ortho panel, update the option values.
def updateOpts(*a): def updateOpts(*a):
x, y, z = image.worldToVox([displayCtx.location])[0] x, y, z = transform.transform([displayCtx.location], d2vMat)[0]
if x >= image.shape[0]: x = image.shape[0] - 1 if x >= image.shape[0]: x = image.shape[0] - 1
elif x < 0: x = 0 elif x < 0: x = 0
...@@ -222,7 +226,7 @@ def selectHeadCentre(opts, button): ...@@ -222,7 +226,7 @@ def selectHeadCentre(opts, button):
# done after the frame has been displayed, i.e # done after the frame has been displayed, i.e
# via wx.CallAfter or similar. # via wx.CallAfter or similar.
voxCoords = [opts.xCoordinate, opts.yCoordinate, opts.zCoordinate] voxCoords = [opts.xCoordinate, opts.yCoordinate, opts.zCoordinate]
worldCoords = image.voxToWorld([voxCoords])[0] worldCoords = transform.transform([voxCoords], v2dMat)[0]
panel.pos = worldCoords panel.pos = worldCoords
# Position the dialog by the button that was clicked # Position the dialog by the button that was clicked
......
...@@ -18,6 +18,7 @@ import argparse ...@@ -18,6 +18,7 @@ import argparse
import props import props
import fsl.data.image as fslimage import fsl.data.image as fslimage
import fsl.utils.transform as transform
import fsl.fslview.displaycontext as displaycontext import fsl.fslview.displaycontext as displaycontext
...@@ -252,12 +253,14 @@ def handleImageArgs(args): ...@@ -252,12 +253,14 @@ def handleImageArgs(args):
if args.worldloc: if args.worldloc:
loc = args.worldloc loc = args.worldloc
elif args.voxelloc: elif args.voxelloc:
loc = imageList[0].voxToWorld([args.voxelloc])[0] display = imageList[0].getAttribute('display')
xform = display.voxToDisplayMat
loc = transform.transform([[args.voxelloc]], xform)[0]
else: else:
loc = [imageList.bounds.xlo + 0.5 * imageList.bounds.xlen, loc = [displayCtx.bounds.xlo + 0.5 * displayCtx.bounds.xlen,
imageList.bounds.ylo + 0.5 * imageList.bounds.ylen, displayCtx.bounds.ylo + 0.5 * displayCtx.bounds.ylen,
imageList.bounds.zlo + 0.5 * imageList.bounds.zlen] displayCtx.bounds.zlo + 0.5 * displayCtx.bounds.zlen]
displayCtx.location.xyz = loc displayCtx.location.xyz = loc
......
...@@ -162,6 +162,7 @@ def run(args, context): ...@@ -162,6 +162,7 @@ def run(args, context):
c = slicecanvas.OSMesaSliceCanvas( c = slicecanvas.OSMesaSliceCanvas(
imageList, imageList,
displayCtx,
zax=i, zax=i,
width=width, width=width,
height=height, height=height,
......
#!/usr/bin/env python
#
# transform.py - Functions for working with affine transformation matrices.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides functions related to 3D image transformations and
spaces.
"""
import numpy as np
import numpy.linalg as linalg
import collections
def invert(x):
"""Inverts the given matrix. """
return linalg.inv(x)
def concat(x1, x2):
"""Combines the two matrices (returns the dot product)."""
return np.dot(x1, x2)
def axisBounds(shape, xform, axis):
"""Returns the (lo, hi) bounds of the specified axis."""
x, y, z = shape
x -= 0.5
y -= 0.5
z -= 0.5
points = np.zeros((8, 3), dtype=np.float32)
points[0, :] = [-0.5, -0.5, -0.5]
points[1, :] = [-0.5, -0.5, z]
points[2, :] = [-0.5, y, -0.5]
points[3, :] = [-0.5, y, z]
points[4, :] = [x, -0.5, -0.5]
points[5, :] = [x, -0.5, z]
points[6, :] = [x, y, -0.5]
points[7, :] = [x, y, z]
tx = transform(points, xform)
lo = tx[:, axis].min()
hi = tx[:, axis].max()
return (lo, hi)
def axisLength(shape, xform, axis):
"""Return the length, in real world units, of the specified axis.
"""
points = np.zeros((2, 3), dtype=np.float32)
points[:] = [-0.5, -0.5, -0.5]
points[1, axis] = shape[axis] - 0.5
tx = transform(points, xform)
# euclidean distance between each boundary point
return sum((tx[0, :] - tx[1, :]) ** 2) ** 0.5
def transform(p, xform, axes=None):
"""Transforms the given set of points ``p`` according to the given affine
transformation ``x``. The transformed points are returned as a
:class:``numpy.float64`` array.
"""
p = _fillPoints(p, axes)
t = np.zeros((len(p), 3), dtype=np.float64)
x = p[:, 0]
y = p[:, 1]
z = p[:, 2]
t[:, 0] = x * xform[0, 0] + y * xform[1, 0] + z * xform[2, 0] + xform[3, 0]
t[:, 1] = x * xform[0, 1] + y * xform[1, 1] + z * xform[2, 1] + xform[3, 1]
t[:, 2] = x * xform[0, 2] + y * xform[1, 2] + z * xform[2, 2] + xform[3, 2]
if axes is None: axes = [0, 1, 2]
tx = np.array(t[:, axes], dtype=np.float64)
if tx.size == 1: return tx[0]
else: return tx
def _fillPoints(p, axes):
"""Used by the :func:`transform` function. Turns the given array p into
a N*3 array of x,y,z coordinates. The array p may be a 1D array, or an
N*2 or N*3 array.
"""
if not isinstance(p, collections.Iterable): p = [p]
p = np.array(p)
if axes is None: return p
if not isinstance(axes, collections.Iterable): axes = [axes]
if p.ndim == 1:
p = p.reshape((len(p), 1))
if p.ndim != 2:
raise ValueError('Points array must be either one or two '
'dimensions')
if len(axes) != p.shape[1]:
raise ValueError('Points array shape does not match specified '
'number of axes')
newp = np.zeros((len(p), 3), dtype=p.dtype)
for i, ax in enumerate(axes):
newp[:, ax] = p[:, i]
return newp
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