Execution Model Reference Systems
The issue
In Slicer3, every geometric entity is associated with a transform (via the MRML tree hierarchy): every image, model or fiducial (vtkImageData, vtkPolyData, ...) is associated with a vtkMatrix4x4 defining its orientation in space. Therefore, the actual point coordinates stored in vtkPolyData may be expressed in arbitrary coordinate systems, but they will be properly located in the MRML scene, in the RAS coordinate system. Also, vtkImageData objects, which are defined in VTK as structured grids oriented with the x,y,z axes, can have arbitrary orientations in space.
While this is a powerful mechanism, maintaining consistency within the Execution Model is challenging.
When calling a CLI plugin, Slicer writes temporary data files that are fed to the CLI:
- the vtkPolyData point coordinates are first transformed in RAS (i.e. its points are transformed with the proper vtkMatrix4x4) and the file is written in VTK format. When the CLI program reads the VTK file, it implicitly has the data and the transform (which has become the identity matrix after the transformation has been applied berfore the call to the CLI program).
- fiducials are passed along as a comma-separated list of float arguments, and are expressed in RAS (for now, although the extension to LPS and IJK has been planned - by the way, if one specifies LPS, he should also specify LPS of what image, otherwise one fiducial in LPS corresponds to many fiducials in RAS)
- vtkImageData is stored in a nrrd file, with the information about the vtkMatrix4x4 stored in the header as space origin and space directions (which also include spacing); when the Archetype reader in the CLI reads the file in, the two objects are recreated: in the current implementation the vtkImageData has origin and spacing information, while vtkMatrix4x4 expresses the RAS to IJK transform.
At this stage, if a CLI program has to locate a point on the input surface on the input image, it first has to set the image origin and spacing to 0,0,0 and 1,1,1 respectively (whilch could eventually be done in the reader), apply the transform to the point, locate the transformed point. Conversely, if a pixel has to be turned into a geometric entity, it has to be transformed with the inverse of the vtkMatrix4x4. This way, all operations would be performed in IJK coordinates. There are two main disadvantages to this IJK approach: i) filters may not behave properly if images do not have anisotropic spacing; ii) while constantly dealing with transform is not a problem for small CLI programs written with Slicer in mind, it might mean a major code revision for VTK-based projects that have to be integrated with Slicer. This last point could be overcome by pre-transforming all input geometry and fiducials in IJK, but this is in general a bad idea, since surface curvature, etc will change in case of anisotropic voxels.
An alternative solution could be to extend the Archetype reader to output the RAS to LPS matrix as well (i.e. origin and spacing would be factored out from the vtkMatrix4x4). This way, assuming all images in the CLI have the same orientation matrix (which is reasonable since it's a constraint imposed by VTK), all vtkPolyData and fiducials can be transformed before the actual processing without losing their shape, and point location or extraction could be left unmodified in the CLI algorithm code. The plugin coder would have to worry about transforms only at the beginning and at the end of the CLI program, which would ease the effort of interfacing existing projects with Slicer.
Optionally, this last solution could be implemented in Slicer itself. The XML description would indicate which image entity provides the RAS to LPS transform, and all geometry and fiducials woudl be transformed in this coordinate system before the call to the CLI. After the CLI spits out data in the reference image LPS, Slicer would take care of applying the RAS to LPS inverse to whatever it loads up. The benefit of this approach is nullified if two images with different orientations are passed to the CLI, but i) the RAS to LPS could be optional, ii) it wouldn't hurt a orientation-aware CLI anyway. The disadvantage is that potentially large vtkPolyData obejcts have to be duplicated (but this is common to all solutions except the first).