/* # --------------------------------------------------------------------- # # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image # pour la SantÈ) # Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton # Previous Authors : Laurent Guigues, Jean-Pierre Roux # CreaTools website : www.creatis.insa-lyon.fr/site/fr/creatools_accueil # # This software is governed by the CeCILL-B license under French law and # abiding by the rules of distribution of free software. You can use, # modify and/ or redistribute the software under the terms of the CeCILL-B # license as circulated by CEA, CNRS and INRIA at the following URL # http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html # or in the file LICENSE.txt. # # As a counterpart to the access to the source code and rights to copy, # modify and redistribute granted by the license, users are provided only # with a limited warranty and the software's author, the holder of the # economic rights, and the successive licensors have only limited # liability. # # The fact that you are presently reading this means that you have had # knowledge of the CeCILL-B license and that you accept its terms. # ------------------------------------------------------------------------ */ /*========================================================================= Program: bbtk Module: $RCSfile: bbvtkImagePlanes.cxx,v $ Language: C++ Date: $Date: 2012/11/16 08:51:58 $ Version: $Revision: 1.38 $ =========================================================================*/ /** * \file * \brief */ #ifdef _USE_VTK_ #include "bbvtkImagePlanes.h" #include "bbvtkPackage.h" #include "vtkCellPicker.h" #include "vtkProperty.h" #include "vtkPolyData.h" #include "vtkMetaImageWriter.h" #include "vtkPNGWriter.h" #include "bbstdCast.h" #include #include "vtkImageData.h" //#include "vtkOutlineFilter.h" //#include "vtkPolyDataMapper.h" //#include "vtkActor.h" #include "vtkImagePlaneWidget.h" #include "vtkCellPicker.h" //#include "vtkProperty.h" //#include "vtkRenderer.h" //#include "vtkCamera.h" #include "vtkPlaneWidget.h" #include #include "bbstdRelay.h" #include "vtkObjectFactory.h" #include "vtkImageFlip.h" #include "vtkImageReslice.h" #include "vtkImageChangeInformation.h" namespace bbstd { //==================================================================== BBTK_BLACK_BOX_TEMPLATE2_IMPLEMENTATION(Cast, bbtk::AtomicBlackBox); //==================================================================== //==================================================================== // BBTK_BLACK_BOX_TEMPLATE_IMPLEMENTATION(Relay, // bbtk::AtomicBlackBox); //==================================================================== } using namespace bbstd; /* namespace bbtk { typedef vtkImageData::Pointer vtkImageDataPointer; BBTK_DEFINE_HUMAN_READABLE_TYPE_NAME(vtkImageDataPointer, "vtkImageDataPointer"); } */ namespace bbvtk { //==================================================================== // Add the specialized adaptors to the package typedef vtkImagePlaneWidget* I; typedef vtkInteractorObserver* O; BBTK_ADD_TEMPLATE2_BLACK_BOX_TO_PACKAGE(vtk,Cast,I,O); BBTK_DEFINE_RELAY_BLACK_BOX(vtkImageDataPointer,vtk,vtkImageDataPointerRelay); BBTK_BLACK_BOX_IMPLEMENTATION(vtkImageDataPointerRelay,bbtk::AtomicBlackBox); BBTK_ADD_BLACK_BOX_TO_PACKAGE(vtk,vtkImageDataPointerRelay); // BBTK_ADD_TEMPLATE_BLACK_BOX_TO_PACKAGE(vtk,Relay,vtkImageDataPointer); //Pointer); } namespace bbvtk { //================================================================ class ImagePlanes::VtkCallbackType : public vtkCommand { public: static VtkCallbackType *New() { return new VtkCallbackType; } //vtkTypeRevisionMacro(VtkCallbackType,vtkCommand); virtual void Execute(vtkObject *caller, unsigned long, void*) { mBlackBox->Process(); mBlackBox->bbSignalOutputModification(); } void SetBlackBox(ImagePlanes *BB) { mBlackBox = BB;}; // void SetVtkPlaneWidget( vtkImagePlaneWidget *planeWidget ); VtkCallbackType() {}; private: // vtkPlaneWidget *planeWidget; ImagePlanes *mBlackBox; }; //================================================================ //vtkCxxRevisionMacro(ImagePlanes::VtkCallbackType, "$Revision: 1.38 $"); //================================================================ BBTK_ADD_BLACK_BOX_TO_PACKAGE(vtk,ImagePlanes) BBTK_BLACK_BOX_IMPLEMENTATION(ImagePlanes,bbtk::AtomicBlackBox); void ImagePlanes::bbUserSetDefaultValues() { bbSetOutputPlaneX(NULL); bbSetOutputPlaneY(NULL); bbSetOutputPlaneZ(NULL); bbSetOutputImageX(NULL); bbSetOutputImageY(NULL); bbSetOutputImageZ(NULL); bbSetInputIn(NULL); std::vector vect; vect.push_back(0); vect.push_back(0); bbSetInputWindowLevel (vect); mVtkCallback = 0; std::vector vectpoints; bbSetOutputPlane3Pts(0); bbSetOutputImage3Pts(0); bbSetInputPointsX(vectpoints); bbSetInputPointsY(vectpoints); bbSetInputPointsZ(vectpoints); _imageReslicer = NULL; image = NULL; _transform = NULL; _matrix = NULL; bbSetInputInterpolation(1); } void ImagePlanes::bbUserInitializeProcessing() { /// CREATION DES WIDGETS if (bbGetOutputPlaneX() != 0) return; // The shared picker enables us to use 3 planes at one time // and gets the picking order right vtkCellPicker* picker = vtkCellPicker::New(); picker->SetTolerance(0.005); // The 3 image plane widgets vtkImagePlaneWidget* planeWidgetX = GetPlaneWidget('x', 1, 0, 0, picker); vtkImagePlaneWidget* planeWidgetY = GetPlaneWidget('y', 1, 1, 0, picker); planeWidgetY->SetLookupTable(planeWidgetX->GetLookupTable()); vtkImagePlaneWidget* planeWidgetZ = GetPlaneWidget('z', 0, 0, 1, picker); planeWidgetZ->SetLookupTable(planeWidgetX->GetLookupTable()); vtkImagePlaneWidget* planeWidget3Pts = GetPlaneWidget('3', 0, 1, 1, picker); planeWidget3Pts->SetLookupTable(planeWidgetX->GetLookupTable()); // EED MPR view orientation correction.. vtkImageFlip *flipYFilter = vtkImageFlip::New(); flipYFilter->SetFilteredAxis(1); // flip y axis flipYFilter->SetInput( planeWidgetX->GetResliceOutput() ); flipYFilter->Update(); vtkImageChangeInformation *image = vtkImageChangeInformation::New(); image->SetInput( planeWidgetY->GetResliceOutput() ); image->SetOutputSpacing( 1,1,1 ); image->CenterImageOn(); image->Update(); _imageTransform = vtkTransform::New(); vtkImageReslice *slicer =vtkImageReslice::New(); slicer->SetInput( image->GetOutput() ); slicer->SetInformationInput( image->GetOutput() ); slicer->SetResliceTransform( _imageTransform ); slicer->SetOutputOrigin(0 , 0 , 0 ); slicer->SetInterpolationModeToNearestNeighbor(); slicer->Update(); vtkImageChangeInformation *imageResult = vtkImageChangeInformation::New(); imageResult->SetInput( slicer->GetOutput() ); double spc[3]; planeWidgetY->GetResliceOutput()->GetSpacing(spc); imageResult->SetOutputSpacing( spc[1], spc[0], spc[2] ); imageResult->SetOutputOrigin( 0,0,0 ); bbSetOutputPlaneX(planeWidgetX); bbSetOutputPlaneY(planeWidgetY); bbSetOutputPlaneZ(planeWidgetZ); bbSetOutputPlane3Pts(planeWidget3Pts); bbSetOutputImageX( flipYFilter->GetOutput() ); // EED MPR view orientation correction.. bbSetOutputImageY( imageResult->GetOutput() ); // EED MPR view orientation correction.. bbSetOutputImageZ(planeWidgetZ->GetResliceOutput()); bbSetInputInteractor(0); //bbSetOutputImage3Pts(planeWidget3Pts->GetResliceOutput()); if(picker != 0) { picker->UnRegister(NULL); } mVtkCallback = VtkCallbackType::New(); mVtkCallback->SetBlackBox(this); planeWidgetX->AddObserver(vtkCommand::InteractionEvent,mVtkCallback); planeWidgetY->AddObserver(vtkCommand::InteractionEvent,mVtkCallback); planeWidgetZ->AddObserver(vtkCommand::InteractionEvent,mVtkCallback); } //--------------------------------------------------------------------- void ImagePlanes::bbUserFinalizeProcessing() { if (bbGetOutputPlaneX()) { /* bbGetOutputPlaneX()->RemoveObserver(mVtkCallback); bbGetOutputPlaneY()->RemoveObserver(mVtkCallback); bbGetOutputPlaneZ()->RemoveObserver(mVtkCallback); bbGetOutputPlaneX()->Delete(); bbGetOutputPlaneY()->Delete(); bbGetOutputPlaneZ()->Delete(); mVtkCallback->Delete(); */ //bbGetOutputPlaneX()->SetInput(NULL); //bbGetOutputPlaneY()->SetInput(NULL); //bbGetOutputPlaneZ()->SetInput(NULL); } } //--------------------------------------------------------------------- void ImagePlanes::Process() { if (bbGetInputIn()!=0) { int dim[3]; int ext[6]; bbGetOutputPlaneX()->GetResliceOutput()->GetWholeExtent(ext); dim[0] = ext[1]-ext[0]+1; dim[1] = ext[3]-ext[2]+1; dim[2] = ext[5]-ext[4]+1; _imageTransform->Identity(); _imageTransform->PostMultiply(); _imageTransform->Translate( (int)(-(dim[0]/2)) , (int)(-(dim[1]/2)) ,0); _imageTransform->RotateZ(90); if ( image != bbGetInputIn()){//bbGetInputStatus("In") != bbtk::UPTODATE ){ // Input image has changed : reinitialize planes image = bbGetInputIn(); // Initial values : center of the volume (in real world, not in pixels!) int xMin, xMax, yMin, yMax, zMin, zMax; bbGetInputIn()->GetExtent(xMin, xMax, yMin, yMax, zMin, zMax); double xSpacing, ySpacing, zSpacing; bbGetInputIn()->GetSpacing(xSpacing, ySpacing, zSpacing); bbGetOutputPlaneX()->SetInput(bbGetInputIn()); bbGetOutputPlaneX()->SetPlaneOrientationToXAxes(); bbGetOutputPlaneX()->SetSlicePosition((xMax+xMin)/2.*xSpacing); // bbGetOutputPlaneX()->SetOrigin( 58*xSpacing , 80*ySpacing , 82*zSpacing ); // bbGetOutputPlaneX()->SetPoint1( 0*xSpacing, 146*ySpacing, 186*zSpacing); // bbGetOutputPlaneX()->SetPoint2( 126*xSpacing, 146*ySpacing, 0*zSpacing); bbGetOutputPlaneY()->SetInput(bbGetInputIn()); bbGetOutputPlaneY()->SetPlaneOrientationToYAxes(); bbGetOutputPlaneY()->SetSlicePosition((yMax+yMin)/2.*ySpacing); bbGetOutputPlaneZ()->SetInput(bbGetInputIn()); bbGetOutputPlaneZ()->SetPlaneOrientationToZAxes(); bbGetOutputPlaneZ()->SetSlicePosition((zMax+zMin)/2.*zSpacing); if (bbGetInputWindowLevel()[0]!=0) { bbGetOutputPlaneZ()->SetWindowLevel(bbGetInputWindowLevel()[0], bbGetInputWindowLevel()[1]); } else { double *range = image->GetScalarRange(); bbGetOutputPlaneZ()->SetWindowLevel(range[1]-range[0], 0.5*(range[1]+range[0])); } // windowlevel updateInteractor(); dim[0] = xMax-xMin+1; dim[1] = yMax-yMin+1; dim[2] = zMax-zMin+1; _imageTransform->Identity(); _imageTransform->PostMultiply(); _imageTransform->Translate( (int)(-(dim[0]/2)*(1/xSpacing)) , (int)(-(dim[2]/2)*(1/zSpacing)) ,0); _imageTransform->RotateZ(90); } // image // UPDATE DES SORTIES bbGetOutputPlaneX()->SetResliceInterpolate( bbGetInputInterpolation() ); bbGetOutputPlaneY()->SetResliceInterpolate( bbGetInputInterpolation() ); bbGetOutputPlaneZ()->SetResliceInterpolate( bbGetInputInterpolation() ); bbGetOutputPlaneX()->GetResliceOutput()->Update(); bbGetOutputPlaneY()->GetResliceOutput()->Update(); bbGetOutputPlaneZ()->GetResliceOutput()->Update(); std::vector pointsx = bbGetInputPointsX(); std::vector pointsy = bbGetInputPointsY(); std::vector pointsz = bbGetInputPointsZ(); //std::cout<=3) { //Get the corresponding three points out of the vectors double origin[3]; origin[0] = pointsx[0]; origin[1] = pointsy[0]; origin[2] = pointsz[0]; double point1[3]; point1[0] = pointsx[1]; point1[1] = pointsy[1]; point1[2] = pointsz[1]; double point2[3]; point2[0] = pointsx[2]; point2[1] = pointsy[2]; point2[2] = pointsz[2]; //With the three points we create the corresponding X, Y and Z vectors all orthogonal to each other double* vect1 = getNormal(makeVector(origin, point1)); double* vect2 = getNormal(makeVector(origin, point2)); double* crossp = getCrossProduct(vect1, vect2); double *newx = getCrossProduct(vect2, crossp); int ext[6],factor = 0; bbGetInputIn()->GetExtent(ext); factor = ext[0]SetInput(bbGetInputIn()); double xSpacing, ySpacing, zSpacing; bbGetInputIn()->GetSpacing(xSpacing, ySpacing, zSpacing); plane3pts->SetOrigin(pointsx[0]*xSpacing,pointsy[0]*ySpacing,pointsz[0]*zSpacing); plane3pts->SetPoint1((origin[0]+newx[0]*factor)*xSpacing, (origin[1]+newx[1]*factor)*ySpacing, (origin[2]+newx[2]*factor)*zSpacing); plane3pts->SetPoint2((origin[0]+vect2[0]*factor)*xSpacing, (origin[1]+vect2[1]*factor)*ySpacing, (origin[2]+vect2[2]*factor)*zSpacing); plane3pts->GetResliceOutput()->Update(); //To get the slice of image out of the selected volume if (_imageReslicer==NULL) { _imageReslicer = vtkImageReslice::New(); _imageReslicer->SetOutputDimensionality(2); _transform = vtkTransform::New(); _matrix = vtkMatrix4x4::New(); } // if _imageReslicer->SetInterpolationMode( bbGetInputInterpolation() ); _imageReslicer->SetInput( bbGetInputIn() ); _imageReslicer->SetInformationInput(bbGetInputIn()); //fill out the information with the created vectors and using the spacing of the image _imageReslicer->SetResliceAxesDirectionCosines(newx[0]*xSpacing,newx[1]*xSpacing,newx[2]*xSpacing, vect2[0]*ySpacing,vect2[1]*ySpacing,vect2[2]*ySpacing, crossp[0]*zSpacing,crossp[1]*zSpacing,crossp[2]*zSpacing); _imageReslicer->SetResliceAxesOrigin(origin[0]*xSpacing,origin[1]*ySpacing,origin[2]*zSpacing); _imageReslicer->GetOutput()->Update(); _imageReslicer->GetOutput()->UpdateInformation(); bbSetOutputImage3Pts(_imageReslicer->GetOutput()); _matrix->Identity(); _matrix->SetElement(0,0,newx[0]*xSpacing); _matrix->SetElement(1,0,newx[1]*xSpacing); _matrix->SetElement(2,0,newx[2]*xSpacing); _matrix->SetElement(0,1,vect2[0]*ySpacing); _matrix->SetElement(1,1,vect2[1]*ySpacing); _matrix->SetElement(2,1,vect2[2]*ySpacing); _matrix->SetElement(0,2,crossp[0]*zSpacing); _matrix->SetElement(1,2,crossp[1]*zSpacing); _matrix->SetElement(2,2,crossp[2]*zSpacing); _matrix->SetElement(0,3,origin[0]*xSpacing); _matrix->SetElement(1,3,origin[1]*ySpacing); _matrix->SetElement(2,3,origin[2]*zSpacing); _transform->SetMatrix(_matrix); //set the transformation out to be used by other bbBoxes bbSetOutputTransform3Pts((vtkLinearTransform*)_transform); } // pointsx pointsy pointsz } // bbGetInputIn } void ImagePlanes::updateInteractor() { vtkRenderWindowInteractor* interactor = bbGetInputInteractor(); if(interactor) { bbGetOutputPlaneX()->SetInteractor(interactor); bbGetOutputPlaneX()->EnabledOn(); bbGetOutputPlaneY()->SetInteractor(interactor); bbGetOutputPlaneY()->EnabledOn(); bbGetOutputPlaneZ()->SetInteractor(interactor); bbGetOutputPlaneZ()->EnabledOn(); bbGetOutputPlane3Pts()->SetInteractor(interactor); bbGetOutputPlane3Pts()->EnabledOn(); } // if } //----------------------------------------------------------------- void vtkImageDataPointerRelay::bbUserSetDefaultValues() { } //----------------------------------------------------------------- void vtkImageDataPointerRelay::bbUserInitializeProcessing() { } //----------------------------------------------------------------- void vtkImageDataPointerRelay::bbUserFinalizeProcessing() { } vtkImagePlaneWidget* ImagePlanes::GetPlaneWidget(unsigned char activationkey, double r, double g, double b, vtkCellPicker* picker) { vtkProperty* prop1 = 0; vtkImagePlaneWidget* planeWidget = 0; planeWidget = vtkImagePlaneWidget::New(); planeWidget->DisplayTextOn(); planeWidget->SetPicker(picker); planeWidget->SetKeyPressActivationValue(activationkey); prop1 = planeWidget->GetPlaneProperty(); prop1->SetColor(r, g, b); return planeWidget; } double* ImagePlanes::getCrossProduct(double* vect0,double* vect1){ double* vectCross; vectCross = new double[3]; vectCross[0] = vect0[1]*vect1[2]-(vect0[2]*vect1[1]); vectCross[1] = -(vect0[0]*vect1[2]-(vect0[2]*vect1[0])); vectCross[2] = vect0[0]*vect1[1]-(vect0[1]*vect1[0]); return vectCross; } /** ** Returns the magnitud of the given vector **/ double ImagePlanes::getMagnitud(double* vect){ double mag; mag = sqrt(pow(vect[0],2) + pow(vect[1],2) + pow(vect[2],2)); //std::cout<<"mag "<