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

FIXED bug resulting from merge conflicts + code simplification

parent aa092313
......@@ -36,6 +36,7 @@
#include <vtkQuad.h>
#include <vtkDataSetMapper.h>
#include <vtkImageMapToColors.h>
#include <vtkImageChangeInformation.h>
using namespace std;
......@@ -61,7 +62,7 @@ Slice::~Slice() {
void Slice::init() {
currentSliceIndex = 0;
for (int i=0; i<3; i++) {
for (int i = 0; i < 3; i++) {
originalSpacing[i] = 1.0;
}
......@@ -72,13 +73,8 @@ void Slice::init() {
pickPlaneActorPointSet = nullptr;
pixelActor = nullptr;
pixelActorPointSet = nullptr;
image2DChangeInfo = vtkSmartPointer<vtkImageChangeInformation>::New();
image2DReslicer = vtkSmartPointer<vtkImageReslice>::New();
transformReslicer = vtkSmartPointer<vtkTransform>::New();
resliceTransform = vtkSmartPointer<vtkTransform>::New();
transformReslicer->Identity();
resliceTransform->Identity();
image2DReslicer = nullptr;
resliceTransform = nullptr;
}
// -------------------- getImageData --------------------
......@@ -93,22 +89,22 @@ void Slice::setOriginalVolume(vtkSmartPointer<vtkImageData> volume) {
originalVolume = volume;
// Get the original volume information
// Original volume dimensions in number of voxels (x, y and z)
int originalDimensions[3];
// Original volume dimensions in number of voxels (x, y and z)
int originalDimensions[3];
originalVolume->GetDimensions(originalDimensions);
originalVolume->GetSpacing(originalSpacing);
for (int i=0; i<3; i++) {
for (int i = 0; i < 3; i++) {
// compute original size (nb of slice * spacing)
originalSize[i] = originalDimensions[i] * originalSpacing[i];
// 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
if (originalSpacing[i] == 0.0) {
originalSpacing[i] = 1.0;
}
}
// Prepare all the visualization pipeline
initActors();
}
......@@ -143,12 +139,12 @@ int Slice::getNumberOfSlices() const {
// 0 & 1 -> x; 2 and 3 -> y; 4 & 5 -> z
int extent[6];
originalVolume->GetExtent(extent);
int nbSlices;
switch (sliceOrientation) {
case ARBITRARY:
nbSlices = max(max(extent[1] - extent[0], extent[3] - extent[2]), extent[5] - extent[4]) + 1;
break;
case ARBITRARY:
nbSlices = max(max(extent[1] - extent[0], extent[3] - extent[2]), extent[5] - extent[4]) + 1;
break;
case AXIAL:
case AXIAL_NEURO:
nbSlices = extent[5] - extent[4] + 1;
......@@ -193,9 +189,9 @@ void Slice::setSlice(int s) {
originalVolume->GetExtent(extent);
switch (sliceOrientation) {
case ARBITRARY:
updateReslice();
break;
case ARBITRARY:
updateReslice();
break;
case AXIAL:
case AXIAL_NEURO:
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) {
// Set pixel position in current slice.
setPixelRealPosition(x, y, z);
// show the pixel actor
pixelActor->VisibilityOn();
pixelActor->VisibilityOn();
}
// -------------------- getNumberOfColors --------------------
......@@ -263,45 +259,11 @@ void Slice::setPixelRealPosition(double x, double y, double z) {
// -------------------- setReslicerTransform --------------------
void Slice::setReslicerTransform(vtkSmartPointer<vtkTransform> t) {
// 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
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 --------------------
vtkSmartPointer<vtkImageActor> Slice::get2DImageActor() const {
return image2DActor;
......@@ -331,15 +293,6 @@ void Slice::initActors() {
// set the lookupTable
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
image3DActor = vtkSmartPointer<vtkImageActor>::New();
image3DActor->GetMapper()->SetInputConnection(imgToMapFilter->GetOutputPort());
......@@ -349,11 +302,30 @@ void Slice::initActors() {
image2DActor->GetMapper()->SetInputConnection(imgToMapFilter->GetOutputPort());
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();
updatePickPlane();
// pixel
// Picked pixel
initPixelActor();
updatePixelActor();
}
......@@ -381,7 +353,7 @@ void Slice::initPickPlaneActor() {
topQuad->GetPointIds()->SetId(1, 5);
topQuad->GetPointIds()->SetId(2, 1);
topQuad->GetPointIds()->SetId(3, 0);
vtkSmartPointer<vtkQuad> rightQuad = vtkSmartPointer<vtkQuad>::New();
rightQuad->GetPointIds()->SetId(0, 5);
rightQuad->GetPointIds()->SetId(1, 4);
......@@ -393,7 +365,7 @@ void Slice::initPickPlaneActor() {
bottomQuad->GetPointIds()->SetId(1, 2);
bottomQuad->GetPointIds()->SetId(2, 6);
bottomQuad->GetPointIds()->SetId(3, 7);
// Create the unstructured grid that includes the two quads
pickPlaneActorPointSet = vtkSmartPointer<vtkUnstructuredGrid>::New();
pickPlaneActorPointSet->Allocate(4);
......@@ -439,7 +411,7 @@ void Slice::initPickPlaneActor() {
//-- pickPlaneActor can not be picked
pickPlaneActor->PickableOff();
// by default, the plane actor is always visible
pickPlaneActor->VisibilityOn();
}
......@@ -527,8 +499,8 @@ void Slice::updatePickPlane() {
switch (sliceOrientation) {
case AXIAL_NEURO:
case AXIAL:
sliceBackPlane = currentSliceIndex*originalSpacing[2] - originalSpacing[2] / 2.0;
sliceFrontPlane = currentSliceIndex*originalSpacing[2] + originalSpacing[2] / 2.0;
sliceBackPlane = 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(1, 0.0, 0.0, sliceFrontPlane);
pickPlaneActorPointSet->GetPoints()->SetPoint(2, 0.0, originalSize[1], sliceFrontPlane);
......@@ -540,8 +512,8 @@ void Slice::updatePickPlane() {
break;
case CORONAL:
sliceBackPlane = currentSliceIndex*originalSpacing[1] - originalSpacing[1] / 2.0;
sliceFrontPlane = currentSliceIndex*originalSpacing[1] + originalSpacing[1] / 2.0;
sliceBackPlane = 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(1, 0.0, sliceFrontPlane, 0.0);
pickPlaneActorPointSet->GetPoints()->SetPoint(2, 0.0, sliceFrontPlane, originalSize[2]);
......@@ -553,8 +525,8 @@ void Slice::updatePickPlane() {
break;
case SAGITTAL:
sliceBackPlane = currentSliceIndex*originalSpacing[0] - originalSpacing[0] / 2.0;
sliceFrontPlane = currentSliceIndex*originalSpacing[0] + originalSpacing[0] / 2.0;
sliceBackPlane = 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(1, sliceFrontPlane, 0.0, 0.0);
pickPlaneActorPointSet->GetPoints()->SetPoint(2, sliceFrontPlane, 0.0, originalSize[2]);
......@@ -636,6 +608,52 @@ void Slice::updatePixelActor(double x, double y, double z) {
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 @@
#include <vtkActor.h>
#include <vtkImageActor.h>
#include <vtkUnstructuredGrid.h>
#include <vtkImageReslice.h>
namespace camitk {
/**
......@@ -47,6 +48,8 @@ namespace camitk {
*
* 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.
* 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:
* - image2DActor that provides a 2D representation (the slice in the world reference frame)
......@@ -302,26 +305,18 @@ protected:
/// @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
/// this can be any transform, unlike the image orientation
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;
/// The image reslicer computes the arbitrary slice pixels
vtkSmartPointer<vtkImageReslice> image2DReslicer;
/// update the 2D reslicer
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
......@@ -376,3 +371,4 @@ protected:
}
#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