-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using pure transforms for image and geometry data #7403
Conversation
Signed-off-by: Ben Murray <[email protected]>
Signed-off-by: Ben Murray <[email protected]>
Signed-off-by: Ben Murray <[email protected]>
Signed-off-by: Ben Murray <[email protected]>
Hi Ben, first thank you for the detailed PR and explanation; I have a few questions according to your proposal:
|
Thanks for the detailed feedback!
No, I haven't implemented
Ahh, no. We pass the The resampling operation analyses the matrix that is passed to it and uses the cheapest operation it can use, and will always attempt to do so in a lossless fashion if possible. The logic is as follows:
The benefit of such a 'universal' resampler is that the logic for efficiently resampling data can be taken out of the transforms themselves and put somewhere where every transform can benefit from improvements in resampling operations. This is a key part of what allows the pure transforms without any downsides. When operating lazily, it also allows for cases where the cumulative transform is an interpolate or even a tensor operation, even if the individual transforms wouldn't do so.
I have examples of this for crop and pad that I can add to the PR.
Ooops! This is adapted from the lazy resampling implementation that the paper was based on. MetaMatrix should be gone, and it is my mistake if there are some left in there. I'll tidy it up. |
An approach to implement #4027 that uses pure transforms to minimise the need for additional transforms.
NOTE: the implementation is untested in its current form and is missing components. There should be enough here to demostrate the approach; please let me know if anything is unclear.
NOTE: although this PR talks about pure transforms, we don't actually need to reimplement the transforms; we could instead modify them to have geometry paths, although this adds to the already high-complexity of the spatial transform implementations.
Introduction
This approach uses the concept of pure transforms. These are transforms that don't directly manipulate and resample data, but rather simply specify the operation that is to be carried out in terms of either an affine matrix or a deformation grid. This description is then given to a function that executes the transform, and does so depending on the nature of the data that is provided.
Initially, we should first go over the design principles that this PR adheres to
Geometry preprocessing design principles
Geometry data should be handled in the same way as Image data (as much as is possible)
We should avoid Image and Geometry versions of each transform if possible
We should support pure Geometry applications
Compose
and geometry:Compose
Compose
Critical geometry design decisions
The principle design decision for geometry is what unit space looks like. Given the desire that geometry is not subordinate to image data, we should tie unit space to physical units (i.e. millimetres) rather than pixel / voxel space. This has the following consequences:
Why does this matter? We need to separate the notion of transforms for overall geometry and transforms for raster space.
Most transforms express pure world-space operations
flip
,orientation
,rotate(keep_size=True)
,rotate90
,zoom
etc.The transforms that are image specific express raster-space operations that may or may not also have identity world-space transforms
resample
,resample_to_match
,rotate(keep_size=False)
,spatial_resample
,spacing
Note that
rotate
is an interesting case. Rotate generally expresses pure world-space operations, but whenkeep_size
is False, it specifies a raster-space transform that modifies the image viewport.Categorising transforms
Not image-specific
Image-specific transforms
Transforms using grids
Array and Dictionary
Open questions
Geometry specific transforms
The following transforms have been identified as needing to exist in some form:
LoadGeometry
TransformToImage
Translate
LoadGeometry
This transform loads geometric data. It can in theory wrap all identified geometric types but at a minimum it needs to support arrays of points.
Later we might also support loading of indexed meshes and higher order geometric primitives
We might also want to support loading of other metadata such affine matrices
TransformToImage
This transform takes geometry data and maps it to a given image. This is useful when the geometry data doesn't have a defined space and must be mapped to an image.
TransformLike
TransformLike
is a way of aligning point clouds tensors with image tensors following transforms that only really work on images. Transforms such asResize
/Resized
calculate a scaling matrix that can only be determined from the physical characteristics of an image. However, corresponding point cloud data still needs updating to match the transformed image. soTransformLike
is provided to take the latest transform from applied or pending and either apply it or add it to pending on the point cloud tensors.Note that
TransformLike
seems close in functionality toResampleToMatch
and extending the latter may be better than implementing the former.Modifications to existing transforms
Array transforms
Array transforms specific to images might be modified so that geometry data can be updated. This can be done via additional operation parameters that take a tensor or tuple of tensors:
Another way to achieve this would be to add an extra key field that indicates fields that should have the recent transform applied to them, but this would have to be added to all spatial dictionary transforms.
Dictionary transforms
Dictionary transforms specific to images can refer to geometry by name rather than requiring to pass tensors in directly
An example pure transform
All pure transforms are implemented as pure functions. The array and dictionary, class-based transforms simply wrap the functional transform and pass the necessary parameters to it. This is true for both deterministic and random transforms.
Applying transform descriptions
Applying transform descriptions is simple matter of writing a resampler that knows how to handle point data. We add a
kind
property toMetaTensor
(currently"pixel"
and"point"
) to indicate what kind of tensor data a given tensor contains and when we arrive at the point of resampling we check the tensor kind and call the appropriate function,resample_image
orresample_points
. This will update the tensor accordingly when passed either an affine matrix or a deformation field.The call stack is
An example pipeline
Types of changes
./runtests.sh -f -u --net --coverage
../runtests.sh --quick --unittests --disttests
.make html
command in thedocs/
folder.