========================= Registration API Design ========================= This contains design ideas for the end-user api when registering images in nipy. We want to provide a simple api, but with enough flexibility to allow users to changes various components of the pipeline. We will also provide various **Standard** scripts that perform typical pipelines. The pluggable script:: func_img = load_image(filename) anat_img = load_image(filename) interpolator = SplineInterpolator(order=3) metric = NormalizedMutualInformation() optimizer = Powell() strategy = RegistrationStrategy(interpolator, metric, optimizer) w2w = strategy.apply(img_fixed, img_moving) To apply the transform and resample the image:: new_img = resample(img_moving, w2w, interp=interpolator) Or:: new_img = Image(img_moving, w2w*img_moving.coordmap) Transform Multiplication ------------------------ The multiplication order is important and coordinate systems must *make sense*. The *output coordinates* of the mapping on the right-hand of the operator, must match the *input coordinates* of the mapping on the left-hand side of the operator. For example, imageA has a mapping from voxels-to-world (v2w), imageB has a mapping from world-to-world (w2w). So the output of imageA, *world*, maps to the input of imageB, *world*. We would compose a new mapping (transform) from these mappings like this:: new_coordmap = imageB.coordmap * imageA.coordmap If one tried to compose a mapping in the other order, an error should be raised as the code would detect a mismatch of trying to map output coordinates from imageB, *world* to the input coordinates of imageA, *voxels*:: new_coordmap = imageA.coordmap * imageB.coordmap raise ValueError!!! Note: We should consider a meaningful error message to help people quickly correct this mistake. One way to remember this ordering is to think of composing functions. If these were functions, the output of the first function to evaluate (imageA.coordmap) is passed as input to the second function (imageB.coordmap). And therefore they must match:: new_coordmap = imageB.coordmap(imageA.coordmap()) Matching Coordinate Systems --------------------------- We need to make sure we can detect mismatched coordinate mappings. The CoordinateSystem class has a check for equality (__eq__ method) based on the axis and name attributes. Long-term this may not be robust enough, but it's a starting place. We should write tests for failing cases of this, if they don't already exists. CoordinateMap ------------- Recall the CoordinateMap defines a mapping between two coordinate systems, an input coordinate system and an output coordinate system. One example of this would be a mapping from voxel space to scanner space. In a Nifti1 header we would have an affine transform to apply this mapping. The *input coordinates* would be voxel space, the *output coordinates* would be world space, and the affine transform provides the mapping between them.