/*========================================================================= Program: vv http://www.creatis.insa-lyon.fr/rio/vv Authors belong to: - University of LYON http://www.universite-lyon.fr/ - Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the copyright notices for more information. It is distributed under dual licence - BSD See included LICENSE.txt file - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html ======================================================================-====*/ #include "vvSlicer.h" #include "vvImage.h" #include "vvSlicerManagerCommand.h" #include "vvGlyphSource.h" #include "vvGlyph2D.h" #include "vvImageMapToWLColors.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include vtkCxxRevisionMacro(vvSlicer, "DummyRevision"); vtkStandardNewMacro(vvSlicer); //------------------------------------------------------------------------------ vvSlicer::vvSlicer() { this->UnInstallPipeline(); mImage = NULL; mCurrentTSlice = 0; mUseReducedExtent = false; mCurrent[0] = -VTK_DOUBLE_MAX; mCurrent[1] = -VTK_DOUBLE_MAX; mCurrent[2] = -VTK_DOUBLE_MAX; mCursor[0] = -VTK_DOUBLE_MAX; mCursor[1] = -VTK_DOUBLE_MAX; mCursor[2] = -VTK_DOUBLE_MAX; mCursor[3] = -VTK_DOUBLE_MAX; mSubSampling = 5; mScale = 1; mVFLog = 0; mVFWidth = 1; mVFColor[0] = 0; mVFColor[1] = 1; mVFColor[2] = 0; std::string text = "F1 = sagital; F2 = coronal; F3 = axial\n"; text += "F5 = horizontal flip; F6 = vertical flip\n\n"; text += "0,1,2,3,4,5 : preset windowing\n"; text += "6,7,8,9 : preset colormap\n"; text += "z : local windowing\n"; text += "r : reset view\n"; text += "l : reload image\n"; text += "f : fly to mouse position\n"; text += "g : go to cross hair position\n\n"; text += "Up,down : change slice\n"; text += "Left,right : change tenporal slice\n\n"; text += "Scrollbar (or w/x) : zoom in/out\n"; text += "left button : synchronize all views\n"; text += "middle button : grab image\n"; text += "right button : change windowing\n"; crossCursor = vtkSmartPointer::New(); crossCursor->AllOff(); crossCursor->AxesOn(); crossCursor->SetTranslationMode(1); crossCursor->SetRadius(2); pdm = vtkSmartPointer::New(); pdm->SetInput(crossCursor->GetOutput()); pdmA = vtkSmartPointer::New(); pdmA->SetMapper(pdm); pdmA->GetProperty()->SetColor(255,10,212); pdmA->SetVisibility(0); pdmA->SetPickable(0); ca = vtkSmartPointer::New(); ca->GetTextProperty()->SetColor(255,10,212); ca->SetVisibility(1); mFileName = ""; mVF = NULL; mOverlay = NULL; mFusion = NULL; mLandmarks = NULL; legend = vtkSmartPointer::New(); //legend->SetTitle("test!"); legend->SetPosition(0.82,0.18); legend->SetWidth(0.1); legend->SetVisibility(0); legend->SetLabelFormat("%.1f"); this->GetRenderer()->AddActor(legend); this->WindowLevel->Delete(); this->WindowLevel = vvImageMapToWLColors::New(); this->InstallPipeline(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ vtkImageMapToWindowLevelColors* vvSlicer::GetOverlayMapper() { return mOverlayMapper.GetPointer(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ vvBlendImageActor* vvSlicer::GetOverlayActor() { return mOverlayActor.GetPointer(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ vtkImageMapToWindowLevelColors* vvSlicer::GetFusionMapper() { return mFusionMapper.GetPointer(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ vtkImageActor* vvSlicer::GetFusionActor() { return mFusionActor.GetPointer(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ vtkActor* vvSlicer::GetVFActor() { return mVFActor.GetPointer(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ vtkCornerAnnotation* vvSlicer::GetAnnotation() { return ca.GetPointer(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::EnableReducedExtent(bool b) { mUseReducedExtent = b; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetReducedExtent(int * ext) { mReducedExtent = ext; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::AddContour(vvMesh::Pointer contour,bool propagate) { mSurfaceCutActors.push_back(new vvMeshActor()); if (propagate) mSurfaceCutActors.back()->Init(contour,mCurrentTSlice,mVF); else mSurfaceCutActors.back()->Init(contour,mCurrentTSlice); mSurfaceCutActors.back()->SetSlicingOrientation(SliceOrientation); this->GetRenderer()->AddActor(mSurfaceCutActors.back()->GetActor()); SetContourSlice(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::ToggleContourSuperposition() { for (std::vector::iterator i=mSurfaceCutActors.begin(); i!=mSurfaceCutActors.end(); i++) (*i)->ToggleSuperposition(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetCursorColor(int r,int g, int b) { pdmA->GetProperty()->SetColor(r,g,b); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetCursorVisibility(bool s) { pdmA->SetVisibility(s); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ bool vvSlicer::GetCursorVisibility() { return pdmA->GetVisibility(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetCornerAnnotationVisibility(bool s) { ca->SetVisibility(s); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ bool vvSlicer::GetCornerAnnotationVisibility() { return ca->GetVisibility(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ vvSlicer::~vvSlicer() { for (std::vector::iterator i=mSurfaceCutActors.begin(); i!=mSurfaceCutActors.end(); i++) delete (*i); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetCurrentPosition(double x, double y, double z, int t) { mCurrent[0] = x; mCurrent[1] = y; mCurrent[2] = z; mCurrentTSlice = t; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetImage(vvImage::Pointer image) { if (image->GetVTKImages().size()) { mImage = image; this->Superclass::SetInput(image->GetTransformedVTKImages()[0]); int extent[6]; this->GetInput()->GetWholeExtent(extent); // Prevent crash when reload -> change slice if outside extent if (Slice < extent[SliceOrientation*2] || Slice>=extent[SliceOrientation*2+1]) { Slice = (extent[SliceOrientation*2+1]-extent[SliceOrientation*2])/2.0; } // Make sure that the required part image has been computed extent[SliceOrientation*2] = Slice; extent[SliceOrientation*2+1] = Slice; image->GetTransformedVTKImages()[0]->SetUpdateExtent(extent); image->GetTransformedVTKImages()[0]->Update(); this->UpdateDisplayExtent(); mCurrentTSlice = 0; ca->SetText(0,mFileName.c_str()); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetOverlay(vvImage::Pointer overlay) { if (overlay->GetVTKImages().size()) { mOverlay = overlay; if (!mOverlayMapper) mOverlayMapper = vtkSmartPointer::New(); mOverlayMapper->SetInput(overlay->GetTransformedVTKImages()[0]); if (!mOverlayActor) { mOverlayActor = vtkSmartPointer::New(); mOverlayActor->SetInput(mOverlayMapper->GetOutput()); mOverlayActor->SetPickable(0); mOverlayActor->SetVisibility(false); mOverlayActor->SetOpacity(0.5); this->UpdateDisplayExtent(); } //stupid but necessary : the Overlay need to be rendered before fusion if (mFusionActor) { this->GetRenderer()->RemoveActor(mFusionActor); this->GetRenderer()->AddActor(mOverlayActor); this->GetRenderer()->AddActor(mFusionActor); } else this->GetRenderer()->AddActor(mOverlayActor); //Synchronize slice SetTSlice(mCurrentTSlice); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetFusion(vvImage::Pointer fusion) { if (fusion->GetVTKImages().size()) { mFusion = fusion; if (!mFusionMapper) mFusionMapper = vtkSmartPointer::New(); mFusionMapper->SetInput(fusion->GetTransformedVTKImages()[0]); if (!mFusionActor) { mFusionActor = vtkSmartPointer::New(); mFusionActor->SetInput(mFusionMapper->GetOutput()); mFusionActor->SetPickable(0); mFusionActor->SetVisibility(false); mFusionActor->SetOpacity(0.7); this->UpdateDisplayExtent(); this->GetRenderer()->AddActor(mFusionActor); } //Synchronize slice SetTSlice(mCurrentTSlice); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetActorVisibility(const std::string& actor_type, int overlay_index ,bool vis) { if (actor_type == "vector") { this->mVFActor->SetVisibility(vis); } if (actor_type == "overlay") { this->mOverlayActor->SetVisibility(vis); } if (actor_type == "fusion") { this->mFusionActor->SetVisibility(vis); } if (actor_type == "contour") this->mSurfaceCutActors[overlay_index]->GetActor()->SetVisibility(vis); UpdateDisplayExtent(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetVF(vvImage::Pointer vf) { if (vf->GetVTKImages().size()) { mVF = vf; if (!mAAFilter) { mAAFilter= vtkSmartPointer::New(); mVOIFilter = vtkSmartPointer::New(); mVOIFilter->SetSampleRate(mSubSampling,mSubSampling,mSubSampling); } mVOIFilter->SetInput(vf->GetTransformedVTKImages()[0]); mAAFilter->SetInput(mVOIFilter->GetOutput()); ///This tells VTK to use the scalar (pixel) data of the image to draw the little arrows mAAFilter->Assign(vtkDataSetAttributes::SCALARS, vtkDataSetAttributes::VECTORS, vtkAssignAttribute::POINT_DATA); if (!mArrow) mArrow = vtkSmartPointer::New(); mArrow->SetGlyphTypeToSpecificArrow(); mArrow->SetScale(mScale); mArrow->FilledOff(); // Glyph the gradient vector (with arrows) if (!mGlyphFilter) mGlyphFilter = vtkSmartPointer::New(); mGlyphFilter->SetInput(mAAFilter->GetOutput()); mGlyphFilter->SetSource(mArrow->GetOutput()); mGlyphFilter->ScalingOn(); mGlyphFilter->SetScaleModeToScaleByVector(); mGlyphFilter->OrientOn(); mGlyphFilter->SetVectorModeToUseVector(); mGlyphFilter->SetColorModeToColorByVector(); if (!mVFColorLUT) mVFColorLUT = vtkSmartPointer::New(); double mVFColorHSV[3]; vtkMath::RGBToHSV(mVFColor, mVFColorHSV); mVFColorLUT->SetHueRange(mVFColorHSV[0], mVFColorHSV[0]); mVFColorLUT->SetSaturationRange(mVFColorHSV[1],mVFColorHSV[1]); mVFColorLUT->SetValueRange(mVFColorHSV[2], mVFColorHSV[2]); if (!mVFMapper) mVFMapper = vtkSmartPointer::New(); mVFMapper->SetInput(mGlyphFilter->GetOutput()); mVFMapper->ImmediateModeRenderingOn(); mVFMapper->SetLookupTable(mVFColorLUT); if (!mVFActor) mVFActor = vtkSmartPointer::New(); mVFActor->SetMapper(mVFMapper); mVFActor->SetPickable(0); mVFActor->GetProperty()->SetLineWidth(mVFWidth); this->UpdateDisplayExtent(); this->GetRenderer()->AddActor(mVFActor); //Synchronize slice SetTSlice(mCurrentTSlice); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetLandmarks(vvLandmarks* landmarks) { mLandmarks = landmarks; if (landmarks) { if (!mCross) mCross = vtkSmartPointer::New(); mCross->SetFocalPoint(0.0,0.0,0.0); mCross->SetModelBounds(-10,10,-10,10,-10,10); mCross->AllOff(); mCross->AxesOn(); if (!mLandGlyph) mLandGlyph = vtkSmartPointer::New(); mLandGlyph->SetSource(mCross->GetOutput()); mLandGlyph->SetInput(landmarks->GetOutput()); //mLandGlyph->SetIndexModeToScalar(); mLandGlyph->SetRange(0,1); mLandGlyph->ScalingOff(); mLandGlyph->SetColorModeToColorByScalar(); if (!mClipBox) mClipBox = vtkSmartPointer::New(); if (!mLandClipper) mLandClipper = vtkSmartPointer::New(); mLandClipper->InsideOutOn(); mLandClipper->SetInput(mLandGlyph->GetOutput()); mLandClipper->SetClipFunction(mClipBox); if (!mLandMapper) mLandMapper = vtkSmartPointer::New(); mLandMapper->SetInputConnection(mLandClipper->GetOutputPort()); //mLandMapper->ScalarVisibilityOff(); if (!mLandActor) mLandActor = vtkSmartPointer::New(); mLandActor->SetMapper(mLandMapper); mLandActor->GetProperty()->SetColor(255,10,212); mLandActor->SetPickable(0); mLandActor->SetVisibility(true); this->UpdateDisplayExtent(); this->GetRenderer()->AddActor(mLandActor); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ //FIXME: this function leaks memory, we should fix it someday :) void vvSlicer::RemoveActor(const std::string& actor_type, int overlay_index) { if (actor_type == "vector") { Renderer->RemoveActor(mVFActor); mGlyphFilter=NULL; mVF = NULL; mArrow = NULL; mAAFilter=NULL; mVOIFilter = NULL; mVFMapper = NULL; mVFActor = NULL; } if (actor_type == "overlay") { Renderer->RemoveActor(mOverlayActor); mOverlay = NULL; mOverlayActor = NULL; mOverlayMapper = NULL; } if (actor_type == "fusion") { Renderer->RemoveActor(mFusionActor); mFusion = NULL; mFusionActor = NULL; mFusionMapper = NULL; } if (actor_type == "contour") { Renderer->RemoveActor(this->mSurfaceCutActors[overlay_index]->GetActor()); mSurfaceCutActors.erase(mSurfaceCutActors.begin()+overlay_index); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetVFSubSampling(int sub) { if (mVOIFilter) { mVOIFilter->SetSampleRate(mSubSampling,mSubSampling,mSubSampling); mSubSampling = sub; } UpdateDisplayExtent(); Render(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetVFScale(int scale) { mScale = scale; if (mArrow) mArrow->SetScale(mScale); UpdateDisplayExtent(); Render(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetVFWidth(int width) { mVFWidth = width; if (mVFActor) mVFActor->GetProperty()->SetLineWidth(mVFWidth); UpdateDisplayExtent(); Render(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetVFLog(int log) { mVFLog = log; if (mGlyphFilter) { mGlyphFilter->SetUseLog(mVFLog); mGlyphFilter->Modified(); } UpdateDisplayExtent(); Render(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetTSlice(int t) { if (t < 0) t = 0; else if ((unsigned int)t >= mImage->GetVTKImages().size()) t = mImage->GetVTKImages().size() -1; if (mCurrentTSlice == t) return; mCurrentTSlice = t; this->SetInput(mImage->GetTransformedVTKImages()[t]); if (mVF && mVFActor->GetVisibility()) { if (mVF->GetVTKImages().size() > (unsigned int)mCurrentTSlice) mVOIFilter->SetInput(mVF->GetTransformedVTKImages()[mCurrentTSlice]); } if (mOverlay && mOverlayActor->GetVisibility()) { if (mOverlay->GetTransformedVTKImages().size() > (unsigned int)mCurrentTSlice) mOverlayMapper->SetInput(mOverlay->GetTransformedVTKImages()[mCurrentTSlice]); } if (mFusion && mFusionActor->GetVisibility()) { if (mFusion->GetVTKImages().size() > (unsigned int)mCurrentTSlice) mFusionMapper->SetInput(mFusion->GetTransformedVTKImages()[mCurrentTSlice]); } if (mSurfaceCutActors.size() > 0) for (std::vector::iterator i=mSurfaceCutActors.begin(); i!=mSurfaceCutActors.end(); i++) (*i)->SetTimeSlice(mCurrentTSlice); UpdateDisplayExtent(); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ int vvSlicer::GetTSlice() { return mCurrentTSlice; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetSliceOrientation(int orientation) { //if 2D image, force to watch in Axial View int extent[6]; this->GetInput()->GetWholeExtent(extent); if (extent[5]-extent[4] <= 2) orientation=2; if (orientation < vtkImageViewer2::SLICE_ORIENTATION_YZ || orientation > vtkImageViewer2::SLICE_ORIENTATION_XY) { vtkErrorMacro("Error - invalid slice orientation " << orientation); return; } this->SliceOrientation = orientation; // Update the viewer int *range = this->GetSliceRange(); if (range) this->Slice = static_cast((range[0] + range[1]) * 0.5); // Go to current cursor position // double* cursorPos = GetCursorPosition(); // DDV(cursorPos, 3); // SetCurrentPosition(cursorPos[0],cursorPos[1],cursorPos[2],cursorPos[3]); this->UpdateOrientation(); this->UpdateDisplayExtent(); if (this->Renderer && this->GetInput()) { double scale = this->Renderer->GetActiveCamera()->GetParallelScale(); this->Renderer->ResetCamera(); this->Renderer->GetActiveCamera()->SetParallelScale(scale); } SetContourSlice(); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- int * vvSlicer::GetExtent() { int *w_ext; if (mUseReducedExtent) { w_ext = mReducedExtent; } else w_ext = GetInput()->GetWholeExtent(); return w_ext; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- int vvSlicer::GetOrientation() { return this->SliceOrientation; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::UpdateDisplayExtent() { vtkImageData *input = this->GetInput(); if (!input || !this->ImageActor) { return; } input->UpdateInformation(); int *w_ext;// = input->GetWholeExtent(); if (mUseReducedExtent) { w_ext = mReducedExtent; } else w_ext = input->GetWholeExtent(); switch (this->SliceOrientation) { case vtkImageViewer2::SLICE_ORIENTATION_XY: this->ImageActor->SetDisplayExtent( w_ext[0], w_ext[1], w_ext[2], w_ext[3], this->Slice, this->Slice); if (mVF && mVFActor->GetVisibility()) { int vfExtent[6]; ComputeVFDisplayedExtent(w_ext[0], w_ext[1], w_ext[2], w_ext[3], this->Slice, this->Slice,vfExtent); mVOIFilter->SetVOI(vfExtent); mGlyphFilter->SetOrientation(1,1,0); mVFMapper->Update(); // put the vector field between the image and the camera if (Renderer->GetActiveCamera()->GetPosition()[2] > this->Slice) mVFActor->SetPosition(0,0,ImageActor->GetBounds()[5]+2); else mVFActor->SetPosition(0,0,ImageActor->GetBounds()[4]-2); } if (mOverlay && mOverlayActor->GetVisibility()) { int overExtent[6]; ComputeOverlayDisplayedExtent(w_ext[0], w_ext[1], w_ext[2], w_ext[3], this->Slice, this->Slice,overExtent); mOverlayActor->SetDisplayExtent(overExtent); if (Renderer->GetActiveCamera()->GetPosition()[2] > this->Slice) mOverlayActor->SetPosition(0,0,1); else mOverlayActor->SetPosition(0,0,-1); } if (mFusion && mFusionActor->GetVisibility()) { int fusExtent[6]; ComputeFusionDisplayedExtent(w_ext[0], w_ext[1], w_ext[2], w_ext[3], this->Slice, this->Slice,fusExtent); mFusionActor->SetDisplayExtent(fusExtent); if (Renderer->GetActiveCamera()->GetPosition()[2] > this->Slice) mFusionActor->SetPosition(0,0,1.5); else mFusionActor->SetPosition(0,0,-1.5); } if (mLandActor) { if (mClipBox) { double bounds [6]; bounds[0] = ImageActor->GetBounds()[0]; bounds[1] = ImageActor->GetBounds()[1]; bounds[2] = ImageActor->GetBounds()[2]; bounds[3] = ImageActor->GetBounds()[3]; bounds[4] = ImageActor->GetBounds()[4]-fabs(0.5/this->GetInput()->GetSpacing()[2]); bounds[5] = ImageActor->GetBounds()[5]+fabs(0.5/this->GetInput()->GetSpacing()[2]); mClipBox->SetBounds(bounds); UpdateLandmarks(); } mLandActor->SetPosition(0,0,-1.5); /* if (Renderer->GetActiveCamera()->GetPosition()[2] > this->Slice) mLandActor->SetPosition(0,0,1.5); else mLandActor->SetPosition(0,0,-1.5); */ } break; case vtkImageViewer2::SLICE_ORIENTATION_XZ: this->ImageActor->SetDisplayExtent( w_ext[0], w_ext[1], this->Slice, this->Slice, w_ext[4], w_ext[5]); if (mVF && mVFActor->GetVisibility()) { int vfExtent[6]; ComputeVFDisplayedExtent(w_ext[0], w_ext[1], this->Slice, this->Slice, w_ext[4], w_ext[5],vfExtent); mVOIFilter->SetVOI(vfExtent); mGlyphFilter->SetOrientation(1,0,1); mVFMapper->Update(); // put the vector field between the image aSpacingnd the camera if (Renderer->GetActiveCamera()->GetPosition()[1] > this->Slice) mVFActor->SetPosition(0,ImageActor->GetBounds()[3]+2,0); else mVFActor->SetPosition(0,ImageActor->GetBounds()[2]-2,0); } if (mOverlay && mOverlayActor->GetVisibility()) { int overExtent[6]; ComputeOverlayDisplayedExtent(w_ext[0], w_ext[1], this->Slice, this->Slice, w_ext[4], w_ext[5],overExtent); mOverlayActor->SetDisplayExtent(overExtent); if (Renderer->GetActiveCamera()->GetPosition()[1] > this->Slice) mOverlayActor->SetPosition(0,1,0); else mOverlayActor->SetPosition(0,-1,0); } if (mFusion && mFusionActor->GetVisibility()) { int fusExtent[6]; ComputeFusionDisplayedExtent(w_ext[0], w_ext[1], this->Slice, this->Slice, w_ext[4], w_ext[5],fusExtent); mFusionActor->SetDisplayExtent(fusExtent); if (Renderer->GetActiveCamera()->GetPosition()[1] > this->Slice) mFusionActor->SetPosition(0,1.5,0); else mFusionActor->SetPosition(0,-1.5,0); } if (mLandActor) { if (mClipBox) { double bounds [6]; bounds[0] = ImageActor->GetBounds()[0]; bounds[1] = ImageActor->GetBounds()[1]; bounds[2] = ImageActor->GetBounds()[2]-fabs(0.5/this->GetInput()->GetSpacing()[1]); bounds[3] = ImageActor->GetBounds()[3]+fabs(0.5/this->GetInput()->GetSpacing()[1]); bounds[4] = ImageActor->GetBounds()[4]; bounds[5] = ImageActor->GetBounds()[5]; mClipBox->SetBounds(bounds); UpdateLandmarks(); } if (Renderer->GetActiveCamera()->GetPosition()[1] > this->Slice) mLandActor->SetPosition(0,1.5,0); else mLandActor->SetPosition(0,-1.5,0); } break; case vtkImageViewer2::SLICE_ORIENTATION_YZ: this->ImageActor->SetDisplayExtent( this->Slice, this->Slice, w_ext[2], w_ext[3], w_ext[4], w_ext[5]); if (mVF && mVFActor->GetVisibility()) { int vfExtent[6]; ComputeVFDisplayedExtent(this->Slice, this->Slice, w_ext[2], w_ext[3], w_ext[4], w_ext[5],vfExtent); mVOIFilter->SetVOI(vfExtent); mGlyphFilter->SetOrientation(0,1,1); mVFMapper->Update(); // put the vector field between the image and the camera if (Renderer->GetActiveCamera()->GetPosition()[0] > this->Slice) mVFActor->SetPosition(ImageActor->GetBounds()[1]+2,0,0); else mVFActor->SetPosition(ImageActor->GetBounds()[0]-2,0,0); } if (mOverlay && mOverlayActor->GetVisibility()) { int overExtent[6]; ComputeOverlayDisplayedExtent(this->Slice, this->Slice, w_ext[2], w_ext[3], w_ext[4], w_ext[5],overExtent); mOverlayActor->SetDisplayExtent(overExtent); if (Renderer->GetActiveCamera()->GetPosition()[0] > this->Slice) mOverlayActor->SetPosition(1,0,0); else mOverlayActor->SetPosition(-1,0,0); } if (mFusion && mFusionActor->GetVisibility()) { int fusExtent[6]; ComputeFusionDisplayedExtent(this->Slice, this->Slice, w_ext[2], w_ext[3], w_ext[4], w_ext[5],fusExtent); mFusionActor->SetDisplayExtent(fusExtent); if (Renderer->GetActiveCamera()->GetPosition()[0] > this->Slice) mFusionActor->SetPosition(1.5,0,0); else mFusionActor->SetPosition(-1.5,0,0); } if (mLandActor) { if (mClipBox) { double bounds [6]; bounds[0] = ImageActor->GetBounds()[0]-fabs(0.5/this->GetInput()->GetSpacing()[0]); bounds[1] = ImageActor->GetBounds()[1]+fabs(0.5/this->GetInput()->GetSpacing()[0]); bounds[2] = ImageActor->GetBounds()[2]; bounds[3] = ImageActor->GetBounds()[3]; bounds[4] = ImageActor->GetBounds()[4]; bounds[5] = ImageActor->GetBounds()[5]; mClipBox->SetBounds(bounds); UpdateLandmarks(); } if (Renderer->GetActiveCamera()->GetPosition()[0] > this->Slice) mLandActor->SetPosition(1.5,0,0); else mLandActor->SetPosition(-1.5,0,0); } break; } // Figure out the correct clipping range if (this->Renderer) { if (this->InteractorStyle && this->InteractorStyle->GetAutoAdjustCameraClippingRange()) { this->Renderer->ResetCameraClippingRange(); } else { vtkCamera *cam = this->Renderer->GetActiveCamera(); if (cam) { double bounds[6]; this->ImageActor->GetBounds(bounds); double spos = (double)bounds[this->SliceOrientation * 2]; double cpos = (double)cam->GetPosition()[this->SliceOrientation]; double range = fabs(spos - cpos); double *spacing = input->GetSpacing(); double avg_spacing = ((double)spacing[0] + (double)spacing[1] + (double)spacing[2]) / 3.0; cam->SetClippingRange( range - avg_spacing * 3.0, range + avg_spacing * 3.0); } } } } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::ComputeVFDisplayedExtent(int x1,int x2,int y1,int y2,int z1,int z2,int vfExtent[6]) { double dVfExtent[6]; vtkImageData* image = this->GetInput(); dVfExtent[0] = image->GetOrigin()[0] + x1*image->GetSpacing()[0]; dVfExtent[1] = image->GetOrigin()[0] + x2*image->GetSpacing()[0]; dVfExtent[2] = image->GetOrigin()[1] + y1*image->GetSpacing()[1]; dVfExtent[3] = image->GetOrigin()[1] + y2*image->GetSpacing()[1]; dVfExtent[4] = image->GetOrigin()[2] + z1*image->GetSpacing()[2]; dVfExtent[5] = image->GetOrigin()[2] + z2*image->GetSpacing()[2]; vtkImageData* vf = mVF->GetTransformedVTKImages()[0]; vf->UpdateInformation(); for(unsigned int i=0; i<6; i++) vfExtent[i] = itk::Math::Round((dVfExtent[i]- vf->GetOrigin()[i/2]) / vf->GetSpacing()[i/2]); ClipDisplayedExtent(vfExtent,mVOIFilter->GetInput()->GetWholeExtent()); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::ComputeOverlayDisplayedExtent(int x1,int x2,int y1,int y2,int z1,int z2,int overExtent[6]) { double dOverExtent[6]; vtkImageData* image = this->GetInput(); dOverExtent[0] = image->GetOrigin()[0] + x1*image->GetSpacing()[0]; dOverExtent[1] = image->GetOrigin()[0] + x2*image->GetSpacing()[0]; dOverExtent[2] = image->GetOrigin()[1] + y1*image->GetSpacing()[1]; dOverExtent[3] = image->GetOrigin()[1] + y2*image->GetSpacing()[1]; dOverExtent[4] = image->GetOrigin()[2] + z1*image->GetSpacing()[2]; dOverExtent[5] = image->GetOrigin()[2] + z2*image->GetSpacing()[2]; vtkImageData* overlay = mOverlay->GetTransformedVTKImages()[0]; overlay->UpdateInformation(); for(unsigned int i=0; i<6; i++) overExtent[i] = itk::Math::Round((dOverExtent[i]- overlay->GetOrigin()[i/2]) / overlay->GetSpacing()[i/2]); ClipDisplayedExtent(overExtent, mOverlayMapper->GetInput()->GetWholeExtent()); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::ComputeFusionDisplayedExtent(int x1,int x2,int y1,int y2,int z1,int z2,int fusExtent[6]) { double dFusExtent[6]; vtkImageData* image = this->GetInput(); dFusExtent[0] = image->GetOrigin()[0] + x1*image->GetSpacing()[0]; dFusExtent[1] = image->GetOrigin()[0] + x2*image->GetSpacing()[0]; dFusExtent[2] = image->GetOrigin()[1] + y1*image->GetSpacing()[1]; dFusExtent[3] = image->GetOrigin()[1] + y2*image->GetSpacing()[1]; dFusExtent[4] = image->GetOrigin()[2] + z1*image->GetSpacing()[2]; dFusExtent[5] = image->GetOrigin()[2] + z2*image->GetSpacing()[2]; vtkImageData* fusion = mFusion->GetTransformedVTKImages()[0]; fusion->UpdateInformation(); for(unsigned int i=0; i<6; i++) fusExtent[i] = itk::Math::Round((dFusExtent[i]- fusion->GetOrigin()[i/2]) / fusion->GetSpacing()[i/2]); ClipDisplayedExtent(fusExtent, mFusionMapper->GetInput()->GetWholeExtent()); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::ClipDisplayedExtent(int extent[6], int refExtent[6]) { bool out = false; int maxBound = 6; //2D overlay on 3D image specific case if (refExtent[4] == refExtent[5]) { maxBound = 4; extent[4] = refExtent[4]; extent[5] = refExtent[5]; } for (int i = 0; i < maxBound; i = i+2) { //if we are totally outside the image if ( extent[i] > refExtent[i+1] || extent[i+1] < refExtent[i] ) { out = true; break; } //crop to the limit of the image extent[i] = (extent[i] > refExtent[i]) ? extent[i] : refExtent[i]; extent[i] = (extent[i] < refExtent[i+1]) ? extent[i] : refExtent[i+1]; extent[i+1] = (extent[i+1] > refExtent[i]) ? extent[i+1] : refExtent[i]; extent[i+1] = (extent[i+1] < refExtent[i+1]) ? extent[i+1] : refExtent[i+1]; } if (out) for (int i = 0; i < maxBound; i = i+2) { extent[i] = refExtent[i]; extent[i+1] = refExtent[i]; } } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::UpdateOrientation() { // Set the camera position vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL; if (cam) { switch (this->SliceOrientation) { case vtkImageViewer2::SLICE_ORIENTATION_XY: cam->SetFocalPoint(0,0,0); cam->SetPosition(0,0,-1); // -1 if medical ? cam->SetViewUp(0,-1,0); break; case vtkImageViewer2::SLICE_ORIENTATION_XZ: cam->SetFocalPoint(0,0,0); cam->SetPosition(0,-1,0); // 1 if medical ? cam->SetViewUp(0,0,1); break; case vtkImageViewer2::SLICE_ORIENTATION_YZ: cam->SetFocalPoint(0,0,0); cam->SetPosition(-1,0,0); // -1 if medical ? cam->SetViewUp(0,0,1); break; } } } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::SetOpacity(double s) { this->GetImageActor()->SetOpacity(s); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::SetRenderWindow(int orientation, vtkRenderWindow * rw) { this->Superclass::SetRenderWindow(rw); this->SetupInteractor(rw->GetInteractor()); ca->SetImageActor(this->GetImageActor()); ca->SetWindowLevel(this->GetWindowLevel()); ca->SetText(2, ""); ca->SetText(3, "\n"); double bounds[6]; double max = 65000; bounds[0] = -max; bounds[1] = max; bounds[2] = -max; bounds[3] = max; bounds[4] = -max; bounds[5] = max; crossCursor->SetModelBounds(bounds); this->GetRenderer()->AddActor(pdmA); this->GetRenderer()->AddActor(ca); this->GetRenderer()->ResetCamera(); //this is just a mapping between the labeling of the orientations presented to the user and //the one used by vtk SetSliceOrientation(2-(orientation%3)); ResetCamera(); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::ResetCamera() { this->GetRenderer()->ResetCamera(); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::SetDisplayMode(bool i) { this->GetImageActor()->SetVisibility(i); this->GetAnnotation()->SetVisibility(i); this->GetRenderer()->SetDraw(i); if (mLandActor) mLandActor->SetVisibility(i); pdmA->SetVisibility(i); if (i) UpdateDisplayExtent(); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::FlipHorizontalView() { vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL; if (cam) { double *position = cam->GetPosition(); switch (this->SliceOrientation) { case vtkImageViewer2::SLICE_ORIENTATION_XY: cam->SetPosition(position[0],position[1],-position[2]); break; case vtkImageViewer2::SLICE_ORIENTATION_XZ: cam->SetPosition(position[0],-position[1],position[2]); break; case vtkImageViewer2::SLICE_ORIENTATION_YZ: cam->SetPosition(-position[0],position[1],position[2]); break; } this->Renderer->ResetCameraClippingRange(); this->UpdateDisplayExtent(); } } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::FlipVerticalView() { vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL; if (cam) { FlipHorizontalView(); double *viewup = cam->GetViewUp(); cam->SetViewUp(-viewup[0],-viewup[1],-viewup[2]); this->UpdateDisplayExtent(); } } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::SetColorWindow(double window) { vtkLookupTable* LUT = static_cast(this->GetWindowLevel()->GetLookupTable()); if ( LUT ) { double level = this->GetWindowLevel()->GetLevel(); LUT->SetTableRange(level-fabs(window)/4,level+fabs(window)/4); LUT->Build(); } this->vtkImageViewer2::SetColorWindow(window); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::SetColorLevel(double level) { vtkLookupTable* LUT = static_cast(this->GetWindowLevel()->GetLookupTable()); if ( LUT ) { double window = this->GetWindowLevel()->GetWindow(); LUT->SetTableRange(level-fabs(window)/4,level+fabs(window)/4); LUT->Build(); } this->vtkImageViewer2::SetColorLevel(level); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // Returns the min an the max value in a 41x41 region around the mouse pointer void vvSlicer::GetExtremasAroundMousePointer(double & min, double & max) { //Get mouse pointer position in view coordinates double fLocalExtents[6]; for(int i=0; i<3; i++) { fLocalExtents[i*2 ] = mCurrent[i]; fLocalExtents[i*2+1] = mCurrent[i]; } this->Renderer->WorldToView(fLocalExtents[0], fLocalExtents[2], fLocalExtents[4]); this->Renderer->WorldToView(fLocalExtents[1], fLocalExtents[3], fLocalExtents[5]); for(int i=0; i<3; i++) { if (i!=SliceOrientation) { //SR: assumes that SliceOrientation is valid in ViewCoordinates (???) fLocalExtents[i*2 ] -= 0.2; fLocalExtents[i*2+1] += 0.2; } } this->Renderer->ViewToWorld(fLocalExtents[0], fLocalExtents[2], fLocalExtents[4]); this->Renderer->ViewToWorld(fLocalExtents[1], fLocalExtents[3], fLocalExtents[5]); //Convert to image pixel coordinates (rounded) int iLocalExtents[6]; for(int i=0; i<3; i++) { fLocalExtents[i*2 ] = (fLocalExtents[i*2 ] - this->GetInput()->GetOrigin()[i])/this->GetInput()->GetSpacing()[i]; fLocalExtents[i*2+1] = (fLocalExtents[i*2+1] - this->GetInput()->GetOrigin()[i])/this->GetInput()->GetSpacing()[i]; iLocalExtents[i*2 ] = lrint(fLocalExtents[i*2 ]); iLocalExtents[i*2+1] = lrint(fLocalExtents[i*2+1]); if(iLocalExtents[i*2 ]>iLocalExtents[i*2+1]) std::swap(iLocalExtents[i*2], iLocalExtents[i*2+1]); } vtkSmartPointer voiFilter = vtkSmartPointer::New(); voiFilter->SetInput(this->GetInput()); voiFilter->SetVOI(iLocalExtents); voiFilter->Update(); if (!voiFilter->GetOutput()->GetNumberOfPoints()) { min = 0; max = 0; return; } vtkSmartPointer accFilter = vtkSmartPointer::New(); accFilter->SetInput(voiFilter->GetOutput()); accFilter->Update(); min = *(accFilter->GetMin()); max = *(accFilter->GetMax()); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- double vvSlicer::GetScalarComponentAsDouble(vtkImageData *image, int X, double Y, double Z, int &ix, int &iy, int &iz, int component) { ix = lrint(X); iy = lrint(Y); iz = lrint(Z); if (ix < image->GetWholeExtent()[0] || ix > image->GetWholeExtent()[1] || iy < image->GetWholeExtent()[2] || iy > image->GetWholeExtent()[3] || iz < image->GetWholeExtent()[4] || iz > image->GetWholeExtent()[5] ) return sqrt(-1.); image->SetUpdateExtent(ix, ix, iy, iy, iz, iz); image->Update(); return image->GetScalarComponentAsDouble(ix, iy, iz, component); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::Render() { if (this->GetWindowLevel()->GetLookupTable() && !this->mOverlay && !this->mFusion) { legend->SetLookupTable(this->GetWindowLevel()->GetLookupTable()); legend->SetVisibility(1); } else legend->SetVisibility(0); if (ca->GetVisibility()) { std::string worldPos = ""; std::stringstream world1; std::stringstream world2; std::stringstream world3; world1 << (int)mCurrent[0]; world2 << (int)mCurrent[1]; world3 << (int)mCurrent[2]; double X = (mCurrent[0] - this->GetInput()->GetOrigin()[0])/this->GetInput()->GetSpacing()[0]; double Y = (mCurrent[1] - this->GetInput()->GetOrigin()[1])/this->GetInput()->GetSpacing()[1]; double Z = (mCurrent[2] - this->GetInput()->GetOrigin()[2])/this->GetInput()->GetSpacing()[2]; if (pdmA->GetVisibility()) { double x = mCursor[0]; double y = mCursor[1]; double z = mCursor[2]; double xCursor = (x - this->GetInput()->GetOrigin()[0])/this->GetInput()->GetSpacing()[0]; double yCursor = (y - this->GetInput()->GetOrigin()[1])/this->GetInput()->GetSpacing()[1]; double zCursor = (z - this->GetInput()->GetOrigin()[2])/this->GetInput()->GetSpacing()[2]; if (xCursor >= this->GetImageActor()->GetDisplayExtent()[0] && xCursor < this->GetImageActor()->GetDisplayExtent()[1]+1 && yCursor >= this->GetImageActor()->GetDisplayExtent()[2] && yCursor < this->GetImageActor()->GetDisplayExtent()[3]+1 && zCursor >= this->GetImageActor()->GetDisplayExtent()[4] && zCursor < this->GetImageActor()->GetDisplayExtent()[5]+1 ) { vtkRenderer * renderer = this->Renderer; renderer->WorldToView(x,y,z); renderer->ViewToNormalizedViewport(x,y,z); renderer->NormalizedViewportToViewport(x,y); renderer->ViewportToNormalizedDisplay(x,y); renderer->NormalizedDisplayToDisplay(x,y); crossCursor->SetFocalPoint(x,y,z); } else crossCursor->SetFocalPoint(-1,-1,z); } if (X >= this->GetInput()->GetWholeExtent()[0] && X <= this->GetInput()->GetWholeExtent()[1] && Y >= this->GetInput()->GetWholeExtent()[2] && Y <= this->GetInput()->GetWholeExtent()[3] && Z >= this->GetInput()->GetWholeExtent()[4] && Z <= this->GetInput()->GetWholeExtent()[5]) { int ix, iy, iz; double value = this->GetScalarComponentAsDouble(this->GetInput(), X, Y, Z, ix, iy, iz); std::stringstream pixel1; std::stringstream pixel2; std::stringstream pixel3; std::stringstream temps; pixel1 << ix; pixel2 << iy; pixel3 << iz; temps << mCurrentTSlice; std::stringstream val; val << value; worldPos += "data value : " + val.str(); worldPos += "\n mm : " + world1.str() + " " + world2.str() + " " + world3.str() + " " + temps.str(); worldPos += "\n pixel : " + pixel1.str() + " " + pixel2.str() + " " + pixel3.str() + " " + temps.str(); } ca->SetText(1,worldPos.c_str()); } if (mOverlay && mOverlayActor->GetVisibility()) { mOverlayMapper->SetWindow(this->GetColorWindow()); mOverlayMapper->SetLevel(this->GetColorLevel()); mOverlayMapper->GetOutput()->SetUpdateExtent(mOverlayActor->GetDisplayExtent()); mOverlayMapper->GetOutput()->Update(); mOverlayMapper->Update(); } if (mLandMapper) UpdateLandmarks(); //this->Superclass::Render(); this->GetRenderWindow()->Render(); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::UpdateCursorPosition() { if (this->GetImageActor()->GetVisibility()) { pdmA->SetVisibility(true); mCursor[0] = mCurrent[0]; mCursor[1] = mCurrent[1]; mCursor[2] = mCurrent[2]; mCursor[3] = mCurrentTSlice; } } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::UpdateLandmarks() { vtkPolyData *pd = static_cast(mLandClipper->GetInput()); if (pd->GetPoints()) { mLandGlyph->SetRange(0,1); mLandGlyph->Modified(); mLandGlyph->Update(); mClipBox->Modified(); mLandClipper->Update(); mLandMapper->Update(); } } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::SetSlice(int slice) { int *range = this->GetSliceRange(); if (range) { if (slice < range[0]) { slice = range[0]; } else if (slice > range[1]) { slice = range[1]; } } if (this->Slice == slice) { return; } this->Slice = slice; SetContourSlice(); this->Modified(); this->UpdateDisplayExtent(); // Seems to work without this line // this->Render(); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::SetContourSlice() { if (mSurfaceCutActors.size() > 0) for (std::vector::iterator i=mSurfaceCutActors.begin(); i!=mSurfaceCutActors.end(); i++) (*i)->SetCutSlice((this->Slice)*this->GetImage()->GetSpacing()[this->SliceOrientation]+ this->GetImage()->GetOrigin()[this->SliceOrientation]); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::ForceUpdateDisplayExtent() { this->UpdateDisplayExtent(); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- int* vvSlicer::GetDisplayExtent() { return this->GetImageActor()->GetDisplayExtent(); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::SetVFColor(double r, double g, double b) { double mVFColorHSV[3]; mVFColor[0] = r; mVFColor[1] = g; mVFColor[2] = b; vtkMath::RGBToHSV(mVFColor, mVFColorHSV); mVFColorLUT->SetHueRange(mVFColorHSV[0], mVFColorHSV[0]); mVFColorLUT->SetSaturationRange(mVFColorHSV[1],mVFColorHSV[1]); mVFColorLUT->SetValueRange(mVFColorHSV[2], mVFColorHSV[2]); this->Render(); }