SliceOrder
Description¶
Permute image and other geometric data to maintain proper orientation regardless of the acquisition order.
For examples showing the usage of this snippet please see FroggieSurface and FroggieView.
To use the snippet, click the Copy to clipboard at the upper right of the code blocks.
Implementation¶
# from vtkmodules.vtkCommonMath import vtkMatrix4x4
# from vtkmodules.vtkCommonTransforms import vtkTransform
class SliceOrder:
"""
These transformations permute image and other geometric data to maintain proper
orientation regardless of the acquisition order. After applying these transforms with
vtkTransformFilter, a view up of 0, -1, 0 will result in the body part
facing the viewer.
NOTE: some transformations have a -1 scale factor for one of the components.
To ensure proper polygon orientation and normal direction, you must
apply the vtkPolyDataNormals filter.
Naming (the nomenclature is medical):
si - superior to inferior (top to bottom)
is - inferior to superior (bottom to top)
ap - anterior to posterior (front to back)
pa - posterior to anterior (back to front)
lr - left to right
rl - right to left
"""
def __init__(self):
self.si_mat = vtkMatrix4x4([[1, 0, 0, 0], [0, 0, 1, 0], [0, -1, 0, 0], [0, 0, 0, 1]])
self.is_mat = vtkMatrix4x4([[1, 0, 0, 0], [0, 0, -1, 0], [0, -1, 0, 0], [0, 0, 0, 1]])
self.lr_mat = vtkMatrix4x4([[0, 0, -1, 0], [0, -1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]])
self.rl_mat = vtkMatrix4x4([[0, 0, 1, 0], [0, -1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]])
self.transform = dict()
si_trans = vtkTransform()
si_trans.SetMatrix(self.si_mat)
self.transform['si'] = si_trans
is_trans = vtkTransform()
is_trans.SetMatrix(self.is_mat)
self.transform['is'] = is_trans
ap_trans = vtkTransform()
ap_trans.Scale(1, -1, 1)
self.transform['ap'] = ap_trans
pa_trans = vtkTransform()
pa_trans.Scale(1, -1, -1)
self.transform['pa'] = pa_trans
lr_trans = vtkTransform()
lr_trans.SetMatrix(self.lr_mat)
self.transform['lr'] = lr_trans
rl_trans = vtkTransform()
rl_trans.SetMatrix(self.rl_mat)
self.transform['rl'] = rl_trans
"""
The previous transforms assume radiological views of the slices
(viewed from the feet).
Other modalities such as physical sectioning may view from the head.
The following transforms modify the original with a 180° rotation
about the y-axis.
"""
self.hf_mat = vtkMatrix4x4([[-1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])
hf_trans = vtkTransform()
hf_trans.SetMatrix(self.hf_mat)
self.transform['hf'] = hf_trans
hf_si_trans = vtkTransform()
hf_si_trans.SetMatrix(self.hf_mat)
hf_si_trans.Concatenate(self.si_mat)
self.transform['hfsi'] = hf_si_trans
hf_is_trans = vtkTransform()
hf_is_trans.SetMatrix(self.hf_mat)
hf_is_trans.Concatenate(self.is_mat)
self.transform['hfis'] = hf_is_trans
hf_ap_trans = vtkTransform()
hf_ap_trans.SetMatrix(self.hf_mat)
hf_ap_trans.Scale(1, -1, 1)
self.transform['hfap'] = hf_ap_trans
hf_pa_trans = vtkTransform()
hf_pa_trans.SetMatrix(self.hf_mat)
hf_pa_trans.Scale(1, -1, -1)
self.transform['hfpa'] = hf_pa_trans
hf_lr_trans = vtkTransform()
hf_lr_trans.SetMatrix(self.hf_mat)
hf_lr_trans.Concatenate(self.lr_mat)
self.transform['hflr'] = hf_lr_trans
hf_rl_trans = vtkTransform()
hf_rl_trans.SetMatrix(self.hf_mat)
hf_rl_trans.Concatenate(self.rl_mat)
self.transform['hfrl'] = hf_rl_trans
# Identity
self.transform['I'] = vtkTransform()
# Zero
z_trans = vtkTransform()
z_trans.Scale(0, 0, 0)
self.transform['Z'] = z_trans
def print_transform(self, order):
"""
Print the homogenous matrix corresponding to the slice order.
:param order: The slice order.
:return:
"""
print(order)
m = self.transform[order].GetMatrix()
for i in range(0, 4):
row = list()
for j in range(0, 4):
row.append(f'{m.GetElement(i, j):>6.2g}')
print(' '.join(row))
def print_all_transforms(self):
"""
Print all the homogenous matrices corresponding to the slice orders.
:return:
"""
print(self.transform.keys())
for k in self.transform.keys():
self.print_transform(k)
def get(self, order):
"""
Returns the vtkTransform corresponding to the slice order.
:param order: The slice order.
:return: The vtkTransform to use.
"""
if order in self.transform.keys():
return self.transform[order]
else:
s = 'No such transform "{:s}" exists.'.format(order)
raise Exception(s)
Usage¶
so = SliceOrder()
# so.print_all_transforms()