diff --git a/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.cpp b/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.cpp index f4d718687d..783e680228 100644 --- a/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.cpp +++ b/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.cpp @@ -1,825 +1,860 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include #include #include #include #include #include #include #include #include #include #include #include "mitkImageStatisticsHolder.h" #include "mitkPlaneClipping.h" #include "mitkRegVisPropertyTags.h" #include "mitkRegVisHelper.h" #include "mitkRegEvalStyleProperty.h" #include "mitkRegEvalWipeStyleProperty.h" //MITK Rendering #include "mitkRegEvaluationMapper2D.h" #include "vtkMitkThickSlicesFilter.h" #include "vtkMitkLevelWindowFilter.h" #include "vtkNeverTranslucentTexture.h" //VTK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include //ITK #include #include //MatchPoint #include #include mitk::RegEvaluationMapper2D::RegEvaluationMapper2D() { } mitk::RegEvaluationMapper2D::~RegEvaluationMapper2D() { } //set the two points defining the textured plane according to the dimension and spacing void mitk::RegEvaluationMapper2D::GeneratePlane(mitk::BaseRenderer* renderer, double planeBounds[6]) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); float depth = this->CalculateLayerDepth(renderer); //Set the origin to (xMin; yMin; depth) of the plane. This is necessary for obtaining the correct //plane size in crosshair rotation and swivel mode. localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], depth); //These two points define the axes of the plane in combination with the origin. //Point 1 is the x-axis and point 2 the y-axis. //Each plane is transformed according to the view (axial, coronal and saggital) afterwards. localStorage->m_Plane->SetPoint1(planeBounds[1] , planeBounds[2], depth); //P1: (xMax, yMin, depth) localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], depth); //P2: (xMin, yMax, depth) } float mitk::RegEvaluationMapper2D::CalculateLayerDepth(mitk::BaseRenderer* renderer) { //get the clipping range to check how deep into z direction we can render images double maxRange = renderer->GetVtkRenderer()->GetActiveCamera()->GetClippingRange()[1]; //Due to a VTK bug, we cannot use the whole clipping range. /100 is empirically determined float depth = -maxRange*0.01; // divide by 100 int layer = 0; GetDataNode()->GetIntProperty( "layer", layer, renderer); //add the layer property for each image to render images with a higher layer on top of the others depth += layer*10; //*10: keep some room for each image (e.g. for QBalls in between) if(depth > 0.0f) { depth = 0.0f; MITK_WARN << "Layer value exceeds clipping range. Set to minimum instead."; } return depth; } const mitk::Image* mitk::RegEvaluationMapper2D::GetTargetImage( void ) { const mitk::RegEvaluationObject* evalObj = dynamic_cast< const mitk::RegEvaluationObject* >( GetDataNode()->GetData() ); if (evalObj) { return evalObj->GetTargetImage(); } return NULL; } const mitk::Image* mitk::RegEvaluationMapper2D::GetMovingImage( void ) { const mitk::RegEvaluationObject* evalObj = dynamic_cast< const mitk::RegEvaluationObject* >( GetDataNode()->GetData() ); if (evalObj) { return evalObj->GetMovingImage(); } return NULL; } +const mitk::DataNode* mitk::RegEvaluationMapper2D::GetTargetNode(void) +{ + const mitk::RegEvaluationObject* evalObj = dynamic_cast< const mitk::RegEvaluationObject* >(GetDataNode()->GetData()); + if (evalObj) + { + return evalObj->GetTargetNode(); + } + + return NULL; +} + +const mitk::DataNode* mitk::RegEvaluationMapper2D::GetMovingNode(void) +{ + const mitk::RegEvaluationObject* evalObj = dynamic_cast< const mitk::RegEvaluationObject* >(GetDataNode()->GetData()); + if (evalObj) + { + return evalObj->GetMovingNode(); + } + + return NULL; +} + const mitk::MAPRegistrationWrapper* mitk::RegEvaluationMapper2D::GetRegistration( void ) { const mitk::RegEvaluationObject* evalObj = dynamic_cast< const mitk::RegEvaluationObject* >( GetDataNode()->GetData() ); if (evalObj) { return evalObj->GetRegistration(); } return NULL; } vtkProp* mitk::RegEvaluationMapper2D::GetVtkProp(mitk::BaseRenderer* renderer) { //return the actor corresponding to the renderer return m_LSH.GetLocalStorage(renderer)->m_Actors; } void mitk::RegEvaluationMapper2D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { bool updated = false; LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); mitk::Image::Pointer targetInput = const_cast< mitk::Image * >( this->GetTargetImage() ); mitk::DataNode* datanode = this->GetDataNode(); if ( targetInput.IsNull() || targetInput->IsInitialized() == false ) { return; } mitk::Image::ConstPointer movingInput = this->GetMovingImage(); if ( movingInput.IsNull() || movingInput->IsInitialized() == false ) { return; } mitk::MAPRegistrationWrapper::ConstPointer reg = this->GetRegistration(); //check if there is a valid worldGeometry const Geometry2D *worldGeometry = renderer->GetCurrentWorldGeometry2D(); if( ( worldGeometry == NULL ) || ( !worldGeometry->IsValid() ) || ( !worldGeometry->HasReferenceGeometry() )) { return; } if(targetInput->GetMTime()>localStorage->m_LastUpdateTime || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2DUpdateTime()) //was the geometry modified? || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2D()->GetMTime())) { //target input has been modified -> reslice target input targetInput->Update(); // early out if there is no intersection of the current rendering geometry // and the geometry of the image that is to be rendered. if ( !RenderingGeometryIntersectsImage( worldGeometry, targetInput->GetSlicedGeometry() ) ) { // set image to NULL, to clear the texture in 3D, because // the latest image is used there if the plane is out of the geometry // see bug-13275 localStorage->m_EvaluationImage = NULL; localStorage->m_Mapper->SetInputData( localStorage->m_EmptyPolyData ); return; } //set main input for ExtractSliceFilter localStorage->m_Reslicer->SetInput(targetInput); localStorage->m_Reslicer->SetWorldGeometry(worldGeometry); localStorage->m_Reslicer->SetTimeStep( this->GetTimestep() ); //set the transformation of the image to adapt reslice axis localStorage->m_Reslicer->SetResliceTransformByGeometry( targetInput->GetTimeGeometry()->GetGeometryForTimeStep( this->GetTimestep() ) ); //is the geometry of the slice based on the input image or the worldgeometry? bool inPlaneResampleExtentByGeometry = false; datanode->GetBoolProperty("in plane resample extent by geometry", inPlaneResampleExtentByGeometry, renderer); localStorage->m_Reslicer->SetInPlaneResampleExtentByGeometry(inPlaneResampleExtentByGeometry); // Initialize the interpolation mode for resampling; switch to nearest // neighbor if the input image is too small. if ( (targetInput->GetDimension() >= 3) && (targetInput->GetDimension(2) > 1) ) { VtkResliceInterpolationProperty *resliceInterpolationProperty; datanode->GetProperty( resliceInterpolationProperty, "reslice interpolation" ); int interpolationMode = VTK_RESLICE_NEAREST; if ( resliceInterpolationProperty != NULL ) { interpolationMode = resliceInterpolationProperty->GetInterpolation(); } switch ( interpolationMode ) { case VTK_RESLICE_NEAREST: localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST); break; case VTK_RESLICE_LINEAR: localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_LINEAR); break; case VTK_RESLICE_CUBIC: localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_CUBIC); break; } } else { localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST); } //this is needed when thick mode was enable bevore. These variable have to be reset to default values localStorage->m_Reslicer->SetOutputDimensionality( 2 ); localStorage->m_Reslicer->SetOutputSpacingZDirection(1.0); localStorage->m_Reslicer->SetOutputExtentZDirection( 0, 0 ); localStorage->m_Reslicer->Modified(); //start the pipeline with updating the largest possible, needed if the geometry of the input has changed localStorage->m_Reslicer->UpdateLargestPossibleRegion(); localStorage->m_slicedTargetImage = localStorage->m_Reslicer->GetOutput(); updated = true; } if(updated || movingInput->GetMTime() > localStorage->m_LastUpdateTime || reg->GetMTime() > localStorage->m_LastUpdateTime) { //Map moving image localStorage->m_slicedMappedImage = mitk::ImageMappingHelper::map(movingInput,reg,false,0,localStorage->m_slicedTargetImage->GetGeometry(),false,0); updated = true; } + // Bounds information for reslicing (only required if reference geometry + // is present) + //this used for generating a vtkPLaneSource with the right size + double sliceBounds[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + + if (updated + || (localStorage->m_LastUpdateTime < datanode->GetPropertyList()->GetMTime()) //was a property modified? + || (localStorage->m_LastUpdateTime < datanode->GetPropertyList(renderer)->GetMTime()) + || (localStorage->m_LastUpdateTime < this->GetTargetNode()->GetMTime()) + || (localStorage->m_LastUpdateTime < this->GetMovingNode()->GetMTime())) + { + localStorage->m_Reslicer->GetClippedPlaneBounds(sliceBounds); + + //get the spacing of the slice + localStorage->m_mmPerPixel = localStorage->m_Reslicer->GetOutputSpacing(); + + // calculate minimum bounding rect of IMAGE in texture + { + double textureClippingBounds[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + + // Calculate the actual bounds of the transformed plane clipped by the + // dataset bounding box; this is required for drawing the texture at the + // correct position during 3D mapping. + + const PlaneGeometry *planeGeometry = dynamic_cast(worldGeometry); + mitk::PlaneClipping::CalculateClippedPlaneBounds(targetInput->GetGeometry(), planeGeometry, textureClippingBounds); + + textureClippingBounds[0] = static_cast(textureClippingBounds[0] / localStorage->m_mmPerPixel[0] + 0.5); + textureClippingBounds[1] = static_cast(textureClippingBounds[1] / localStorage->m_mmPerPixel[0] + 0.5); + textureClippingBounds[2] = static_cast(textureClippingBounds[2] / localStorage->m_mmPerPixel[1] + 0.5); + textureClippingBounds[3] = static_cast(textureClippingBounds[3] / localStorage->m_mmPerPixel[1] + 0.5); + + //clipping bounds for cutting the image + localStorage->m_TargetLevelWindowFilter->SetClippingBounds(textureClippingBounds); + localStorage->m_MappedLevelWindowFilter->SetClippingBounds(textureClippingBounds); + } + + this->ApplyLookuptable(renderer, this->GetTargetNode(), localStorage->m_TargetLevelWindowFilter); + this->ApplyLookuptable(renderer, this->GetMovingNode(), localStorage->m_MappedLevelWindowFilter); + this->ApplyLevelWindow(renderer, this->GetTargetNode(), localStorage->m_TargetLevelWindowFilter); + this->ApplyLevelWindow(renderer, this->GetMovingNode(), localStorage->m_MappedLevelWindowFilter); + + //connect the input with the levelwindow filter + localStorage->m_TargetLevelWindowFilter->SetInputData(localStorage->m_slicedTargetImage->GetVtkImageData()); + localStorage->m_MappedLevelWindowFilter->SetInputData(localStorage->m_slicedMappedImage->GetVtkImageData()); + localStorage->m_TargetLevelWindowFilter->Update(); + localStorage->m_MappedLevelWindowFilter->Update(); + + updated = true; + } + //Generate evaulation image bool isStyleOutdated = mitk::PropertyIsOutdated(datanode,mitk::nodeProp_RegEvalStyle,localStorage->m_LastUpdateTime); bool isBlendOutdated = mitk::PropertyIsOutdated(datanode,mitk::nodeProp_RegEvalBlendFactor,localStorage->m_LastUpdateTime); bool isCheckerOutdated = mitk::PropertyIsOutdated(datanode,mitk::nodeProp_RegEvalCheckerCount,localStorage->m_LastUpdateTime); bool isWipeStyleOutdated = mitk::PropertyIsOutdated(datanode,mitk::nodeProp_RegEvalWipeStyle,localStorage->m_LastUpdateTime); bool isContourOutdated = mitk::PropertyIsOutdated(datanode,mitk::nodeProp_RegEvalTargetContour,localStorage->m_LastUpdateTime); if (updated || isStyleOutdated || isBlendOutdated || isCheckerOutdated || isWipeStyleOutdated || isContourOutdated) { mitk::RegEvalStyleProperty::Pointer evalStyleProp = mitk::RegEvalStyleProperty::New(); datanode->GetProperty(evalStyleProp, mitk::nodeProp_RegEvalStyle); switch (evalStyleProp->GetValueAsId()) { case 0 : { PrepareBlend(datanode, localStorage); break; } case 1 : { PrepareColorBlend(localStorage); break; } case 2 : { PrepareCheckerBoard(datanode, localStorage); break; } case 3 : { PrepareWipe(datanode, localStorage); break; } case 4 : { PrepareDifference(localStorage); break; } case 5 : { PrepareContour(datanode, localStorage); break; } } updated = true; } if(updated || (localStorage->m_LastUpdateTime < datanode->GetPropertyList()->GetMTime()) //was a property modified? || (localStorage->m_LastUpdateTime < datanode->GetPropertyList(renderer)->GetMTime()) ) { - // Bounds information for reslicing (only required if reference geometry - // is present) - //this used for generating a vtkPLaneSource with the right size - double sliceBounds[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; - localStorage->m_Reslicer->GetClippedPlaneBounds(sliceBounds); - - //get the spacing of the slice - localStorage->m_mmPerPixel = localStorage->m_Reslicer->GetOutputSpacing(); - - // calculate minimum bounding rect of IMAGE in texture - { - double textureClippingBounds[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; - - // Calculate the actual bounds of the transformed plane clipped by the - // dataset bounding box; this is required for drawing the texture at the - // correct position during 3D mapping. - - const PlaneGeometry *planeGeometry = dynamic_cast< const PlaneGeometry * >( worldGeometry ); - mitk::PlaneClipping::CalculateClippedPlaneBounds( targetInput->GetGeometry(), planeGeometry, textureClippingBounds ); - - textureClippingBounds[0] = static_cast< int >( textureClippingBounds[0] / localStorage->m_mmPerPixel[0] + 0.5 ); - textureClippingBounds[1] = static_cast< int >( textureClippingBounds[1] / localStorage->m_mmPerPixel[0] + 0.5 ); - textureClippingBounds[2] = static_cast< int >( textureClippingBounds[2] / localStorage->m_mmPerPixel[1] + 0.5 ); - textureClippingBounds[3] = static_cast< int >( textureClippingBounds[3] / localStorage->m_mmPerPixel[1] + 0.5 ); - - //clipping bounds for cutting the image - localStorage->m_LevelWindowFilter->SetClippingBounds(textureClippingBounds); - } - this->ApplyOpacity( renderer ); - this->ApplyLookuptable( renderer ); - this->ApplyLevelWindow( renderer ); - this->ApplyColor( renderer ); - // do not use a VTK lookup table (we do that ourselves in m_LevelWindowFilter) localStorage->m_Texture->MapColorScalarsThroughLookupTableOff(); - //connect the input with the levelwindow filter - localStorage->m_LevelWindowFilter->SetInputData(localStorage->m_EvaluationImage); + ////connect the input with the levelwindow filter + //localStorage->m_LevelWindowFilter->SetInputData(localStorage->m_EvaluationImage); // check for texture interpolation property bool textureInterpolation = false; GetDataNode()->GetBoolProperty( "texture interpolation", textureInterpolation, renderer ); //set the interpolation modus according to the property localStorage->m_Texture->SetInterpolate(textureInterpolation); // connect the texture with the output of the levelwindow filter - localStorage->m_Texture->SetInputConnection(localStorage->m_LevelWindowFilter->GetOutputPort()); + localStorage->m_Texture->SetInputData(localStorage->m_EvaluationImage); this->TransformActor( renderer ); vtkActor* contourShadowActor = dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0)); //Connect the mapper with the input texture. This is the standard case. //setup the textured plane this->GeneratePlane( renderer, sliceBounds ); //set the plane as input for the mapper localStorage->m_Mapper->SetInputConnection(localStorage->m_Plane->GetOutputPort()); //set the texture for the actor localStorage->m_Actor->SetTexture(localStorage->m_Texture); contourShadowActor->SetVisibility( false ); // We have been modified => save this for next Update() localStorage->m_LastUpdateTime.Modified(); } } void mitk::RegEvaluationMapper2D::PrepareContour( mitk::DataNode* datanode, LocalStorage * localStorage ) { bool targetContour = true; datanode->GetBoolProperty(mitk::nodeProp_RegEvalTargetContour,targetContour); + vtkSmartPointer extractFilter1 = + vtkSmartPointer::New(); + vtkSmartPointer extractFilter2 = + vtkSmartPointer::New(); + extractFilter1->SetInputConnection(localStorage->m_TargetLevelWindowFilter->GetOutputPort()); + extractFilter1->SetComponents(0); + extractFilter2->SetInputConnection(localStorage->m_MappedLevelWindowFilter->GetOutputPort()); + extractFilter2->SetComponents(0); + vtkSmartPointer magFilter = vtkSmartPointer::New(); if(targetContour) { - magFilter->AddInputData(localStorage->m_slicedTargetImage->GetVtkImageData()); + magFilter->SetInputConnection(extractFilter1->GetOutputPort()); } else { - magFilter->AddInputData(localStorage->m_slicedMappedImage->GetVtkImageData()); + magFilter->SetInputConnection(extractFilter2->GetOutputPort()); } vtkSmartPointer appendFilter = vtkSmartPointer::New(); appendFilter->AddInputConnection(magFilter->GetOutputPort()); appendFilter->AddInputConnection(magFilter->GetOutputPort()); if(targetContour) { - appendFilter->AddInputData(localStorage->m_slicedMappedImage->GetVtkImageData()); + appendFilter->AddInputConnection(extractFilter2->GetOutputPort()); } else { - appendFilter->AddInputData(localStorage->m_slicedTargetImage->GetVtkImageData()); + appendFilter->AddInputConnection(extractFilter1->GetOutputPort()); } appendFilter->Update(); localStorage->m_EvaluationImage = appendFilter->GetOutput(); } void mitk::RegEvaluationMapper2D::PrepareDifference( LocalStorage * localStorage ) { vtkSmartPointer diffFilter = vtkSmartPointer::New(); vtkSmartPointer absFilter = vtkSmartPointer::New(); - diffFilter->SetInput1Data(localStorage->m_slicedTargetImage->GetVtkImageData()); - diffFilter->SetInput2Data(localStorage->m_slicedMappedImage->GetVtkImageData()); + vtkSmartPointer extractFilter1 = + vtkSmartPointer::New(); + vtkSmartPointer extractFilter2 = + vtkSmartPointer::New(); + + extractFilter1->SetInputConnection(localStorage->m_TargetLevelWindowFilter->GetOutputPort()); + extractFilter1->SetComponents(0); + extractFilter2->SetInputConnection(localStorage->m_MappedLevelWindowFilter->GetOutputPort()); + extractFilter2->SetComponents(0); + + diffFilter->SetInputConnection(0, extractFilter1->GetOutputPort()); + diffFilter->SetInputConnection(1, extractFilter1->GetOutputPort()); diffFilter->SetOperationToSubtract(); absFilter->SetInputConnection(diffFilter->GetOutputPort()); absFilter->SetOperationToAbsoluteValue(); diffFilter->Update(); localStorage->m_EvaluationImage = diffFilter->GetOutput(); } void mitk::RegEvaluationMapper2D::PrepareWipe( mitk::DataNode* datanode, LocalStorage * localStorage ) { mitk::RegEvalWipeStyleProperty::Pointer evalWipeStyleProp = mitk::RegEvalWipeStyleProperty::New(); datanode->GetProperty(evalWipeStyleProp, mitk::nodeProp_RegEvalWipeStyle); vtkSmartPointer wipedFilter = vtkSmartPointer::New(); - wipedFilter->SetInput1Data(localStorage->m_slicedTargetImage->GetVtkImageData()); - wipedFilter->SetInput2Data(localStorage->m_slicedMappedImage->GetVtkImageData()); - wipedFilter->SetPosition(30,30); + wipedFilter->SetInputConnection(0, localStorage->m_TargetLevelWindowFilter->GetOutputPort()); + wipedFilter->SetInputConnection(1, localStorage->m_MappedLevelWindowFilter->GetOutputPort()); + wipedFilter->SetPosition(30, 30); if (evalWipeStyleProp->GetValueAsId() == 0) { wipedFilter->SetWipeToQuad(); } else if (evalWipeStyleProp->GetValueAsId() == 1) { wipedFilter->SetWipeToHorizontal(); } else if (evalWipeStyleProp->GetValueAsId() == 2) { wipedFilter->SetWipeToVertical(); } wipedFilter->Update(); localStorage->m_EvaluationImage = wipedFilter->GetOutput(); } void mitk::RegEvaluationMapper2D::PrepareCheckerBoard( mitk::DataNode* datanode, LocalStorage * localStorage ) { int checkerCount = 5; datanode->GetIntProperty(mitk::nodeProp_RegEvalCheckerCount,checkerCount); vtkSmartPointer checkerboardFilter = vtkSmartPointer::New(); - checkerboardFilter->SetInput1Data(localStorage->m_slicedTargetImage->GetVtkImageData()); - checkerboardFilter->SetInput2Data(localStorage->m_slicedMappedImage->GetVtkImageData()); - checkerboardFilter->SetNumberOfDivisions(checkerCount,checkerCount,1); + checkerboardFilter->SetInputConnection(0, localStorage->m_TargetLevelWindowFilter->GetOutputPort()); + checkerboardFilter->SetInputConnection(1, localStorage->m_MappedLevelWindowFilter->GetOutputPort()); + checkerboardFilter->SetNumberOfDivisions(checkerCount, checkerCount, 1); checkerboardFilter->Update(); localStorage->m_EvaluationImage = checkerboardFilter->GetOutput(); } void mitk::RegEvaluationMapper2D::PrepareColorBlend( LocalStorage * localStorage ) { vtkSmartPointer appendFilter = vtkSmartPointer::New(); + vtkSmartPointer appendFilter2 = + vtkSmartPointer::New(); + + vtkSmartPointer extractFilter1 = + vtkSmartPointer::New(); + vtkSmartPointer extractFilter2 = + vtkSmartPointer::New(); + vtkSmartPointer extractFilter3 = + vtkSmartPointer::New(); + //red channel - appendFilter->AddInputData(localStorage->m_slicedMappedImage->GetVtkImageData()); + extractFilter1->SetInputConnection(localStorage->m_MappedLevelWindowFilter->GetOutputPort()); + extractFilter1->SetComponents(0); + appendFilter->AddInputConnection(extractFilter1->GetOutputPort()); //green channel - appendFilter->AddInputData(localStorage->m_slicedMappedImage->GetVtkImageData()); + extractFilter2->SetInputConnection(localStorage->m_MappedLevelWindowFilter->GetOutputPort()); + extractFilter2->SetComponents(0); + appendFilter->AddInputConnection(extractFilter2->GetOutputPort()); + //blue channel - appendFilter->AddInputData(localStorage->m_slicedTargetImage->GetVtkImageData()); - appendFilter->Update(); + extractFilter3->SetInputConnection(localStorage->m_TargetLevelWindowFilter->GetOutputPort()); + extractFilter3->SetComponents(0); + appendFilter2->AddInputConnection(appendFilter->GetOutputPort()); + appendFilter->AddInputConnection(extractFilter3->GetOutputPort()); + appendFilter2->Update(); localStorage->m_EvaluationImage = appendFilter->GetOutput(); } void mitk::RegEvaluationMapper2D::PrepareBlend( mitk::DataNode* datanode, LocalStorage * localStorage ) { int blendfactor = 50; datanode->GetIntProperty(mitk::nodeProp_RegEvalBlendFactor,blendfactor); vtkSmartPointer blendFilter = vtkSmartPointer::New(); - blendFilter->AddInputData(localStorage->m_slicedTargetImage->GetVtkImageData()); - blendFilter->AddInputData(localStorage->m_slicedMappedImage->GetVtkImageData()); - blendFilter->SetWeight(0,(100-blendfactor)/100.); + + vtkSmartPointer extractFilter1 = + vtkSmartPointer::New(); + vtkSmartPointer extractFilter2 = + vtkSmartPointer::New(); + + extractFilter1->SetInputConnection(localStorage->m_TargetLevelWindowFilter->GetOutputPort()); + extractFilter1->SetComponents(0); + extractFilter2->SetInputConnection(localStorage->m_MappedLevelWindowFilter->GetOutputPort()); + extractFilter2->SetComponents(0); + + blendFilter->AddInputConnection(extractFilter1->GetOutputPort()); + blendFilter->AddInputConnection(extractFilter2->GetOutputPort()); + blendFilter->SetWeight(0, (100 - blendfactor) / 100.); blendFilter->SetWeight(1,blendfactor/100.); blendFilter->Update(); localStorage->m_EvaluationImage = blendFilter->GetOutput(); } -void mitk::RegEvaluationMapper2D::ApplyLevelWindow(mitk::BaseRenderer *renderer) +void mitk::RegEvaluationMapper2D::ApplyLevelWindow(mitk::BaseRenderer *renderer, const mitk::DataNode* dataNode, vtkMitkLevelWindowFilter* levelFilter) { LocalStorage *localStorage = this->GetLocalStorage( renderer ); LevelWindow levelWindow; - this->GetDataNode()->GetLevelWindow( levelWindow, renderer, "levelwindow" ); - localStorage->m_LevelWindowFilter->GetLookupTable()->SetRange( levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound() ); + dataNode->GetLevelWindow(levelWindow, renderer, "levelwindow"); + levelFilter->GetLookupTable()->SetRange(levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound()); mitk::LevelWindow opacLevelWindow; - if( this->GetDataNode()->GetLevelWindow( opacLevelWindow, renderer, "opaclevelwindow" ) ) + if (dataNode->GetLevelWindow(opacLevelWindow, renderer, "opaclevelwindow")) { //pass the opaque level window to the filter - localStorage->m_LevelWindowFilter->SetMinOpacity(opacLevelWindow.GetLowerWindowBound()); - localStorage->m_LevelWindowFilter->SetMaxOpacity(opacLevelWindow.GetUpperWindowBound()); + levelFilter->SetMinOpacity(opacLevelWindow.GetLowerWindowBound()); + levelFilter->SetMaxOpacity(opacLevelWindow.GetUpperWindowBound()); } else { //no opaque level window - localStorage->m_LevelWindowFilter->SetMinOpacity(0.0); - localStorage->m_LevelWindowFilter->SetMaxOpacity(255.0); + levelFilter->SetMinOpacity(0.0); + levelFilter->SetMaxOpacity(255.0); } } -void mitk::RegEvaluationMapper2D::ApplyColor( mitk::BaseRenderer* renderer ) +void mitk::RegEvaluationMapper2D::ApplyLookuptable(mitk::BaseRenderer* renderer, const mitk::DataNode* dataNode, vtkMitkLevelWindowFilter* levelFilter) { - LocalStorage *localStorage = this->GetLocalStorage( renderer ); + LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer); + vtkLookupTable* usedLookupTable = localStorage->m_ColorLookupTable; - float rgb[3]= { 1.0f, 1.0f, 1.0f }; + // If lookup table or transferfunction use is requested... + mitk::LookupTableProperty::Pointer lookupTableProp = dynamic_cast(dataNode->GetProperty("LookupTable")); - // check for color prop and use it for rendering if it exists - // binary image hovering & binary image selection - bool hover = false; - bool selected = false; - GetDataNode()->GetBoolProperty("binaryimage.ishovering", hover, renderer); - GetDataNode()->GetBoolProperty("selected", selected, renderer); - if(hover && !selected) - { - mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty - ("binaryimage.hoveringcolor", renderer)); - if(colorprop.IsNotNull()) - { - memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); - } - else - { - GetDataNode()->GetColor( rgb, renderer, "color" ); - } - } - if(selected) + if (lookupTableProp.IsNotNull()) // is a lookuptable set? { - mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty - ("binaryimage.selectedcolor", renderer)); - if(colorprop.IsNotNull()) { - memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); - } - else - { - GetDataNode()->GetColor(rgb, renderer, "color"); - } - } - if(!hover && !selected) - { - GetDataNode()->GetColor( rgb, renderer, "color" ); + usedLookupTable = lookupTableProp->GetLookupTable()->GetVtkLookupTable(); } - - double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK - dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(rgbConv); - localStorage->m_Actor->GetProperty()->SetColor(rgbConv); - - if ( localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1 ) + else { - float rgb[3]= { 1.0f, 1.0f, 1.0f }; - mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty - ("outline binary shadow color", renderer)); - if(colorprop.IsNotNull()) - { - memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); - } - double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK - dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) )->GetProperty()->SetColor(rgbConv); + //"Image Rendering.Mode was set to use a lookup table but there is no property 'LookupTable'. + //A default (rainbow) lookup table will be used. + //Here have to do nothing. Warning for the user has been removed, due to unwanted console output + //in every interation of the rendering. } + levelFilter->SetLookupTable(usedLookupTable); } void mitk::RegEvaluationMapper2D::ApplyOpacity( mitk::BaseRenderer* renderer ) { LocalStorage* localStorage = this->GetLocalStorage( renderer ); float opacity = 1.0f; // check for opacity prop and use it for rendering if it exists GetDataNode()->GetOpacity( opacity, renderer, "opacity" ); //set the opacity according to the properties localStorage->m_Actor->GetProperty()->SetOpacity(opacity); if ( localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1 ) { dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) )->GetProperty()->SetOpacity(opacity); } } -void mitk::RegEvaluationMapper2D::ApplyLookuptable( mitk::BaseRenderer* renderer ) -{ - LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer); - vtkLookupTable* usedLookupTable = localStorage->m_ColorLookupTable; - - // If lookup table or transferfunction use is requested... - mitk::LookupTableProperty::Pointer lookupTableProp = dynamic_cast(this->GetDataNode()->GetProperty("LookupTable")); - - if( lookupTableProp.IsNotNull() ) // is a lookuptable set? - { - usedLookupTable = lookupTableProp->GetLookupTable()->GetVtkLookupTable(); - } - else - { - //"Image Rendering.Mode was set to use a lookup table but there is no property 'LookupTable'. - //A default (rainbow) lookup table will be used. - //Here have to do nothing. Warning for the user has been removed, due to unwanted console output - //in every interation of the rendering. - } - localStorage->m_LevelWindowFilter->SetLookupTable(usedLookupTable); -} - void mitk::RegEvaluationMapper2D::Update(mitk::BaseRenderer* renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) { return; } mitk::Image* data = const_cast( this->GetTargetImage() ); if ( data == NULL ) { return; } // Calculate time step of the input data for the specified renderer (integer value) this->CalculateTimeStep( renderer ); // Check if time step is valid const TimeGeometry *dataTimeGeometry = data->GetTimeGeometry(); if ( ( dataTimeGeometry == NULL ) || ( dataTimeGeometry->CountTimeSteps() == 0 ) || ( !dataTimeGeometry->IsValidTimeStep( this->GetTimestep() ) ) ) { return; } const DataNode *node = this->GetDataNode(); data->UpdateOutputInformation(); LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); //check if something important has changed and we need to rerender if ( (localStorage->m_LastUpdateTime < node->GetMTime()) //was the node modified? || (localStorage->m_LastUpdateTime < data->GetPipelineMTime()) //Was the data modified? || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2DUpdateTime()) //was the geometry modified? || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2D()->GetMTime()) || (localStorage->m_LastUpdateTime < node->GetPropertyList()->GetMTime()) //was a property modified? - || (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ) + || (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) + || (localStorage->m_LastUpdateTime < this->GetTargetNode()->GetMTime()) //was the target node modified? + || (localStorage->m_LastUpdateTime < this->GetMovingNode()->GetMTime()) //was the moving node modified? + || (localStorage->m_LastUpdateTime < this->GetTargetNode()->GetPropertyList()->GetMTime()) //was a target node property modified? + || (localStorage->m_LastUpdateTime < this->GetTargetNode()->GetPropertyList(renderer)->GetMTime()) + || (localStorage->m_LastUpdateTime < this->GetMovingNode()->GetPropertyList()->GetMTime()) //was a moving node property modified? + || (localStorage->m_LastUpdateTime < this->GetMovingNode()->GetPropertyList(renderer)->GetMTime())) { this->GenerateDataForRenderer( renderer ); } // since we have checked that nothing important has changed, we can set // m_LastUpdateTime to the current time localStorage->m_LastUpdateTime.Modified(); } void mitk::RegEvaluationMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { mitk::RegEvaluationObject* regEval = dynamic_cast(node->GetData()); if(!regEval) { return; } // Properties common for both images and segmentations node->AddProperty( "depthOffset", mitk::FloatProperty::New( 0.0 ), renderer, overwrite ); if(regEval->GetTargetImage() && regEval->GetTargetImage()->IsRotated()) node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_CUBIC) ); else node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ); node->AddProperty( "texture interpolation", mitk::BoolProperty::New( false ) ); // set to user configurable default value (see global options) node->AddProperty( "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ); node->AddProperty( "bounding box", mitk::BoolProperty::New( false ) ); mitk::RenderingModeProperty::Pointer renderingModeProperty = mitk::RenderingModeProperty::New(); node->AddProperty( "Image Rendering.Mode", renderingModeProperty); // Set default grayscale look-up table mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); mitk::LookupTableProperty::Pointer mitkLutProp = mitk::LookupTableProperty::New(); mitkLutProp->SetLookupTable(mitkLut); node->SetProperty("LookupTable", mitkLutProp); node->AddProperty( "opacity", mitk::FloatProperty::New(1.0f), renderer, overwrite ); node->AddProperty( "color", ColorProperty::New(1.0,1.0,1.0), renderer, overwrite ); node->AddProperty( "binary", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty("layer", mitk::IntProperty::New(0), renderer, overwrite); node->AddProperty(mitk::nodeProp_RegEvalStyle, mitk::RegEvalStyleProperty::New(0), renderer, overwrite); node->AddProperty(mitk::nodeProp_RegEvalBlendFactor, mitk::IntProperty::New(50), renderer, overwrite); node->AddProperty(mitk::nodeProp_RegEvalCheckerCount, mitk::IntProperty::New(3), renderer, overwrite); node->AddProperty(mitk::nodeProp_RegEvalTargetContour, mitk::BoolProperty::New(true), renderer, overwrite); node->AddProperty(mitk::nodeProp_RegEvalWipeStyle, mitk::RegEvalWipeStyleProperty::New(0), renderer, overwrite); Superclass::SetDefaultProperties(node, renderer, overwrite); } mitk::RegEvaluationMapper2D::LocalStorage* mitk::RegEvaluationMapper2D::GetLocalStorage(mitk::BaseRenderer* renderer) { return m_LSH.GetLocalStorage(renderer); } void mitk::RegEvaluationMapper2D::TransformActor(mitk::BaseRenderer* renderer) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); //get the transformation matrix of the reslicer in order to render the slice as axial, coronal or saggital vtkSmartPointer trans = vtkSmartPointer::New(); vtkSmartPointer matrix = localStorage->m_Reslicer->GetResliceAxes(); trans->SetMatrix(matrix); //transform the plane/contour (the actual actor) to the corresponding view (axial, coronal or saggital) localStorage->m_Actor->SetUserTransform(trans); //transform the origin to center based coordinates, because MITK is center based. localStorage->m_Actor->SetPosition( -0.5*localStorage->m_mmPerPixel[0], -0.5*localStorage->m_mmPerPixel[1], 0.0); if ( localStorage->m_Actors->GetNumberOfPaths() > 1 ) { vtkActor* secondaryActor = dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) ); secondaryActor->SetUserTransform(trans); secondaryActor->SetPosition( -0.5*localStorage->m_mmPerPixel[0], -0.5*localStorage->m_mmPerPixel[1], 0.0); } } bool mitk::RegEvaluationMapper2D::RenderingGeometryIntersectsImage( const Geometry2D* renderingGeometry, SlicedGeometry3D* imageGeometry ) { // if either one of the two geometries is NULL we return true // for safety reasons if ( renderingGeometry == NULL || imageGeometry == NULL ) return true; // get the distance for the first cornerpoint ScalarType initialDistance = renderingGeometry->SignedDistance( imageGeometry->GetCornerPoint( 0 ) ); for( int i=1; i<8; i++ ) { mitk::Point3D cornerPoint = imageGeometry->GetCornerPoint( i ); // get the distance to the other cornerpoints ScalarType distance = renderingGeometry->SignedDistance( cornerPoint ); // if it has not the same signing as the distance of the first point if ( initialDistance * distance < 0 ) { // we have an intersection and return true return true; } } // all distances have the same sign, no intersection and we return false return false; } mitk::RegEvaluationMapper2D::LocalStorage::~LocalStorage() { } mitk::RegEvaluationMapper2D::LocalStorage::LocalStorage() { - - m_LevelWindowFilter = vtkSmartPointer::New(); + m_TargetLevelWindowFilter = vtkSmartPointer::New(); + m_MappedLevelWindowFilter = vtkSmartPointer::New(); //Do as much actions as possible in here to avoid double executions. m_Plane = vtkSmartPointer::New(); //m_Texture = vtkSmartPointer::New().GetPointer(); m_Texture = vtkSmartPointer::New().GetPointer(); m_DefaultLookupTable = vtkSmartPointer::New(); m_ColorLookupTable = vtkSmartPointer::New(); m_Mapper = vtkSmartPointer::New(); m_Actor = vtkSmartPointer::New(); m_Actors = vtkSmartPointer::New(); m_Reslicer = mitk::ExtractSliceFilter::New(); m_EvaluationImage = vtkSmartPointer::New(); m_EmptyPolyData = vtkSmartPointer::New(); mitk::LookupTable::Pointer mitkLUT = mitk::LookupTable::New(); //built a default lookuptable mitkLUT->SetType(mitk::LookupTable::GRAYSCALE); m_DefaultLookupTable = mitkLUT->GetVtkLookupTable(); mitkLUT->SetType(mitk::LookupTable::JET); m_ColorLookupTable = mitkLUT->GetVtkLookupTable(); //do not repeat the texture (the image) m_Texture->RepeatOff(); //set the mapper for the actor m_Actor->SetMapper( m_Mapper ); vtkSmartPointer outlineShadowActor = vtkSmartPointer::New(); outlineShadowActor->SetMapper( m_Mapper ); m_Actors->AddPart( outlineShadowActor ); m_Actors->AddPart( m_Actor ); } diff --git a/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.h b/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.h index 6f1fced4e5..0dbfb1cd8b 100644 --- a/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.h +++ b/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.h @@ -1,243 +1,246 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITK_REG_EVALUATION_MAPPER_2D_H #define MITK_REG_EVALUATION_MAPPER_2D_H //MatchPoint #include #include "mitkRegEvaluationObject.h" //MITK #include //MITK Rendering #include "mitkBaseRenderer.h" #include "mitkVtkMapper.h" #include "mitkExtractSliceFilter.h" //VTK #include #include //MITK #include "MitkMatchPointRegistrationExports.h" class vtkActor; class vtkPolyDataMapper; class vtkPlaneSource; class vtkImageData; class vtkLookupTable; class vtkImageExtractComponents; class vtkImageReslice; class vtkImageChangeInformation; class vtkPoints; class vtkMitkThickSlicesFilter; class vtkPolyData; class vtkMitkApplyLevelWindowToRGBFilter; class vtkMitkLevelWindowFilter; namespace mitk { /** \brief Mapper to resample and display 2D slices of registration evaluation visualization. * \ingroup Mapper */ class MITKMATCHPOINTREGISTRATION_EXPORT RegEvaluationMapper2D : public VtkMapper { public: /** Standard class typedefs. */ mitkClassMacro( RegEvaluationMapper2D,VtkMapper ); /** Method for creation through the object factory. */ itkFactorylessNewMacro(Self) - itkCloneMacro(Self) + itkCloneMacro(Self) + const mitk::DataNode* GetTargetNode(void); + const mitk::DataNode* GetMovingNode(void); /** \brief Get the target image to map */ const mitk::Image *GetTargetImage(void); /** \brief Get the moving image to map */ const mitk::Image *GetMovingImage(void); /** \brief Get the target image to map */ const mitk::MAPRegistrationWrapper *GetRegistration(void); /** \brief Checks whether this mapper needs to update itself and generate * data. */ virtual void Update(mitk::BaseRenderer * renderer); //### methods of MITK-VTK rendering pipeline virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer); //### end of methods of MITK-VTK rendering pipeline /** \brief Internal class holding the mapper, actor, etc. for each of the 3 2D render windows */ /** * To render transveral, coronal, and sagittal, the mapper is called three times. * For performance reasons, the corresponding data for each view is saved in the * internal helper class LocalStorage. This allows rendering n views with just * 1 mitkMapper using n vtkMapper. * */ class MITKMATCHPOINTREGISTRATION_EXPORT LocalStorage : public mitk::Mapper::BaseLocalStorage { public: /** \brief Actor of a 2D render window. */ vtkSmartPointer m_Actor; vtkSmartPointer m_Actors; /** \brief Mapper of a 2D render window. */ vtkSmartPointer m_Mapper; /** \brief Current slice of a 2D render window.*/ vtkSmartPointer m_EvaluationImage; + /** \brief Empty vtkPolyData that is set when rendering geometry does not * intersect the image geometry. * \warning This member variable is set to NULL, * if no image geometry is inside the plane geometry * of the respective render window. Any user of this * slice has to check whether it is set to NULL! */ vtkSmartPointer m_EmptyPolyData; /** \brief Plane on which the slice is rendered as texture. */ vtkSmartPointer m_Plane; /** \brief The texture which is used to render the current slice. */ vtkSmartPointer m_Texture; /** \brief The lookuptables for colors and level window */ vtkSmartPointer m_ColorLookupTable; vtkSmartPointer m_DefaultLookupTable; /** \brief The actual reslicer (one per renderer) */ mitk::ExtractSliceFilter::Pointer m_Reslicer; /** part of the target image that is relevant for the rendering*/ mitk::Image::Pointer m_slicedTargetImage; /** part of the moving image mapped into the slicedTargetImage geometry*/ mitk::Image::Pointer m_slicedMappedImage; /** \brief Timestamp of last update of stored data. */ itk::TimeStamp m_LastUpdateTime; /** \brief mmPerPixel relation between pixel and mm. (World spacing).*/ mitk::ScalarType* m_mmPerPixel; - /** \brief This filter is used to apply the level window to Grayvalue and RBG(A) images. */ - vtkSmartPointer m_LevelWindowFilter; + /** \brief This filter is used to apply the level window to target image. */ + vtkSmartPointer m_TargetLevelWindowFilter; + + /** \brief This filter is used to apply the level window to moving image. */ + vtkSmartPointer m_MappedLevelWindowFilter; /** \brief Default constructor of the local storage. */ LocalStorage(); /** \brief Default deconstructor of the local storage. */ ~LocalStorage(); }; /** \brief The LocalStorageHandler holds all (three) LocalStorages for the three 2D render windows. */ mitk::LocalStorageHandler m_LSH; /** \brief Get the LocalStorage corresponding to the current renderer. */ LocalStorage* GetLocalStorage(mitk::BaseRenderer* renderer); /** \brief Set the default properties for general image rendering. */ static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); protected: /** \brief Transforms the actor to the actual position in 3D. * \param renderer The current renderer corresponding to the render window. */ void TransformActor(mitk::BaseRenderer* renderer); /** \brief Generates a plane according to the size of the resliced image in milimeters. * * \image html texturedPlane.png * * In VTK a vtkPlaneSource is defined through three points. The origin and two * points defining the axes of the plane (see VTK documentation). The origin is * set to (xMin; yMin; Z), where xMin and yMin are the minimal bounds of the * resliced image in space. Z is relevant for blending and the layer property. * The center of the plane (C) is also the center of the view plane (cf. the image above). * * \note For the standard MITK view with three 2D render windows showing three * different slices, three such planes are generated. All these planes are generated * in the XY-plane (even if they depict a YZ-slice of the volume). * */ void GeneratePlane(mitk::BaseRenderer* renderer, double planeBounds[6]); /** Default constructor */ RegEvaluationMapper2D(); /** Default deconstructor */ virtual ~RegEvaluationMapper2D(); /** \brief Does the actual resampling, without rendering the image yet. * All the data is generated inside this method. The vtkProp (or Actor) * is filled with content (i.e. the resliced image). * * After generation, a 4x4 transformation matrix(t) of the current slice is obtained * from the vtkResliceImage object via GetReslicesAxis(). This matrix is * applied to each textured plane (actor->SetUserTransform(t)) to transform everything * to the actual 3D position (cf. the following image). * * \image html cameraPositioning3D.png * */ virtual void GenerateDataForRenderer(mitk::BaseRenderer *renderer); void PrepareContour( mitk::DataNode* datanode, LocalStorage * localStorage ); void PrepareDifference( LocalStorage * localStorage ); void PrepareWipe( mitk::DataNode* datanode, LocalStorage * localStorage ); void PrepareCheckerBoard( mitk::DataNode* datanode, LocalStorage * localStorage ); void PrepareColorBlend( LocalStorage * localStorage ); void PrepareBlend( mitk::DataNode* datanode, LocalStorage * localStorage ); /** \brief This method uses the vtkCamera clipping range and the layer property * to calcualte the depth of the object (e.g. image or contour). The depth is used * to keep the correct order for the final VTK rendering.*/ float CalculateLayerDepth(mitk::BaseRenderer* renderer); /** \brief This method applies (or modifies) the lookuptable for all types of images. * \warning To use the lookup table, the property 'Lookup Table' must be set and a 'Image Rendering.Mode' * which uses the lookup table must be set. */ - void ApplyLookuptable(mitk::BaseRenderer* renderer); + void ApplyLookuptable(mitk::BaseRenderer* renderer, const mitk::DataNode* dataNode, vtkMitkLevelWindowFilter* levelFilter); /** * @brief ApplyLevelWindow Apply the level window for the given renderer. * \warning To use the level window, the property 'LevelWindow' must be set and a 'Image Rendering.Mode' which uses the level window must be set. * @param renderer Level window for which renderer? */ - void ApplyLevelWindow(mitk::BaseRenderer* renderer); - - /** \brief Set the color of the image/polydata */ - void ApplyColor( mitk::BaseRenderer* renderer ); + void ApplyLevelWindow(mitk::BaseRenderer *renderer, const mitk::DataNode* dataNode, vtkMitkLevelWindowFilter* levelFilter); /** \brief Set the opacity of the actor. */ void ApplyOpacity( mitk::BaseRenderer* renderer ); /** * \brief Calculates whether the given rendering geometry intersects the * given SlicedGeometry3D. * * This method checks if the given Geometry2D intersects the given * SlicedGeometry3D. It calculates the distance of the Geometry2D to all * 8 cornerpoints of the SlicedGeometry3D. If all distances have the same * sign (all positive or all negative) there is no intersection. * If the distances have different sign, there is an intersection. **/ bool RenderingGeometryIntersectsImage( const Geometry2D* renderingGeometry, SlicedGeometry3D* imageGeometry ); }; } // namespace mitk #endif /* MITKRegEvaluationMapper2D_H_HEADER_INCLUDED_C10E906E */ diff --git a/Modules/MatchPointRegistration/mitkRegEvaluationObject.cpp b/Modules/MatchPointRegistration/mitkRegEvaluationObject.cpp index a504ef51c2..674bca0013 100644 --- a/Modules/MatchPointRegistration/mitkRegEvaluationObject.cpp +++ b/Modules/MatchPointRegistration/mitkRegEvaluationObject.cpp @@ -1,133 +1,161 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include "mitkRegEvaluationObject.h" #include namespace mitk { RegEvaluationObject::RegEvaluationObject() { } RegEvaluationObject::~RegEvaluationObject() { } void RegEvaluationObject::SetRequestedRegionToLargestPossibleRegion() { //nothing to do } bool RegEvaluationObject::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool RegEvaluationObject::VerifyRequestedRegion() { return true; } void RegEvaluationObject::SetRequestedRegion(const itk::DataObject*) { //nothing to do } + void RegEvaluationObject::SetTargetNode(const DataNode* tNode) + { + itkDebugMacro("setting TargetNode to " << tNode); + + m_TargetNode = tNode; + + if (tNode) + { + this->m_TargetImage = dynamic_cast(tNode->GetData()); + } + + this->Modified(); + }; + + void RegEvaluationObject::SetMovingNode(const DataNode* mNode) + { + itkDebugMacro("setting MovingNode to " << mNode); + + m_MovingNode = mNode; + + if (mNode) + { + this->m_MovingImage = dynamic_cast(mNode->GetData()); + } + + this->Modified(); + }; + void RegEvaluationObject::SetTargetImage(const mitk::Image* tImg) { itkDebugMacro("setting TargetImage to " << tImg); AccessFixedDimensionByItk_n(tImg, doConversion, 3, (m_TargetImage)); this->Modified(); }; void RegEvaluationObject::SetMovingImage(const mitk::Image* mImg) { itkDebugMacro("setting MovingImage to " << mImg); AccessFixedDimensionByItk_n(mImg, doConversion, 3, (m_MovingImage)); this->Modified(); }; template void RegEvaluationObject::doConversion(const ::itk::Image* input, mitk::Image::Pointer& result) const { typedef ::itk::Image InputImageType; typedef itk::CastImageFilter CastFilterType; typedef itk::RescaleIntensityImageFilter RescaleFilterType; typename CastFilterType::Pointer caster = CastFilterType::New(); typename RescaleFilterType::Pointer rescaler = RescaleFilterType::New(); rescaler->SetInput(input); rescaler->SetOutputMinimum(0); rescaler->SetOutputMaximum(255); caster->SetInput(rescaler->GetOutput()); caster->Update(); InternalImageType::Pointer internalImage = caster->GetOutput(); mitk::CastToMitkImage<>(internalImage,result); } void RegEvaluationObject::PrintSelf (std::ostream &os, itk::Indent indent) const { Superclass::PrintSelf(os,indent); if (m_Registration.IsNull()) { os<< "Error. Eval object points to invalid registration (NULL)."; } else { os<Print(os,indent.GetNextIndent()); } if (m_TargetImage.IsNull()) { os<< "Error. Eval object points to invalid target image (NULL)."; } else { os<Print(os,indent.GetNextIndent()); } if (m_MovingImage.IsNull()) { os<< "Error. Eval object points to invalid moving image (NULL)."; } else { os<Print(os,indent.GetNextIndent()); } } } diff --git a/Modules/MatchPointRegistration/mitkRegEvaluationObject.h b/Modules/MatchPointRegistration/mitkRegEvaluationObject.h index 9d70665dc4..d8aa2a4b9d 100644 --- a/Modules/MatchPointRegistration/mitkRegEvaluationObject.h +++ b/Modules/MatchPointRegistration/mitkRegEvaluationObject.h @@ -1,105 +1,116 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkRegEvaluationObject_h #define mitkRegEvaluationObject_h //MITK #include +#include //MatchPoint #include #include #include #include //MITK #include "mitkMAPRegistrationWrapper.h" #include "MitkMatchPointRegistrationExports.h" namespace mitk { /*! \brief RegEvaluationObject Class that containes all data to realize an evaluation of registrations via images. */ class MITKMATCHPOINTREGISTRATION_EXPORT RegEvaluationObject: public mitk::BaseData { public: mitkClassMacro( RegEvaluationObject, BaseData ); itkNewMacro( Self ); /** * Pass through to the target image that defines the region */ virtual void SetRequestedRegionToLargestPossibleRegion(); /** * Pass through to the target image that defines the region */ virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); /** * Pass through to the target image that defines the region */ virtual bool VerifyRequestedRegion(); /** * Pass through to the target image that defines the region */ virtual void SetRequestedRegion(const itk::DataObject*); itkSetObjectMacro(Registration, mitk::MAPRegistrationWrapper); /**takes the input image, rescales it and converts it to pixel type int to be used for visualization as target image*/ void SetTargetImage(const mitk::Image* tImg); /**takes the input image, rescales it and converts it to pixel type int to be used for visualization as mapped moving*/ void SetMovingImage(const mitk::Image* mImg); itkGetObjectMacro(Registration, mitk::MAPRegistrationWrapper); itkGetObjectMacro(TargetImage, mitk::Image); itkGetObjectMacro(MovingImage, mitk::Image); itkGetConstObjectMacro(Registration, mitk::MAPRegistrationWrapper); itkGetConstObjectMacro(TargetImage, mitk::Image); itkGetConstObjectMacro(MovingImage, mitk::Image); + /**takes the input image, rescales it and converts it to pixel type int to be used for visualization as target image*/ + void SetTargetNode(const mitk::DataNode* tNode); + /**takes the input image, rescales it and converts it to pixel type int to be used for visualization as mapped moving*/ + void SetMovingNode(const mitk::DataNode* mNode); + + itkGetConstObjectMacro(TargetNode, mitk::DataNode); + itkGetConstObjectMacro(MovingNode, mitk::DataNode); + protected: typedef ::itk::Image InternalImageType; template void doConversion(const ::itk::Image* input, mitk::Image::Pointer& result) const; virtual void PrintSelf (std::ostream &os, itk::Indent indent) const; RegEvaluationObject(); virtual ~RegEvaluationObject(); mitk::MAPRegistrationWrapper::Pointer m_Registration; mitk::Image::Pointer m_TargetImage; mitk::Image::Pointer m_MovingImage; + mitk::DataNode::ConstPointer m_TargetNode; + mitk::DataNode::ConstPointer m_MovingNode; private: RegEvaluationObject& operator = (const RegEvaluationObject&); RegEvaluationObject(const RegEvaluationObject&); }; } #endif diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 8e07308e30..d20b9b4651 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,83 +1,84 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:OFF org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF #org.blueberry.test:ON #org.blueberry.uitest:ON #Testing/org.blueberry.core.runtime.tests:ON #Testing/org.blueberry.osgi.tests:ON org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.diffusionimaging:OFF org.mitk.simulation:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.coreapplication:OFF org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.diffusionimagingapp:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.dicominspector:OFF org.mitk.gui.qt.diffusionimaging:OFF org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.openigtlink:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.registration:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.simulation:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.igt.app.echotrack:OFF org.mitk.gui.qt.spectrocamrecorder:OFF org.mitk.gui.qt.classificationsegmentation:OFF org.mitk.gui.qt.overlaymanager:OFF org.mitk.gui.qt.multilabelsegmentation:ON org.mitk.matchpoint.core.helper:OFF org.mitk.gui.qt.matchpoint.algorithm.browser:OFF org.mitk.gui.qt.matchpoint.algorithm.control:OFF org.mitk.gui.qt.matchpoint.algorithm.batch:OFF org.mitk.gui.qt.matchpoint.mapper:OFF org.mitk.gui.qt.matchpoint.framereg:OFF org.mitk.gui.qt.matchpoint.visualizer:OFF + org.mitk.gui.qt.matchpoint.evaluator:OFF ) diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/CMakeLists.txt b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/CMakeLists.txt new file mode 100644 index 0000000000..0b4e7a4fac --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_gui_qt_matchpoint_evaluator) + +mitk_create_plugin( + EXPORT_DIRECTIVE MITK_GUI_QT_MATCHPOINT_REGEVAL_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgetsExt MitkMatchPointRegistration +) diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/Manual.dox new file mode 100644 index 0000000000..b495d7d957 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/Manual.dox @@ -0,0 +1,78 @@ +/** +\page org_mitk_gui_qt_registration_evaluator The MatchPoint Registration Evaluation View + +\image html map-icon-regeval.png "Icon of the MatchPoint Registration Evaluator" + +\li \ref MAP_REGEVAL_Introduction +\li \ref MAP_REGEVAL_Contact +\li \ref MAP_REGEVAL_Usage + +\section MAP_REGEVAL_Introduction Introduction +This view offers the possibility to map any image in the data manager using a user selected registration object. +Using the Mapper the user can control the field of view (image geometry) the image should be mapped into, as well as +interpolation strategy that should be used.\n +It is one of several MatchPoint registration plugins.\n +Typical usage scenarios\n +\li You have registered image I1 onto image I2. Now you want to transfer the segmentation of I1 to I2 in order to evaluate I2 within this mapped segmentation using \ref org_mitk_views_imagestatistics . +\li You have registered image I1 onto image I2. Now you want to map I3 (e.g. an other MRI sequence of the same session) also onto I2 with the same registration. + +\section MAP_REGEVAL_Contact Contact information +This plug-in is being developed by the SIDT group (Software development for Integrated Diagnostics +and Therapy) at the DKFZ (German Cancer Research Center). If you have any questions, need support, +find a bug or have a feature request, feel free to contact us at dipp@dkfz.de. + +\section MAP_REGEVAL_Usage Usage +\image html mapper-examplescreen.png "Example screenshot showing the Mapper plugin in use." +To use the mapper at least a Registration object and an input image must be selected. Registration objects are marked with a small blue icon +(e.g. the data "Registration" in the data manager of the screen shot above). The view will try to automatically determine the reference image +(by default it is the target image of the selected registration). The Reference image defines the geometry (field of view, orientation, spacing) +that should be used for the result image. The reference image can be also defined by the user (or must be defined, if the Mapper cannot determin it automatically).\n +You can multiselect registration and image(s) (press the CTRL-key while selecting the nodes in the data manager). +The Mapper will automatically sort the selections in the correct "slots" of the view. + +\image html mapper.png "Details of the mapper view." +(1) The currently selected registration, that will be used for mapping.\n +(2) The currently selected input image, that will be mapped.\n +(3) The currently (automatically or by user) selected reference image, that defines the geometry of the result.\n +(4) The name of the result image in the data manger.\n +(5) The start button(s) to commence the mapping process. For details regarding the two options see \ref MAP_REGEVAL_Refine.\n +(6) Log windows with messages regarding the mapping process.\n\n + +Every "slot" has the ability to be locked. If locked the last selection will be kept, regardless the current selection in the data manager. +You can use this for example to lock the registration, if you want to map multiple images. Doing so it is enough to just select the next image +in the data manager. To lock a slot, click at the "lock" button at the right side (see example images below). +\image html node-unlocked.png "Unlocked slot/node (default state). Changes with the selections in the data manager." +\image html node-locked.png "Locked slot/node. Stays, regardless the selections in the data manager." + +\section MAP_REGEVAL_Refine Mapping or geometry refinement +The mapper view offers two options to map images:\n +\li "Map" (default) +\li "Refine geometry" +"Map" fills the pixels of the output image by interpolating input image pixels using the registration object. This option always works. +But may take longer and introduces interpolation errors, because a new image is resampled.\n +The second option "Refine geometry" is only offered, if the registration (more precise its inverse kernel) is matrix based. In this case it just clones the image +and refines the image geometry (origin, orientation, ...); thus no interpolation artefacts are introduced. +\remark If you want to use a mapped image in conjunction with the statistic plugin and an mask of the reference image, you must use "Map" to ensure the same geometry. +Otherwise the statistic plugin will fail. + +\section MAP_REGEVAL_Settings Settings +If you map the image (and not just refine the geometry), you have several settings available:\n +\li "Allow undefined pixels": Activate to handle pixels of the result image that are not in the field of view of the input image. This pixel will get the "padding value". +\li "Allow error pixels": Activate to handle pixels of the result image that can not be mapped because the registration does not support this part of the output image. This pixel will get the "error value". +\li "Interpolator": Set to choose the interpolation strategy that should be used for mapping. +\li "Activate super/sub sampling": Activate if you want to use origin and orientation of the reference image but want to alter the spacing. + +\section MAP_REGEVAL_Interpolation Interpolation +You can choose from the following interpolation strategies:\n +\li "nearest neighbour": Use the value of the nearest pixel. Fastest, but high interpolation errors for gray value images. Right choice for label images or masks. +\li "Linear": Fast linear interpolation with often sufficient quality. Tends to blur edges. +\li "BSpline (3rd order)": Good trade off between time and quality. +\li "Windowed Sinc (Hamming)": Good interpolation quality but very time consuming. +\li "Windowed Sinc (Welch)": Good interpolation quality but very time consuming. + +\section MAP_REGEVAL_Masks Handling of masks/segmentations +If you select an mask as input image, the plugin will be automatically reconfigured to settings that are suitable for the task of mapping masks. +Most importantly the interpolator will be set to "nearest neighbour". + +*/ + diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/map-icon-regeval-gen.png b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/map-icon-regeval-gen.png new file mode 100644 index 0000000000..9699ee15dc Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/map-icon-regeval-gen.png differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/map-icon-regeval.png b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/map-icon-regeval.png new file mode 100644 index 0000000000..68ca9eb544 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/map-icon-regeval.png differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/node-locked.png b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/node-locked.png new file mode 100644 index 0000000000..2b8c73709d Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/node-locked.png differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/node-unlocked.png b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/node-unlocked.png new file mode 100644 index 0000000000..40bb1a1e8a Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/node-unlocked.png differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/doxygen/modules.dox b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/doxygen/modules.dox new file mode 100644 index 0000000000..8f11a06f78 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/doxygen/modules.dox @@ -0,0 +1,16 @@ +/** + \defgroup org_mitk_gui_qt_registration_evaluator org.mitk.gui.qt.registration.evaluator + \ingroup MITKPlugins + + \brief Describe your plugin here. + +*/ + +/** + \defgroup org_mitk_internal Internal + \ingroup org_mitk + + \brief This subcategory includes the internal classes of the org.mitk plugin. Other + plugins must not rely on these classes. They contain implementation details and their interface + may change at any time. We mean it. +*/ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/files.cmake b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/files.cmake new file mode 100644 index 0000000000..5b0726b63c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/files.cmake @@ -0,0 +1,47 @@ +set(SRC_CPP_FILES + +) + +set(INTERNAL_CPP_FILES + org_mitk_gui_qt_matchpoint_evaluator_Activator.cpp + QmitkMatchPointRegistrationEvaluator.cpp + QmitkMatchPointRegistrationEvalGenerator.cpp +) + +set(UI_FILES + src/internal/QmitkMatchPointRegistrationEvaluator.ui + src/internal/QmitkMatchPointRegistrationEvalGenerator.ui +) + +set(MOC_H_FILES + src/internal/org_mitk_gui_qt_matchpoint_evaluator_Activator.h + src/internal/QmitkMatchPointRegistrationEvaluator.h + src/internal/QmitkMatchPointRegistrationEvalGenerator.h +) + +# list of resource files which can be used by the plug-in +# system without loading the plug-ins shared library, +# for example the icon used in the menu and tabs for the +# plug-in views in the workbench +set(CACHED_RESOURCE_FILES + resources/evaluator.png + resources/evalgen.png + plugin.xml +) + +# list of Qt .qrc files which contain additional resources +# specific to this plugin +set(QRC_FILES + +) + +set(CPP_FILES ) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) + diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/manifest_headers.cmake new file mode 100644 index 0000000000..c025011f3f --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "MatchPoint Registration Evaluator") +set(Plugin-Version "0.1") +set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") +set(Plugin-ContactAddress "http://www.mitk.org") +set(Require-Plugin org.mitk.gui.qt.common org.mitk.gui.qt.datamanager) diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/plugin.xml b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/plugin.xml new file mode 100644 index 0000000000..cd93496830 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/plugin.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/resources/evalgen.png b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/resources/evalgen.png new file mode 100644 index 0000000000..9699ee15dc Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/resources/evalgen.png differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/resources/evaluator.png b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/resources/evaluator.png new file mode 100644 index 0000000000..68ca9eb544 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/resources/evaluator.png differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvalGenerator.cpp b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvalGenerator.cpp new file mode 100644 index 0000000000..9e9104e918 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvalGenerator.cpp @@ -0,0 +1,237 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// Blueberry +#include +#include + +// Mitk +#include +#include +#include +#include "mitkMAPRegistrationWrapper.h" +#include "mitkMatchPointPropertyTags.h" +#include "mitkRegEvaluationObject.h" +#include "mitkRegistrationHelper.h" +#include "mitkRegEvaluationMapper2D.h" +#include "mitkAlgorithmHelper.h" + +// Qmitk +#include "QmitkMatchPointRegistrationEvalGenerator.h" + +// Qt +#include +#include + +const std::string QmitkMatchPointRegistrationEvalGenerator::VIEW_ID = + "org.mitk.views.matchpoint.registration.evaluation.generator"; + +QmitkMatchPointRegistrationEvalGenerator::QmitkMatchPointRegistrationEvalGenerator() + : m_Parent(NULL) +{ +} + +void QmitkMatchPointRegistrationEvalGenerator::SetFocus() +{ + //m_Controls.buttonPerformImageProcessing->setFocus(); +} + +void QmitkMatchPointRegistrationEvalGenerator::Error(QString msg) +{ + mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); + MITK_ERROR << msg.toStdString().c_str(); +} + +void QmitkMatchPointRegistrationEvalGenerator::CreateQtPartControl(QWidget* parent) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi(parent); + + m_Parent = parent; + + connect(m_Controls.pbEval, SIGNAL(clicked()), this, SLOT(OnEvalBtnPushed())); + + this->CheckInputs(); + this->ConfigureMappingControls(); +} + +void QmitkMatchPointRegistrationEvalGenerator::CheckInputs() +{ + QList dataNodes = this->GetDataManagerSelection(); + this->m_autoMoving = false; + this->m_autoTarget = false; + this->m_spSelectedMovingNode = NULL; + this->m_spSelectedTargetNode = NULL; + this->m_spSelectedRegNode = NULL; + + if (dataNodes.size() > 0) + { + //test if auto select works + if (mitk::MITKRegistrationHelper::IsRegNode(dataNodes[0])) + { + this->m_spSelectedRegNode = dataNodes[0]; + dataNodes.pop_front(); + + mitk::BaseProperty* uidProp = m_spSelectedRegNode->GetProperty(mitk::nodeProp_RegAlgMovingData); + + if (uidProp) + { + //search for the moving node + mitk::NodePredicateProperty::Pointer predicate = mitk::NodePredicateProperty::New(mitk::nodeProp_UID, + uidProp); + this->m_spSelectedMovingNode = this->GetDataStorage()->GetNode(predicate); + this->m_autoMoving = this->m_spSelectedMovingNode.IsNotNull(); + } + + uidProp = m_spSelectedRegNode->GetProperty(mitk::nodeProp_RegAlgTargetData); + + if (uidProp) + { + //search for the target node + mitk::NodePredicateProperty::Pointer predicate = mitk::NodePredicateProperty::New(mitk::nodeProp_UID, + uidProp); + this->m_spSelectedTargetNode = this->GetDataStorage()->GetNode(predicate); + this->m_autoTarget = this->m_spSelectedTargetNode.IsNotNull(); + } + } + + //if still nodes are selected -> ignore possible auto select + if (!dataNodes.empty()) + { + mitk::Image* inputImage = dynamic_cast(dataNodes[0]->GetData()); + + if (inputImage) + { + this->m_spSelectedMovingNode = dataNodes[0]; + this->m_autoMoving = false; + dataNodes.pop_front(); + } + } + + if (!dataNodes.empty()) + { + mitk::Image* inputImage = dynamic_cast(dataNodes[0]->GetData()); + + if (inputImage) + { + this->m_spSelectedTargetNode = dataNodes[0]; + this->m_autoTarget = false; + dataNodes.pop_front(); + } + } + } + + if (this->m_spSelectedRegNode.IsNull()) + { + if (this->m_spSelectedMovingNode.IsNotNull() && this->m_spSelectedTargetNode.IsNotNull()) + { + m_Controls.lbRegistrationName->setText( + QString("No registration selected! Direct comparison")); + } + else + { + m_Controls.lbRegistrationName->setText( + QString("No registration selected!")); + } + } + else + { + m_Controls.lbRegistrationName->setText(QString::fromStdString( + this->m_spSelectedRegNode->GetName())); + } + + if (this->m_spSelectedMovingNode.IsNull()) + { + m_Controls.lbMovingName->setText(QString("no moving image selected!")); + } + else + { + if (this->m_autoMoving) + { + m_Controls.lbMovingName->setText(QString("") + QString::fromStdString( + this->m_spSelectedMovingNode->GetName()) + QString(" (auto selected)")); + } + else + { + m_Controls.lbMovingName->setText(QString::fromStdString(this->m_spSelectedMovingNode->GetName())); + } + } + + if (this->m_spSelectedTargetNode.IsNull()) + { + m_Controls.lbTargetName->setText(QString("no target image selected!")); + } + else + { + if (this->m_autoTarget) + { + m_Controls.lbTargetName->setText(QString("") + QString::fromStdString( + this->m_spSelectedTargetNode->GetName()) + QString(" (auto selected)")); + } + else + { + m_Controls.lbTargetName->setText(QString::fromStdString(this->m_spSelectedTargetNode->GetName())); + } + } +} + +void QmitkMatchPointRegistrationEvalGenerator::ConfigureMappingControls() +{ + this->m_Controls.pbEval->setEnabled(this->m_spSelectedMovingNode.IsNotNull() + && this->m_spSelectedTargetNode.IsNotNull()); +} + +void QmitkMatchPointRegistrationEvalGenerator::OnSelectionChanged( + berry::IWorkbenchPart::Pointer /*source*/, + const QList& nodes) +{ + this->CheckInputs(); + this->ConfigureMappingControls(); +} + +void QmitkMatchPointRegistrationEvalGenerator::OnEvalBtnPushed() +{ + mitk::RegEvaluationObject::Pointer regEval = mitk::RegEvaluationObject::New(); + + mitk::MAPRegistrationWrapper::Pointer reg; + + if (m_spSelectedRegNode.IsNotNull()) + { + reg = dynamic_cast(this->m_spSelectedRegNode->GetData()); + } + else + { + //generate a dymme reg to use + reg = mitk::GenerateIdentityRegistration3D(); + } + + regEval->SetRegistration(reg); + regEval->SetTargetNode(this->m_spSelectedTargetNode); + regEval->SetMovingNode(this->m_spSelectedMovingNode); + + mitk::DataNode::Pointer regEvalNode = mitk::DataNode::New(); + regEvalNode->SetData(regEval); + regEvalNode->SetName("RegistrationEvaluationHelper"); + + mitk::RegEvaluationMapper2D::SetDefaultProperties(regEvalNode); + + this->GetDataStorage()->Add(regEvalNode); + + this->GetRenderWindowPart()->RequestUpdate(); + + this->CheckInputs(); + this->ConfigureMappingControls(); +} \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvalGenerator.h b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvalGenerator.h new file mode 100644 index 0000000000..a20e5b3515 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvalGenerator.h @@ -0,0 +1,93 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __Q_MITK_MATCHPOINT_REGISTRATION_EVAL_GENERATOR_H +#define __Q_MITK_MATCHPOINT_REGISTRATION_EVAL_GENERATOR_H + +#include + +#include "ui_QmitkMatchPointRegistrationEvalGenerator.h" + +/*! + \brief QmitkMatchPointRegistrationEvalGenerator + + Class implements the eval generator view, containing the needed business logic and interaction schemes. + Purpose of the view is to generate registration eval (helper) objects by (auto) selecting appropriate + data nodes from the data manager. + + \sa QmitkFunctionality + \ingroup ${plugin_target}_internal +*/ +class QmitkMatchPointRegistrationEvalGenerator : public QmitkAbstractView +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + /** + * Creates smartpointer typedefs + */ + berryObjectMacro(QmitkMatchPointRegistrationEvalGenerator) + + QmitkMatchPointRegistrationEvalGenerator(); + + virtual void CreateQtPartControl(QWidget* parent); + +protected slots: + + /// \brief Called when the user clicks the GUI button + void OnEvalBtnPushed(); + +protected: + virtual void SetFocus(); + + /// \brief called by QmitkFunctionality when DataManager's selection has changed + virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, + const QList& nodes); + + Ui::MatchPointRegistrationEvalGeneratorControls m_Controls; + +private: + QWidget* m_Parent; + + void Error(QString msg); + + /** + * Checks if appropriated nodes are selected in the data manager. If nodes are selected, + * they are stored m_spSelectedRegNode, m_spSelectedInputNode and m_spSelectedRefNode. + * They are also checked for vadility and stored in m_ValidInput,... . + * It also sets the info lables accordingly.*/ + void CheckInputs(); + + /** + * Updates the state of mapping control button regarding to selected + * input, registration and reference.*/ + void ConfigureMappingControls(); + + mitk::DataNode::Pointer m_spSelectedRegNode; + mitk::DataNode::Pointer m_spSelectedMovingNode; + mitk::DataNode::Pointer m_spSelectedTargetNode; + + bool m_autoTarget; + bool m_autoMoving; +}; + +#endif // MatchPoint_h + diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvalGenerator.ui b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvalGenerator.ui new file mode 100644 index 0000000000..30d9de3fb2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvalGenerator.ui @@ -0,0 +1,301 @@ + + + MatchPointRegistrationEvalGeneratorControls + + + + 0 + 0 + 392 + 581 + + + + + 5 + + + 5 + + + + + Selected registration: + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + + 0 + 170 + 0 + + + + + + + + + 0 + 170 + 0 + + + + + + + + + 159 + 158 + 158 + + + + + + + + + 75 + true + + + + Registration that should be used to map the moving image... + + + QFrame::StyledPanel + + + 2 + + + 1 + + + + + + + + + + Selected moving image: + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + + 0 + 170 + 0 + + + + + + + + + 0 + 170 + 0 + + + + + + + + + 159 + 158 + 158 + + + + + + + + + 75 + true + + + + Moving image that should be mapped... + + + QFrame::StyledPanel + + + 2 + + + 1 + + + + + + + + + + Selected target image: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 170 + 0 + + + + + + + + + 0 + 170 + 0 + + + + + + + + + 159 + 158 + 158 + + + + + + + + + 75 + true + + + + Reference image that is used to determine the field of view mapped into... + + + QFrame::StyledPanel + + + 2 + + + 1 + + + + + + + + + + <html><head/><body><p>Starts the mapping of the input image with the current settings.</p></body></html> + + + Visualize mapping + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 5 + + + 5 + + + true + + + true + + + true + + + diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp new file mode 100644 index 0000000000..0ff086731d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp @@ -0,0 +1,250 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// Blueberry +#include +#include + +// Mitk +#include +#include +#include +#include +#include "mitkRegVisPropertyTags.h" +#include "mitkRegEvaluationObject.h" +#include "mitkRegEvalStyleProperty.h" +#include "mitkRegEvalWipeStyleProperty.h" + +// Qmitk +#include "QmitkMatchPointRegistrationEvaluator.h" + +// Qt +#include +#include + + +const std::string QmitkMatchPointRegistrationEvaluator::VIEW_ID = + "org.mitk.views.matchpoint.registration.evaluator"; + +QmitkMatchPointRegistrationEvaluator::QmitkMatchPointRegistrationEvaluator() + : m_Parent(NULL), m_internalBlendUpdate(false) +{ +} + +void QmitkMatchPointRegistrationEvaluator::SetFocus() +{ + +} + +void QmitkMatchPointRegistrationEvaluator::Error(QString msg) +{ + mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); + MITK_ERROR << msg.toStdString().c_str(); +} + +void QmitkMatchPointRegistrationEvaluator::CreateQtPartControl(QWidget* parent) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi(parent); + + m_Parent = parent; + + mitk::RegEvalStyleProperty::Pointer sampleProp = mitk::RegEvalStyleProperty::New(); + + for (unsigned int pos = 0; pos < sampleProp->Size(); ++pos) + { + this->m_Controls.comboStyle->insertItem(pos, + QString::fromStdString(sampleProp->GetEnumString(pos))); + } + + connect(m_Controls.comboStyle, SIGNAL(currentIndexChanged(int)), this, + SLOT(OnComboStyleChanged(int))); + + connect(m_Controls.pbBlend50, SIGNAL(clicked()), this, SLOT(OnBlend50Pushed())); + connect(m_Controls.pbBlendTarget, SIGNAL(clicked()), this, SLOT(OnBlendTargetPushed())); + connect(m_Controls.pbBlendMoving, SIGNAL(clicked()), this, SLOT(OnBlendMovingPushed())); + connect(m_Controls.pbBlendToggle, SIGNAL(clicked()), this, SLOT(OnBlendTogglePushed())); + connect(m_Controls.slideBlend, SIGNAL(valueChanged(int)), this, SLOT(OnSlideBlendChanged(int))); + connect(m_Controls.sbBlend, SIGNAL(valueChanged(int)), this, SLOT(OnSpinBlendChanged(int))); + + connect(m_Controls.sbChecker, SIGNAL(valueChanged(int)), this, SLOT(OnSpinCheckerChanged(int))); + + connect(m_Controls.radioWipeCross, SIGNAL(toggled(bool)), this, SLOT(OnWipeStyleChanged())); + connect(m_Controls.radioWipeH, SIGNAL(toggled(bool)), this, SLOT(OnWipeStyleChanged())); + connect(m_Controls.radioWipeV, SIGNAL(toggled(bool)), this, SLOT(OnWipeStyleChanged())); + + connect(m_Controls.radioTargetContour, SIGNAL(toggled(bool)), this, SLOT(OnContourStyleChanged())); + + this->ConfigureControls(); +} + +void QmitkMatchPointRegistrationEvaluator::OnSelectionChanged(berry::IWorkbenchPart::Pointer source, + const QList& nodes) +{ + m_selectedEvalNode = NULL; + + if (nodes.size() > 0) + { + mitk::RegEvaluationObject* evalObj = dynamic_cast(nodes[0]->GetData()); + + if (evalObj) + { + this->m_selectedEvalNode = nodes[0]; + } + } + + ConfigureControls(); +}; + +void QmitkMatchPointRegistrationEvaluator::ConfigureControls() +{ + this->m_Controls.comboStyle->setEnabled(this->m_selectedEvalNode.IsNotNull()); + this->m_Controls.labelNoSelect->setVisible(this->m_selectedEvalNode.IsNull()); + + if (this->m_selectedEvalNode.IsNotNull()) + { + mitk::RegEvalStyleProperty* evalProp = NULL; + + if (this->m_selectedEvalNode->GetProperty(evalProp, mitk::nodeProp_RegEvalStyle)) + { + OnComboStyleChanged(evalProp->GetValueAsId()); + this->m_Controls.comboStyle->setCurrentIndex(evalProp->GetValueAsId()); + } + else + { + this->Error(QString("Cannot configure plugin controlls correctly. Node property ") + QString( + mitk::nodeProp_RegEvalStyle) + QString(" has not the assumed type.")); + } + + int factor = 50; + this->m_selectedEvalNode->GetIntProperty(mitk::nodeProp_RegEvalBlendFactor, factor); + this->m_Controls.sbBlend->setValue(factor); + + int count = 3; + this->m_selectedEvalNode->GetIntProperty(mitk::nodeProp_RegEvalCheckerCount, count); + this->m_Controls.sbChecker->setValue(count); + + bool targetContour = true; + this->m_selectedEvalNode->GetBoolProperty(mitk::nodeProp_RegEvalTargetContour, targetContour); + this->m_Controls.radioTargetContour->setChecked(targetContour); + } + else + { + this->m_Controls.groupBlend->setVisible(false); + this->m_Controls.groupCheck->setVisible(false); + this->m_Controls.groupWipe->setVisible(false); + this->m_Controls.groupContour->setVisible(false); + } +} + +void QmitkMatchPointRegistrationEvaluator::OnComboStyleChanged(int index) +{ + m_Controls.groupBlend->setVisible(index == 0); + m_Controls.groupCheck->setVisible(index == 2); + m_Controls.groupWipe->setVisible(index == 3); + m_Controls.groupContour->setVisible(index == 5); + + if (m_selectedEvalNode.IsNotNull()) + { + m_selectedEvalNode->SetProperty(mitk::nodeProp_RegEvalStyle, mitk::RegEvalStyleProperty::New(index)); + this->GetRenderWindowPart()->RequestUpdate(); + } +}; + +void QmitkMatchPointRegistrationEvaluator::OnBlend50Pushed() +{ + m_Controls.sbBlend->setValue(50); +}; + +void QmitkMatchPointRegistrationEvaluator::OnBlendTargetPushed() +{ + m_Controls.sbBlend->setValue(0); +}; + +void QmitkMatchPointRegistrationEvaluator::OnBlendMovingPushed() +{ + m_Controls.sbBlend->setValue(100); +}; + +void QmitkMatchPointRegistrationEvaluator::OnBlendTogglePushed() +{ + m_Controls.sbBlend->setValue(100 - m_Controls.sbBlend->value()); +}; + +void QmitkMatchPointRegistrationEvaluator::OnSlideBlendChanged(int factor) +{ + m_internalBlendUpdate = true; + m_Controls.sbBlend->setValue(factor); + m_internalBlendUpdate = false; +}; + +void QmitkMatchPointRegistrationEvaluator::OnSpinBlendChanged(int factor) +{ + if (m_selectedEvalNode.IsNotNull()) + { + m_selectedEvalNode->SetIntProperty(mitk::nodeProp_RegEvalBlendFactor, factor); + this->GetRenderWindowPart()->RequestUpdate(); + + if (!m_internalBlendUpdate) + { + this->m_Controls.slideBlend->setValue(factor); + } + } +}; + +void QmitkMatchPointRegistrationEvaluator::OnSpinCheckerChanged(int count) +{ + if (m_selectedEvalNode.IsNotNull()) + { + m_selectedEvalNode->SetIntProperty(mitk::nodeProp_RegEvalCheckerCount, count); + this->GetRenderWindowPart()->RequestUpdate(); + } +}; + +void QmitkMatchPointRegistrationEvaluator::OnWipeStyleChanged() +{ + if (m_selectedEvalNode.IsNotNull()) + { + if (this->m_Controls.radioWipeCross->isChecked()) + { + m_selectedEvalNode->SetProperty(mitk::nodeProp_RegEvalWipeStyle, + mitk::RegEvalWipeStyleProperty::New(0)); + } + else if (this->m_Controls.radioWipeH->isChecked()) + { + m_selectedEvalNode->SetProperty(mitk::nodeProp_RegEvalWipeStyle, + mitk::RegEvalWipeStyleProperty::New(1)); + } + else + { + m_selectedEvalNode->SetProperty(mitk::nodeProp_RegEvalWipeStyle, + mitk::RegEvalWipeStyleProperty::New(2)); + } + + this->GetRenderWindowPart()->RequestUpdate(); + } +}; + + +void QmitkMatchPointRegistrationEvaluator::OnContourStyleChanged() +{ + if (m_selectedEvalNode.IsNotNull()) + { + m_selectedEvalNode->SetBoolProperty(mitk::nodeProp_RegEvalTargetContour, + m_Controls.radioTargetContour->isChecked()); + this->GetRenderWindowPart()->RequestUpdate(); + } +}; \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.h b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.h new file mode 100644 index 0000000000..b901de54c9 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.h @@ -0,0 +1,95 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef __Q_MITK_MATCHPOINT_REGISTRATION_EVALUATOR_H +#define __Q_MITK_MATCHPOINT_REGISTRATION_EVALUATOR_H + +#include + +#include "ui_QmitkMatchPointRegistrationEvaluator.h" + +/*! +\brief QmitkMatchPointRegistrationEvaluator + +\warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. + +\sa QmitkFunctionality +\ingroup ${plugin_target}_internal +*/ +class QmitkMatchPointRegistrationEvaluator : public QmitkAbstractView +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + /** + * Creates smartpointer typedefs + */ + berryObjectMacro(QmitkMatchPointRegistrationEvaluator) + + QmitkMatchPointRegistrationEvaluator(); + + virtual void CreateQtPartControl(QWidget *parent); + + protected slots: + + /// \brief Called when the user clicks the GUI button + + void OnComboStyleChanged(int); + void OnBlend50Pushed(); + void OnBlendTargetPushed(); + void OnBlendMovingPushed(); + void OnBlendTogglePushed(); + void OnSlideBlendChanged(int); + void OnSpinBlendChanged(int); + void OnSpinCheckerChanged(int); + void OnWipeStyleChanged(); + void OnContourStyleChanged(); + +protected: + /// \brief called by QmitkFunctionality when DataManager's selection has changed + virtual void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, + const QList& nodes); + + virtual void SetFocus(); + + Ui::MatchPointRegistrationEvaluatorControls m_Controls; + +private: + QWidget *m_Parent; + + void Error(QString msg); + + /** Methods returns a list of all eval nodes in the data manager.*/ + QList GetEvalNodes(); + + /** + * Updates the state of controls regarding to selected eval object.*/ + void ConfigureControls(); + + mitk::DataNode::Pointer m_selectedEvalNode; + mitk::DataStorage::SetOfObjects::ConstPointer m_evalNodes; + + bool m_internalBlendUpdate; +}; + +#endif // MatchPoint_h + diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.ui b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.ui new file mode 100644 index 0000000000..3d470be346 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.ui @@ -0,0 +1,324 @@ + + + MatchPointRegistrationEvaluatorControls + + + + 0 + 0 + 379 + 694 + + + + + 5 + + + 5 + + + + + Evaluation visualization style: + + + + + + + + + + Blend settings: + + + + 5 + + + 1 + + + 5 + + + + + + 60 + 16777215 + + + + Sets the blend factor to 0% (only target is visible) + + + target + + + + + + + + 60 + 16777215 + + + + Sets the blend factor to 100% (only mapped moving image is visible) + + + mapped + + + + + + + "Inverts" the current blend factor. + + + Toggle + + + + + + + + + 100 + + + 50 + + + Qt::Horizontal + + + + + + + % + + + 100 + + + 50 + + + + + + + + + + + + 60 + 16777215 + + + + Sets blend factor to 50%:50% + + + 50:50 + + + + + + + + + + + + Checkerboard settings: + + + + 5 + + + 5 + + + + + Field counts: + + + + + + + 1 + + + + + + + + + + Wipe settings: + + + + 5 + + + 5 + + + + + Cross + + + true + + + + + + + Horizontal Wipe + + + + + + + Vertical wipe + + + + + + + + + + Contour settings + + + + 5 + + + 5 + + + + + Target image as contour + + + + + + + Mapped image as contour + + + + + + + + + + + + + + + 170 + 0 + 0 + + + + + + + + + 170 + 0 + 0 + + + + + + + + + 120 + 120 + 120 + + + + + + + + + 75 + true + + + + No registration evaluation object selected! + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 5 + + + 5 + + + true + + + true + + + true + + + diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/org_mitk_gui_qt_matchpoint_evaluator_Activator.cpp b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/org_mitk_gui_qt_matchpoint_evaluator_Activator.cpp new file mode 100644 index 0000000000..c5a0c68e8b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/org_mitk_gui_qt_matchpoint_evaluator_Activator.cpp @@ -0,0 +1,45 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "org_mitk_gui_qt_matchpoint_evaluator_Activator.h" + +#include "QmitkMatchPointRegistrationEvaluator.h" +#include "QmitkMatchPointRegistrationEvalGenerator.h" + +ctkPluginContext* org_mitk_gui_qt_matchpoint_evaluator_Activator::m_Context = 0; + +void org_mitk_gui_qt_matchpoint_evaluator_Activator::start( + ctkPluginContext* context) +{ + BERRY_REGISTER_EXTENSION_CLASS(QmitkMatchPointRegistrationEvaluator, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkMatchPointRegistrationEvalGenerator, context) + + m_Context = context; +} + +void org_mitk_gui_qt_matchpoint_evaluator_Activator::stop( + ctkPluginContext* context) +{ + Q_UNUSED(context) + + m_Context = 0; +} + +ctkPluginContext* org_mitk_gui_qt_matchpoint_evaluator_Activator::GetContext() +{ + return m_Context; +} diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/org_mitk_gui_qt_matchpoint_evaluator_Activator.h b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/org_mitk_gui_qt_matchpoint_evaluator_Activator.h new file mode 100644 index 0000000000..49c3f5ece7 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/org_mitk_gui_qt_matchpoint_evaluator_Activator.h @@ -0,0 +1,42 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef org_mitk_gui_qt_matchpoint_evaluator_Activator_h +#define org_mitk_gui_qt_matchpoint_evaluator_Activator_h + +#include + +class org_mitk_gui_qt_matchpoint_evaluator_Activator : + public QObject, public ctkPluginActivator +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_matchpoint_evaluator") + Q_INTERFACES(ctkPluginActivator) + +public: + + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + + static ctkPluginContext* GetContext(); + +private: + + static ctkPluginContext* m_Context; + +}; // org_mitk_gui_qt_matchpoint_evaluator_Activator + +#endif // org_mitk_gui_qt_matchpoint_evaluator_Activator_h