Commit 94ad509e authored by Emmanuel Promayon's avatar Emmanuel Promayon

FIXED bug resulting from merge conflicts + code simplification

parent aa092313
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <vtkQuad.h> #include <vtkQuad.h>
#include <vtkDataSetMapper.h> #include <vtkDataSetMapper.h>
#include <vtkImageMapToColors.h> #include <vtkImageMapToColors.h>
#include <vtkImageChangeInformation.h>
using namespace std; using namespace std;
...@@ -61,7 +62,7 @@ Slice::~Slice() { ...@@ -61,7 +62,7 @@ Slice::~Slice() {
void Slice::init() { void Slice::init() {
currentSliceIndex = 0; currentSliceIndex = 0;
for (int i=0; i<3; i++) { for (int i = 0; i < 3; i++) {
originalSpacing[i] = 1.0; originalSpacing[i] = 1.0;
} }
...@@ -72,13 +73,8 @@ void Slice::init() { ...@@ -72,13 +73,8 @@ void Slice::init() {
pickPlaneActorPointSet = nullptr; pickPlaneActorPointSet = nullptr;
pixelActor = nullptr; pixelActor = nullptr;
pixelActorPointSet = nullptr; pixelActorPointSet = nullptr;
image2DReslicer = nullptr;
image2DChangeInfo = vtkSmartPointer<vtkImageChangeInformation>::New(); resliceTransform = nullptr;
image2DReslicer = vtkSmartPointer<vtkImageReslice>::New();
transformReslicer = vtkSmartPointer<vtkTransform>::New();
resliceTransform = vtkSmartPointer<vtkTransform>::New();
transformReslicer->Identity();
resliceTransform->Identity();
} }
// -------------------- getImageData -------------------- // -------------------- getImageData --------------------
...@@ -93,22 +89,22 @@ void Slice::setOriginalVolume(vtkSmartPointer<vtkImageData> volume) { ...@@ -93,22 +89,22 @@ void Slice::setOriginalVolume(vtkSmartPointer<vtkImageData> volume) {
originalVolume = volume; originalVolume = volume;
// Get the original volume information // Get the original volume information
// Original volume dimensions in number of voxels (x, y and z) // Original volume dimensions in number of voxels (x, y and z)
int originalDimensions[3]; int originalDimensions[3];
originalVolume->GetDimensions(originalDimensions); originalVolume->GetDimensions(originalDimensions);
originalVolume->GetSpacing(originalSpacing); originalVolume->GetSpacing(originalSpacing);
for (int i=0; i<3; i++) { for (int i = 0; i < 3; i++) {
// compute original size (nb of slice * spacing) // compute original size (nb of slice * spacing)
originalSize[i] = originalDimensions[i] * originalSpacing[i]; originalSize[i] = originalDimensions[i] * originalSpacing[i];
// As originalSpacing[i] will be used to get the slice number // As originalSpacing[i] will be used to get the slice number
// for 2D images, lets replace 0.0 by 1.0 to avoid division by 0 // for 2D images, lets replace 0.0 by 1.0 to avoid division by 0
if (originalSpacing[i] == 0.0) { if (originalSpacing[i] == 0.0) {
originalSpacing[i] = 1.0; originalSpacing[i] = 1.0;
} }
} }
// Prepare all the visualization pipeline // Prepare all the visualization pipeline
initActors(); initActors();
} }
...@@ -143,12 +139,12 @@ int Slice::getNumberOfSlices() const { ...@@ -143,12 +139,12 @@ int Slice::getNumberOfSlices() const {
// 0 & 1 -> x; 2 and 3 -> y; 4 & 5 -> z // 0 & 1 -> x; 2 and 3 -> y; 4 & 5 -> z
int extent[6]; int extent[6];
originalVolume->GetExtent(extent); originalVolume->GetExtent(extent);
int nbSlices; int nbSlices;
switch (sliceOrientation) { switch (sliceOrientation) {
case ARBITRARY: case ARBITRARY:
nbSlices = max(max(extent[1] - extent[0], extent[3] - extent[2]), extent[5] - extent[4]) + 1; nbSlices = max(max(extent[1] - extent[0], extent[3] - extent[2]), extent[5] - extent[4]) + 1;
break; break;
case AXIAL: case AXIAL:
case AXIAL_NEURO: case AXIAL_NEURO:
nbSlices = extent[5] - extent[4] + 1; nbSlices = extent[5] - extent[4] + 1;
...@@ -193,9 +189,9 @@ void Slice::setSlice(int s) { ...@@ -193,9 +189,9 @@ void Slice::setSlice(int s) {
originalVolume->GetExtent(extent); originalVolume->GetExtent(extent);
switch (sliceOrientation) { switch (sliceOrientation) {
case ARBITRARY: case ARBITRARY:
updateReslice(); updateReslice();
break; break;
case AXIAL: case AXIAL:
case AXIAL_NEURO: case AXIAL_NEURO:
image3DActor->SetDisplayExtent(extent[0], extent[1], extent[2], extent[3], s, s); image3DActor->SetDisplayExtent(extent[0], extent[1], extent[2], extent[3], s, s);
...@@ -245,9 +241,9 @@ void Slice::setSlice(double x, double y, double z) { ...@@ -245,9 +241,9 @@ void Slice::setSlice(double x, double y, double z) {
// Set pixel position in current slice. // Set pixel position in current slice.
setPixelRealPosition(x, y, z); setPixelRealPosition(x, y, z);
// show the pixel actor // show the pixel actor
pixelActor->VisibilityOn(); pixelActor->VisibilityOn();
} }
// -------------------- getNumberOfColors -------------------- // -------------------- getNumberOfColors --------------------
...@@ -263,45 +259,11 @@ void Slice::setPixelRealPosition(double x, double y, double z) { ...@@ -263,45 +259,11 @@ void Slice::setPixelRealPosition(double x, double y, double z) {
// -------------------- setReslicerTransform -------------------- // -------------------- setReslicerTransform --------------------
void Slice::setReslicerTransform(vtkSmartPointer<vtkTransform> t) { void Slice::setReslicerTransform(vtkSmartPointer<vtkTransform> t) {
// store the transformation pointer // store the transformation pointer
// (when the transformation is changed, you need to call updateReslice() in order // (when the transformation is changed, you need to call updateReslice() in order
// to take the new transformation into account and update the arbitrary slice image // to take the new transformation into account and update the arbitrary slice image
resliceTransform = t; resliceTransform = t;
} }
// -------------------- updateReslice --------------------
void Slice::updateReslice() {
if (sliceOrientation == ARBITRARY) {
double wxyz[4];
transformReslicer->Identity();
transformReslicer->Translate(originalDimensions[0] / 2, originalDimensions[1] / 2, originalDimensions[2] / 2);
resliceTransform->GetOrientationWXYZ(wxyz);
transformReslicer->RotateWXYZ(wxyz[0], wxyz[1], wxyz[2], wxyz[3]);
transformReslicer->Translate(-originalDimensions[0] / 2, -originalDimensions[1] / 2, -originalDimensions[2] / 2);
transformReslicer->Translate(0.0, 0.0, currentSliceIndex);
image2DReslicer->SetResliceAxes(transformReslicer->GetMatrix());
image2DReslicer->Update();
image3DActor->SetUserMatrix(resliceTransform->GetMatrix());
image3DActor->SetInputData(image2DReslicer->GetOutput());
image3DActor->Update();
}
updateLocalTransformation();
updatePickPlane();
}
// -------------------- updateLocalTransformation --------------------
void Slice::updateLocalTransformation() {
image2DReslicer->SetOutputDimensionality(3);
image2DReslicer->UpdateInformation();
image2DReslicer->SetOutputDimensionality(2);
image2DReslicer->UpdateInformation();
}
// -------------------- get2DImageActor -------------------- // -------------------- get2DImageActor --------------------
vtkSmartPointer<vtkImageActor> Slice::get2DImageActor() const { vtkSmartPointer<vtkImageActor> Slice::get2DImageActor() const {
return image2DActor; return image2DActor;
...@@ -331,15 +293,6 @@ void Slice::initActors() { ...@@ -331,15 +293,6 @@ void Slice::initActors() {
// set the lookupTable // set the lookupTable
imgToMapFilter->SetLookupTable(lut); imgToMapFilter->SetLookupTable(lut);
image2DChangeInfo->SetInputData(imgToMapFilter->GetOutput());
image2DChangeInfo->SetOutputOrigin(0.0, 0.0, 0.0);
image2DReslicer->SetInputConnection(image2DChangeInfo->GetOutputPort());
image2DReslicer->SetInformationInput(imgToMapFilter->GetOutput());
image2DReslicer->AutoCropOutputOn();
image2DReslicer->SetOutputOriginToDefault();
image2DReslicer->SetOutputExtentToDefault();
image2DReslicer->SetOutputSpacingToDefault();
// the 2D and 3D image actors are directly plugged to the output of imgToMapFilter // the 2D and 3D image actors are directly plugged to the output of imgToMapFilter
image3DActor = vtkSmartPointer<vtkImageActor>::New(); image3DActor = vtkSmartPointer<vtkImageActor>::New();
image3DActor->GetMapper()->SetInputConnection(imgToMapFilter->GetOutputPort()); image3DActor->GetMapper()->SetInputConnection(imgToMapFilter->GetOutputPort());
...@@ -349,11 +302,30 @@ void Slice::initActors() { ...@@ -349,11 +302,30 @@ void Slice::initActors() {
image2DActor->GetMapper()->SetInputConnection(imgToMapFilter->GetOutputPort()); image2DActor->GetMapper()->SetInputConnection(imgToMapFilter->GetOutputPort());
image2DActor->InterpolateOn(); image2DActor->InterpolateOn();
// Pick plane // reslicer for the arbitrary slice
// image2DChangeInfo builds a simple image from the original image
// that has default origin, extent and spacing
vtkSmartPointer<vtkImageChangeInformation> image2DChangeInfo = vtkSmartPointer<vtkImageChangeInformation>::New();
image2DChangeInfo->SetInputData(imgToMapFilter->GetOutput());
image2DChangeInfo->SetOutputOrigin(0.0, 0.0, 0.0);
image2DReslicer = vtkSmartPointer<vtkImageReslice>::New();
image2DReslicer->SetInputConnection(image2DChangeInfo->GetOutputPort());
image2DReslicer->SetInformationInput(imgToMapFilter->GetOutput());
image2DReslicer->AutoCropOutputOn();
image2DReslicer->SetOutputOriginToDefault();
image2DReslicer->SetOutputExtentToDefault();
image2DReslicer->SetOutputSpacingToDefault();
// use identity by default for the arbitrary slice
resliceTransform = vtkSmartPointer<vtkTransform>::New();
resliceTransform->Identity();
// Picked plane
initPickPlaneActor(); initPickPlaneActor();
updatePickPlane(); updatePickPlane();
// pixel // Picked pixel
initPixelActor(); initPixelActor();
updatePixelActor(); updatePixelActor();
} }
...@@ -381,7 +353,7 @@ void Slice::initPickPlaneActor() { ...@@ -381,7 +353,7 @@ void Slice::initPickPlaneActor() {
topQuad->GetPointIds()->SetId(1, 5); topQuad->GetPointIds()->SetId(1, 5);
topQuad->GetPointIds()->SetId(2, 1); topQuad->GetPointIds()->SetId(2, 1);
topQuad->GetPointIds()->SetId(3, 0); topQuad->GetPointIds()->SetId(3, 0);
vtkSmartPointer<vtkQuad> rightQuad = vtkSmartPointer<vtkQuad>::New(); vtkSmartPointer<vtkQuad> rightQuad = vtkSmartPointer<vtkQuad>::New();
rightQuad->GetPointIds()->SetId(0, 5); rightQuad->GetPointIds()->SetId(0, 5);
rightQuad->GetPointIds()->SetId(1, 4); rightQuad->GetPointIds()->SetId(1, 4);
...@@ -393,7 +365,7 @@ void Slice::initPickPlaneActor() { ...@@ -393,7 +365,7 @@ void Slice::initPickPlaneActor() {
bottomQuad->GetPointIds()->SetId(1, 2); bottomQuad->GetPointIds()->SetId(1, 2);
bottomQuad->GetPointIds()->SetId(2, 6); bottomQuad->GetPointIds()->SetId(2, 6);
bottomQuad->GetPointIds()->SetId(3, 7); bottomQuad->GetPointIds()->SetId(3, 7);
// Create the unstructured grid that includes the two quads // Create the unstructured grid that includes the two quads
pickPlaneActorPointSet = vtkSmartPointer<vtkUnstructuredGrid>::New(); pickPlaneActorPointSet = vtkSmartPointer<vtkUnstructuredGrid>::New();
pickPlaneActorPointSet->Allocate(4); pickPlaneActorPointSet->Allocate(4);
...@@ -439,7 +411,7 @@ void Slice::initPickPlaneActor() { ...@@ -439,7 +411,7 @@ void Slice::initPickPlaneActor() {
//-- pickPlaneActor can not be picked //-- pickPlaneActor can not be picked
pickPlaneActor->PickableOff(); pickPlaneActor->PickableOff();
// by default, the plane actor is always visible // by default, the plane actor is always visible
pickPlaneActor->VisibilityOn(); pickPlaneActor->VisibilityOn();
} }
...@@ -527,8 +499,8 @@ void Slice::updatePickPlane() { ...@@ -527,8 +499,8 @@ void Slice::updatePickPlane() {
switch (sliceOrientation) { switch (sliceOrientation) {
case AXIAL_NEURO: case AXIAL_NEURO:
case AXIAL: case AXIAL:
sliceBackPlane = currentSliceIndex*originalSpacing[2] - originalSpacing[2] / 2.0; sliceBackPlane = currentSliceIndex * originalSpacing[2] - originalSpacing[2] / 2.0;
sliceFrontPlane = currentSliceIndex*originalSpacing[2] + originalSpacing[2] / 2.0; sliceFrontPlane = currentSliceIndex * originalSpacing[2] + originalSpacing[2] / 2.0;
pickPlaneActorPointSet->GetPoints()->SetPoint(0, 0.0, 0.0, sliceBackPlane); pickPlaneActorPointSet->GetPoints()->SetPoint(0, 0.0, 0.0, sliceBackPlane);
pickPlaneActorPointSet->GetPoints()->SetPoint(1, 0.0, 0.0, sliceFrontPlane); pickPlaneActorPointSet->GetPoints()->SetPoint(1, 0.0, 0.0, sliceFrontPlane);
pickPlaneActorPointSet->GetPoints()->SetPoint(2, 0.0, originalSize[1], sliceFrontPlane); pickPlaneActorPointSet->GetPoints()->SetPoint(2, 0.0, originalSize[1], sliceFrontPlane);
...@@ -540,8 +512,8 @@ void Slice::updatePickPlane() { ...@@ -540,8 +512,8 @@ void Slice::updatePickPlane() {
break; break;
case CORONAL: case CORONAL:
sliceBackPlane = currentSliceIndex*originalSpacing[1] - originalSpacing[1] / 2.0; sliceBackPlane = currentSliceIndex * originalSpacing[1] - originalSpacing[1] / 2.0;
sliceFrontPlane = currentSliceIndex*originalSpacing[1] + originalSpacing[1] / 2.0; sliceFrontPlane = currentSliceIndex * originalSpacing[1] + originalSpacing[1] / 2.0;
pickPlaneActorPointSet->GetPoints()->SetPoint(0, 0.0, sliceBackPlane, 0.0); pickPlaneActorPointSet->GetPoints()->SetPoint(0, 0.0, sliceBackPlane, 0.0);
pickPlaneActorPointSet->GetPoints()->SetPoint(1, 0.0, sliceFrontPlane, 0.0); pickPlaneActorPointSet->GetPoints()->SetPoint(1, 0.0, sliceFrontPlane, 0.0);
pickPlaneActorPointSet->GetPoints()->SetPoint(2, 0.0, sliceFrontPlane, originalSize[2]); pickPlaneActorPointSet->GetPoints()->SetPoint(2, 0.0, sliceFrontPlane, originalSize[2]);
...@@ -553,8 +525,8 @@ void Slice::updatePickPlane() { ...@@ -553,8 +525,8 @@ void Slice::updatePickPlane() {
break; break;
case SAGITTAL: case SAGITTAL:
sliceBackPlane = currentSliceIndex*originalSpacing[0] - originalSpacing[0] / 2.0; sliceBackPlane = currentSliceIndex * originalSpacing[0] - originalSpacing[0] / 2.0;
sliceFrontPlane = currentSliceIndex*originalSpacing[0] + originalSpacing[0] / 2.0; sliceFrontPlane = currentSliceIndex * originalSpacing[0] + originalSpacing[0] / 2.0;
pickPlaneActorPointSet->GetPoints()->SetPoint(0, sliceBackPlane, 0.0, 0.0); pickPlaneActorPointSet->GetPoints()->SetPoint(0, sliceBackPlane, 0.0, 0.0);
pickPlaneActorPointSet->GetPoints()->SetPoint(1, sliceFrontPlane, 0.0, 0.0); pickPlaneActorPointSet->GetPoints()->SetPoint(1, sliceFrontPlane, 0.0, 0.0);
pickPlaneActorPointSet->GetPoints()->SetPoint(2, sliceFrontPlane, 0.0, originalSize[2]); pickPlaneActorPointSet->GetPoints()->SetPoint(2, sliceFrontPlane, 0.0, originalSize[2]);
...@@ -636,6 +608,52 @@ void Slice::updatePixelActor(double x, double y, double z) { ...@@ -636,6 +608,52 @@ void Slice::updatePixelActor(double x, double y, double z) {
pixelActorPointSet->Modified(); pixelActorPointSet->Modified();
} }
// -------------------- updateReslice --------------------
void Slice::updateReslice() {
if (sliceOrientation == ARBITRARY) {
double wxyz[4];
// Original volume dimensions in number of voxels (x, y and z)
int originalDimensions[3];
originalVolume->GetDimensions(originalDimensions);
// Transformations required to compute the arbitrary slice inside the volume
vtkSmartPointer<vtkTransform> transformationInsideVolume = vtkTransform::New();
transformationInsideVolume->Identity();
// go to the image center
transformationInsideVolume->Translate(originalDimensions[0] / 2, originalDimensions[1] / 2, originalDimensions[2] / 2);
// apply the current rotation from the frame
resliceTransform->GetOrientationWXYZ(wxyz);
transformationInsideVolume->RotateWXYZ(wxyz[0], wxyz[1], wxyz[2], wxyz[3]);
// go back to the image origin
transformationInsideVolume->Translate(-originalDimensions[0] / 2, -originalDimensions[1] / 2, -originalDimensions[2] / 2);
// translate to the current slice
transformationInsideVolume->Translate(0.0, 0.0, currentSliceIndex);
image2DReslicer->SetResliceAxes(transformationInsideVolume->GetMatrix());
image2DReslicer->Update();
image3DActor->SetUserMatrix(resliceTransform->GetMatrix());
image3DActor->SetInputData(image2DReslicer->GetOutput());
image3DActor->Update();
}
updateLocalTransformation();
updatePickPlane();
}
// -------------------- updateLocalTransformation --------------------
void Slice::updateLocalTransformation() {
image2DReslicer->SetOutputDimensionality(3);
image2DReslicer->UpdateInformation();
image2DReslicer->SetOutputDimensionality(2);
image2DReslicer->UpdateInformation();
}
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <vtkActor.h> #include <vtkActor.h>
#include <vtkImageActor.h> #include <vtkImageActor.h>
#include <vtkUnstructuredGrid.h> #include <vtkUnstructuredGrid.h>
#include <vtkImageReslice.h>
namespace camitk { namespace camitk {
/** /**
...@@ -47,6 +48,8 @@ namespace camitk { ...@@ -47,6 +48,8 @@ namespace camitk {
* *
* This class manages the visual representation of one slice of a volume image. * This class manages the visual representation of one slice of a volume image.
* The slice depends on the orientation and the currently selected slice index. * The slice depends on the orientation and the currently selected slice index.
* A special case is the arbitrary orientation, where the orientation is not perpendicular to one
* of the axes, but can have any free orientation and translation.
* *
* A slice is represented in 2D and 3D thanks to: * A slice is represented in 2D and 3D thanks to:
* - image2DActor that provides a 2D representation (the slice in the world reference frame) * - image2DActor that provides a 2D representation (the slice in the world reference frame)
...@@ -302,26 +305,18 @@ protected: ...@@ -302,26 +305,18 @@ protected:
/// @name Management of the arbitrary slice /// @name Management of the arbitrary slice
/// @{ /// @{
/// Transformation relative to the 3D image actor (it is not parallel to one
/// of the main axe, but has a specific rotation). This should be initialized
/// using the single image component transformation to the world or parent.
vtkSmartPointer<vtkTransform> resliceTransform;
/// Transformations required to compute the arbitrary slice inside the volume /// The image reslicer computes the arbitrary slice pixels
/// this can be any transform, unlike the image orientation vtkSmartPointer<vtkImageReslice> image2DReslicer;
vtkSmartPointer<vtkTransform> transformReslicer;
/// Transformation relative to the 3D image actor (it is not parallel to one
/// of the main axe, but has a specific rotation)
vtkSmartPointer<vtkTransform> resliceTransform;
/// update the 2D reslicer /// update the 2D reslicer
void updateLocalTransformation(); void updateLocalTransformation();
/// This is required for the arbitrary slice.
/// It builds a simple image from the original image
/// that has default origin, extent and spacing
vtkSmartPointer<vtkImageChangeInformation> image2DChangeInfo;
/// The image reslicer computes the arbitrary slice pixels
vtkSmartPointer<vtkImageReslice> image2DReslicer;
/// @} /// @}
/// @name Used to visualize the current picking /// @name Used to visualize the current picking
...@@ -376,3 +371,4 @@ protected: ...@@ -376,3 +371,4 @@ protected:
} }
#endif // CANONICAL_SLICE_H #endif // CANONICAL_SLICE_H
Markdown is supported
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