X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=vv%2FvvSlicer.cxx;h=a915a6b84b1b616e16430e23dad84853e2d7eee3;hb=497f4e3a54a75a1dce99ad4a94a3aaa1ea904323;hp=2255cce74c5b8a719ec671caaddbea425636eb4b;hpb=4990db0e34e1095b4812a203d7cd46618a5e8c3d;p=clitk.git diff --git a/vv/vvSlicer.cxx b/vv/vvSlicer.cxx index 2255cce..a915a6b 100644 --- a/vv/vvSlicer.cxx +++ b/vv/vvSlicer.cxx @@ -3,7 +3,7 @@ Authors belong to: - University of LYON http://www.universite-lyon.fr/ - - Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr + - Léon Bérard cancer center http://www.centreleonberard.fr - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr This software is distributed WITHOUT ANY WARRANTY; without even @@ -14,14 +14,13 @@ - 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 @@ -66,26 +65,34 @@ #include #include #include +#if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION >= 10) +# include +#endif vtkCxxRevisionMacro(vvSlicer, "DummyRevision"); vtkStandardNewMacro(vvSlicer); - +static void copyExtent(int* in, int* to){ + for(int i=0; i<6; ++i) to[i]=in[i]; +} //------------------------------------------------------------------------------ vvSlicer::vvSlicer() { this->UnInstallPipeline(); mImage = NULL; + mReducedExtent = new int[6]; mCurrentTSlice = 0; + mCurrentFusionTSlice = 0; + mCurrentOverlayTSlice = 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; + mCursor[0] = 0;//-VTK_DOUBLE_MAX; + mCursor[1] = 0;//-VTK_DOUBLE_MAX; + mCursor[2] = 0;//-VTK_DOUBLE_MAX; + mCursor[3] = 0;//-VTK_DOUBLE_MAX; mSubSampling = 5; mScale = 1; @@ -95,22 +102,6 @@ vvSlicer::vvSlicer() 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(); @@ -143,11 +134,20 @@ vvSlicer::vvSlicer() legend->SetVisibility(0); legend->SetLabelFormat("%.1f"); this->GetRenderer()->AddActor(legend); - - this->WindowLevel->Delete(); - this->WindowLevel = vvImageMapToWLColors::New(); + showFusionLegend = false; this->InstallPipeline(); + + mLinkOverlayWindowLevel = true; + +#if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION >= 10) + this->GetImageActor()->GetMapper()->BorderOn(); +#endif + + mSlicingTransform = vtkSmartPointer::New(); + mConcatenatedTransform = vtkSmartPointer::New(); + mConcatenatedFusionTransform = vtkSmartPointer::New(); + mConcatenatedOverlayTransform = vtkSmartPointer::New(); } //------------------------------------------------------------------------------ @@ -169,7 +169,7 @@ vvBlendImageActor* vvSlicer::GetOverlayActor() //------------------------------------------------------------------------------ -vtkImageMapToWindowLevelColors* vvSlicer::GetFusionMapper() +vtkImageMapToColors* vvSlicer::GetFusionMapper() { return mFusionMapper.GetPointer(); } @@ -211,7 +211,7 @@ void vvSlicer::EnableReducedExtent(bool b) //------------------------------------------------------------------------------ void vvSlicer::SetReducedExtent(int * ext) { - mReducedExtent = ext; + copyExtent(ext, mReducedExtent); } //------------------------------------------------------------------------------ @@ -289,17 +289,25 @@ vvSlicer::~vvSlicer() for (std::vector::iterator i=mSurfaceCutActors.begin(); i!=mSurfaceCutActors.end(); i++) delete (*i); + delete [] mReducedExtent; } //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +double* vvSlicer::GetCurrentPosition() +{ + return mCurrentBeforeSlicingTransform; +} +//------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetCurrentPosition(double x, double y, double z, int t) { - mCurrent[0] = x; - mCurrent[1] = y; - mCurrent[2] = z; - mCurrentTSlice = t; + mCurrentBeforeSlicingTransform[0]=x; + mCurrentBeforeSlicingTransform[1]=y; + mCurrentBeforeSlicingTransform[2]=z; + mSlicingTransform->GetInverse()->TransformPoint(mCurrentBeforeSlicingTransform,mCurrent); + SetTSlice(t); } //------------------------------------------------------------------------------ @@ -309,21 +317,36 @@ void vvSlicer::SetImage(vvImage::Pointer image) { if (image->GetVTKImages().size()) { mImage = image; - this->Superclass::SetInput(image->GetTransformedVTKImages()[0]); + + if (!mImageReslice) { + mImageReslice = vtkSmartPointer::New(); + mImageReslice->SetInterpolationModeToLinear(); + mImageReslice->AutoCropOutputOn(); + mImageReslice->SetBackgroundColor(-1000,-1000,-1000,1); + } + + mConcatenatedTransform->Identity(); + mConcatenatedTransform->Concatenate(mImage->GetTransform()[0]); + mConcatenatedTransform->Concatenate(mSlicingTransform); + mImageReslice->SetResliceTransform(mConcatenatedTransform); + mImageReslice->SetInput(0, mImage->GetFirstVTKImageData()); + mImageReslice->UpdateInformation(); + + this->Superclass::SetInput(mImageReslice->GetOutput()); 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; + 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(); + mImageReslice->GetOutput()->SetUpdateExtent(extent); + mImageReslice->GetOutput()->Update(); this->UpdateDisplayExtent(); @@ -339,19 +362,35 @@ void vvSlicer::SetOverlay(vvImage::Pointer overlay) { if (overlay->GetVTKImages().size()) { mOverlay = overlay; + + if (!mOverlayReslice) { + mOverlayReslice = vtkSmartPointer::New(); + mOverlayReslice->SetInterpolationModeToLinear(); + mOverlayReslice->AutoCropOutputOn(); + mOverlayReslice->SetBackgroundColor(-1000,-1000,-1000,1); + } + + mConcatenatedOverlayTransform->Identity(); + mConcatenatedOverlayTransform->Concatenate(mOverlay->GetTransform()[0]); + mConcatenatedOverlayTransform->Concatenate(mSlicingTransform); + mOverlayReslice->SetResliceTransform(mConcatenatedOverlayTransform); + mOverlayReslice->SetInput(0, mOverlay->GetFirstVTKImageData()); + mImageReslice->UpdateInformation(); if (!mOverlayMapper) mOverlayMapper = vtkSmartPointer::New(); - mOverlayMapper->SetInput(overlay->GetTransformedVTKImages()[0]); + mOverlayMapper->SetInput(mOverlayReslice->GetOutput()); if (!mOverlayActor) { mOverlayActor = vtkSmartPointer::New(); mOverlayActor->SetInput(mOverlayMapper->GetOutput()); mOverlayActor->SetPickable(0); - mOverlayActor->SetVisibility(false); + mOverlayActor->SetVisibility(true); mOverlayActor->SetOpacity(0.5); - this->UpdateDisplayExtent(); - } +#if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION >= 10) + mOverlayActor->GetMapper()->BorderOn(); +#endif + } //stupid but necessary : the Overlay need to be rendered before fusion if (mFusionActor) { @@ -361,8 +400,10 @@ void vvSlicer::SetOverlay(vvImage::Pointer overlay) } else this->GetRenderer()->AddActor(mOverlayActor); - //Synchronize slice - SetTSlice(mCurrentTSlice); + //Synchronize orientation and slice + AdjustResliceToSliceOrientation(mOverlayReslice); + this->UpdateDisplayExtent(); + this->SetTSlice(mCurrentTSlice); } } //------------------------------------------------------------------------------ @@ -374,46 +415,96 @@ void vvSlicer::SetFusion(vvImage::Pointer fusion) if (fusion->GetVTKImages().size()) { mFusion = fusion; + if (!mFusionReslice) { + mFusionReslice = vtkSmartPointer::New(); + mFusionReslice->SetInterpolationModeToLinear(); + mFusionReslice->AutoCropOutputOn(); + mFusionReslice->SetBackgroundColor(-1000,-1000,-1000,1); + } + + mConcatenatedFusionTransform->Identity(); + mConcatenatedFusionTransform->Concatenate(mFusion->GetTransform()[0]); + mConcatenatedFusionTransform->Concatenate(mSlicingTransform); + mFusionReslice->SetResliceTransform(mConcatenatedFusionTransform); + mFusionReslice->SetInput(0, mFusion->GetFirstVTKImageData()); + mFusionReslice->UpdateInformation(); + if (!mFusionMapper) - mFusionMapper = vtkSmartPointer::New(); - mFusionMapper->SetInput(fusion->GetTransformedVTKImages()[0]); + mFusionMapper = vtkSmartPointer::New(); + + vtkSmartPointer lut = vtkLookupTable::New(); + lut->SetRange(0, 1); + lut->SetValueRange(0, 1); + lut->SetSaturationRange(0, 0); + lut->Build(); + mFusionMapper->SetLookupTable(lut); + mFusionMapper->SetInput(mFusionReslice->GetOutput()); if (!mFusionActor) { mFusionActor = vtkSmartPointer::New(); mFusionActor->SetInput(mFusionMapper->GetOutput()); mFusionActor->SetPickable(0); - mFusionActor->SetVisibility(false); + mFusionActor->SetVisibility(true); mFusionActor->SetOpacity(0.7); - this->UpdateDisplayExtent(); +#if VTK_MAJOR_VERSION >= 6 || (VTK_MAJOR_VERSION >= 5 && VTK_MINOR_VERSION >= 10) + mFusionActor->GetMapper()->BorderOn(); +#endif this->GetRenderer()->AddActor(mFusionActor); } - //Synchronize slice - SetTSlice(mCurrentTSlice); + //Synchronize orientation and slice + AdjustResliceToSliceOrientation(mFusionReslice); + this->UpdateDisplayExtent(); + this->SetTSlice(mCurrentTSlice); } } //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +bool vvSlicer::GetActorVisibility(const std::string& actor_type, int overlay_index) +{ + bool vis = false; + if (actor_type == "image") { + vis = this->ImageActor->GetVisibility(); + } + else if (actor_type == "vector") { + vis = this->mVFActor->GetVisibility(); + } + else if (actor_type == "overlay") { + vis = this->mOverlayActor->GetVisibility(); + } + else if (actor_type == "fusion") { + vis = this->mFusionActor->GetVisibility(); + } + else if (actor_type == "contour") + vis = this->mSurfaceCutActors[overlay_index]->GetActor()->GetVisibility(); + + return vis; +} +//------------------------------------------------------------------------------ + //------------------------------------------------------------------------------ void vvSlicer::SetActorVisibility(const std::string& actor_type, int overlay_index ,bool vis) { - if (actor_type == "vector") { + if (actor_type == "image") { + this->ImageActor->SetVisibility(vis); + } + else if (actor_type == "vector") { this->mVFActor->SetVisibility(vis); } - if (actor_type == "overlay") { + else if (actor_type == "overlay") { this->mOverlayActor->SetVisibility(vis); } - if (actor_type == "fusion") { + else if (actor_type == "fusion") { this->mFusionActor->SetVisibility(vis); } - if (actor_type == "contour") + else if (actor_type == "contour") this->mSurfaceCutActors[overlay_index]->GetActor()->SetVisibility(vis); UpdateDisplayExtent(); } //------------------------------------------------------------------------------ - //------------------------------------------------------------------------------ void vvSlicer::SetVF(vvImage::Pointer vf) { @@ -425,7 +516,7 @@ void vvSlicer::SetVF(vvImage::Pointer vf) mVOIFilter = vtkSmartPointer::New(); mVOIFilter->SetSampleRate(mSubSampling,mSubSampling,mSubSampling); } - mVOIFilter->SetInput(vf->GetTransformedVTKImages()[0]); + mVOIFilter->SetInput(vf->GetFirstVTKImageData()); 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); @@ -613,25 +704,44 @@ void vvSlicer::SetVFLog(int log) void vvSlicer::SetTSlice(int t) { if (t < 0) - t = 0; + mCurrentTSlice = 0; else if ((unsigned int)t >= mImage->GetVTKImages().size()) - t = mImage->GetVTKImages().size() -1; + mCurrentTSlice = mImage->GetVTKImages().size() -1; + else + mCurrentTSlice = t; - if (mCurrentTSlice == t) return; + // Update transform + mConcatenatedTransform->Identity(); + mConcatenatedTransform->Concatenate(mImage->GetTransform()[mCurrentTSlice]); + mConcatenatedTransform->Concatenate(mSlicingTransform); - mCurrentTSlice = t; - this->SetInput(mImage->GetTransformedVTKImages()[t]); + // Update image data + mImageReslice->SetInput( mImage->GetVTKImages()[mCurrentTSlice] ); if (mVF && mVFActor->GetVisibility()) { if (mVF->GetVTKImages().size() > (unsigned int)mCurrentTSlice) - mVOIFilter->SetInput(mVF->GetTransformedVTKImages()[mCurrentTSlice]); + mVOIFilter->SetInput(mVF->GetVTKImages()[mCurrentTSlice]); } if (mOverlay && mOverlayActor->GetVisibility()) { - if (mOverlay->GetTransformedVTKImages().size() > (unsigned int)mCurrentTSlice) - mOverlayMapper->SetInput(mOverlay->GetTransformedVTKImages()[mCurrentTSlice]); + if (mOverlay->GetVTKImages().size() > (unsigned int)t) { + mCurrentOverlayTSlice = t; + mOverlayReslice->SetInput( mOverlay->GetVTKImages()[mCurrentOverlayTSlice] ); + + // Update overlay transform + mConcatenatedOverlayTransform->Identity(); + mConcatenatedOverlayTransform->Concatenate(mOverlay->GetTransform()[mCurrentOverlayTSlice]); + mConcatenatedOverlayTransform->Concatenate(mSlicingTransform); + } } if (mFusion && mFusionActor->GetVisibility()) { - if (mFusion->GetVTKImages().size() > (unsigned int)mCurrentTSlice) - mFusionMapper->SetInput(mFusion->GetTransformedVTKImages()[mCurrentTSlice]); + if (mFusion->GetVTKImages().size() > (unsigned int)t) { + mCurrentFusionTSlice = t; + mFusionReslice->SetInput( mFusion->GetVTKImages()[mCurrentFusionTSlice]); + + // Update fusion transform + mConcatenatedFusionTransform->Identity(); + mConcatenatedFusionTransform->Concatenate(mFusion->GetTransform()[mCurrentFusionTSlice]); + mConcatenatedFusionTransform->Concatenate(mSlicingTransform); + } } if (mSurfaceCutActors.size() > 0) for (std::vector::iterator i=mSurfaceCutActors.begin(); @@ -649,6 +759,31 @@ int vvSlicer::GetTSlice() } //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +int vvSlicer::GetMaxCurrentTSlice() +{ + int t = mCurrentTSlice; + if(mOverlay) + t = std::max(t, mCurrentOverlayTSlice); + if(mFusion) + t = std::max(t, mCurrentFusionTSlice); + return t; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int vvSlicer::GetFusionTSlice() +{ + return mCurrentFusionTSlice; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int vvSlicer::GetOverlayTSlice() +{ + return mCurrentOverlayTSlice; +} +//------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvSlicer::SetSliceOrientation(int orientation) @@ -657,26 +792,39 @@ void vvSlicer::SetSliceOrientation(int orientation) int extent[6]; this->GetInput()->GetWholeExtent(extent); if (extent[5]-extent[4] <= 2) - orientation=2; + orientation = vtkImageViewer2::SLICE_ORIENTATION_XY; 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); + if(mFusion) + AdjustResliceToSliceOrientation(mFusionReslice); + + if(mOverlay) + AdjustResliceToSliceOrientation(mOverlayReslice); + // Update the viewer + // Go to current cursor position // double* cursorPos = GetCursorPosition(); // DDV(cursorPos, 3); // SetCurrentPosition(cursorPos[0],cursorPos[1],cursorPos[2],cursorPos[3]); + if (this->Renderer && this->GetInput()) { + double s = mCursor[orientation]; + double sCursor = (s - this->GetInput()->GetOrigin()[orientation])/this->GetInput()->GetSpacing()[orientation]; + this->Slice = static_cast(sCursor); + } + +// int *range = this->GetSliceRange(); +// if (range) +// this->Slice = static_cast((range[0] + range[1]) * 0.5); + this->UpdateOrientation(); this->UpdateDisplayExtent(); @@ -690,10 +838,47 @@ void vvSlicer::SetSliceOrientation(int orientation) } //---------------------------------------------------------------------------- +//------------------------------------------------------------------------------ +// This function ensures that we sample the slices of a vtkImageReslice filter +// in the direction of the slicer (SliceOrientation) similarly as mImageReslice. +// In other words, we change the grid of the reslice in the same way as the grid +// of the displayed image in the slicing direction. +void vvSlicer::AdjustResliceToSliceOrientation(vtkImageReslice *reslice) +{ + // Reset autocrop and update output information + reslice->SetOutputOriginToDefault(); + reslice->SetOutputSpacingToDefault(); + reslice->GetOutput()->UpdateInformation(); + + // Ge new origin / spacing + double origin[3]; + double spacing[3]; + reslice->GetOutput()->GetOrigin(origin); + reslice->GetOutput()->GetSpacing(spacing); + + // Use similar spacing as the image in the direction SliceOrientation + spacing[this->SliceOrientation] = mImageReslice->GetOutput()->GetSpacing()[this->SliceOrientation]; + + // Modify origin to be on the image grid in the direction SliceOrientation in 3 steps + // Step 1: from world coordinates to image coordinates + origin[this->SliceOrientation] -= mImageReslice->GetOutput()->GetOrigin()[this->SliceOrientation]; + origin[this->SliceOrientation] /= mImageReslice->GetOutput()->GetSpacing()[this->SliceOrientation]; + // Step 2: round to superior grid positionInc + origin[this->SliceOrientation] = itk::Math::Ceil(origin[this->SliceOrientation]); + // Step 3: back to world coordinates + origin[this->SliceOrientation] *= mImageReslice->GetOutput()->GetSpacing()[this->SliceOrientation]; + origin[this->SliceOrientation] += mImageReslice->GetOutput()->GetOrigin()[this->SliceOrientation]; + + // Set new spacing and origin + reslice->SetOutputOrigin(origin); + reslice->SetOutputSpacing(spacing); + reslice->UpdateInformation(); + reslice->GetOutput()->UpdateInformation(); +} +//------------------------------------------------------------------------------ //---------------------------------------------------------------------------- -int * vvSlicer::GetExtent() -{ +int * vvSlicer::GetExtent(){ int *w_ext; if (mUseReducedExtent) { w_ext = mReducedExtent; @@ -710,6 +895,7 @@ int vvSlicer::GetOrientation() } //---------------------------------------------------------------------------- + //---------------------------------------------------------------------------- void vvSlicer::UpdateDisplayExtent() { @@ -721,73 +907,80 @@ void vvSlicer::UpdateDisplayExtent() // Local copy of extent int w_ext[6]; - for(unsigned int i=0; i<6; i++){ - if (mUseReducedExtent) - w_ext[i] = mReducedExtent[i]; - else - w_ext[i] = input->GetWholeExtent()[i]; - } - + int* ext = GetExtent(); + copyExtent(ext, w_ext); // Set slice value - w_ext[ this->SliceOrientation*2 ] = this->Slice; - w_ext[ this->SliceOrientation*2+1 ] = this->Slice; + int s = this->Slice > ext[this->SliceOrientation*2+1] ? ext[this->SliceOrientation*2 + 1] : this->Slice; + w_ext[ this->SliceOrientation*2 ] = s; + w_ext[ this->SliceOrientation*2+1 ] = s; // Image actor this->ImageActor->SetDisplayExtent(w_ext); - // Position vector - double position[3] = {0.,0.,0.}; - double positionInc = (Renderer->GetActiveCamera()->GetPosition()[this->SliceOrientation] > this->Slice)?10:-10; - position[this->SliceOrientation] += positionInc; - // Overlay image actor if (mOverlay && mOverlayActor->GetVisibility()) { + AdjustResliceToSliceOrientation(mOverlayReslice); int overExtent[6]; - mOverlay->GetTransformedVTKImages()[0]->UpdateInformation(); - this->ConvertImageToImageDisplayExtent(input, w_ext, mOverlay->GetTransformedVTKImages()[0], overExtent); + this->ConvertImageToImageDisplayExtent(input, w_ext, mOverlayReslice->GetOutput(), overExtent); ClipDisplayedExtent(overExtent, mOverlayMapper->GetInput()->GetWholeExtent()); mOverlayActor->SetDisplayExtent( overExtent ); - mOverlayActor->SetPosition(position); } - position[this->SliceOrientation] += positionInc; // Fusion image actor if (mFusion && mFusionActor->GetVisibility()) { + AdjustResliceToSliceOrientation(mFusionReslice); int fusExtent[6]; - mFusion->GetTransformedVTKImages()[0]->UpdateInformation(); - this->ConvertImageToImageDisplayExtent(input, w_ext, mFusion->GetTransformedVTKImages()[0], fusExtent); + this->ConvertImageToImageDisplayExtent(input, w_ext, mFusionReslice->GetOutput(), fusExtent); ClipDisplayedExtent(fusExtent, mFusionMapper->GetInput()->GetWholeExtent()); mFusionActor->SetDisplayExtent(fusExtent); - mFusionActor->SetPosition(position); } - position[this->SliceOrientation] += positionInc; // Vector field actor + double* camera = Renderer->GetActiveCamera()->GetPosition(); + double* image_bounds = ImageActor->GetBounds(); + double position[3] = {0, 0, 0}; + position[this->SliceOrientation] = image_bounds[this->SliceOrientation*2]; + + //print_vector("camera", camera); + //print_vector("image_bounds", image_bounds); + //print_vector("position", position); + + // find where to place the VF actor. to deal with + // z-buffer issues, the VF is placed right in front of the image, + // subject to a small offset. the position actually depends on the + // the location of the camera relative to the image. + double offset = 1; + if (camera[this->SliceOrientation] < image_bounds[this->SliceOrientation*2]) + offset = -1; + if (mVF && mVFActor->GetVisibility()) { int vfExtent[6]; - mVF->GetTransformedVTKImages()[0]->UpdateInformation(); - this->ConvertImageToImageDisplayExtent(input, w_ext, mVF->GetTransformedVTKImages()[0], vfExtent); + mVF->GetVTKImages()[0]->UpdateInformation(); + this->ConvertImageToImageDisplayExtent(input, w_ext, mVF->GetVTKImages()[0], vfExtent); ClipDisplayedExtent(vfExtent, mVOIFilter->GetInput()->GetWholeExtent()); mVOIFilter->SetVOI(vfExtent); int orientation[3] = {1,1,1}; orientation[this->SliceOrientation] = 0; mGlyphFilter->SetOrientation(orientation[0], orientation[1], orientation[2]); mVFMapper->Update(); + + position[this->SliceOrientation] += offset; mVFActor->SetPosition(position); } - position[this->SliceOrientation] += positionInc; - + // Landmarks actor if (mLandActor) { if (mClipBox) { double bounds [6]; for(unsigned int i=0; i<6; i++) bounds[i] = ImageActor->GetBounds()[i]; - bounds[ this->SliceOrientation*2 ] = ImageActor->GetBounds()[ this->SliceOrientation*2 ]-fabs(0.5/this->GetInput()->GetSpacing()[this->SliceOrientation]); - bounds[ this->SliceOrientation*2+1 ] = ImageActor->GetBounds()[ this->SliceOrientation*2+1 ]+fabs(0.5/this->GetInput()->GetSpacing()[this->SliceOrientation]); + bounds[ this->SliceOrientation*2 ] = ImageActor->GetBounds()[ this->SliceOrientation*2 ]-fabs(this->GetInput()->GetSpacing()[this->SliceOrientation]); + bounds[ this->SliceOrientation*2+1 ] = ImageActor->GetBounds()[ this->SliceOrientation*2+1 ]+fabs(this->GetInput()->GetSpacing()[this->SliceOrientation]); mClipBox->SetBounds(bounds); UpdateLandmarks(); } + + position[this->SliceOrientation] = offset; mLandActor->SetPosition(position); } @@ -805,12 +998,12 @@ void vvSlicer::UpdateDisplayExtent() 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); + double sumSpacing = spacing[0] + spacing[1] + spacing[2]; + cam->SetClippingRange(range - sumSpacing, range + sumSpacing); } } } + } //---------------------------------------------------------------------------- @@ -827,7 +1020,8 @@ void vvSlicer::ConvertImageToImageDisplayExtent(vtkImageData *sourceImage, const dExtents[i] = (dExtents[i]- targetImage->GetOrigin()[i/2]) / targetImage->GetSpacing()[i/2]; // Round to nearest - targetExtent[i] = itk::Math::Round(dExtents[i]); + //targetExtent[i] = itk::Math::Round(dExtents[i]); + targetExtent[i] = itk::Math::Floor(dExtents[i]); } } //---------------------------------------------------------------------------- @@ -948,12 +1142,7 @@ void vvSlicer::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(); } @@ -966,7 +1155,11 @@ void vvSlicer::FlipHorizontalView() vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : NULL; if (cam) { double *position = cam->GetPosition(); - switch (this->SliceOrientation) { + double factor[3] = {1, 1, 1}; + factor[this->SliceOrientation] = -1; + cam->SetPosition(factor[0]*position[0],factor[1]*position[1],factor[2]*position[2]); + +/* switch (this->SliceOrientation) { case vtkImageViewer2::SLICE_ORIENTATION_XY: cam->SetPosition(position[0],position[1],-position[2]); break; @@ -978,7 +1171,8 @@ void vvSlicer::FlipHorizontalView() case vtkImageViewer2::SLICE_ORIENTATION_YZ: cam->SetPosition(-position[0],position[1],position[2]); break; - } + }*/ + this->Renderer->ResetCameraClippingRange(); this->UpdateDisplayExtent(); } @@ -1006,21 +1200,20 @@ 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->SetTableRange(level-fabs(window)/2,level+fabs(window)/2); 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->SetTableRange(level-fabs(window)/2,level+fabs(window)/2); LUT->Build(); } this->vtkImageViewer2::SetColorLevel(level); @@ -1028,41 +1221,81 @@ void vvSlicer::SetColorLevel(double level) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -// Returns the min an the max value in a 41x41 region around the mouse pointer -void vvSlicer::GetExtremasAroundMousePointer(double & min, double & max) +double vvSlicer::GetOverlayColorWindow() +{ + if(mOverlayMapper) + return mOverlayMapper->GetWindow(); + else + return 0.; +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +double vvSlicer::GetOverlayColorLevel() +{ + if(mOverlayMapper) + return mOverlayMapper->GetLevel(); + else + return 0.; +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicer::SetOverlayColorWindow(double window) +{ + mOverlayMapper->SetWindow(window); +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +void vvSlicer::SetOverlayColorLevel(double level) +{ + mOverlayMapper->SetLevel(level); +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// Returns the min an the max value in a 20%x20% region around the mouse pointer +void vvSlicer::GetExtremasAroundMousePointer(double & min, double & max, vtkImageData *image, vtkTransform *transform) { //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]); + double corner1[3]; + double corner2[3]; 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; - } + corner1[i] = mCurrent[i]; + corner2[i] = mCurrent[i]; } - this->Renderer->ViewToWorld(fLocalExtents[0], fLocalExtents[2], fLocalExtents[4]); - this->Renderer->ViewToWorld(fLocalExtents[1], fLocalExtents[3], fLocalExtents[5]); + + this->Renderer->WorldToView(corner1[0], corner1[1], corner1[2]); + this->Renderer->WorldToView(corner2[0], corner2[1], corner2[2]); + + // In view coordinates, x is the slicer width and y is the slicer height are the in-plane axis + int w, h; + this->Renderer->GetTiledSize(&w, &h); + corner1[0] -= 0.2*h/(double)w; + corner2[0] += 0.2*h/(double)w; + corner1[1] -= 0.2; + corner2[1] += 0.2; + this->Renderer->ViewToWorld(corner1[0], corner1[1], corner1[2]); + this->Renderer->ViewToWorld(corner2[0], corner2[1], corner2[2]); //Convert to image pixel coordinates (rounded) + transform->TransformPoint(corner1, corner1); + transform->TransformPoint(corner2, corner2); 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]; + corner1[i] = (corner1[i] - image->GetOrigin()[i])/image->GetSpacing()[i]; + corner2[i] = (corner2[i] - image->GetOrigin()[i])/image->GetSpacing()[i]; - iLocalExtents[i*2 ] = lrint(fLocalExtents[i*2 ]); - iLocalExtents[i*2+1] = lrint(fLocalExtents[i*2+1]); + iLocalExtents[i*2 ] = lrint(corner1[i]); + iLocalExtents[i*2+1] = lrint(corner2[i]); 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->SetInput(image); voiFilter->SetVOI(iLocalExtents); voiFilter->Update(); if (!voiFilter->GetOutput()->GetNumberOfPoints()) { @@ -1081,7 +1314,7 @@ void vvSlicer::GetExtremasAroundMousePointer(double & min, double & max) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -double vvSlicer::GetScalarComponentAsDouble(vtkImageData *image, int X, double Y, double Z, int &ix, int &iy, int &iz, int component) +double vvSlicer::GetScalarComponentAsDouble(vtkImageData *image, double X, double Y, double Z, int &ix, int &iy, int &iz, int component) { ix = lrint(X); iy = lrint(Y); @@ -1092,7 +1325,7 @@ double vvSlicer::GetScalarComponentAsDouble(vtkImageData *image, int X, double Y iy > image->GetWholeExtent()[3] || iz < image->GetWholeExtent()[4] || iz > image->GetWholeExtent()[5] ) - return sqrt(-1.); + return std::numeric_limits::quiet_NaN(); image->SetUpdateExtent(ix, ix, iy, iy, iz, iz); image->Update(); @@ -1103,59 +1336,51 @@ double vvSlicer::GetScalarComponentAsDouble(vtkImageData *image, int X, double Y //---------------------------------------------------------------------------- void vvSlicer::Render() { - if (this->GetWindowLevel()->GetLookupTable() && !this->mOverlay && !this->mFusion) { + if (this->mFusion && mFusionActor->GetVisibility() && showFusionLegend) { + legend->SetLookupTable(this->GetFusionMapper()->GetLookupTable()); + legend->UseOpacityOn(); + legend->SetVisibility(1); + } + else if (this->GetWindowLevel()->GetLookupTable() && !this->mOverlay) { legend->SetLookupTable(this->GetWindowLevel()->GetLookupTable()); + legend->UseOpacityOff(); 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 (X < this->GetInput()->GetWholeExtent()[0]) X = this->GetInput()->GetWholeExtent()[0]; -// else if (X > this->GetInput()->GetWholeExtent()[1]) X = this->GetInput()->GetWholeExtent()[1]; -// if (Y < this->GetInput()->GetWholeExtent()[2]) Y = this->GetInput()->GetWholeExtent()[2]; -// else if (Y > this->GetInput()->GetWholeExtent()[3]) Y = this->GetInput()->GetWholeExtent()[3]; -// if (Z < this->GetInput()->GetWholeExtent()[4]) Z = this->GetInput()->GetWholeExtent()[4]; -// else if (Z > this->GetInput()->GetWholeExtent()[5]) Z = this->GetInput()->GetWholeExtent()[5]; - - 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]) { + std::stringstream worldPos; + double pt[3]; + mConcatenatedTransform->TransformPoint(mCurrent, pt); + double X = (pt[0] - mImage->GetVTKImages()[mCurrentTSlice]->GetOrigin()[0])/mImage->GetVTKImages()[mCurrentTSlice]->GetSpacing()[0]; + double Y = (pt[1] - mImage->GetVTKImages()[mCurrentTSlice]->GetOrigin()[1])/mImage->GetVTKImages()[mCurrentTSlice]->GetSpacing()[1]; + double Z = (pt[2] - mImage->GetVTKImages()[mCurrentTSlice]->GetOrigin()[2])/mImage->GetVTKImages()[mCurrentTSlice]->GetSpacing()[2]; + + if (X >= mImage->GetVTKImages()[mCurrentTSlice]->GetWholeExtent()[0]-0.5 && + X <= mImage->GetVTKImages()[mCurrentTSlice]->GetWholeExtent()[1]+0.5 && + Y >= mImage->GetVTKImages()[mCurrentTSlice]->GetWholeExtent()[2]-0.5 && + Y <= mImage->GetVTKImages()[mCurrentTSlice]->GetWholeExtent()[3]+0.5 && + Z >= mImage->GetVTKImages()[mCurrentTSlice]->GetWholeExtent()[4]-0.5 && + Z <= mImage->GetVTKImages()[mCurrentTSlice]->GetWholeExtent()[5]+0.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(); + double value = this->GetScalarComponentAsDouble(mImage->GetVTKImages()[mCurrentTSlice], X, Y, Z, ix, iy, iz); + + if(ImageActor->GetVisibility()) + worldPos << "data value : " << value << std::endl; + + worldPos << "mm : " << lrint(mCurrentBeforeSlicingTransform[0]) << ' ' + << lrint(mCurrentBeforeSlicingTransform[1]) << ' ' + << lrint(mCurrentBeforeSlicingTransform[2]) << ' ' + << mCurrentTSlice + << std::endl; + worldPos << "pixel : " << ix << ' ' + << iy << ' ' + << iz << ' ' + << mCurrentTSlice + << std::endl; } - ca->SetText(1,worldPos.c_str()); + ca->SetText(1,worldPos.str().c_str()); } if (pdmA->GetVisibility()) { @@ -1186,8 +1411,10 @@ void vvSlicer::Render() if (mOverlay && mOverlayActor->GetVisibility()) { - mOverlayMapper->SetWindow(this->GetColorWindow()); - mOverlayMapper->SetLevel(this->GetColorLevel()); + if(mLinkOverlayWindowLevel) { + mOverlayMapper->SetWindow(this->GetColorWindow()); + mOverlayMapper->SetLevel(this->GetColorLevel()); + } mOverlayMapper->GetOutput()->SetUpdateExtent(mOverlayActor->GetDisplayExtent()); mOverlayMapper->GetOutput()->Update(); mOverlayMapper->Update(); @@ -1203,13 +1430,11 @@ void vvSlicer::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; - } + pdmA->SetVisibility(true); + mCursor[0] = mCurrent[0]; + mCursor[1] = mCurrent[1]; + mCursor[2] = mCurrent[2]; + mCursor[3] = mCurrentTSlice; } //---------------------------------------------------------------------------- @@ -1258,15 +1483,26 @@ void vvSlicer::SetSlice(int slice) } //---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- +int vvSlicer::GetTMax() { + int tmax = (int)mImage->GetVTKImages().size() - 1; + if(mOverlay) + tmax = std::max(tmax, (int)mOverlay->GetVTKImages().size()-1); + return tmax; +} +//---------------------------------------------------------------------------- //---------------------------------------------------------------------------- void vvSlicer::SetContourSlice() { if (mSurfaceCutActors.size() > 0) for (std::vector::iterator i=mSurfaceCutActors.begin(); - i!=mSurfaceCutActors.end(); i++) + i!=mSurfaceCutActors.end(); i++) { + + (*i)->SetSlicingOrientation(this->SliceOrientation); (*i)->SetCutSlice((this->Slice)*this->GetImage()->GetSpacing()[this->SliceOrientation]+ this->GetImage()->GetOrigin()[this->SliceOrientation]); + } } //----------------------------------------------------------------------------