diff --git a/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.cpp b/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.cpp index f4d718687d..5ca8b677ec 100644 --- a/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.cpp +++ b/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.cpp @@ -1,825 +1,842 @@ /*=================================================================== 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; } - //Generate evaulation image + // 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_TargetExtractFilter->SetInputConnection(localStorage->m_TargetLevelWindowFilter->GetOutputPort()); + localStorage->m_MappedExtractFilter->SetInputConnection(localStorage->m_MappedLevelWindowFilter->GetOutputPort()); + localStorage->m_TargetExtractFilter->SetComponents(0); + localStorage->m_MappedExtractFilter->SetComponents(0); + + updated = true; + } + + //Generate evaluation 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); + bool isPositionOutdated = mitk::PropertyIsOutdated(datanode, mitk::nodeProp_RegEvalCurrentPosition, localStorage->m_LastUpdateTime); if (updated || isStyleOutdated || isBlendOutdated || isCheckerOutdated || isWipeStyleOutdated || - isContourOutdated) + isContourOutdated || + isPositionOutdated) { 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); + const PlaneGeometry *worldGeometry = renderer->GetCurrentWorldGeometry2D(); + + Point3D currentPos3D; + datanode->GetPropertyValue(mitk::nodeProp_RegEvalCurrentPosition, currentPos3D); + + Point2D currentPos2D; + worldGeometry->Map(currentPos3D, currentPos2D); + Point2D currentIndex2D; + worldGeometry->WorldToIndex(currentPos2D, currentIndex2D); + + PrepareWipe(datanode, localStorage, currentIndex2D); 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); - // 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 magFilter = vtkSmartPointer::New(); + if(targetContour) { - magFilter->AddInputData(localStorage->m_slicedTargetImage->GetVtkImageData()); + magFilter->SetInputConnection(localStorage->m_TargetExtractFilter->GetOutputPort()); } else { - magFilter->AddInputData(localStorage->m_slicedMappedImage->GetVtkImageData()); + magFilter->SetInputConnection(localStorage->m_MappedExtractFilter->GetOutputPort()); } vtkSmartPointer appendFilter = vtkSmartPointer::New(); appendFilter->AddInputConnection(magFilter->GetOutputPort()); appendFilter->AddInputConnection(magFilter->GetOutputPort()); if(targetContour) { - appendFilter->AddInputData(localStorage->m_slicedMappedImage->GetVtkImageData()); + appendFilter->AddInputConnection(localStorage->m_MappedExtractFilter->GetOutputPort()); } else { - appendFilter->AddInputData(localStorage->m_slicedTargetImage->GetVtkImageData()); + appendFilter->AddInputConnection(localStorage->m_TargetExtractFilter->GetOutputPort()); } appendFilter->Update(); localStorage->m_EvaluationImage = appendFilter->GetOutput(); } void mitk::RegEvaluationMapper2D::PrepareDifference( LocalStorage * localStorage ) { vtkSmartPointer diffFilter = vtkSmartPointer::New(); - vtkSmartPointer absFilter = + vtkSmartPointer minFilter = vtkSmartPointer::New(); - diffFilter->SetInput1Data(localStorage->m_slicedTargetImage->GetVtkImageData()); - diffFilter->SetInput2Data(localStorage->m_slicedMappedImage->GetVtkImageData()); + vtkSmartPointer maxFilter = + vtkSmartPointer::New(); + + minFilter->SetInputConnection(0, localStorage->m_TargetExtractFilter->GetOutputPort()); + minFilter->SetInputConnection(1, localStorage->m_MappedExtractFilter->GetOutputPort()); + minFilter->SetOperationToMin(); + maxFilter->SetInputConnection(0, localStorage->m_TargetExtractFilter->GetOutputPort()); + maxFilter->SetInputConnection(1, localStorage->m_MappedExtractFilter->GetOutputPort()); + maxFilter->SetOperationToMax(); + + diffFilter->SetInputConnection(0, maxFilter->GetOutputPort()); + diffFilter->SetInputConnection(1, minFilter->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 ) +void mitk::RegEvaluationMapper2D::PrepareWipe(mitk::DataNode* datanode, LocalStorage * localStorage, const Point2D& currentIndex2D) { 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(currentIndex2D[0], currentIndex2D[1]); 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(); + //red channel - appendFilter->AddInputData(localStorage->m_slicedMappedImage->GetVtkImageData()); + appendFilter->AddInputConnection(localStorage->m_MappedExtractFilter->GetOutputPort()); //green channel - appendFilter->AddInputData(localStorage->m_slicedMappedImage->GetVtkImageData()); + appendFilter->AddInputConnection(localStorage->m_MappedExtractFilter->GetOutputPort()); + //blue channel - appendFilter->AddInputData(localStorage->m_slicedTargetImage->GetVtkImageData()); + appendFilter->AddInputConnection(localStorage->m_TargetExtractFilter->GetOutputPort()); appendFilter->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.); + + blendFilter->AddInputConnection(localStorage->m_TargetExtractFilter->GetOutputPort()); + blendFilter->AddInputConnection(localStorage->m_MappedExtractFilter->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) + if (lookupTableProp.IsNotNull()) // is a lookuptable set? { - 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) - { - 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); - + node->AddProperty(mitk::nodeProp_RegEvalCurrentPosition, mitk::GenericProperty::New(mitk::Point3D()), 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_TargetLevelWindowFilter = vtkSmartPointer::New(); + m_MappedLevelWindowFilter = vtkSmartPointer::New(); + + m_TargetExtractFilter = vtkSmartPointer::New(); + m_MappedExtractFilter = vtkSmartPointer::New(); + - m_LevelWindowFilter = 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..05b2e628fe 100644 --- a/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.h +++ b/Modules/MatchPointRegistration/Rendering/mitkRegEvaluationMapper2D.h @@ -1,243 +1,249 @@ /*=================================================================== 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; + + vtkSmartPointer m_TargetExtractFilter; + vtkSmartPointer m_MappedExtractFilter; /** \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 PrepareWipe(mitk::DataNode* datanode, LocalStorage * localStorage, const Point2D& currentIndex2D); 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/Rendering/mitkRegVisPropertyTags.h b/Modules/MatchPointRegistration/Rendering/mitkRegVisPropertyTags.h index 83cd3a4791..1aded79c0a 100644 --- a/Modules/MatchPointRegistration/Rendering/mitkRegVisPropertyTags.h +++ b/Modules/MatchPointRegistration/Rendering/mitkRegVisPropertyTags.h @@ -1,60 +1,61 @@ /*=================================================================== 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_VIS_PROPERTY_TAGS__H_ #define _MITK_REG_VIS_PROPERTY_TAGS__H_ // MITK #include "MitkMatchPointRegistrationExports.h" namespace mitk { const char* const nodeProp_RegVisGrid = "matchpoint.RegVis.Grid"; const char* const nodeProp_RegVisGlyph = "matchpoint.RegVis.Glyph"; const char* const nodeProp_RegVisPoints = "matchpoint.RegVis.Points"; const char* const nodeProp_RegVisDirection = "matchpoint.RegVis.Direction"; const char* const nodeProp_RegVisFOVSize = "matchpoint.RegVis.FOV.size"; const char* const nodeProp_RegVisFOVOrigin = "matchpoint.RegVis.FOV.origin"; const char* const nodeProp_RegVisFOVSpacing = "matchpoint.RegVis.FOV.spacing"; const char* const nodeProp_RegVisFOVOrientation1 = "matchpoint.RegVis.FOV.orientation.row.1"; const char* const nodeProp_RegVisFOVOrientation2 = "matchpoint.RegVis.FOV.orientation.row.2"; const char* const nodeProp_RegVisFOVOrientation3 = "matchpoint.RegVis.FOV.orientation.row.3"; const char* const nodeProp_RegVisGridFrequence = "matchpoint.RegVis.Grid.Frequence"; const char* const nodeProp_RegVisGridShowStart = "matchpoint.RegVis.Grid.ShowStart"; const char* const nodeProp_RegVisColorStyle = "matchpoint.RegVis.ColorStyle"; const char* const nodeProp_RegVisGridStartColor = "matchpoint.RegVis.Grid.StartColor"; const char* const nodeProp_RegVisColorUni = "matchpoint.RegVis.Color.uni"; const char* const nodeProp_RegVisColor1Value = "matchpoint.RegVis.Color.1.value"; const char* const nodeProp_RegVisColor1Magnitude = "matchpoint.RegVis.Color.1.magnitude"; const char* const nodeProp_RegVisColor2Value = "matchpoint.RegVis.Color.2.value"; const char* const nodeProp_RegVisColor2Magnitude = "matchpoint.RegVis.Color.2.magnitude"; const char* const nodeProp_RegVisColor3Value = "matchpoint.RegVis.Color.3.value"; const char* const nodeProp_RegVisColor3Magnitude = "matchpoint.RegVis.Color.3.magnitude"; const char* const nodeProp_RegVisColor4Value = "matchpoint.RegVis.Color.4.value"; const char* const nodeProp_RegVisColor4Magnitude = "matchpoint.RegVis.Color.4.magnitude"; const char* const nodeProp_RegVisColorInterpolate = "matchpoint.RegVis.ColorInterpolate"; const char* const nodeProp_RegEvalStyle = "matchpoint.RegEval.Style"; const char* const nodeProp_RegEvalBlendFactor = "matchpoint.RegEval.BlendFactor"; const char* const nodeProp_RegEvalCheckerCount = "matchpoint.RegEval.CheckerCount"; const char* const nodeProp_RegEvalWipeStyle = "matchpoint.RegEval.WipeStyle"; const char* const nodeProp_RegEvalTargetContour = "matchpoint.RegEval.TargetContour"; +const char* const nodeProp_RegEvalCurrentPosition = "matchpoint.RegEval.CurrentPosition"; } #endif 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/Modules/MatchPointRegistrationUI/Qmitk/QmitkRegEvalSettingsWidget.cpp b/Modules/MatchPointRegistrationUI/Qmitk/QmitkRegEvalSettingsWidget.cpp new file mode 100644 index 0000000000..7c5751cd7a --- /dev/null +++ b/Modules/MatchPointRegistrationUI/Qmitk/QmitkRegEvalSettingsWidget.cpp @@ -0,0 +1,218 @@ +/*=================================================================== + +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 "QmitkRegEvalSettingsWidget.h" + +#include +#include "mitkMatchPointPropertyTags.h" +#include "mitkRegEvaluationObject.h" +#include "mitkRegVisPropertyTags.h" +#include "mitkRegEvalStyleProperty.h" +#include "mitkRegEvalWipeStyleProperty.h" + +void QmitkRegEvalSettingsWidget::SetNode(mitk::DataNode* node) +{ + if (this->m_selectedEvalNode.GetPointer() != node) + { + this->m_selectedEvalNode = node; + ConfigureControls(); + } +}; + + +QmitkRegEvalSettingsWidget::QmitkRegEvalSettingsWidget(QWidget*) : m_internalBlendUpdate(false), m_internalUpdate(false) +{ + this->setupUi(this); + + mitk::RegEvalStyleProperty::Pointer sampleProp = mitk::RegEvalStyleProperty::New(); + + for (unsigned int pos = 0; pos < sampleProp->Size(); ++pos) + { + this->comboStyle->insertItem(pos, + QString::fromStdString(sampleProp->GetEnumString(pos))); + } + + connect(comboStyle, SIGNAL(currentIndexChanged(int)), this, + SLOT(OnComboStyleChanged(int))); + + connect(pbBlend50, SIGNAL(clicked()), this, SLOT(OnBlend50Pushed())); + connect(pbBlendTarget, SIGNAL(clicked()), this, SLOT(OnBlendTargetPushed())); + connect(pbBlendMoving, SIGNAL(clicked()), this, SLOT(OnBlendMovingPushed())); + connect(pbBlendToggle, SIGNAL(clicked()), this, SLOT(OnBlendTogglePushed())); + connect(slideBlend, SIGNAL(valueChanged(int)), this, SLOT(OnSlideBlendChanged(int))); + connect(sbBlend, SIGNAL(valueChanged(int)), this, SLOT(OnSpinBlendChanged(int))); + + connect(sbChecker, SIGNAL(valueChanged(int)), this, SLOT(OnSpinCheckerChanged(int))); + + connect(radioWipeCross, SIGNAL(toggled(bool)), this, SLOT(OnWipeStyleChanged())); + connect(radioWipeH, SIGNAL(toggled(bool)), this, SLOT(OnWipeStyleChanged())); + connect(radioWipeV, SIGNAL(toggled(bool)), this, SLOT(OnWipeStyleChanged())); + + connect(radioTargetContour, SIGNAL(toggled(bool)), this, SLOT(OnContourStyleChanged())); + + this->ConfigureControls(); +} + +void QmitkRegEvalSettingsWidget::ConfigureControls() +{ + m_internalUpdate = true; + this->comboStyle->setEnabled(this->m_selectedEvalNode.IsNotNull()); + + if (this->m_selectedEvalNode.IsNotNull()) + { + mitk::RegEvalStyleProperty* evalProp = NULL; + + if (this->m_selectedEvalNode->GetProperty(evalProp, mitk::nodeProp_RegEvalStyle)) + { + OnComboStyleChanged(evalProp->GetValueAsId()); + this->comboStyle->setCurrentIndex(evalProp->GetValueAsId()); + } + + int factor = 50; + this->m_selectedEvalNode->GetIntProperty(mitk::nodeProp_RegEvalBlendFactor, factor); + this->sbBlend->setValue(factor); + + int count = 3; + this->m_selectedEvalNode->GetIntProperty(mitk::nodeProp_RegEvalCheckerCount, count); + this->sbChecker->setValue(count); + + bool targetContour = true; + this->m_selectedEvalNode->GetBoolProperty(mitk::nodeProp_RegEvalTargetContour, targetContour); + this->radioTargetContour->setChecked(targetContour); + } + else + { + this->groupBlend->setVisible(false); + this->groupCheck->setVisible(false); + this->groupWipe->setVisible(false); + this->groupContour->setVisible(false); + } + m_internalUpdate = false; +} + +void QmitkRegEvalSettingsWidget::OnComboStyleChanged(int index) +{ + groupBlend->setVisible(index == 0); + groupCheck->setVisible(index == 2); + groupWipe->setVisible(index == 3); + groupContour->setVisible(index == 5); + + if (m_selectedEvalNode.IsNotNull()) + { + m_selectedEvalNode->SetProperty(mitk::nodeProp_RegEvalStyle, mitk::RegEvalStyleProperty::New(index)); + if (!m_internalUpdate) + { + emit SettingsChanged(m_selectedEvalNode.GetPointer()); + } + } +}; + +void QmitkRegEvalSettingsWidget::OnBlend50Pushed() +{ + sbBlend->setValue(50); +}; + +void QmitkRegEvalSettingsWidget::OnBlendTargetPushed() +{ + sbBlend->setValue(0); +}; + +void QmitkRegEvalSettingsWidget::OnBlendMovingPushed() +{ + sbBlend->setValue(100); +}; + +void QmitkRegEvalSettingsWidget::OnBlendTogglePushed() +{ + sbBlend->setValue(100 - sbBlend->value()); +}; + +void QmitkRegEvalSettingsWidget::OnSlideBlendChanged(int factor) +{ + m_internalBlendUpdate = true; + sbBlend->setValue(factor); + m_internalBlendUpdate = false; +}; + +void QmitkRegEvalSettingsWidget::OnSpinBlendChanged(int factor) +{ + if (m_selectedEvalNode.IsNotNull()) + { + m_selectedEvalNode->SetIntProperty(mitk::nodeProp_RegEvalBlendFactor, factor); + + if (!m_internalBlendUpdate) + { + this->slideBlend->setValue(factor); + } + if (!m_internalUpdate) + { + emit SettingsChanged(m_selectedEvalNode.GetPointer()); + } + } +}; + +void QmitkRegEvalSettingsWidget::OnSpinCheckerChanged(int count) +{ + if (m_selectedEvalNode.IsNotNull()) + { + m_selectedEvalNode->SetIntProperty(mitk::nodeProp_RegEvalCheckerCount, count); + if (!m_internalUpdate) + { + emit SettingsChanged(m_selectedEvalNode.GetPointer()); + } + } +}; + +void QmitkRegEvalSettingsWidget::OnWipeStyleChanged() +{ + if (m_selectedEvalNode.IsNotNull()) + { + if (this->radioWipeCross->isChecked()) + { + m_selectedEvalNode->SetProperty(mitk::nodeProp_RegEvalWipeStyle, + mitk::RegEvalWipeStyleProperty::New(0)); + } + else if (this->radioWipeH->isChecked()) + { + m_selectedEvalNode->SetProperty(mitk::nodeProp_RegEvalWipeStyle, + mitk::RegEvalWipeStyleProperty::New(1)); + } + else + { + m_selectedEvalNode->SetProperty(mitk::nodeProp_RegEvalWipeStyle, + mitk::RegEvalWipeStyleProperty::New(2)); + } + + if (!m_internalUpdate) + { + emit SettingsChanged(m_selectedEvalNode.GetPointer()); + } + } +}; + + +void QmitkRegEvalSettingsWidget::OnContourStyleChanged() +{ + if (m_selectedEvalNode.IsNotNull()) + { + m_selectedEvalNode->SetBoolProperty(mitk::nodeProp_RegEvalTargetContour, + radioTargetContour->isChecked()); + if (!m_internalUpdate) + { + emit SettingsChanged(m_selectedEvalNode.GetPointer()); + } + } +}; \ No newline at end of file diff --git a/Modules/MatchPointRegistrationUI/Qmitk/QmitkRegEvalSettingsWidget.h b/Modules/MatchPointRegistrationUI/Qmitk/QmitkRegEvalSettingsWidget.h new file mode 100644 index 0000000000..594937eb92 --- /dev/null +++ b/Modules/MatchPointRegistrationUI/Qmitk/QmitkRegEvalSettingsWidget.h @@ -0,0 +1,73 @@ +/*=================================================================== + +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 QMITK_REG_EVAL_SETTINGS_WIDGET_H +#define QMITK_REG_EVAL_SETTINGS_WIDGET_H + +#include + +#include "ui_QmitkRegEvalSettingsWidget.h" +#include + +#include + +/** + * \class QmitkRegEvalSettingsWidget + * \brief Widget that views the information and profile of an algorithm stored in an DLLInfo object. + */ +class MITKMATCHPOINTREGISTRATIONUI_EXPORT QmitkRegEvalSettingsWidget : public QWidget, private Ui::QmitkRegEvalSettingsWidget +{ + Q_OBJECT + +public: + QmitkRegEvalSettingsWidget(QWidget* parent=0); + + /** + * Configures the passed settings according to the current state of the + * widget. + * \param pointer to a instance based on QmitkMappingJobSettings. + * \pre settings must point to a valid instance.. + */ + void ConfigureControls(); + +public Q_SLOTS: + /** + * \brief Slot that can be used to set the node that should be configured by the widget.*/ + void SetNode(mitk::DataNode* node); + +signals: + void SettingsChanged(mitk::DataNode* node); + +protected Q_SLOTS: +void OnComboStyleChanged(int); +void OnBlend50Pushed(); +void OnBlendTargetPushed(); +void OnBlendMovingPushed(); +void OnBlendTogglePushed(); +void OnSlideBlendChanged(int); +void OnSpinBlendChanged(int); +void OnSpinCheckerChanged(int); +void OnWipeStyleChanged(); +void OnContourStyleChanged(); + +private: + mitk::DataNode::Pointer m_selectedEvalNode; + + bool m_internalBlendUpdate; + bool m_internalUpdate; +}; + +#endif // QmitkRegEvalSettingsWidget_H diff --git a/Modules/MatchPointRegistrationUI/Qmitk/QmitkRegEvalSettingsWidget.ui b/Modules/MatchPointRegistrationUI/Qmitk/QmitkRegEvalSettingsWidget.ui new file mode 100644 index 0000000000..b5d50b0c7f --- /dev/null +++ b/Modules/MatchPointRegistrationUI/Qmitk/QmitkRegEvalSettingsWidget.ui @@ -0,0 +1,274 @@ + + + QmitkRegEvalSettingsWidget + + + + 0 + 0 + 400 + 374 + + + + Form + + + + + + Evaluation visualization style: + + + + + + + + + + Blend settings: + + + + 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + 1 + + + + + + 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 + + + 5 + + + 5 + + + 5 + + + + + Field counts: + + + + + + + 1 + + + + + + + + + + Wipe settings: + + + + 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Cross + + + true + + + + + + + Horizontal Wipe + + + + + + + Vertical wipe + + + + + + + + + + Contour settings + + + + 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + Target image as contour + + + + + + + Mapped image as contour + + + + + + + + + + + diff --git a/Modules/MatchPointRegistrationUI/files.cmake b/Modules/MatchPointRegistrationUI/files.cmake index c87d37bc9f..30349910aa 100644 --- a/Modules/MatchPointRegistrationUI/files.cmake +++ b/Modules/MatchPointRegistrationUI/files.cmake @@ -1,36 +1,39 @@ set(CPP_FILES Qmitk/QmitkRegistrationJob.cpp Qmitk/QmitkMappingJob.cpp Qmitk/QmitkFramesRegistrationJob.cpp Qmitk/QmitkAlgorithmProfileViewer.cpp Qmitk/QmitkAlgorithmSettingsConfig.cpp Qmitk/QmitkMAPAlgorithmModel.cpp Qmitk/QmitkAlgorithmListModel.cpp Qmitk/QmitkMapPropertyDelegate.cpp Qmitk/QmitkMapperSettingsWidget.cpp + Qmitk/QmitkRegEvalSettingsWidget.cpp ) set(H_FILES ) set(TPP_FILES ) set(UI_FILES Qmitk/QmitkAlgorithmProfileViewer.ui Qmitk/QmitkAlgorithmSettingsConfig.ui Qmitk/QmitkMapperSettingsWidget.ui + Qmitk/QmitkRegEvalSettingsWidget.ui ) set(MOC_H_FILES Qmitk/QmitkRegistrationJob.h Qmitk/QmitkMappingJob.h Qmitk/QmitkFramesRegistrationJob.h Qmitk/QmitkAlgorithmProfileViewer.h Qmitk/QmitkAlgorithmSettingsConfig.h Qmitk/QmitkMAPAlgorithmModel.h Qmitk/QmitkAlgorithmListModel.h Qmitk/QmitkMapPropertyDelegate.h Qmitk/QmitkMapperSettingsWidget.h + Qmitk/QmitkRegEvalSettingsWidget.h ) 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.common/files.cmake b/Plugins/org.mitk.gui.qt.common/files.cmake index 26169e2fbf..2564418383 100755 --- a/Plugins/org.mitk.gui.qt.common/files.cmake +++ b/Plugins/org.mitk.gui.qt.common/files.cmake @@ -1,36 +1,38 @@ set(SRC_CPP_FILES QmitkAbstractRenderEditor.cpp QmitkAbstractView.cpp QmitkDataNodeSelectionProvider.cpp QmitkDnDFrameWidget.cpp + QmitkSliceNavigationListener.cpp ) set(INTERNAL_CPP_FILES QmitkCommonActivator.cpp QmitkDataNodeItemModel.cpp QmitkDataNodeSelection.cpp QmitkViewCoordinator.cpp ) set(MOC_H_FILES src/QmitkAbstractRenderEditor.h src/QmitkDnDFrameWidget.h + src/QmitkSliceNavigationListener.h src/internal/QmitkCommonActivator.h ) set(CACHED_RESOURCE_FILES ) 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.common/src/QmitkSliceNavigationListener.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.cpp new file mode 100644 index 0000000000..5de6acb82d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.cpp @@ -0,0 +1,176 @@ +/*=================================================================== + +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. + +===================================================================*/ + +// Qmitk +#include "QmitkRenderWindow.h" +#include "QmitkSliceNavigationListener.h" + +#include "mitkIRenderWindowPart.h" + +// Qt +#include +#include + + +///********************************************** +QmitkSliceNavigationListener::QmitkSliceNavigationListener(): m_renderWindowPart(NULL), +m_PendingSliceChangedEvent(false), +m_internalUpdateFlag(false) +{ +} + +QmitkSliceNavigationListener::~QmitkSliceNavigationListener() +{ + this->RemoveAllObservers(); +}; + +void QmitkSliceNavigationListener::OnSliceChangedDelayed() +{ + m_PendingSliceChangedEvent = false; + emit SliceChanged(); +}; + +void +QmitkSliceNavigationListener::OnSliceChangedInternal(const itk::EventObject& e) +{ + // Taken from QmitkStdMultiWidget::HandleCrosshairPositionEvent(). + // Since there are always 3 events arriving (one for each render window) every time the slice + // or time changes, the slot OnSliceChangedDelayed is triggered - and only if it hasn't been + // triggered yet - so it is only executed once for every slice/time change. + if (!m_PendingSliceChangedEvent) + { + m_PendingSliceChangedEvent = true; + + QTimer::singleShot(0, this, SLOT(OnSliceChangedDelayed())); + } +}; + +void QmitkSliceNavigationListener::OnSliceNavigationControllerDeleted(const itk::Object* sender, const itk::EventObject& /*e*/) +{ + const mitk::SliceNavigationController* sendingSlicer = + dynamic_cast(sender); + + this->RemoveObservers(sendingSlicer); +}; + +void QmitkSliceNavigationListener::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) +{ + if (m_renderWindowPart != renderWindowPart) + { + m_renderWindowPart = renderWindowPart; + + if (!InitObservers()) + { + QMessageBox::information(NULL, "Error", "Unable to set up the event observers. The " \ + "plot will not be triggered on changing the crosshair, " \ + "position or time step."); + } + } +}; + +void QmitkSliceNavigationListener::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) +{ + m_renderWindowPart = NULL; + this->RemoveAllObservers(renderWindowPart); +}; + +bool QmitkSliceNavigationListener::InitObservers() +{ + bool result = true; + + typedef QHash WindowMapType; + WindowMapType windowMap = m_renderWindowPart->GetQmitkRenderWindows(); + + auto i = windowMap.begin(); + + while (i != windowMap.end()) + { + mitk::SliceNavigationController* sliceNavController = + i.value()->GetSliceNavigationController(); + + if (sliceNavController) + { + itk::ReceptorMemberCommand::Pointer cmdSliceEvent = + itk::ReceptorMemberCommand::New(); + cmdSliceEvent->SetCallbackFunction(this, &QmitkSliceNavigationListener::OnSliceChangedInternal); + int tag = sliceNavController->AddObserver( + mitk::SliceNavigationController::GeometrySliceEvent(NULL, 0), + cmdSliceEvent); + + m_ObserverMap.insert(std::make_pair(sliceNavController, ObserverInfo(sliceNavController, tag, + i.key().toStdString(), m_renderWindowPart))); + + itk::ReceptorMemberCommand::Pointer cmdTimeEvent = + itk::ReceptorMemberCommand::New(); + cmdTimeEvent->SetCallbackFunction(this, &QmitkSliceNavigationListener::OnSliceChangedInternal); + tag = sliceNavController->AddObserver( + mitk::SliceNavigationController::GeometryTimeEvent(NULL, 0), + cmdTimeEvent); + + m_ObserverMap.insert(std::make_pair(sliceNavController, ObserverInfo(sliceNavController, tag, + i.key().toStdString(), m_renderWindowPart))); + + itk::MemberCommand::Pointer cmdDelEvent = + itk::MemberCommand::New(); + cmdDelEvent->SetCallbackFunction(this, + &QmitkSliceNavigationListener::OnSliceNavigationControllerDeleted); + tag = sliceNavController->AddObserver( + itk::DeleteEvent(), cmdDelEvent); + + m_ObserverMap.insert(std::make_pair(sliceNavController, ObserverInfo(sliceNavController, tag, + i.key().toStdString(), m_renderWindowPart))); + } + + ++i; + + result = result && sliceNavController; + } + + return result; +}; + +void QmitkSliceNavigationListener::RemoveObservers(const mitk::SliceNavigationController* deletedSlicer) +{ + std::pair < ObserverMapType::const_iterator, ObserverMapType::const_iterator> obsRange = + m_ObserverMap.equal_range(deletedSlicer); + + for (ObserverMapType::const_iterator pos = obsRange.first; pos != obsRange.second; ++pos) + { + pos->second.controller->RemoveObserver(pos->second.observerTag); + } + + m_ObserverMap.erase(deletedSlicer); +}; + +void QmitkSliceNavigationListener::RemoveAllObservers(mitk::IRenderWindowPart* deletedPart) +{ + for (ObserverMapType::const_iterator pos = m_ObserverMap.begin(); pos != m_ObserverMap.end();) + { + ObserverMapType::const_iterator delPos = pos++; + + if (deletedPart == NULL || deletedPart == delPos->second.renderWindowPart) + { + delPos->second.controller->RemoveObserver(delPos->second.observerTag); + m_ObserverMap.erase(delPos); + } + } +}; + +QmitkSliceNavigationListener::ObserverInfo::ObserverInfo(mitk::SliceNavigationController* controller, int observerTag, + const std::string& renderWindowName, mitk::IRenderWindowPart* part) : controller(controller), observerTag(observerTag), + renderWindowName(renderWindowName), renderWindowPart(part) +{ +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.h b/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.h new file mode 100644 index 0000000000..52cbc22f90 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSliceNavigationListener.h @@ -0,0 +1,122 @@ +/*=================================================================== + +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_SLICE_NAVIGATION_LISTENER_H +#define __Q_MITK_SLICE_NAVIGATION_LISTENER_H + +#include + +#include + +#include + +namespace itk +{ + class Object; +} + +namespace mitk +{ + class SliceNavigationController; + struct IRenderWindowPart; +} + + +/** @brief Helper class to allow QmitkAbstractView and derived classes to react on changes of the slice/time navigation. + Purpose of the class to be used in view and to give the respective view class (by composition) the posibility to react + on changes of the currently selected timepoint or position in the world geometry.\n + In order to setup this class properly the following things must be regarded: + - View class must also derive public from mitk::IRenderWindowPartListener + - View class must implement void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) and pass the renderWindowPart to the listener. + + void QmitkMyView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) + { + this->m_SliceNavigationListener.RenderWindowPartActivated(renderWindowPart); + } + + - View class must implement void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) and pass the renderWindowPart to the listener. + + void QmitkMyView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) + { + this->m_SliceNavigationListener.RenderWindowPartDeactivated(renderWindowPart); + } + + - View class must pass its on render window part in its CreateQtPartControl(QWidget* parent) + + this->m_SliceNavigationListener.RenderWindowPartActivated(this->GetRenderWindowPart()); + + - View class must connect the SliceChanged signal of the listener as see fit. +*/ +class MITK_QT_COMMON QmitkSliceNavigationListener : public QObject + { + Q_OBJECT + + public: + QmitkSliceNavigationListener(); + virtual ~QmitkSliceNavigationListener(); + + signals: + void SliceChanged(); + + public slots: + void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart); + void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart); + + protected slots: + /** Overwrite function to implement the behavior on slice/time changes. */ + void OnSliceChangedDelayed(); + + protected: + + /** @brief Calls OnSliceChangedDelayed so the event isn't triggered multiple times. */ + void OnSliceChangedInternal(const itk::EventObject& e); + + void OnSliceNavigationControllerDeleted(const itk::Object* sender, const itk::EventObject& /*e*/); + + /** Initializes and sets the observers that are used to monitor changes in the selected position + or time point in order to actualize the view.h*/ + bool InitObservers(); + void RemoveObservers(const mitk::SliceNavigationController* deletedSlicer); + /** Removes all observers of the deletedPart. If null pointer is passed all observers will be removed.*/ + void RemoveAllObservers(mitk::IRenderWindowPart* deletedPart = NULL); + + mitk::IRenderWindowPart* m_renderWindowPart; + + // Needed for observing the events for when a slice or time step is changed. + bool m_PendingSliceChangedEvent; + + /**Helper structure to manage the registered observer events.*/ + struct ObserverInfo + { + mitk::SliceNavigationController* controller; + int observerTag; + std::string renderWindowName; + mitk::IRenderWindowPart* renderWindowPart; + + ObserverInfo(mitk::SliceNavigationController* controller, int observerTag, + const std::string& renderWindowName, mitk::IRenderWindowPart* part); + }; + + typedef std::multimap ObserverMapType; + ObserverMapType m_ObserverMap; + + /** @brief Is a visualization currently running? */ + bool m_internalUpdateFlag; + }; + +#endif + 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..56a7b399b3 --- /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 MitkMatchPointRegistrationUI +) 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..dba898a1bd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/Manual.dox @@ -0,0 +1,52 @@ +/** +\page org_mitk_gui_qt_matchpoint_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 evaluate the quality of the registration/mapping of two given images by visual inspection. +One may select no registration. Then the images will be displayed in evaluation mode assuming an identity transform (so no mapping). +It is one of several MatchPoint registration plug-ins.\n + +\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 www.mitk.org. + +\section MAP_REGEVAL_Usage Usage +\imageMacro{view_example.png, "Example screenshot showing the plug-in in use.", 14} +To use the evaluation view you must have selected at least the moving and the target image you want to use to evaluate. +If you select a registration with referenced target and moving image (the normal state if you generate registrations with the matchpoint plugins) +these images will be auto selected by just clicking on the registration. +If you select no registration the view will assume that an identity transform should be used.\n +As long as no valid set of data is selected the "Start evaluation" button will be disabled. If its enabled you may start the evaluation mode with it. + +\imageMacro{no_data_selected.png, "Example screenshot showing the state if no data is selected", 5} + +If the evaluation view is active you can choose between differnt modes of visualization. For more details see \ref MAP_REGEVAL_Styles.\n +To stop the evaluation mode, you may use the "Stop evaluation" button or just close the evaluation view. + +\remark The evaluation view will use the level window settings of the used images. So to changes the level windowing of the evaluation view, you must change the +level windowing of the respective images. + +\section MAP_REGEVAL_Styles Visualization styles +You can choose from the following visualization styles to evaluate the registration/mapping quality:\n +\li "Blend": Blends the images with a user defined weight. Default is 50:50. +\imageMacro{style_blend.png, "Example for mode: Blend", 5} +\li "Checkerboard": Checkerboard style that composes both images. You may define the resolution of the checkerboard. +\imageMacro{style_checkerboard.png, "Example for mode: Checkerboard", 5} +\li "Color blend": Color blend of the images (blue: target image; yellow: moving). Areas where you see no color implies good intensity matchings. +\imageMacro{style_color_blend.png, "Example for mode: Color blend", 5} +\li "Contour": Blend mode that display one image as blue "background" and the other image in yellow contours. You may choose the role of the images. +\imageMacro{style_contour.png, "Example for mode: Contour", 5} +\li "Difference": Displays the absolute difference of both images. +\li "Wipe": Blend mode that makes a rectilinear combination of the images. You can choose the mode how the images are splitted. The split is synchronized with the current selection. So you may interact with the split border to position it on interesting areas. +\imageMacro{style_wipe_cross.png, "Example for mode: Wipe cross", 5} +\imageMacro{style_wipe_horizontal.png, "Example for mode: Wipe horizontal", 5} + +*/ + 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/no_data_selected.PNG b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/no_data_selected.PNG new file mode 100644 index 0000000000..f29f99696a Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/no_data_selected.PNG differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_blend.PNG b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_blend.PNG new file mode 100644 index 0000000000..3ee4b16d5a Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_blend.PNG differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_checkerboard.png b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_checkerboard.png new file mode 100644 index 0000000000..77b538a41e Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_checkerboard.png differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_color_blend.png b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_color_blend.png new file mode 100644 index 0000000000..d69df4aaa3 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_color_blend.png differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_contour.png b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_contour.png new file mode 100644 index 0000000000..3beae15a4b Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_contour.png differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_wipe_cross.PNG b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_wipe_cross.PNG new file mode 100644 index 0000000000..e2949e4d34 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_wipe_cross.PNG differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_wipe_horizontal.PNG b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_wipe_horizontal.PNG new file mode 100644 index 0000000000..0276d5a147 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/style_wipe_horizontal.PNG differ diff --git a/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/view_example.PNG b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/view_example.PNG new file mode 100644 index 0000000000..e93c82da0b Binary files /dev/null and b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/documentation/UserManual/view_example.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..dbf00eb6df --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/files.cmake @@ -0,0 +1,43 @@ +set(SRC_CPP_FILES + +) + +set(INTERNAL_CPP_FILES + org_mitk_gui_qt_matchpoint_evaluator_Activator.cpp + QmitkMatchPointRegistrationEvaluator.cpp +) + +set(UI_FILES + src/internal/QmitkMatchPointRegistrationEvaluator.ui +) + +set(MOC_H_FILES + src/internal/org_mitk_gui_qt_matchpoint_evaluator_Activator.h + src/internal/QmitkMatchPointRegistrationEvaluator.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 + 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..d0082ac6c5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/plugin.xml @@ -0,0 +1,11 @@ + + + + + + + + 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/QmitkMatchPointRegistrationEvaluator.cpp b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp new file mode 100644 index 0000000000..c1e9d871e2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.cpp @@ -0,0 +1,328 @@ +/*=================================================================== + +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 "mitkMatchPointPropertyTags.h" +#include "mitkRegEvaluationObject.h" +#include "mitkRegistrationHelper.h" +#include "mitkRegEvaluationMapper2D.h" +#include + +// Qmitk +#include "QmitkRenderWindow.h" +#include "QmitkMatchPointRegistrationEvaluator.h" + +// Qt +#include +#include +#include + + +const std::string QmitkMatchPointRegistrationEvaluator::VIEW_ID = + "org.mitk.views.matchpoint.registration.evaluator"; + +QmitkMatchPointRegistrationEvaluator::QmitkMatchPointRegistrationEvaluator() + : m_Parent(NULL), m_activeEvaluation(false), m_autoMoving(false), m_autoTarget(false), m_currentSelectedTimeStep(0), HelperNodeName("RegistrationEvaluationHelper") +{ + m_currentSelectedPosition.Fill(0.0); +} + +QmitkMatchPointRegistrationEvaluator::~QmitkMatchPointRegistrationEvaluator() +{ + if (this->m_selectedEvalNode.IsNotNull() && this->GetDataStorage().IsNotNull()) + { + this->GetDataStorage()->Remove(this->m_selectedEvalNode); + } +} + +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; + + connect(m_Controls.pbEval, SIGNAL(clicked()), this, SLOT(OnEvalBtnPushed())); + connect(m_Controls.pbStop, SIGNAL(clicked()), this, SLOT(OnStopBtnPushed())); + connect(m_Controls.evalSettings, SIGNAL(SettingsChanged(mitk::DataNode*)), this, SLOT(OnSettingsChanged(mitk::DataNode*))); + + this->m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); + connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); + + m_selectedEvalNode = this->GetDataStorage()->GetNamedNode(HelperNodeName); + + this->CheckInputs(); + this->ConfigureControls(); +} + +void QmitkMatchPointRegistrationEvaluator::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) +{ + this->m_SliceChangeListener.RenderWindowPartActivated(renderWindowPart); +} + +void QmitkMatchPointRegistrationEvaluator::RenderWindowPartDeactivated( + mitk::IRenderWindowPart* renderWindowPart) +{ + this->m_SliceChangeListener.RenderWindowPartDeactivated(renderWindowPart); +} + +void QmitkMatchPointRegistrationEvaluator::CheckInputs() +{ + if (!m_activeEvaluation) + { + 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(); + } + } + } + } +} + + +void QmitkMatchPointRegistrationEvaluator::OnSelectionChanged(berry::IWorkbenchPart::Pointer source, + const QList& nodes) +{ + this->CheckInputs(); + this->ConfigureControls(); +}; + +void QmitkMatchPointRegistrationEvaluator::ConfigureControls() +{ + //configure input data widgets + 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())); + } + } + + //config settings widget + this->m_Controls.evalSettings->setVisible(m_activeEvaluation); + this->m_Controls.pbEval->setEnabled(this->m_spSelectedMovingNode.IsNotNull() + && this->m_spSelectedTargetNode.IsNotNull()); + this->m_Controls.pbEval->setVisible(!m_activeEvaluation); + this->m_Controls.pbStop->setVisible(m_activeEvaluation); + this->m_Controls.lbMovingName->setEnabled(!m_activeEvaluation); + this->m_Controls.lbRegistrationName->setEnabled(!m_activeEvaluation); + this->m_Controls.lbTargetName->setEnabled(!m_activeEvaluation); +} + + +void QmitkMatchPointRegistrationEvaluator::OnSliceChanged() +{ + mitk::Point3D currentSelectedPosition = GetRenderWindowPart()->GetSelectedPosition(NULL); + unsigned int currentSelectedTimeStep = GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); + + if (m_currentSelectedPosition != currentSelectedPosition + || m_currentSelectedTimeStep != currentSelectedTimeStep + || m_selectedNodeTime > m_currentPositionTime) + { + //the current position has been changed or the selected node has been changed since the last position validation -> check position + m_currentSelectedPosition = currentSelectedPosition; + m_currentSelectedTimeStep = currentSelectedTimeStep; + m_currentPositionTime.Modified(); + + if (this->m_selectedEvalNode.IsNotNull()) + { + this->m_selectedEvalNode->SetProperty(mitk::nodeProp_RegEvalCurrentPosition, mitk::GenericProperty::New(currentSelectedPosition)); + } + } +} + +void QmitkMatchPointRegistrationEvaluator::OnSettingsChanged(mitk::DataNode*) +{ + this->GetRenderWindowPart()->RequestUpdate(); +}; + +void QmitkMatchPointRegistrationEvaluator::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); + + if (this->m_selectedEvalNode.IsNotNull()) + { + this->GetDataStorage()->Remove(this->m_selectedEvalNode); + } + + this->m_selectedEvalNode = mitk::DataNode::New(); + this->m_selectedEvalNode->SetData(regEval); + + mitk::RegEvaluationMapper2D::SetDefaultProperties(this->m_selectedEvalNode); + this->m_selectedEvalNode->SetName(HelperNodeName); + this->m_selectedEvalNode->SetBoolProperty("helper object", true); + this->GetDataStorage()->Add(this->m_selectedEvalNode); + + this->m_Controls.evalSettings->SetNode(this->m_selectedEvalNode); + this->OnSliceChanged(); + + this->GetRenderWindowPart()->RequestUpdate(); + + this->m_activeEvaluation = true; + this->CheckInputs(); + this->ConfigureControls(); +} + +void QmitkMatchPointRegistrationEvaluator::OnStopBtnPushed() +{ + this->m_activeEvaluation = false; + + this->GetDataStorage()->Remove(this->m_selectedEvalNode); + this->m_selectedEvalNode = nullptr; + this->m_Controls.evalSettings->SetNode(this->m_selectedEvalNode); + + this->CheckInputs(); + this->ConfigureControls(); + 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..db448a7e5a --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.h @@ -0,0 +1,122 @@ +/*=================================================================== + +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 +#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, public mitk::IRenderWindowPartListener +{ + // 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(); + ~QmitkMatchPointRegistrationEvaluator(); + + virtual void CreateQtPartControl(QWidget *parent); + + protected slots: + + /// \brief Called when the user clicks the GUI button + + void OnEvalBtnPushed(); + void OnStopBtnPushed(); + void OnSettingsChanged(mitk::DataNode*); + + void OnSliceChanged(); + +protected: + /// \brief called by QmitkFunctionality when DataManager's selection has changed + virtual void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, + const QList& nodes); + + virtual void SetFocus(); + + virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart); + virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart); + + 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(); + + /** + * 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 controls regarding to selected eval object.*/ + void ConfigureControls(); + + mitk::DataNode::Pointer m_selectedEvalNode; + mitk::DataStorage::SetOfObjects::ConstPointer m_evalNodes; + + QmitkSliceNavigationListener m_SliceChangeListener; + + itk::TimeStamp m_selectedNodeTime; + itk::TimeStamp m_currentPositionTime; + + /** @brief currently valid selected position in the inspector*/ + mitk::Point3D m_currentSelectedPosition; + /** @brief indicates if the currently selected position is valid for the currently selected fit. + * This it is within the input image */ + unsigned int m_currentSelectedTimeStep; + + mitk::DataNode::Pointer m_spSelectedRegNode; + mitk::DataNode::Pointer m_spSelectedMovingNode; + mitk::DataNode::Pointer m_spSelectedTargetNode; + + bool m_autoTarget; + bool m_autoMoving; + bool m_activeEvaluation; + + const std::string HelperNodeName; +}; + +#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..163812fb96 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/QmitkMatchPointRegistrationEvaluator.ui @@ -0,0 +1,340 @@ + + + MatchPointRegistrationEvaluatorControls + + + + 0 + 0 + 379 + 694 + + + + + 5 + + + 5 + + + 5 + + + 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> + + + Start evaluation + + + + + + + Stop evaluation + + + + + + + + 0 + 0 + + + + + 250 + 10 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QmitkRegEvalSettingsWidget + QWidget +
QmitkRegEvalSettingsWidget.h
+
+
+ + + + + 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..cf7305d1d7 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.matchpoint.evaluator/src/internal/org_mitk_gui_qt_matchpoint_evaluator_Activator.cpp @@ -0,0 +1,43 @@ +/*=================================================================== + +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" + +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) + + 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 diff --git a/Plugins/org.mitk.gui.qt.matchpoint.framereg/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.matchpoint.framereg/documentation/UserManual/Manual.dox index 01c46d8565..f70bda38f4 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.framereg/documentation/UserManual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.matchpoint.framereg/documentation/UserManual/Manual.dox @@ -1,64 +1,64 @@ /** -\page de_dkfz_matchpoint_mitk_gui_qt_algorithm_framereg The MatchPoint Motion/Frame Correction Plugin +\page org_mitk_gui_qt_matchpoint_framereg The MatchPoint Motion/Frame Correction Plugin \imageMacro{"map-icon-run.png", "Icon of the MatchPoint Algorithm Control", 3} \li \ref MAP_FRAME_Introduction \li \ref MAP_FRAME_Contact \li \ref MAP_FRAME_Usage \section MAP_FRAME_Introduction Introduction This plugin offers the user a way to use a selected registration algorithm in order to make a frame/motion correction for a selected 3D+t images. The plugin is for example helpfull if you have a dynamic image with motion artifacts in same time points and you want to reduce/remove this motion artifacts. For the selection of an algorithm please see MatchPoint Algorithm Browser (\ref de_dkfz_matchpoint_mitk_gui_qt_algorithm_browser). \section MAP_FRAME_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_FRAME_Usage Usage \imageMacro{"control_example.png" , "Example screenshot showing the plugin in use.", 15} To use the plugin a registration algorithm must be loaded and the image must be selected, that should be corrected.\n The correction is performed that every frame/timpoint of the image is registered to the first frame. And the corrected frames is mapped in the same geometry then the first frame.\n If an algorithm is loaded and input images are selected, the plugin will automatically switch to the "Execution" tab. \subsection MAP_FRAME_Usage_selection Algorithm selection tab \imageMacro{step1_selection.png, "Details of the algorithm selection tab.", 6} In this tab you can load/"book" the algorithm selected in the MatchPoint Algorithm Browser. In the tab you see the ID of the algorithm selected by the browser and its profile information.\n If you press "Load selected algorithm", the algorithm will be used by the plugin for the frame correction and the name of the algorithm occurs in the text field "Loaded algorithm" (at the top of the plugin view).\n At this point, it has no effect if you change the the selection in the browser. The plugin will keep the loaded algorithm until you choose to load another one. \subsection MAP_FRAME_Usage_exec Execution tab \imageMacro{step2_execution.png, "Details of the execution tab.", 8} In this tab you can specify a name for the correction job (this will determine the names of the result nodes in the data manager).\n "Start" will trigger the correction process. \subsection MAP_FRAME_Usage_settings Settings tab \imageMacro{step3_settings.png, "Details of the settings tab.", 8} In this tab, you can (1) define the mapping settings \ref MAP_FRAME_Mapper_Settings "(See details)", used for the corrected frames, or (2) parametrize the loaded algorithm (before it starts), if it offers any possibility to do so. */ \section MAP_FRAME_Mapper_Settings Mapper settings For the mapping of corrected images, 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. \ref MAP_FRAME_Interpolation "(see details)" \section MAP_FRAME_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. \subsection MAP_FRAME_Usage_frame_selection Frame selection tab \imageMacro{step4_frameselection.png, "Details of the frame selection tab.", 6} In this tab you can specify the frames of the currently selected image that should be corrected. As default all frames of an image will be corrected. If you only select specific frames, these frames will be corrected all other frames will be just copied unchanged. diff --git a/Plugins/org.mitk.gui.qt.matchpoint.visualizer/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.matchpoint.visualizer/documentation/UserManual/Manual.dox index 4335a47bbc..47eb4c4212 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.visualizer/documentation/UserManual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.matchpoint.visualizer/documentation/UserManual/Manual.dox @@ -1,23 +1,23 @@ /** -\page org_mitk_gui_qt_registration_visualizer The MatchPoint Registration Visualizer Plugin +\page org_mitk_gui_qt_matchpoint_visualizer The MatchPoint Registration Visualizer Plugin \imageMacro{map-icon-regvis.png, "Icon of the Registration Visualizer",3} \li \ref MAP_VIS_Introduction \li \ref MAP_VIS_Contact \li \ref MAP_VIS_Usage \section MAP_VIS_Introduction Introduction This plugins is in development to offer the user a way to visualize MatchPoint registrations in an MITK scene. Currently only a simple grid visualization is implemented.\n \remark This is an experimental version and work in progress. So please excuse errors or usage issues and report them. This plugin will be improved and polished with the next releases. \section MAP_VIS_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_VIS_Usage Usage Oops. Documentation is missing and to be done. */