camitk.TransformationManager¶
- class camitk.TransformationManager¶
TransformationManager manages frames of reference and transformations for a CamiTK Application
This class is the entry point to using FrameOfReference and Transformation system.
Every Component that is displayable contains data which are located in space using coordinates. But two Components may not use the same origin in space, or the same axes.
To manage that, the notion of Frame specifies an origin and axes, this is modeled by camitk::FrameOfReference. Each component has a FrameOfReference accessed by Component::getFrame()
Two Components may share a common Frame, for example two meshes of two organs computed from the same image. In this case both components’ getFrame() should return the same FrameOfReference.
TransformationManager stores and manages all the FrameOfReference objects used in a CamiTK Application.
When you need to display two Components, or to apply an Action that uses multiple Components, it is necessary to be able to transform the coordinates of one Component’s data to another.
These geometrical transformations are stored in the camitk::Transformation class. A Transformation stores the frame of origin, the frame of destination and the geometrical transformation itself. Currently it supports linear transformations (represented in a 4x4 homogeneous matrices).
All Transformation objects are also stored and managed in the TransformationManager. The TransformationManager provides and manages a specific and unique “world frame”. This is the frame used by VTK and the default for 3D viewers. Having a world frame simplifies the usage of frames.
Alongside Component, Viewers also have a FrameOfReference, which determines the “point of view” they are using for the visualization. More precisely, it is used to set the camera and orient the vtkActors. The default frame of the 2D and 3D viewers is the world frame.
Their is only one TransformationManager (all public methods are static).
on shared and raw pointers
Transformation and Frames can be manipulated locally using their raw pointer. Use the shared pointer only if you need to own the object as well, that if the Transformation or Frame is part of your class members and need to be kept alive for your code to work. Using a shared pointer ensures that the Frame or Transformation won’t be removed from the system by the TransformationManager. If you only need to access or modify information on a frame or transformation, only use the raw pointer.
section TransformationManager_API
The TransformationManager provides the following utilities: - addFrameOfReference(…) methods add FrameOfReference objects - addTransformation(…) methods add Transformation objects - getTransformationOwnership(..) methods returns the shared_ptr to a Transformation - getTransformation(…) method computes a Transformation between two Frames, if any path exists between them - updateTransformation(…) methods modify the transformation matrix values
Two methods are provided for the manipulation of world frame: - getWorldFrame() returns the unique world frame, to which all frames should have a path to (composed of 1 or more transformations). - ensurePathToWorld() to add a default identity Transformation between the provided Frame and the worldFrame if no Transformation was defined.
section Transformation
A Transformation can either be: - directly defined by the user using addTransformation() -> it holds a user defined 4x4 matrix. It has 0 sources. - an inverse of another Transformation. Inverse Transformation are automatically generated by the TransformationManager. It therefore has 1 source (the direct Transformation it is the inverse of). - a composite transformation defined automatically by the TransformationManager to pass from one source to another one over more than one frame. It is composed by a list of other transformations. It therefore has more than one sources.
Information about a Transformation t can be obtained from the TransformationManager using: - hasSources(t) and getSources(t) - isCompositeTransformation(t) - isInverseTransformation(t) - isDefaultIdentityToWorld(t)
There is three cases where TransformationManager will automatically create a transformation: - when a linear transformation is added using addTransformation(), the inverse transformation is automatically generated and stored in the system. The new transformation will therefore only have 1 source. - when getTransformation() is called and finds a new path of transformations between the two given frames, it will generate a new composed transformation (for optimization) from those transformations. The new transformation will therefore have all those transformations as sources. - when ensurePathToWorld(f) is called, and no path can be found between f and the world frame, then a new identity transformation from f to world frame is created. This new transformation has no source (note that TransformationManager will also create its inverse, which has 1 source). Use isDefaultIdentityToWorld() to check if a transformation was generated this way.
Note that TransformationManager always generates an inverse transformation for any existing linear transformation if it does not exist already.
section Transformation_Sources
The lists of Transformation sources are managed by the TransformationManager. Sources are the transformations that are used (composed) to compute a Transformation t. If any of the sources are modified, t is guaranteed to reflect this update, i.e., it is recomputed from its sources. If t has only one source, this means t is the inverse of this source.
See also
hasSources() getSources()
section FrameOfReference A FrameOfReference represents a specific system of coordinates in which component data’s coordinates are expressed.
It can have a name, a description, and anatomical labels associated to its axes: for example, the X axis may have label L on the lower values, and R on the higher values (for Left/Right anatomical orientation). You can add new Frames of reference using addFrameOfReference methods when creating a new Component (even though Component constructor creates a default one for you), or if you need to manage multiple frames in your component (e.g. for an articulated robot).
If you need to get ownership of a specific FrameOfReference (e.g. you want your Component to store the same Frame as another Component), use getFrameOfReferenceOwnership()
To edit anatomical information, name or description, refer to FrameOfReference class.
section Transformation_Path_Management
When you need a Transformation from one Frame to another, the method to call is getTransformation()
This method first looks if a Transformation was added using addTransformation between those Frames, then if there is already a cached composite Transformation linking both Frames, and finally, it checks whether there is a path in the graph of Frames and Transformations linking those Frames using intermediary Frames.
Private methods hasPath() and getPath() are used to search the graph for a suitable path. If there is one, a new cached composite Transformation is stored (it combines the path of Transformations into one). If there is no path, these methods return nullptr.
When the user wants to ensure that a specific Frame has a Transformation to the WorldFrame, she/he should call ensurePathToWorld(). This will create a default identity Transformation to the WorldFrame if there is no existing path between the Frame and the WorldFrame.
All default identity Transformations are marked, so that if a new Transformation is added using addTransformation, these Transformations can be automatically removed. This is needed to avoid creation of multiple path between Frames (there will therefore never be any cycle in the Frame/Transformation graph).
section Transformation_Memory_management
As FrameOfReference and Transformation constructors are private, all Frames and Transformations must be created through the TransformationManager.
Internally, Transformation and FrameOfReference objects are stored using std::shared_ptr
This means that ownership of these objects is shared between the TransformationManager and custom objects used in CamiTK such as Component (which owns its FrameOfReference), ImageComponent (which also owns its internal Transformation from raw to main).
Most methods of this class return or use raw pointers, meaning they do not return or get ownership of the FrameOfReference or Transformation object. The raw pointers are meant to be used for immediate processing (e.g. getting the name of a Frame, transforming the coordinates of a point using a Transformation) but not to store the pointer. If you need to store the object, you must use getFrameOfReferenceOwnership() and getTransformationOwnership() This makes explicit who is owning Transformations and Frames.
Note that you may not get ownership of a composite Transformation (computed from others) or a default Transformation, as those must be removable at all times.
TransformationManager may delete any Transformation that is not owned outside its internal data structure (which mean they are not used anymore apart from internally).
cleanupFramesAndTransformation(), removeDefaultPaths(), removeTransformation().
To determine whether a Transformation or Frame is owned outside the TransformationManager, std::shared_ptr usage counter is used.
section “Using TransformationManager in your extensions” TransformationManagerUser TransformationManager use cases
Most common use cases for CamiTK extension developers: - adding a new Component: use the default Component constructor which creates a new default FrameOfReference for the Component - adding a new Component created from another one: - if the new Component is using the same Frame, just set its Frame to the original component’s frame using InterfaceFrame::setFrameFrom() - if you need to ensure a Component has its own independent frame, use InterfaceFrame::resetFrame() - Special cases for ImageComponent: ImageComponents have a data frame and a main transformation (from their data to their main frame) that needs to be taken care of. Be aware that ImageComponent::setFrameFrom() and ImageComponent::resetFrame() are reimplemented to take care of the data frame and main transformation. For instance: - your action creates an image outImage from an image inImage, just call
out->setFrameFrom(in)- your action creates an mesh outMesh from an image inImage, call `outMesh-setFrame(TransformationManager::getFrameOfReferenceOwnership(inImage- getDataFrame()));` as the mesh is computed from the image data, the mesh is defined in the image component data frame
Registering a Component to another: for example, compute the
registration between two meshes, then use addTransformation() between the frames of the two meshes.
: if there is already a Transformation path between the meshes and the world frame is not in this path, addTransformation() will return nullptr. This means that computed transformation (for example after previous registration) already gives a transformation between the two meshes. If you want to update previous registration, you should use updateTransformation() instead. If updateTransformation() also returns nullptr, this means you are trying to create a cycle in the transformation graph. - You can use multiple Frames and Transformation inside your own Component, use the TransformationExplorer to check if it is working as expected.
In the case of an articulated robot, each part may have its own FrameOfReference, and each articulation its own Transformation. You can use methods addFrameOfReference, addTransformation, updateTransformation to create and update frames and transformations in your Action and Component extensions.
- __init__(*args, **kwargs)¶
Methods
__init__(*args, **kwargs)addFrameOfReference(name, description)Add a FrameOfReference with a name and description This is the standard way to create a new FrameOfReference
addTransformation(arg0, arg1)Create and register a new identity Transformation between two frames if there is no existing transformation between those frames.
getFramesOfReference()Get a list of all stored FrameOfReference
getTransformation(arg0, arg1)Get a transformation if it exists or compute it if a path exists between the frames.
getTransformations()Returns the list of all transformations managed in the system, independents or not.
getWorldFrame()Get the WorldFrame
preferredDefaultIdentityToWorldLink(arg0)Call this method when you prefer (for visualization purpose only) to have a direct link to world from the given frame instead of any other path.
removeTransformation(*args, **kwargs)Overloaded function.
updateTransformation(*args, **kwargs)Overloaded function.