1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
21 #include "vvSlicerManagerCommand.h"
22 #include "vvGlyphSource.h"
23 #include "vvGlyph2D.h"
24 #include "vvImageMapToWLColors.h"
26 #include <vtkTextProperty.h>
27 #include <vtkTextActor.h>
28 #include <vtkTextSource.h>
29 #include <vtkActor2D.h>
30 #include <vtkCursor2D.h>
31 #include <vtkPolyDataMapper2D.h>
32 #include <vtkProperty2D.h>
33 #include <vtkCornerAnnotation.h>
34 #include <vtkImageMapToWindowLevelColors.h>
35 #include <vtkImageData.h>
36 #include <vtkImageActor.h>
37 #include <vvBlendImageActor.h>
38 #include <vtkToolkits.h>
39 #include <vtkObjectFactory.h>
40 #include <vtkPointData.h>
41 #include <vtkDataArray.h>
42 #include <vtkFloatArray.h>
43 #include <vtkClipPolyData.h>
44 #include <vtkGlyph3D.h>
46 #include <vtkCursor3D.h>
47 #include <vtkProperty.h>
49 #include <vtkLightCollection.h>
50 #include <vtkScalarBarActor.h>
51 #include <vtkLookupTable.h>
53 #include <vtkRenderer.h>
54 #include <vtkRendererCollection.h>
55 #include <vtkRenderWindow.h>
56 #include <vtkRenderWindowInteractor.h>
57 #include <vtkCamera.h>
58 #include <vtkCallbackCommand.h>
59 #include <vtkCommand.h>
60 #include <vtkPolyDataMapper.h>
63 #include <vtkExtractVOI.h>
64 #include <vtkSphereSource.h>
65 #include <vtkCutter.h>
66 #include <vtkAssignAttribute.h>
67 #include <vtkImageAccumulate.h>
68 #include <vtkImageReslice.h>
70 // template <class T, unsigned int dim>
71 // void print_vector(const char* pmsg, T* pvec)
73 // std::cout << pmsg << ": ";
74 // for (unsigned int i = 0; i < dim; i++)
75 // std::cout << pvec[i] << " ";
76 // std::cout << std::endl;
80 vtkCxxRevisionMacro(vvSlicer, "DummyRevision");
81 vtkStandardNewMacro(vvSlicer);
83 //------------------------------------------------------------------------------
86 this->UnInstallPipeline();
89 mUseReducedExtent = false;
91 mCurrent[0] = -VTK_DOUBLE_MAX;
92 mCurrent[1] = -VTK_DOUBLE_MAX;
93 mCurrent[2] = -VTK_DOUBLE_MAX;
95 mCursor[0] = -VTK_DOUBLE_MAX;
96 mCursor[1] = -VTK_DOUBLE_MAX;
97 mCursor[2] = -VTK_DOUBLE_MAX;
98 mCursor[3] = -VTK_DOUBLE_MAX;
108 std::string text = "F1 = sagital; F2 = coronal; F3 = axial\n";
109 text += "F5 = horizontal flip; F6 = vertical flip\n\n";
110 text += "0,1,2,3,4,5 : preset windowing\n";
111 text += "6,7,8,9 : preset colormap\n";
112 text += "z : local windowing\n";
113 text += "r : reset view\n";
114 text += "l : reload image\n";
115 text += "f : fly to mouse position\n";
116 text += "g : go to cross hair position\n\n";
117 text += "Up,down : change slice\n";
118 text += "Left,right : change tenporal slice\n\n";
119 text += "Scrollbar (or w/x) : zoom in/out\n";
120 text += "left button : synchronize all views\n";
121 text += "middle button : grab image\n";
122 text += "right button : change windowing\n";
124 crossCursor = vtkSmartPointer<vtkCursor2D>::New();
125 crossCursor->AllOff();
126 crossCursor->AxesOn();
127 crossCursor->SetTranslationMode(1);
128 crossCursor->SetRadius(2);
130 pdm = vtkSmartPointer<vtkPolyDataMapper2D>::New();
131 pdm->SetInput(crossCursor->GetOutput());
133 pdmA = vtkSmartPointer<vtkActor2D>::New();
134 pdmA->SetMapper(pdm);
135 pdmA->GetProperty()->SetColor(255,10,212);
136 pdmA->SetVisibility(0);
137 pdmA->SetPickable(0);
139 ca = vtkSmartPointer<vtkCornerAnnotation>::New();
140 ca->GetTextProperty()->SetColor(255,10,212);
141 ca->SetVisibility(1);
149 legend = vtkSmartPointer<vtkScalarBarActor>::New();
150 //legend->SetTitle("test!");
151 legend->SetPosition(0.82,0.18);
152 legend->SetWidth(0.1);
153 legend->SetVisibility(0);
154 legend->SetLabelFormat("%.1f");
155 this->GetRenderer()->AddActor(legend);
157 this->WindowLevel->Delete();
158 this->WindowLevel = vvImageMapToWLColors::New();
160 this->InstallPipeline();
162 //------------------------------------------------------------------------------
165 //------------------------------------------------------------------------------
166 vtkImageMapToWindowLevelColors* vvSlicer::GetOverlayMapper()
168 return mOverlayMapper.GetPointer();
170 //------------------------------------------------------------------------------
173 //------------------------------------------------------------------------------
174 vvBlendImageActor* vvSlicer::GetOverlayActor()
176 return mOverlayActor.GetPointer();
178 //------------------------------------------------------------------------------
181 //------------------------------------------------------------------------------
182 vtkImageMapToWindowLevelColors* vvSlicer::GetFusionMapper()
184 return mFusionMapper.GetPointer();
186 //------------------------------------------------------------------------------
189 //------------------------------------------------------------------------------
190 vtkImageActor* vvSlicer::GetFusionActor()
192 return mFusionActor.GetPointer();
194 //------------------------------------------------------------------------------
197 //------------------------------------------------------------------------------
198 vtkActor* vvSlicer::GetVFActor()
200 return mVFActor.GetPointer();
202 //------------------------------------------------------------------------------
205 //------------------------------------------------------------------------------
206 vtkCornerAnnotation* vvSlicer::GetAnnotation()
208 return ca.GetPointer();
210 //------------------------------------------------------------------------------
213 //------------------------------------------------------------------------------
214 void vvSlicer::EnableReducedExtent(bool b)
216 mUseReducedExtent = b;
218 //------------------------------------------------------------------------------
221 //------------------------------------------------------------------------------
222 void vvSlicer::SetReducedExtent(int * ext)
224 mReducedExtent = ext;
226 //------------------------------------------------------------------------------
229 //------------------------------------------------------------------------------
230 void vvSlicer::AddContour(vvMesh::Pointer contour,bool propagate)
233 mSurfaceCutActors.push_back(new vvMeshActor());
235 mSurfaceCutActors.back()->Init(contour,mCurrentTSlice,mVF);
237 mSurfaceCutActors.back()->Init(contour,mCurrentTSlice);
238 mSurfaceCutActors.back()->SetSlicingOrientation(SliceOrientation);
239 this->GetRenderer()->AddActor(mSurfaceCutActors.back()->GetActor());
243 //------------------------------------------------------------------------------
246 //------------------------------------------------------------------------------
247 void vvSlicer::ToggleContourSuperposition()
249 for (std::vector<vvMeshActor*>::iterator i=mSurfaceCutActors.begin();
250 i!=mSurfaceCutActors.end(); i++)
251 (*i)->ToggleSuperposition();
253 //------------------------------------------------------------------------------
256 //------------------------------------------------------------------------------
257 void vvSlicer::SetCursorColor(int r,int g, int b)
259 pdmA->GetProperty()->SetColor(r,g,b);
261 //------------------------------------------------------------------------------
264 //------------------------------------------------------------------------------
265 void vvSlicer::SetCursorVisibility(bool s)
267 pdmA->SetVisibility(s);
269 //------------------------------------------------------------------------------
272 //------------------------------------------------------------------------------
273 bool vvSlicer::GetCursorVisibility()
275 return pdmA->GetVisibility();
277 //------------------------------------------------------------------------------
280 //------------------------------------------------------------------------------
281 void vvSlicer::SetCornerAnnotationVisibility(bool s)
283 ca->SetVisibility(s);
285 //------------------------------------------------------------------------------
288 //------------------------------------------------------------------------------
289 bool vvSlicer::GetCornerAnnotationVisibility()
291 return ca->GetVisibility();
293 //------------------------------------------------------------------------------
296 //------------------------------------------------------------------------------
297 vvSlicer::~vvSlicer()
299 for (std::vector<vvMeshActor*>::iterator i=mSurfaceCutActors.begin();
300 i!=mSurfaceCutActors.end(); i++)
303 //------------------------------------------------------------------------------
306 //------------------------------------------------------------------------------
307 void vvSlicer::SetCurrentPosition(double x, double y, double z, int t)
314 //------------------------------------------------------------------------------
317 //------------------------------------------------------------------------------
318 void vvSlicer::SetImage(vvImage::Pointer image)
320 if (image->GetVTKImages().size()) {
323 if (!mImageReslice) {
324 mImageReslice = vtkSmartPointer<vtkImageReslice>::New();
325 mImageReslice->SetInterpolationModeToLinear();
326 mImageReslice->AutoCropOutputOn();
327 mImageReslice->SetBackgroundColor(-1000,-1000,-1000,1);
329 mImageReslice->SetResliceTransform(mImage->GetTransform());
330 mImageReslice->SetInput(0, mImage->GetFirstVTKImageData());
331 mImageReslice->UpdateInformation();
333 this->Superclass::SetInput(mImageReslice->GetOutput());
336 this->GetInput()->GetWholeExtent(extent);
338 // Prevent crash when reload -> change slice if outside extent
339 if (Slice < extent[SliceOrientation*2] || Slice>=extent[SliceOrientation*2+1]) {
340 Slice = (extent[SliceOrientation*2+1]+extent[SliceOrientation*2])/2.0;
343 // Make sure that the required part image has been computed
344 extent[SliceOrientation*2] = Slice;
345 extent[SliceOrientation*2+1] = Slice;
346 mImageReslice->GetOutput()->SetUpdateExtent(extent);
347 mImageReslice->GetOutput()->Update();
349 this->UpdateDisplayExtent();
352 ca->SetText(0,mFileName.c_str());
355 //------------------------------------------------------------------------------
358 //------------------------------------------------------------------------------
359 void vvSlicer::SetOverlay(vvImage::Pointer overlay)
361 if (overlay->GetVTKImages().size()) {
364 if (!mOverlayReslice) {
365 mOverlayReslice = vtkSmartPointer<vtkImageReslice>::New();
366 mOverlayReslice->SetInterpolationModeToLinear();
367 mOverlayReslice->AutoCropOutputOn();
368 mOverlayReslice->SetBackgroundColor(-1000,-1000,-1000,1);
370 mOverlayReslice->SetResliceTransform(mOverlay->GetTransform());
371 mOverlayReslice->SetInput(0, mOverlay->GetFirstVTKImageData());
374 mOverlayMapper = vtkSmartPointer<vtkImageMapToWindowLevelColors>::New();
375 mOverlayMapper->SetInput(mOverlayReslice->GetOutput());
377 if (!mOverlayActor) {
378 mOverlayActor = vtkSmartPointer<vvBlendImageActor>::New();
379 mOverlayActor->SetInput(mOverlayMapper->GetOutput());
380 mOverlayActor->SetPickable(0);
381 mOverlayActor->SetVisibility(false);
382 mOverlayActor->SetOpacity(0.5);
385 //stupid but necessary : the Overlay need to be rendered before fusion
387 this->GetRenderer()->RemoveActor(mFusionActor);
388 this->GetRenderer()->AddActor(mOverlayActor);
389 this->GetRenderer()->AddActor(mFusionActor);
391 this->GetRenderer()->AddActor(mOverlayActor);
393 //Synchronize orientation and slice
394 this->SetSliceOrientation(this->SliceOrientation);
395 this->SetTSlice(mCurrentTSlice);
398 //------------------------------------------------------------------------------
401 //------------------------------------------------------------------------------
402 void vvSlicer::SetFusion(vvImage::Pointer fusion)
404 if (fusion->GetVTKImages().size()) {
407 if (!mFusionReslice) {
408 mFusionReslice = vtkSmartPointer<vtkImageReslice>::New();
409 mFusionReslice->SetInterpolationModeToLinear();
410 mFusionReslice->AutoCropOutputOn();
411 mFusionReslice->SetBackgroundColor(-1000,-1000,-1000,1);
413 mFusionReslice->SetResliceTransform(mFusion->GetTransform());
414 mFusionReslice->SetInput(0, mFusion->GetFirstVTKImageData());
417 mFusionMapper = vtkSmartPointer<vtkImageMapToWindowLevelColors>::New();
418 mFusionMapper->SetInput(mFusionReslice->GetOutput());
421 mFusionActor = vtkSmartPointer<vtkImageActor>::New();
422 mFusionActor->SetInput(mFusionMapper->GetOutput());
423 mFusionActor->SetPickable(0);
424 mFusionActor->SetVisibility(false);
425 mFusionActor->SetOpacity(0.7);
426 this->GetRenderer()->AddActor(mFusionActor);
429 //Synchronize orientation and slice
430 this->SetSliceOrientation(this->SliceOrientation);
431 this->SetTSlice(mCurrentTSlice);
434 //------------------------------------------------------------------------------
437 //------------------------------------------------------------------------------
438 void vvSlicer::SetActorVisibility(const std::string& actor_type, int overlay_index ,bool vis)
440 if (actor_type == "vector") {
441 this->mVFActor->SetVisibility(vis);
443 if (actor_type == "overlay") {
444 this->mOverlayActor->SetVisibility(vis);
446 if (actor_type == "fusion") {
447 this->mFusionActor->SetVisibility(vis);
449 if (actor_type == "contour")
450 this->mSurfaceCutActors[overlay_index]->GetActor()->SetVisibility(vis);
451 UpdateDisplayExtent();
453 //------------------------------------------------------------------------------
456 //------------------------------------------------------------------------------
457 void vvSlicer::SetVF(vvImage::Pointer vf)
459 if (vf->GetVTKImages().size()) {
463 mAAFilter= vtkSmartPointer<vtkAssignAttribute>::New();
464 mVOIFilter = vtkSmartPointer<vtkExtractVOI>::New();
465 mVOIFilter->SetSampleRate(mSubSampling,mSubSampling,mSubSampling);
467 mVOIFilter->SetInput(vf->GetFirstVTKImageData());
468 mAAFilter->SetInput(mVOIFilter->GetOutput());
469 ///This tells VTK to use the scalar (pixel) data of the image to draw the little arrows
470 mAAFilter->Assign(vtkDataSetAttributes::SCALARS, vtkDataSetAttributes::VECTORS, vtkAssignAttribute::POINT_DATA);
473 mArrow = vtkSmartPointer<vvGlyphSource>::New();
474 mArrow->SetGlyphTypeToSpecificArrow();
475 mArrow->SetScale(mScale);
478 // Glyph the gradient vector (with arrows)
480 mGlyphFilter = vtkSmartPointer<vvGlyph2D>::New();
481 mGlyphFilter->SetInput(mAAFilter->GetOutput());
482 mGlyphFilter->SetSource(mArrow->GetOutput());
483 mGlyphFilter->ScalingOn();
484 mGlyphFilter->SetScaleModeToScaleByVector();
485 mGlyphFilter->OrientOn();
486 mGlyphFilter->SetVectorModeToUseVector();
487 mGlyphFilter->SetColorModeToColorByVector();
490 mVFColorLUT = vtkSmartPointer<vtkLookupTable>::New();
492 double mVFColorHSV[3];
493 vtkMath::RGBToHSV(mVFColor, mVFColorHSV);
494 mVFColorLUT->SetHueRange(mVFColorHSV[0], mVFColorHSV[0]);
495 mVFColorLUT->SetSaturationRange(mVFColorHSV[1],mVFColorHSV[1]);
496 mVFColorLUT->SetValueRange(mVFColorHSV[2], mVFColorHSV[2]);
499 mVFMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
500 mVFMapper->SetInput(mGlyphFilter->GetOutput());
501 mVFMapper->ImmediateModeRenderingOn();
502 mVFMapper->SetLookupTable(mVFColorLUT);
505 mVFActor = vtkSmartPointer<vtkActor>::New();
506 mVFActor->SetMapper(mVFMapper);
507 mVFActor->SetPickable(0);
508 mVFActor->GetProperty()->SetLineWidth(mVFWidth);
509 this->UpdateDisplayExtent();
510 this->GetRenderer()->AddActor(mVFActor);
513 SetTSlice(mCurrentTSlice);
516 //------------------------------------------------------------------------------
519 //------------------------------------------------------------------------------
520 void vvSlicer::SetLandmarks(vvLandmarks* landmarks)
522 mLandmarks = landmarks;
526 mCross = vtkSmartPointer<vtkCursor3D>::New();
527 mCross->SetFocalPoint(0.0,0.0,0.0);
528 mCross->SetModelBounds(-10,10,-10,10,-10,10);
533 mLandGlyph = vtkSmartPointer<vtkGlyph3D>::New();
534 mLandGlyph->SetSource(mCross->GetOutput());
535 mLandGlyph->SetInput(landmarks->GetOutput());
536 //mLandGlyph->SetIndexModeToScalar();
537 mLandGlyph->SetRange(0,1);
538 mLandGlyph->ScalingOff();
540 mLandGlyph->SetColorModeToColorByScalar();
543 mClipBox = vtkSmartPointer<vtkBox>::New();
545 mLandClipper = vtkSmartPointer<vtkClipPolyData>::New();
546 mLandClipper->InsideOutOn();
547 mLandClipper->SetInput(mLandGlyph->GetOutput());
548 mLandClipper->SetClipFunction(mClipBox);
551 mLandMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
552 mLandMapper->SetInputConnection(mLandClipper->GetOutputPort());
553 //mLandMapper->ScalarVisibilityOff();
556 mLandActor = vtkSmartPointer<vtkActor>::New();
557 mLandActor->SetMapper(mLandMapper);
558 mLandActor->GetProperty()->SetColor(255,10,212);
559 mLandActor->SetPickable(0);
560 mLandActor->SetVisibility(true);
561 this->UpdateDisplayExtent();
562 this->GetRenderer()->AddActor(mLandActor);
565 //------------------------------------------------------------------------------
567 //------------------------------------------------------------------------------
568 //FIXME: this function leaks memory, we should fix it someday :)
569 void vvSlicer::RemoveActor(const std::string& actor_type, int overlay_index)
571 if (actor_type == "vector") {
572 Renderer->RemoveActor(mVFActor);
581 if (actor_type == "overlay") {
582 Renderer->RemoveActor(mOverlayActor);
584 mOverlayActor = NULL;
585 mOverlayMapper = NULL;
587 if (actor_type == "fusion") {
588 Renderer->RemoveActor(mFusionActor);
591 mFusionMapper = NULL;
593 if (actor_type == "contour") {
594 Renderer->RemoveActor(this->mSurfaceCutActors[overlay_index]->GetActor());
595 mSurfaceCutActors.erase(mSurfaceCutActors.begin()+overlay_index);
598 //------------------------------------------------------------------------------
601 //------------------------------------------------------------------------------
602 void vvSlicer::SetVFSubSampling(int sub)
605 mVOIFilter->SetSampleRate(mSubSampling,mSubSampling,mSubSampling);
608 UpdateDisplayExtent();
611 //------------------------------------------------------------------------------
614 //------------------------------------------------------------------------------
615 void vvSlicer::SetVFScale(int scale)
619 mArrow->SetScale(mScale);
620 UpdateDisplayExtent();
623 //------------------------------------------------------------------------------
625 //------------------------------------------------------------------------------
626 void vvSlicer::SetVFWidth(int width)
630 mVFActor->GetProperty()->SetLineWidth(mVFWidth);
631 UpdateDisplayExtent();
634 //------------------------------------------------------------------------------
637 //------------------------------------------------------------------------------
638 void vvSlicer::SetVFLog(int log)
642 mGlyphFilter->SetUseLog(mVFLog);
643 mGlyphFilter->Modified();
645 UpdateDisplayExtent();
648 //------------------------------------------------------------------------------
651 //------------------------------------------------------------------------------
652 void vvSlicer::SetTSlice(int t)
656 else if ((unsigned int)t >= mImage->GetVTKImages().size())
657 t = mImage->GetVTKImages().size() -1;
659 if (mCurrentTSlice == t) return;
662 mImageReslice->SetInput( mImage->GetVTKImages()[mCurrentTSlice] );
663 if (mVF && mVFActor->GetVisibility()) {
664 if (mVF->GetVTKImages().size() > (unsigned int)mCurrentTSlice)
665 mVOIFilter->SetInput(mVF->GetVTKImages()[mCurrentTSlice]);
667 if (mOverlay && mOverlayActor->GetVisibility()) {
668 if (mOverlay->GetVTKImages().size() > (unsigned int)mCurrentTSlice)
669 mOverlayReslice->SetInput( mOverlay->GetVTKImages()[mCurrentTSlice] );
671 if (mFusion && mFusionActor->GetVisibility()) {
672 if (mFusion->GetVTKImages().size() > (unsigned int)mCurrentTSlice)
673 mFusionReslice->SetInput( mFusion->GetVTKImages()[mCurrentTSlice]);
675 if (mSurfaceCutActors.size() > 0)
676 for (std::vector<vvMeshActor*>::iterator i=mSurfaceCutActors.begin();
677 i!=mSurfaceCutActors.end(); i++)
678 (*i)->SetTimeSlice(mCurrentTSlice);
679 UpdateDisplayExtent();
681 //------------------------------------------------------------------------------
684 //------------------------------------------------------------------------------
685 int vvSlicer::GetTSlice()
687 return mCurrentTSlice;
689 //------------------------------------------------------------------------------
691 //------------------------------------------------------------------------------
692 void vvSlicer::SetSliceOrientation(int orientation)
694 //if 2D image, force to watch in Axial View
696 this->GetInput()->GetWholeExtent(extent);
697 if (extent[5]-extent[4] <= 2)
698 orientation = vtkImageViewer2::SLICE_ORIENTATION_XY;
700 if (orientation < vtkImageViewer2::SLICE_ORIENTATION_YZ ||
701 orientation > vtkImageViewer2::SLICE_ORIENTATION_XY) {
702 vtkErrorMacro("Error - invalid slice orientation " << orientation);
706 this->SliceOrientation = orientation;
709 AdjustResliceToSliceOrientation(mFusionReslice);
712 AdjustResliceToSliceOrientation(mOverlayReslice);
715 int *range = this->GetSliceRange();
717 this->Slice = static_cast<int>((range[0] + range[1]) * 0.5);
719 // Go to current cursor position
720 // double* cursorPos = GetCursorPosition();
721 // DDV(cursorPos, 3);
722 // SetCurrentPosition(cursorPos[0],cursorPos[1],cursorPos[2],cursorPos[3]);
724 this->UpdateOrientation();
725 this->UpdateDisplayExtent();
727 if (this->Renderer && this->GetInput()) {
728 double scale = this->Renderer->GetActiveCamera()->GetParallelScale();
729 this->Renderer->ResetCamera();
730 this->Renderer->GetActiveCamera()->SetParallelScale(scale);
735 //----------------------------------------------------------------------------
737 //------------------------------------------------------------------------------
738 // This function ensures that we sample the slices of a vtkImageReslice filter
739 // in the direction of the slicer (SliceOrientation) similarly as mImageReslice.
740 // In other words, we change the grid of the reslice in the same way as the grid
741 // of the displayed image in the slicing direction.
742 void vvSlicer::AdjustResliceToSliceOrientation(vtkImageReslice *reslice)
745 double origin[3] = {VTK_DOUBLE_MAX, VTK_DOUBLE_MAX, VTK_DOUBLE_MAX};
746 double spacing[3] = {VTK_DOUBLE_MAX, VTK_DOUBLE_MAX, VTK_DOUBLE_MAX};
747 reslice->SetOutputOrigin(origin);
748 reslice->SetOutputSpacing(spacing);
749 reslice->GetOutput()->UpdateInformation();
750 reslice->GetOutput()->GetOrigin(origin);
751 reslice->GetOutput()->GetSpacing(spacing);
753 // Use similar spacing as the image in the direction SliceOrientation
754 spacing[this->SliceOrientation] = mImageReslice->GetOutput()->GetSpacing()[this->SliceOrientation];
756 // Modify origin to be on the image grid in the direction SliceOrientation in 3 steps
757 // Step 1: from world coordinates to image coordinates
758 origin[this->SliceOrientation] -= mImageReslice->GetOutput()->GetOrigin()[this->SliceOrientation];
759 origin[this->SliceOrientation] /= mImageReslice->GetOutput()->GetSpacing()[this->SliceOrientation];
760 // Step 2: round to superior grid positionInc
761 origin[this->SliceOrientation] = itk::Math::Ceil<double>(origin[this->SliceOrientation]);
762 // Step 3: back to world coordinates
763 origin[this->SliceOrientation] *= mImageReslice->GetOutput()->GetSpacing()[this->SliceOrientation];
764 origin[this->SliceOrientation] += mImageReslice->GetOutput()->GetOrigin()[this->SliceOrientation];
766 // Set new spacing and origin
767 reslice->SetOutputOrigin(origin);
768 reslice->SetOutputSpacing(spacing);
769 reslice->UpdateInformation();
771 //------------------------------------------------------------------------------
773 //----------------------------------------------------------------------------
774 int * vvSlicer::GetExtent()
777 if (mUseReducedExtent) {
778 w_ext = mReducedExtent;
779 } else w_ext = GetInput()->GetWholeExtent();
782 //----------------------------------------------------------------------------
785 //----------------------------------------------------------------------------
786 int vvSlicer::GetOrientation()
788 return this->SliceOrientation;
790 //----------------------------------------------------------------------------
793 //----------------------------------------------------------------------------
794 void vvSlicer::UpdateDisplayExtent()
796 vtkImageData *input = this->GetInput();
797 if (!input || !this->ImageActor) {
800 input->UpdateInformation();
802 // Local copy of extent
804 for(unsigned int i=0; i<6; i++){
805 if (mUseReducedExtent)
806 w_ext[i] = mReducedExtent[i];
808 w_ext[i] = input->GetWholeExtent()[i];
812 w_ext[ this->SliceOrientation*2 ] = this->Slice;
813 w_ext[ this->SliceOrientation*2+1 ] = this->Slice;
816 this->ImageActor->SetDisplayExtent(w_ext);
818 // Overlay image actor
819 if (mOverlay && mOverlayActor->GetVisibility()) {
821 mOverlayReslice->GetOutput()->UpdateInformation();
822 this->ConvertImageToImageDisplayExtent(input, w_ext, mOverlayReslice->GetOutput(), overExtent);
823 ClipDisplayedExtent(overExtent, mOverlayMapper->GetInput()->GetWholeExtent());
824 mOverlayActor->SetDisplayExtent( overExtent );
827 // Fusion image actor
828 if (mFusion && mFusionActor->GetVisibility()) {
830 mFusionReslice->GetOutput()->UpdateInformation();
831 this->ConvertImageToImageDisplayExtent(input, w_ext, mFusionReslice->GetOutput(), fusExtent);
832 ClipDisplayedExtent(fusExtent, mFusionMapper->GetInput()->GetWholeExtent());
833 mFusionActor->SetDisplayExtent(fusExtent);
836 // Vector field actor
837 double* camera = Renderer->GetActiveCamera()->GetPosition();
838 double* image_bounds = ImageActor->GetBounds();
839 double position[3] = {0, 0, 0};
840 position[this->SliceOrientation] = image_bounds[this->SliceOrientation*2];
842 //print_vector<double, 6>("camera", camera);
843 //print_vector<double, 6>("image_bounds", image_bounds);
844 //print_vector<double, 3>("position", position);
846 // find where to place the VF actor. to deal with
847 // z-buffer issues, the VF is placed right in front of the image,
848 // subject to a small offset. the position actually depends on the
849 // the location of the camera relative to the image.
851 if (camera[this->SliceOrientation] < image_bounds[this->SliceOrientation*2])
854 if (mVF && mVFActor->GetVisibility()) {
856 mVF->GetVTKImages()[0]->UpdateInformation();
857 this->ConvertImageToImageDisplayExtent(input, w_ext, mVF->GetVTKImages()[0], vfExtent);
858 ClipDisplayedExtent(vfExtent, mVOIFilter->GetInput()->GetWholeExtent());
859 mVOIFilter->SetVOI(vfExtent);
860 int orientation[3] = {1,1,1};
861 orientation[this->SliceOrientation] = 0;
862 mGlyphFilter->SetOrientation(orientation[0], orientation[1], orientation[2]);
865 position[this->SliceOrientation] += offset;
866 mVFActor->SetPosition(position);
873 for(unsigned int i=0; i<6; i++)
874 bounds[i] = ImageActor->GetBounds()[i];
875 bounds[ this->SliceOrientation*2 ] = ImageActor->GetBounds()[ this->SliceOrientation*2 ]-fabs(this->GetInput()->GetSpacing()[this->SliceOrientation]);
876 bounds[ this->SliceOrientation*2+1 ] = ImageActor->GetBounds()[ this->SliceOrientation*2+1 ]+fabs(this->GetInput()->GetSpacing()[this->SliceOrientation]);
877 mClipBox->SetBounds(bounds);
881 position[this->SliceOrientation] = offset;
882 mLandActor->SetPosition(position);
885 // Figure out the correct clipping range
886 if (this->Renderer) {
887 if (this->InteractorStyle &&
888 this->InteractorStyle->GetAutoAdjustCameraClippingRange()) {
889 this->Renderer->ResetCameraClippingRange();
891 vtkCamera *cam = this->Renderer->GetActiveCamera();
894 this->ImageActor->GetBounds(bounds);
895 double spos = (double)bounds[this->SliceOrientation * 2];
896 double cpos = (double)cam->GetPosition()[this->SliceOrientation];
897 double range = fabs(spos - cpos);
898 double *spacing = input->GetSpacing();
900 ((double)spacing[0] + (double)spacing[1] + (double)spacing[2]) / 3.0;
901 cam->SetClippingRange(range - avg_spacing * 3.0, range + avg_spacing * 3.0);
907 //----------------------------------------------------------------------------
909 //----------------------------------------------------------------------------
910 void vvSlicer::ConvertImageToImageDisplayExtent(vtkImageData *sourceImage, const int sourceExtent[6],
911 vtkImageData *targetImage, int targetExtent[6])
914 for(unsigned int i=0; i<6; i++) {
915 // From source voxel coordinates to world coordinates
916 dExtents[i] = sourceImage->GetOrigin()[i/2] + sourceImage->GetSpacing()[i/2] * sourceExtent[i];
918 // From world coordinates to floating point target voxel coordinates
919 dExtents[i] = (dExtents[i]- targetImage->GetOrigin()[i/2]) / targetImage->GetSpacing()[i/2];
922 targetExtent[i] = itk::Math::Round<double>(dExtents[i]);
925 //----------------------------------------------------------------------------
927 //----------------------------------------------------------------------------
928 void vvSlicer::ClipDisplayedExtent(int extent[6], int refExtent[6])
933 //2D overlay on 3D image specific case
934 if (refExtent[4] == refExtent[5]) {
936 extent[4] = refExtent[4];
937 extent[5] = refExtent[5];
940 for (int i = 0; i < maxBound; i = i+2) {
941 //if we are totally outside the image
942 if ( extent[i] > refExtent[i+1] || extent[i+1] < refExtent[i] ) {
946 //crop to the limit of the image
947 extent[i] = (extent[i] > refExtent[i]) ? extent[i] : refExtent[i];
948 extent[i] = (extent[i] < refExtent[i+1]) ? extent[i] : refExtent[i+1];
949 extent[i+1] = (extent[i+1] > refExtent[i]) ? extent[i+1] : refExtent[i];
950 extent[i+1] = (extent[i+1] < refExtent[i+1]) ? extent[i+1] : refExtent[i+1];
953 for (int i = 0; i < maxBound; i = i+2) {
954 extent[i] = refExtent[i];
955 extent[i+1] = refExtent[i];
958 //----------------------------------------------------------------------------
961 //----------------------------------------------------------------------------
962 void vvSlicer::UpdateOrientation()
964 // Set the camera position
965 vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL;
967 switch (this->SliceOrientation) {
968 case vtkImageViewer2::SLICE_ORIENTATION_XY:
969 cam->SetFocalPoint(0,0,0);
970 cam->SetPosition(0,0,-1); // -1 if medical ?
971 cam->SetViewUp(0,-1,0);
974 case vtkImageViewer2::SLICE_ORIENTATION_XZ:
975 cam->SetFocalPoint(0,0,0);
976 cam->SetPosition(0,-1,0); // 1 if medical ?
977 cam->SetViewUp(0,0,1);
980 case vtkImageViewer2::SLICE_ORIENTATION_YZ:
981 cam->SetFocalPoint(0,0,0);
982 cam->SetPosition(-1,0,0); // -1 if medical ?
983 cam->SetViewUp(0,0,1);
988 //----------------------------------------------------------------------------
991 //----------------------------------------------------------------------------
992 void vvSlicer::SetOpacity(double s)
994 this->GetImageActor()->SetOpacity(s);
996 //----------------------------------------------------------------------------
999 //----------------------------------------------------------------------------
1000 void vvSlicer::SetRenderWindow(int orientation, vtkRenderWindow * rw)
1002 this->Superclass::SetRenderWindow(rw);
1003 this->SetupInteractor(rw->GetInteractor());
1004 ca->SetImageActor(this->GetImageActor());
1005 ca->SetWindowLevel(this->GetWindowLevel());
1006 ca->SetText(2, "<slice>");
1007 ca->SetText(3, "<window>\n<level>");
1019 crossCursor->SetModelBounds(bounds);
1020 this->GetRenderer()->AddActor(pdmA);
1021 this->GetRenderer()->AddActor(ca);
1022 this->GetRenderer()->ResetCamera();
1024 //this is just a mapping between the labeling of the orientations presented to the user and
1025 //the one used by vtk
1026 SetSliceOrientation(2-(orientation%3));
1029 //----------------------------------------------------------------------------
1032 //----------------------------------------------------------------------------
1033 void vvSlicer::ResetCamera()
1035 this->GetRenderer()->ResetCamera();
1037 //----------------------------------------------------------------------------
1040 //----------------------------------------------------------------------------
1041 void vvSlicer::SetDisplayMode(bool i)
1043 this->GetImageActor()->SetVisibility(i);
1044 this->GetAnnotation()->SetVisibility(i);
1045 this->GetRenderer()->SetDraw(i);
1047 mLandActor->SetVisibility(i);
1048 pdmA->SetVisibility(i);
1050 UpdateDisplayExtent();
1052 //----------------------------------------------------------------------------
1055 //----------------------------------------------------------------------------
1056 void vvSlicer::FlipHorizontalView()
1058 vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL;
1060 double *position = cam->GetPosition();
1061 switch (this->SliceOrientation) {
1062 case vtkImageViewer2::SLICE_ORIENTATION_XY:
1063 cam->SetPosition(position[0],position[1],-position[2]);
1066 case vtkImageViewer2::SLICE_ORIENTATION_XZ:
1067 cam->SetPosition(position[0],-position[1],position[2]);
1070 case vtkImageViewer2::SLICE_ORIENTATION_YZ:
1071 cam->SetPosition(-position[0],position[1],position[2]);
1074 this->Renderer->ResetCameraClippingRange();
1075 this->UpdateDisplayExtent();
1078 //----------------------------------------------------------------------------
1081 //----------------------------------------------------------------------------
1082 void vvSlicer::FlipVerticalView()
1084 vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL;
1086 FlipHorizontalView();
1087 double *viewup = cam->GetViewUp();
1088 cam->SetViewUp(-viewup[0],-viewup[1],-viewup[2]);
1089 this->UpdateDisplayExtent();
1092 //----------------------------------------------------------------------------
1095 //----------------------------------------------------------------------------
1096 void vvSlicer::SetColorWindow(double window)
1098 vtkLookupTable* LUT = static_cast<vtkLookupTable*>(this->GetWindowLevel()->GetLookupTable());
1100 double level = this->GetWindowLevel()->GetLevel();
1101 LUT->SetTableRange(level-fabs(window)/4,level+fabs(window)/4);
1104 this->vtkImageViewer2::SetColorWindow(window);
1106 //----------------------------------------------------------------------------
1109 //----------------------------------------------------------------------------
1110 void vvSlicer::SetColorLevel(double level)
1112 vtkLookupTable* LUT = static_cast<vtkLookupTable*>(this->GetWindowLevel()->GetLookupTable());
1114 double window = this->GetWindowLevel()->GetWindow();
1115 LUT->SetTableRange(level-fabs(window)/4,level+fabs(window)/4);
1118 this->vtkImageViewer2::SetColorLevel(level);
1120 //----------------------------------------------------------------------------
1122 //----------------------------------------------------------------------------
1123 // Returns the min an the max value in a 41x41 region around the mouse pointer
1124 void vvSlicer::GetExtremasAroundMousePointer(double & min, double & max)
1126 //Get mouse pointer position in view coordinates
1127 double fLocalExtents[6];
1128 for(int i=0; i<3; i++) {
1129 fLocalExtents[i*2 ] = mCurrent[i];
1130 fLocalExtents[i*2+1] = mCurrent[i];
1132 this->Renderer->WorldToView(fLocalExtents[0], fLocalExtents[2], fLocalExtents[4]);
1133 this->Renderer->WorldToView(fLocalExtents[1], fLocalExtents[3], fLocalExtents[5]);
1134 for(int i=0; i<3; i++) {
1135 if (i!=SliceOrientation) { //SR: assumes that SliceOrientation is valid in ViewCoordinates (???)
1136 fLocalExtents[i*2 ] -= 0.2;
1137 fLocalExtents[i*2+1] += 0.2;
1140 this->Renderer->ViewToWorld(fLocalExtents[0], fLocalExtents[2], fLocalExtents[4]);
1141 this->Renderer->ViewToWorld(fLocalExtents[1], fLocalExtents[3], fLocalExtents[5]);
1143 //Convert to image pixel coordinates (rounded)
1144 int iLocalExtents[6];
1145 for(int i=0; i<3; i++) {
1146 fLocalExtents[i*2 ] = (fLocalExtents[i*2 ] - this->GetInput()->GetOrigin()[i])/this->GetInput()->GetSpacing()[i];
1147 fLocalExtents[i*2+1] = (fLocalExtents[i*2+1] - this->GetInput()->GetOrigin()[i])/this->GetInput()->GetSpacing()[i];
1149 iLocalExtents[i*2 ] = lrint(fLocalExtents[i*2 ]);
1150 iLocalExtents[i*2+1] = lrint(fLocalExtents[i*2+1]);
1152 if(iLocalExtents[i*2 ]>iLocalExtents[i*2+1])
1153 std::swap(iLocalExtents[i*2], iLocalExtents[i*2+1]);
1156 vtkSmartPointer<vtkExtractVOI> voiFilter = vtkSmartPointer<vtkExtractVOI>::New();
1157 voiFilter->SetInput(this->GetInput());
1158 voiFilter->SetVOI(iLocalExtents);
1159 voiFilter->Update();
1160 if (!voiFilter->GetOutput()->GetNumberOfPoints()) {
1166 vtkSmartPointer<vtkImageAccumulate> accFilter = vtkSmartPointer<vtkImageAccumulate>::New();
1167 accFilter->SetInput(voiFilter->GetOutput());
1168 accFilter->Update();
1170 min = *(accFilter->GetMin());
1171 max = *(accFilter->GetMax());
1173 //----------------------------------------------------------------------------
1175 //----------------------------------------------------------------------------
1176 double vvSlicer::GetScalarComponentAsDouble(vtkImageData *image, double X, double Y, double Z, int &ix, int &iy, int &iz, int component)
1181 if (ix < image->GetWholeExtent()[0] ||
1182 ix > image->GetWholeExtent()[1] ||
1183 iy < image->GetWholeExtent()[2] ||
1184 iy > image->GetWholeExtent()[3] ||
1185 iz < image->GetWholeExtent()[4] ||
1186 iz > image->GetWholeExtent()[5] )
1187 return std::numeric_limits<double>::quiet_NaN();
1189 image->SetUpdateExtent(ix, ix, iy, iy, iz, iz);
1191 return image->GetScalarComponentAsDouble(ix, iy, iz, component);
1193 //----------------------------------------------------------------------------
1195 //----------------------------------------------------------------------------
1196 void vvSlicer::Render()
1198 if (this->GetWindowLevel()->GetLookupTable() && !this->mOverlay && !this->mFusion) {
1199 legend->SetLookupTable(this->GetWindowLevel()->GetLookupTable());
1200 legend->SetVisibility(1);
1201 } else legend->SetVisibility(0);
1203 if (ca->GetVisibility()) {
1204 std::stringstream worldPos;
1205 double X = (mCurrent[0] - this->GetInput()->GetOrigin()[0])/this->GetInput()->GetSpacing()[0];
1206 double Y = (mCurrent[1] - this->GetInput()->GetOrigin()[1])/this->GetInput()->GetSpacing()[1];
1207 double Z = (mCurrent[2] - this->GetInput()->GetOrigin()[2])/this->GetInput()->GetSpacing()[2];
1209 // if (X < this->GetInput()->GetWholeExtent()[0]) X = this->GetInput()->GetWholeExtent()[0];
1210 // else if (X > this->GetInput()->GetWholeExtent()[1]) X = this->GetInput()->GetWholeExtent()[1];
1211 // if (Y < this->GetInput()->GetWholeExtent()[2]) Y = this->GetInput()->GetWholeExtent()[2];
1212 // else if (Y > this->GetInput()->GetWholeExtent()[3]) Y = this->GetInput()->GetWholeExtent()[3];
1213 // if (Z < this->GetInput()->GetWholeExtent()[4]) Z = this->GetInput()->GetWholeExtent()[4];
1214 // else if (Z > this->GetInput()->GetWholeExtent()[5]) Z = this->GetInput()->GetWholeExtent()[5];
1216 if (X >= this->GetInput()->GetWholeExtent()[0] &&
1217 X <= this->GetInput()->GetWholeExtent()[1] &&
1218 Y >= this->GetInput()->GetWholeExtent()[2] &&
1219 Y <= this->GetInput()->GetWholeExtent()[3] &&
1220 Z >= this->GetInput()->GetWholeExtent()[4] &&
1221 Z <= this->GetInput()->GetWholeExtent()[5]) {
1225 double value = this->GetScalarComponentAsDouble(this->GetInput(), X, Y, Z, ix, iy, iz);
1227 worldPos << "data value : " << value << std::endl;
1228 worldPos << "mm : " << lrint(mCurrent[0]) << ' '
1229 << lrint(mCurrent[1]) << ' '
1230 << lrint(mCurrent[2]) << ' '
1233 worldPos << "pixel : " << ix << ' '
1239 ca->SetText(1,worldPos.str().c_str());
1242 if (pdmA->GetVisibility()) {
1243 double x = mCursor[0];
1244 double y = mCursor[1];
1245 double z = mCursor[2];
1246 double xCursor = (x - this->GetInput()->GetOrigin()[0])/this->GetInput()->GetSpacing()[0];
1247 double yCursor = (y - this->GetInput()->GetOrigin()[1])/this->GetInput()->GetSpacing()[1];
1248 double zCursor = (z - this->GetInput()->GetOrigin()[2])/this->GetInput()->GetSpacing()[2];
1250 if (xCursor >= this->GetImageActor()->GetDisplayExtent()[0] &&
1251 xCursor < this->GetImageActor()->GetDisplayExtent()[1]+1 &&
1252 yCursor >= this->GetImageActor()->GetDisplayExtent()[2] &&
1253 yCursor < this->GetImageActor()->GetDisplayExtent()[3]+1 &&
1254 zCursor >= this->GetImageActor()->GetDisplayExtent()[4] &&
1255 zCursor < this->GetImageActor()->GetDisplayExtent()[5]+1 ) {
1256 vtkRenderer * renderer = this->Renderer;
1258 renderer->WorldToView(x,y,z);
1259 renderer->ViewToNormalizedViewport(x,y,z);
1260 renderer->NormalizedViewportToViewport(x,y);
1261 renderer->ViewportToNormalizedDisplay(x,y);
1262 renderer->NormalizedDisplayToDisplay(x,y);
1263 crossCursor->SetFocalPoint(x,y,z);
1265 crossCursor->SetFocalPoint(-1,-1,z);
1269 if (mOverlay && mOverlayActor->GetVisibility()) {
1270 mOverlayMapper->SetWindow(this->GetColorWindow());
1271 mOverlayMapper->SetLevel(this->GetColorLevel());
1272 mOverlayMapper->GetOutput()->SetUpdateExtent(mOverlayActor->GetDisplayExtent());
1273 mOverlayMapper->GetOutput()->Update();
1274 mOverlayMapper->Update();
1279 this->GetRenderWindow()->Render();
1281 //----------------------------------------------------------------------------
1284 //----------------------------------------------------------------------------
1285 void vvSlicer::UpdateCursorPosition()
1287 if (this->GetImageActor()->GetVisibility()) {
1288 pdmA->SetVisibility(true);
1289 mCursor[0] = mCurrent[0];
1290 mCursor[1] = mCurrent[1];
1291 mCursor[2] = mCurrent[2];
1292 mCursor[3] = mCurrentTSlice;
1295 //----------------------------------------------------------------------------
1298 //----------------------------------------------------------------------------
1299 void vvSlicer::UpdateLandmarks()
1301 vtkPolyData *pd = static_cast<vtkPolyData*>(mLandClipper->GetInput());
1302 if (pd->GetPoints()) {
1303 mLandGlyph->SetRange(0,1);
1304 mLandGlyph->Modified();
1305 mLandGlyph->Update();
1307 mClipBox->Modified();
1308 mLandClipper->Update();
1309 mLandMapper->Update();
1313 //----------------------------------------------------------------------------
1316 //----------------------------------------------------------------------------
1317 void vvSlicer::SetSlice(int slice)
1319 int *range = this->GetSliceRange();
1321 if (slice < range[0]) {
1323 } else if (slice > range[1]) {
1328 if (this->Slice == slice) {
1332 this->Slice = slice;
1335 this->UpdateDisplayExtent();
1337 // Seems to work without this line
1340 //----------------------------------------------------------------------------
1343 //----------------------------------------------------------------------------
1344 void vvSlicer::SetContourSlice()
1346 if (mSurfaceCutActors.size() > 0)
1347 for (std::vector<vvMeshActor*>::iterator i=mSurfaceCutActors.begin();
1348 i!=mSurfaceCutActors.end(); i++)
1349 (*i)->SetCutSlice((this->Slice)*this->GetImage()->GetSpacing()[this->SliceOrientation]+
1350 this->GetImage()->GetOrigin()[this->SliceOrientation]);
1352 //----------------------------------------------------------------------------
1355 //----------------------------------------------------------------------------
1356 void vvSlicer::ForceUpdateDisplayExtent()
1358 this->UpdateDisplayExtent();
1360 //----------------------------------------------------------------------------
1363 //----------------------------------------------------------------------------
1364 int* vvSlicer::GetDisplayExtent()
1366 return this->GetImageActor()->GetDisplayExtent();
1368 //----------------------------------------------------------------------------
1371 //----------------------------------------------------------------------------
1372 void vvSlicer::PrintSelf(ostream& os, vtkIndent indent)
1374 this->Superclass::PrintSelf(os, indent);
1376 //----------------------------------------------------------------------------
1378 //----------------------------------------------------------------------------
1379 void vvSlicer::SetVFColor(double r, double g, double b)
1381 double mVFColorHSV[3];
1386 vtkMath::RGBToHSV(mVFColor, mVFColorHSV);
1387 mVFColorLUT->SetHueRange(mVFColorHSV[0], mVFColorHSV[0]);
1388 mVFColorLUT->SetSaturationRange(mVFColorHSV[1],mVFColorHSV[1]);
1389 mVFColorLUT->SetValueRange(mVFColorHSV[2], mVFColorHSV[2]);