Commit a102c917 authored by saubatn's avatar saubatn
Browse files

FEATURE 609 Image orientation fixed. Frame always stores the same...

FEATURE 609 Image orientation fixed. Frame always stores the same transformation as the one done on the image (from parent to it) => revert on this point from rev. 1671.

git-svn-id: svn+ssh://scm.forge.imag.fr/var/lib/gforge/chroot/scmrepos/svn/camitk/trunk/camitk@1961 ec899d31-69d1-42ba-9299-647d76f65fb3
parent fc21d78e
......@@ -214,7 +214,13 @@ void ImageComponent::updateProperty(QString name, QVariant value) {
}
// -------------------- setImageData --------------------
void ImageComponent::setImageData(vtkSmartPointer<vtkImageData> anImageData, bool copy, ImageOrientationHelper::PossibleImageOrientations initialOrientation) {
void ImageComponent::setImageData(vtkSmartPointer<vtkImageData> anImageData,
bool copy,
ImageOrientationHelper::PossibleImageOrientations initialOrientation,
vtkSmartPointer<vtkMatrix4x4> initialRotationMatrix ) {
double* orig = anImageData->GetOrigin();
CAMITK_DEBUG("ImageComponent", "setImageData", "initial origin = (" + QString::number(orig[0]).toStdString() + ", " + QString::number(orig[1]).toStdString() + ", " + QString::number(orig[2]).toStdString() + ")")
this->initialOrientation = initialOrientation;
......@@ -233,61 +239,65 @@ void ImageComponent::setImageData(vtkSmartPointer<vtkImageData> anImageData, boo
} else
originalImageData = anImageData;
// Store the initial image orientation as property
Property* orientationProperty = new Property(tr("Initial Image Orientation"), ImageOrientationHelper::getOrientationAsQString(initialOrientation), tr("The initial orientation of the image when it was acquired by the medical device. \nRemember, we display image in the RAI format."), "");
orientationProperty->setReadOnly(true);
addProperty(orientationProperty);
// 1. Get / compute the initial transformation of the image
vtkSmartPointer<vtkMatrix4x4> initialTransformationMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
// a. Get translation from the origin of the vtkImageData
double t_x, t_y, t_z;
originalImageData->GetOrigin(t_x, t_y, t_z);
vtkSmartPointer<vtkTransform> initialTranslation = vtkTransform::New();
initialTranslation->Identity();
initialTranslation->Translate(t_x, t_y, t_z);
initialTranslation->Update();
// b. Get the rotation if provided
if(initialRotationMatrix){
vtkMatrix4x4::Multiply4x4(initialTranslation->GetMatrix(), initialRotationMatrix, initialTransformationMatrix);
}else{
initialTransformationMatrix = initialTranslation->GetMatrix();
}
// Reorient the image according to its initial orientation to RAI
// 1st Get the transformation matrix for the given orientation
double* imgSpacing = anImageData->GetSpacing();
int* imgDims = anImageData->GetDimensions();
// 2. Get the orientation of the image
double* imgSpacing = originalImageData->GetSpacing();
int* imgDims = originalImageData->GetDimensions();
double dims[3];
dims[0] = imgSpacing[0] * imgDims[0];
dims[1] = imgSpacing[1] * imgDims[1];
dims[2] = imgSpacing[2] * imgDims[2];
vtkSmartPointer<vtkMatrix4x4> orientationToRAIMatrix = ImageOrientationHelper::getTransformToRAI(initialOrientation, dims[0], dims[1], dims[2]);
// 2nd Store the translation information not in the image data, but in its frame
// This is a convention for all volumic images. It allows the picking to work correctly
// Get translation transformation
double t_x, t_y, t_z;
originalImageData->GetOrigin(t_x, t_y, t_z);
vtkSmartPointer<vtkTransform> translation = vtkTransform::New();
translation->Identity();
translation->Translate(t_x, t_y, t_z);
translation->Update();
vtkSmartPointer<vtkTransform> oppositeTranslation = vtkTransform::New();
oppositeTranslation->Identity();
oppositeTranslation->Translate(-t_x, -t_y, -t_z);
oppositeTranslation->Update();
// compute the full transformation (translation + orientation)
// 3. Store the orientation information as a property of the Image
Property* orientationProperty = new Property(tr("Initial Image Orientation"), ImageOrientationHelper::getOrientationAsQString(initialOrientation), tr("The initial orientation of the image when it was acquired by the medical device. \nRemember, we display image in the RAI format."), "");
orientationProperty->setReadOnly(true);
addProperty(orientationProperty);
// 4. Compute the full transform (translation + rotation + orientation)
vtkSmartPointer<vtkMatrix4x4> transformMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
vtkMatrix4x4::Multiply4x4(translation->GetMatrix(), orientationToRAIMatrix, transformMatrix);
vtkMatrix4x4::Multiply4x4(initialTransformationMatrix, orientationToRAIMatrix, transformMatrix);
// 3rd Apply this transformation to the image data
// 5. Apply this transform to the data (when using rotation in a Matrix -> need to use vtkImageReslice filter)
vtkSmartPointer<vtkImageReslice> imageResliceFilter = vtkSmartPointer<vtkImageReslice>::New();
imageResliceFilter->SetInput(anImageData);
imageResliceFilter->SetOutputDimensionality(3);
imageResliceFilter->SetOutputOrigin(0, 0, 0);
// imageResliceFilter->SetOutputOrigin(0, 0, 0);
imageResliceFilter->SetResliceAxes(transformMatrix);
originalImageData = imageResliceFilter->GetOutput();
originalImageData->Update();
// 4th Store the opposite transformation
// 6. Compute the inverse transformation
vtkSmartPointer<vtkTransform> inverseTransform = vtkTransform::New();
inverseTransform->SetMatrix(transformMatrix);
inverseTransform->Inverse();
inverseTransform->Update();
// 7. Save this inverse transform in case of saving
backToOriginalTransform = inverseTransform;
// 8. Store this transform as the current frame
// note: we need to get another matrix instance for the transformation (else it is deleted)
vtkSmartPointer<vtkMatrix4x4> originalMatrix = this->getTransform()->GetMatrix();
// first, translate
vtkSmartPointer<vtkMatrix4x4> oppositeTranslationMatrix = oppositeTranslation->GetMatrix();
vtkSmartPointer<vtkMatrix4x4> translatedMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
vtkMatrix4x4::Multiply4x4(originalMatrix, oppositeTranslationMatrix, translatedMatrix);
// second, reorient
vtkSmartPointer<vtkMatrix4x4> orientationFromRAIMatrix = ImageOrientationHelper::getTransformFromRAI(initialOrientation, dims[0], dims[1], dims[2]);
vtkSmartPointer<vtkMatrix4x4> updatedMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
vtkMatrix4x4::Multiply4x4(translatedMatrix, orientationFromRAIMatrix, updatedMatrix);
vtkMatrix4x4::Multiply4x4(originalMatrix, transformMatrix, updatedMatrix);
vtkSmartPointer<vtkTransform> updatedTransform = vtkSmartPointer<vtkTransform>::New();
updatedTransform->SetMatrix(updatedMatrix);
setTransform(updatedTransform);
// Build default lookup table
......@@ -298,18 +308,36 @@ void ImageComponent::setImageData(vtkSmartPointer<vtkImageData> anImageData, boo
// Init or update camitk:Properties
updateImageProperties();
orig = originalImageData->GetOrigin();
CAMITK_DEBUG("ImageComponent", "setImageData", "end initial origin = (" + QString::number(orig[0]).toStdString() + ", " + QString::number(orig[1]).toStdString() + ", " + QString::number(orig[2]).toStdString() + ")")
}
// -------------------- prepareForSaving --------------------
void ImageComponent::prepareForSaving() {
// 3rd Apply the frame transformation to the original image date in order to save it
vtkSmartPointer<vtkImageReslice> imageResliceFilter = vtkSmartPointer<vtkImageReslice>::New();
imageResliceFilter->SetInput(originalImageData);
imageResliceFilter->SetOutputDimensionality(3);
// imageResliceFilter->SetOutputOrigin(originalImageData->GetOrigin());
vtkSmartPointer<vtkMatrix4x4> frameMatrix = getFrame()->getTransformFromWorld()->GetMatrix();
imageResliceFilter->SetResliceAxes(frameMatrix);
originalImageData = imageResliceFilter->GetOutput();
// 1st apply inverse orientation transform
vtkSmartPointer<vtkImageReslice> backToOrigingFilter = vtkSmartPointer<vtkImageReslice>::New();
backToOrigingFilter->SetInput(originalImageData);
backToOrigingFilter->SetOutputDimensionality(3);
backToOrigingFilter->SetResliceAxes(backToOriginalTransform->GetMatrix());
originalImageData = backToOrigingFilter->GetOutput();
originalImageData->Update();
// 2. Retrieve the user transformation made since opening of the image by cancelling
// the transformations made by opening the image stored in the frame.
const vtkSmartPointer<vtkTransform> frame = getTransform();
vtkSmartPointer<vtkMatrix4x4> frameMatrix = frame->GetMatrix();
vtkSmartPointer<vtkMatrix4x4> userMatrix = vtkMatrix4x4::New();
vtkMatrix4x4::Multiply4x4(backToOriginalTransform->GetMatrix(), frameMatrix, userMatrix);
// 3. Apply user modifications to the image data to save them.
vtkSmartPointer<vtkImageReslice> userFilter = vtkSmartPointer<vtkImageReslice>::New();
userFilter->SetInput(originalImageData);
userFilter->SetOutputDimensionality(3);
userFilter->SetResliceAxes(userMatrix);
originalImageData = userFilter->GetOutput();
originalImageData->Update();
}
......
......@@ -38,6 +38,7 @@
#include <vtkTransform.h>
#include <vtkImageFlip.h>
#include <vtkWindowLevelLookupTable.h>
#include <vtkMatrix4x4.h>
// -- QT stuff classes
class QMenu;
......@@ -217,7 +218,17 @@ public:
protected:
virtual void setImageData( vtkSmartPointer<vtkImageData> anImageData, bool copy, ImageOrientationHelper::PossibleImageOrientations initialOrientation = ImageOrientationHelper::RAI);
/**
* Set the image data of the volumic images with the given orientation options.
* @param anImageData The main vtkImageData of the volumic image.
* @param copy Indicate if we do a vtk deep copy of these data or directly work on the one provided.
* @param initialOrientation Initial image orientation
* @param initialTransformMatrix Initial image rotation (provided as a 3x3 matrix)
*/
virtual void setImageData( vtkSmartPointer<vtkImageData> anImageData,
bool copy,
ImageOrientationHelper::PossibleImageOrientations initialOrientation = ImageOrientationHelper::RAI,
vtkSmartPointer<vtkMatrix4x4> initialTransformMatrix = NULL);
/** Update the Properties displayed in the PropertyExplorer
* It should be called by setImageData to update the properties with respect to the new image data
......@@ -234,7 +245,7 @@ protected:
private:
/// the concrete building of the 3D objects (Slice/Geometry): none in this case!
virtual void initRepresentation() {};
virtual void initRepresentation() {}
// builds default lookup table
void initLookupTable();
......@@ -291,6 +302,14 @@ private:
/// Initial image orientation
ImageOrientationHelper::PossibleImageOrientations initialOrientation;
/// The transform to get the image back to the state it was at opening
/// This transform is the inverse of the transform of these 3 steps:
/// * the initial translation of the image (sometimes call Offset)
/// * the initial rotation of the image (sometimes call TransformMatrix)
/// * the initial image orientation
/// Mainly used to prepare the image for saving
vtkSmartPointer<vtkTransform> backToOriginalTransform;
};
}
......
......@@ -86,6 +86,9 @@ vtkSmartPointer<vtkMatrix4x4> ImageOrientationHelper::getTransformFromRAI(Possib
vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
transform->Identity();
// DEBUG
std::cout << "ImageOrientationHelper::getTransformFromRAI = (" << dimX << ", " << dimY << ", " << dimZ << ")" << std::endl;
switch (orientation) {
default:
case RAI:
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment