1 /*=========================================================================
3 Module: $RCSfile: bbvtkImagePlanes.cxx,v $
5 Date: $Date: 2012/07/09 13:02:42 $
6 Version: $Revision: 1.37 $
7 =========================================================================*/
9 /* ---------------------------------------------------------------------
11 * Copyright (c) CREATIS-LRMN (Centre de Recherche en Imagerie Medicale)
12 * Authors : Eduardo Davila, Laurent Guigues, Jean-Pierre Roux
14 * This software is governed by the CeCILL-B license under French law and
15 * abiding by the rules of distribution of free software. You can use,
16 * modify and/ or redistribute the software under the terms of the CeCILL-B
17 * license as circulated by CEA, CNRS and INRIA at the following URL
18 * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
19 * or in the file LICENSE.txt.
21 * As a counterpart to the access to the source code and rights to copy,
22 * modify and redistribute granted by the license, users are provided only
23 * with a limited warranty and the software's author, the holder of the
24 * economic rights, and the successive licensors have only limited
27 * The fact that you are presently reading this means that you have had
28 * knowledge of the CeCILL-B license and that you accept its terms.
29 * ------------------------------------------------------------------------ */
37 #include "bbvtkImagePlanes.h"
38 #include "bbvtkPackage.h"
39 #include "vtkCellPicker.h"
40 #include "vtkProperty.h"
41 #include "vtkPolyData.h"
44 #include "vtkMetaImageWriter.h"
45 #include "vtkPNGWriter.h"
47 #include "bbstdCast.h"
48 #include <vtkCommand.h>
50 #include "vtkImageData.h"
51 //#include "vtkOutlineFilter.h"
52 //#include "vtkPolyDataMapper.h"
53 //#include "vtkActor.h"
54 #include "vtkImagePlaneWidget.h"
55 #include "vtkCellPicker.h"
56 //#include "vtkProperty.h"
58 //#include "vtkRenderer.h"
59 //#include "vtkCamera.h"
61 #include "vtkPlaneWidget.h"
63 #include <vtkImplicitPlaneWidget.h>
65 #include "bbstdRelay.h"
67 #include "vtkObjectFactory.h"
68 #include "vtkImageFlip.h"
70 #include "vtkImageReslice.h"
71 #include "vtkImageChangeInformation.h"
76 //====================================================================
77 BBTK_BLACK_BOX_TEMPLATE2_IMPLEMENTATION(Cast,
78 bbtk::AtomicBlackBox);
79 //====================================================================
80 //====================================================================
81 // BBTK_BLACK_BOX_TEMPLATE_IMPLEMENTATION(Relay,
82 // bbtk::AtomicBlackBox);
83 //====================================================================
86 using namespace bbstd;
90 typedef vtkImageData::Pointer vtkImageDataPointer;
91 BBTK_DEFINE_HUMAN_READABLE_TYPE_NAME(vtkImageDataPointer,
92 "vtkImageDataPointer");
98 //====================================================================
99 // Add the specialized adaptors to the package
100 typedef vtkImagePlaneWidget* I;
101 typedef vtkInteractorObserver* O;
103 BBTK_ADD_TEMPLATE2_BLACK_BOX_TO_PACKAGE(vtk,Cast,I,O);
105 BBTK_DEFINE_RELAY_BLACK_BOX(vtkImageDataPointer,vtk,vtkImageDataPointerRelay);
106 BBTK_BLACK_BOX_IMPLEMENTATION(vtkImageDataPointerRelay,bbtk::AtomicBlackBox);
108 BBTK_ADD_BLACK_BOX_TO_PACKAGE(vtk,vtkImageDataPointerRelay);
109 // BBTK_ADD_TEMPLATE_BLACK_BOX_TO_PACKAGE(vtk,Relay,vtkImageDataPointer);
117 //================================================================
118 class ImagePlanes::VtkCallbackType : public vtkCommand
121 static VtkCallbackType *New()
123 return new VtkCallbackType;
125 //vtkTypeRevisionMacro(VtkCallbackType,vtkCommand);
127 virtual void Execute(vtkObject *caller, unsigned long, void*)
129 mBlackBox->Process();
130 mBlackBox->bbSignalOutputModification();
132 void SetBlackBox(ImagePlanes *BB) { mBlackBox = BB;};
133 // void SetVtkPlaneWidget( vtkImagePlaneWidget *planeWidget );
134 VtkCallbackType() {};
137 // vtkPlaneWidget *planeWidget;
138 ImagePlanes *mBlackBox;
140 //================================================================
142 //vtkCxxRevisionMacro(ImagePlanes::VtkCallbackType, "$Revision: 1.37 $");
144 //================================================================
146 BBTK_ADD_BLACK_BOX_TO_PACKAGE(vtk,ImagePlanes)
147 BBTK_BLACK_BOX_IMPLEMENTATION(ImagePlanes,bbtk::AtomicBlackBox);
149 void ImagePlanes::bbUserSetDefaultValues()
151 bbSetOutputPlaneX(0);
152 bbSetOutputPlaneY(0);
153 bbSetOutputPlaneZ(0);
154 bbSetOutputImageX(0);
155 bbSetOutputImageY(0);
156 bbSetOutputImageZ(0);
158 std::vector<double> vect;
161 bbSetInputWindowLevel (vect);
164 std::vector<int> vectpoints;
166 bbSetOutputPlane3Pts(0);
167 bbSetOutputImage3Pts(0);
168 bbSetInputPointsX(vectpoints);
169 bbSetInputPointsY(vectpoints);
170 bbSetInputPointsZ(vectpoints);
172 _imageReslicer = NULL;
177 bbSetInputInterpolation(1);
181 void ImagePlanes::bbUserInitializeProcessing()
183 /// CREATION DES WIDGETS
184 if (bbGetOutputPlaneX() != 0) return;
186 // The shared picker enables us to use 3 planes at one time
187 // and gets the picking order right
188 vtkCellPicker* picker = vtkCellPicker::New();
189 picker->SetTolerance(0.005);
191 // The 3 image plane widgets
192 vtkImagePlaneWidget* planeWidgetX = GetPlaneWidget('x', 1, 0, 0, picker);
193 vtkImagePlaneWidget* planeWidgetY = GetPlaneWidget('y', 1, 1, 0, picker);
194 planeWidgetY->SetLookupTable(planeWidgetX->GetLookupTable());
196 vtkImagePlaneWidget* planeWidgetZ = GetPlaneWidget('z', 0, 0, 1, picker);
197 planeWidgetZ->SetLookupTable(planeWidgetX->GetLookupTable());
199 vtkImagePlaneWidget* planeWidget3Pts = GetPlaneWidget('3', 0, 1, 1, picker);
200 planeWidget3Pts->SetLookupTable(planeWidgetX->GetLookupTable());
202 // EED MPR view orientation correction..
203 vtkImageFlip *flipYFilter = vtkImageFlip::New();
204 flipYFilter->SetFilteredAxis(1); // flip y axis
205 flipYFilter->SetInput( planeWidgetX->GetResliceOutput() );
206 flipYFilter->Update();
208 vtkImageChangeInformation *image = vtkImageChangeInformation::New();
209 image->SetInput( planeWidgetY->GetResliceOutput() );
210 image->SetOutputSpacing( 1,1,1 );
211 image->CenterImageOn();
213 _imageTransform = vtkTransform::New();
214 vtkImageReslice *slicer =vtkImageReslice::New();
215 slicer->SetInput( image->GetOutput() );
216 slicer->SetInformationInput( image->GetOutput() );
217 slicer->SetResliceTransform( _imageTransform );
218 slicer->SetOutputOrigin(0 , 0 , 0 );
219 slicer->SetInterpolationModeToNearestNeighbor();
221 vtkImageChangeInformation *imageResult = vtkImageChangeInformation::New();
222 imageResult->SetInput( slicer->GetOutput() );
224 planeWidgetY->GetResliceOutput()->GetSpacing(spc);
225 imageResult->SetOutputSpacing( spc[1], spc[0], spc[2] );
226 imageResult->SetOutputOrigin( 0,0,0 );
229 bbSetOutputPlaneX(planeWidgetX);
230 bbSetOutputPlaneY(planeWidgetY);
231 bbSetOutputPlaneZ(planeWidgetZ);
232 bbSetOutputPlane3Pts(planeWidget3Pts);
233 bbSetOutputImageX( flipYFilter->GetOutput() ); // EED MPR view orientation correction..
234 bbSetOutputImageY( imageResult->GetOutput() ); // EED MPR view orientation correction..
235 bbSetOutputImageZ(planeWidgetZ->GetResliceOutput());
236 bbSetInputInteractor(0);
237 //bbSetOutputImage3Pts(planeWidget3Pts->GetResliceOutput());
240 picker->UnRegister(NULL);
242 mVtkCallback = VtkCallbackType::New();
243 mVtkCallback->SetBlackBox(this);
244 planeWidgetX->AddObserver(vtkCommand::InteractionEvent,mVtkCallback);
245 planeWidgetY->AddObserver(vtkCommand::InteractionEvent,mVtkCallback);
246 planeWidgetZ->AddObserver(vtkCommand::InteractionEvent,mVtkCallback);
250 //---------------------------------------------------------------------
251 void ImagePlanes::bbUserFinalizeProcessing()
254 if (bbGetOutputPlaneX())
258 bbGetOutputPlaneX()->RemoveObserver(mVtkCallback);
259 bbGetOutputPlaneY()->RemoveObserver(mVtkCallback);
260 bbGetOutputPlaneZ()->RemoveObserver(mVtkCallback);
262 bbGetOutputPlaneX()->Delete();
263 bbGetOutputPlaneY()->Delete();
264 bbGetOutputPlaneZ()->Delete();
265 mVtkCallback->Delete();
267 //bbGetOutputPlaneX()->SetInput(NULL);
268 //bbGetOutputPlaneY()->SetInput(NULL);
269 //bbGetOutputPlaneZ()->SetInput(NULL);
274 //---------------------------------------------------------------------
275 void ImagePlanes::Process()
278 if (bbGetInputIn()!=0)
282 bbGetOutputPlaneX()->GetResliceOutput()->GetWholeExtent(ext);
283 dim[0] = ext[1]-ext[0]+1;
284 dim[1] = ext[3]-ext[2]+1;
285 dim[2] = ext[5]-ext[4]+1;
286 _imageTransform->Identity();
287 _imageTransform->PostMultiply();
288 _imageTransform->Translate( (int)(-(dim[0]/2)) , (int)(-(dim[1]/2)) ,0);
289 _imageTransform->RotateZ(90);
292 if ( image != bbGetInputIn()){//bbGetInputStatus("In") != bbtk::UPTODATE ){
293 // Input image has changed : reinitialize planes
294 image = bbGetInputIn();
296 // Initial values : center of the volume (in real world, not in pixels!)
297 int xMin, xMax, yMin, yMax, zMin, zMax;
298 bbGetInputIn()->GetExtent(xMin, xMax, yMin, yMax, zMin, zMax);
299 double xSpacing, ySpacing, zSpacing;
300 bbGetInputIn()->GetSpacing(xSpacing, ySpacing, zSpacing);
302 bbGetOutputPlaneX()->SetInput(bbGetInputIn());
303 bbGetOutputPlaneX()->SetPlaneOrientationToXAxes();
304 bbGetOutputPlaneX()->SetSlicePosition((xMax+xMin)/2.*xSpacing);
306 // bbGetOutputPlaneX()->SetOrigin( 58*xSpacing , 80*ySpacing , 82*zSpacing );
307 // bbGetOutputPlaneX()->SetPoint1( 0*xSpacing, 146*ySpacing, 186*zSpacing);
308 // bbGetOutputPlaneX()->SetPoint2( 126*xSpacing, 146*ySpacing, 0*zSpacing);
310 bbGetOutputPlaneY()->SetInput(bbGetInputIn());
311 bbGetOutputPlaneY()->SetPlaneOrientationToYAxes();
312 bbGetOutputPlaneY()->SetSlicePosition((yMax+yMin)/2.*ySpacing);
314 bbGetOutputPlaneZ()->SetInput(bbGetInputIn());
315 bbGetOutputPlaneZ()->SetPlaneOrientationToZAxes();
316 bbGetOutputPlaneZ()->SetSlicePosition((zMax+zMin)/2.*zSpacing);
318 if (bbGetInputWindowLevel()[0]!=0)
320 bbGetOutputPlaneZ()->SetWindowLevel(bbGetInputWindowLevel()[0],
321 bbGetInputWindowLevel()[1]);
323 double *range = image->GetScalarRange();
324 bbGetOutputPlaneZ()->SetWindowLevel(range[1]-range[0],
325 0.5*(range[1]+range[0]));
329 dim[0] = xMax-xMin+1;
330 dim[1] = yMax-yMin+1;
331 dim[2] = zMax-zMin+1;
332 _imageTransform->Identity();
333 _imageTransform->PostMultiply();
334 _imageTransform->Translate( (int)(-(dim[0]/2)*(1/xSpacing)) , (int)(-(dim[2]/2)*(1/zSpacing)) ,0);
335 _imageTransform->RotateZ(90);
339 // UPDATE DES SORTIES
340 bbGetOutputPlaneX()->SetResliceInterpolate( bbGetInputInterpolation() );
341 bbGetOutputPlaneY()->SetResliceInterpolate( bbGetInputInterpolation() );
342 bbGetOutputPlaneZ()->SetResliceInterpolate( bbGetInputInterpolation() );
345 bbGetOutputPlaneX()->GetResliceOutput()->Update();
346 bbGetOutputPlaneY()->GetResliceOutput()->Update();
347 bbGetOutputPlaneZ()->GetResliceOutput()->Update();
349 std::vector<int> pointsx = bbGetInputPointsX();
350 std::vector<int> pointsy = bbGetInputPointsY();
351 std::vector<int> pointsz = bbGetInputPointsZ();
353 //std::cout<<pointsx.size()<<pointsy.size()<<pointsz.size()<<std::endl;
355 if (pointsx.size()==pointsy.size() && pointsx.size()==pointsz.size()&&pointsx.size()>=3)
358 //Get the corresponding three points out of the vectors
360 origin[0] = pointsx[0];
361 origin[1] = pointsy[0];
362 origin[2] = pointsz[0];
365 point1[0] = pointsx[1];
366 point1[1] = pointsy[1];
367 point1[2] = pointsz[1];
369 point2[0]= pointsx[2];
370 point2[1]= pointsy[2];
371 point2[2]= pointsz[2];
373 //With the three points we create the corresponding X, Y and Z vectors all orthogonal to each other
374 double* vect1= getNormal(makeVector(origin, point1));
375 double* vect2= getNormal(makeVector(origin, point2));
376 double* crossp = getCrossProduct(vect1, vect2);
378 double *newx = getCrossProduct(vect2, crossp);
381 bbGetInputIn()->GetExtent(ext);
383 factor = ext[0]<ext[3]? ext[3] : ext[0];
384 factor = factor<ext[5]? ext[5] : factor;
386 //for the plane widgets
387 vtkImagePlaneWidget* plane3pts = (vtkImagePlaneWidget*)bbGetOutputPlane3Pts();
388 plane3pts->SetInput(bbGetInputIn());
389 double xSpacing, ySpacing, zSpacing;
390 bbGetInputIn()->GetSpacing(xSpacing, ySpacing, zSpacing);
391 plane3pts->SetOrigin(pointsx[0]*xSpacing,pointsy[0]*ySpacing,pointsz[0]*zSpacing);
392 plane3pts->SetPoint1((origin[0]+newx[0]*factor)*xSpacing,
393 (origin[1]+newx[1]*factor)*ySpacing,
394 (origin[2]+newx[2]*factor)*zSpacing);
395 plane3pts->SetPoint2((origin[0]+vect2[0]*factor)*xSpacing,
396 (origin[1]+vect2[1]*factor)*ySpacing,
397 (origin[2]+vect2[2]*factor)*zSpacing);
398 plane3pts->GetResliceOutput()->Update();
399 //To get the slice of image out of the selected volume
400 if (_imageReslicer==NULL){
401 _imageReslicer = vtkImageReslice::New();
402 _imageReslicer->SetOutputDimensionality(2);
403 _transform = vtkTransform::New();
404 _matrix = vtkMatrix4x4::New();
406 _imageReslicer->SetInterpolationMode( bbGetInputInterpolation() );
407 _imageReslicer->SetInput( bbGetInputIn() );
408 _imageReslicer->SetInformationInput(bbGetInputIn());
409 //fill out the information with the created vectors and using the spacing of the image
410 _imageReslicer->SetResliceAxesDirectionCosines(newx[0]*xSpacing,newx[1]*xSpacing,newx[2]*xSpacing,
411 vect2[0]*ySpacing,vect2[1]*ySpacing,vect2[2]*ySpacing,
412 crossp[0]*zSpacing,crossp[1]*zSpacing,crossp[2]*zSpacing);
413 _imageReslicer->SetResliceAxesOrigin(origin[0]*xSpacing,origin[1]*ySpacing,origin[2]*zSpacing);
414 _imageReslicer->GetOutput()->Update();
415 _imageReslicer->GetOutput()->UpdateInformation();
417 bbSetOutputImage3Pts(_imageReslicer->GetOutput());
421 _matrix->SetElement(0,0,newx[0]*xSpacing);
422 _matrix->SetElement(1,0,newx[1]*xSpacing);
423 _matrix->SetElement(2,0,newx[2]*xSpacing);
424 _matrix->SetElement(0,1,vect2[0]*ySpacing);
425 _matrix->SetElement(1,1,vect2[1]*ySpacing);
426 _matrix->SetElement(2,1,vect2[2]*ySpacing);
427 _matrix->SetElement(0,2,crossp[0]*zSpacing);
428 _matrix->SetElement(1,2,crossp[1]*zSpacing);
429 _matrix->SetElement(2,2,crossp[2]*zSpacing);
430 _matrix->SetElement(0,3,origin[0]*xSpacing);
431 _matrix->SetElement(1,3,origin[1]*ySpacing);
432 _matrix->SetElement(2,3,origin[2]*zSpacing);
434 _transform->SetMatrix(_matrix);
436 //set the transformation out to be used by other bbBoxes
437 bbSetOutputTransform3Pts((vtkLinearTransform*)_transform);
438 } // pointsx pointsy pointsz
442 void ImagePlanes::updateInteractor(){
444 vtkRenderWindowInteractor* interactor = bbGetInputInteractor();
447 bbGetOutputPlaneX()->SetInteractor(interactor);
448 bbGetOutputPlaneX()->EnabledOn();
449 bbGetOutputPlaneY()->SetInteractor(interactor);
450 bbGetOutputPlaneY()->EnabledOn();
451 bbGetOutputPlaneZ()->SetInteractor(interactor);
452 bbGetOutputPlaneZ()->EnabledOn();
453 bbGetOutputPlane3Pts()->SetInteractor(interactor);
454 bbGetOutputPlane3Pts()->EnabledOn();
457 //-----------------------------------------------------------------
458 void vtkImageDataPointerRelay::bbUserSetDefaultValues()
463 //-----------------------------------------------------------------
464 void vtkImageDataPointerRelay::bbUserInitializeProcessing()
468 //-----------------------------------------------------------------
469 void vtkImageDataPointerRelay::bbUserFinalizeProcessing()
473 vtkImagePlaneWidget* ImagePlanes::GetPlaneWidget(unsigned char activationkey, double r, double g, double b, vtkCellPicker* picker)
475 vtkProperty* prop1 = 0;
476 vtkImagePlaneWidget* planeWidget = 0;
478 planeWidget = vtkImagePlaneWidget::New();
479 planeWidget->DisplayTextOn();
480 planeWidget->SetPicker(picker);
481 planeWidget->SetKeyPressActivationValue(activationkey);
482 prop1 = planeWidget->GetPlaneProperty();
483 prop1->SetColor(r, g, b);
488 double* ImagePlanes::getCrossProduct(double* vect0,double* vect1){
490 vectCross = new double[3];
491 vectCross[0] = vect0[1]*vect1[2]-(vect0[2]*vect1[1]);
492 vectCross[1] = -(vect0[0]*vect1[2]-(vect0[2]*vect1[0]));
493 vectCross[2] = vect0[0]*vect1[1]-(vect0[1]*vect1[0]);
498 ** Returns the magnitud of the given vector
500 double ImagePlanes::getMagnitud(double* vect){
503 mag = sqrt(pow(vect[0],2) + pow(vect[1],2) + pow(vect[2],2));
504 //std::cout<<"mag "<<mag <<std::endl;
508 ** returns the unitary vector of the given vector
509 ** u = 1/|vect| . vect
511 double* ImagePlanes::getNormal(double* vect){
514 double mag = getMagnitud(vect);
516 vectnorm = new double[3];
519 vectnorm[0] = vect[0]/mag;
520 vectnorm[1] = vect[1]/mag;
521 vectnorm[2] = vect[2]/mag;
531 double* ImagePlanes::makeVector(double podouble0[3], double podouble1[3]){
533 vect = new double[3];
535 vect[0]= podouble1[0]-podouble0[0];
536 vect[1]= podouble1[1]-podouble0[1];
537 vect[2]= podouble1[2]-podouble0[2];