diff --git a/Modules/Segmentation/Interactions/mitkSegTool2D.cpp b/Modules/Segmentation/Interactions/mitkSegTool2D.cpp index 363d7d85c5..0fe7953601 100644 --- a/Modules/Segmentation/Interactions/mitkSegTool2D.cpp +++ b/Modules/Segmentation/Interactions/mitkSegTool2D.cpp @@ -1,476 +1,490 @@ /*=================================================================== 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 "mitkSegTool2D.h" #include "mitkToolManager.h" #include "mitkDataStorage.h" #include "mitkBaseRenderer.h" #include "mitkPlaneGeometry.h" #include "mitkExtractImageFilter.h" #include "mitkExtractDirectedPlaneImageFilter.h" //Include of the new ImageExtractor #include "mitkExtractDirectedPlaneImageFilterNew.h" #include "mitkPlanarCircle.h" #include "mitkOverwriteSliceImageFilter.h" #include "mitkOverwriteDirectedPlaneImageFilter.h" #include "mitkMorphologicalOperations.h" #include "usGetModuleContext.h" //Includes for 3DSurfaceInterpolation #include "mitkImageToContourFilter.h" #include "mitkSurfaceInterpolationController.h" +#include "mitkImageTimeSelector.h" //includes for resling and overwriting #include #include #include #include #include #include "mitkOperationEvent.h" #include "mitkUndoController.h" #include "mitkAbstractTransformGeometry.h" #define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) bool mitk::SegTool2D::m_SurfaceInterpolationEnabled = true; mitk::SegTool2D::SegTool2D(const char* type) :Tool(type), m_LastEventSender(NULL), m_LastEventSlice(0), m_Contourmarkername ("Position"), m_ShowMarkerNodes (false) { } mitk::SegTool2D::~SegTool2D() { } bool mitk::SegTool2D::FilterEvents(InteractionEvent* interactionEvent, DataNode*dataNode) { const InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); bool isValidEvent = ( positionEvent && // Only events of type mitk::InteractionPositionEvent interactionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard2D // Only events from the 2D renderwindows ); return isValidEvent; } bool mitk::SegTool2D::DetermineAffectedImageSlice( const Image* image, const PlaneGeometry* plane, int& affectedDimension, int& affectedSlice ) { assert(image); assert(plane); // compare normal of plane to the three axis vectors of the image Vector3D normal = plane->GetNormal(); Vector3D imageNormal0 = image->GetSlicedGeometry()->GetAxisVector(0); Vector3D imageNormal1 = image->GetSlicedGeometry()->GetAxisVector(1); Vector3D imageNormal2 = image->GetSlicedGeometry()->GetAxisVector(2); normal.Normalize(); imageNormal0.Normalize(); imageNormal1.Normalize(); imageNormal2.Normalize(); imageNormal0.SetVnlVector( vnl_cross_3d(normal.GetVnlVector(),imageNormal0.GetVnlVector()) ); imageNormal1.SetVnlVector( vnl_cross_3d(normal.GetVnlVector(),imageNormal1.GetVnlVector()) ); imageNormal2.SetVnlVector( vnl_cross_3d(normal.GetVnlVector(),imageNormal2.GetVnlVector()) ); double eps( 0.00001 ); // axial if ( imageNormal2.GetNorm() <= eps ) { affectedDimension = 2; } // sagittal else if ( imageNormal1.GetNorm() <= eps ) { affectedDimension = 1; } // frontal else if ( imageNormal0.GetNorm() <= eps ) { affectedDimension = 0; } else { affectedDimension = -1; // no idea return false; } // determine slice number in image BaseGeometry* imageGeometry = image->GetGeometry(0); Point3D testPoint = imageGeometry->GetCenter(); Point3D projectedPoint; plane->Project( testPoint, projectedPoint ); Point3D indexPoint; imageGeometry->WorldToIndex( projectedPoint, indexPoint ); affectedSlice = ROUND( indexPoint[affectedDimension] ); MITK_DEBUG << "indexPoint " << indexPoint << " affectedDimension " << affectedDimension << " affectedSlice " << affectedSlice; // check if this index is still within the image if ( affectedSlice < 0 || affectedSlice >= static_cast(image->GetDimension(affectedDimension)) ) return false; return true; } void mitk::SegTool2D::UpdateSurfaceInterpolation (const Image* slice, const Image* workingImage, const PlaneGeometry *plane, bool detectIntersection) { if (!m_SurfaceInterpolationEnabled) return; ImageToContourFilter::Pointer contourExtractor = ImageToContourFilter::New(); mitk::Surface::Pointer contour; if (detectIntersection) { // Test whether there is something to extract or whether the slice just contains intersections of others mitk::Image::Pointer slice2 = slice->Clone(); mitk::MorphologicalOperations::Erode(slice2, 2, mitk::MorphologicalOperations::Ball); contourExtractor->SetInput(slice2); contourExtractor->Update(); contour = contourExtractor->GetOutput(); if (contour->GetVtkPolyData()->GetNumberOfPoints() == 0) { // Remove contour! mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo; contourInfo.contourNormal = plane->GetNormal(); contourInfo.contourPoint = plane->GetOrigin(); mitk::SurfaceInterpolationController::GetInstance()->RemoveContour(contourInfo); return; } } contourExtractor->SetInput(slice); contourExtractor->Update(); contour = contourExtractor->GetOutput(); - if (contour->GetVtkPolyData()->GetNumberOfPoints() != 0 && workingImage->GetDimension() == 3) + mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); + timeSelector->SetInput( workingImage ); + timeSelector->SetTimeNr( 0 ); + timeSelector->SetChannelNr( 0 ); + timeSelector->Update(); + Image::Pointer dimRefImg = timeSelector->GetOutput(); + + if (contour->GetVtkPolyData()->GetNumberOfPoints() != 0 && dimRefImg->GetDimension() == 3) { mitk::SurfaceInterpolationController::GetInstance()->AddNewContour( contour ); contour->DisconnectPipeline(); } else { // Remove contour! mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo; contourInfo.contourNormal = plane->GetNormal(); contourInfo.contourPoint = plane->GetOrigin(); mitk::SurfaceInterpolationController::GetInstance()->RemoveContour(contourInfo); } } mitk::Image::Pointer mitk::SegTool2D::GetAffectedImageSliceAs2DImage(const InteractionPositionEvent* positionEvent, const Image* image) { if (!positionEvent) return NULL; assert( positionEvent->GetSender() ); // sure, right? unsigned int timeStep = positionEvent->GetSender()->GetTimeStep( image ); // get the timestep of the visible part (time-wise) of the image // first, we determine, which slice is affected const PlaneGeometry* planeGeometry( dynamic_cast (positionEvent->GetSender()->GetCurrentWorldPlaneGeometry() ) ); return this->GetAffectedImageSliceAs2DImage(planeGeometry, image, timeStep); } mitk::Image::Pointer mitk::SegTool2D::GetAffectedImageSliceAs2DImage(const PlaneGeometry* planeGeometry, const Image* image, unsigned int timeStep) { if ( !image || !planeGeometry ) return NULL; //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer vtkSmartPointer reslice = vtkSmartPointer::New(); //set to false to extract a slice reslice->SetOverwriteMode(false); reslice->Modified(); //use ExtractSliceFilter with our specific vtkImageReslice for overwriting and extracting mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput( image ); extractor->SetTimeStep( timeStep ); extractor->SetWorldGeometry( planeGeometry ); extractor->SetVtkOutputRequest(false); extractor->SetResliceTransformByGeometry( image->GetTimeGeometry()->GetGeometryForTimeStep( timeStep ) ); extractor->Modified(); extractor->Update(); Image::Pointer slice = extractor->GetOutput(); /*============= BEGIN undo feature block ========================*/ //specify the undo operation with the non edited slice m_undoOperation = new DiffSliceOperation(const_cast(image), extractor->GetVtkOutput(), dynamic_cast(slice->GetGeometry()), timeStep, const_cast(planeGeometry)); /*============= END undo feature block ========================*/ return slice; } mitk::Image::Pointer mitk::SegTool2D::GetAffectedWorkingSlice(const InteractionPositionEvent* positionEvent) { DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); if ( !workingNode ) return NULL; Image* workingImage = dynamic_cast(workingNode->GetData()); if ( !workingImage ) return NULL; return GetAffectedImageSliceAs2DImage( positionEvent, workingImage ); } mitk::Image::Pointer mitk::SegTool2D::GetAffectedReferenceSlice(const InteractionPositionEvent* positionEvent) { DataNode* referenceNode( m_ToolManager->GetReferenceData(0) ); if ( !referenceNode ) return NULL; Image* referenceImage = dynamic_cast(referenceNode->GetData()); if ( !referenceImage ) return NULL; return GetAffectedImageSliceAs2DImage( positionEvent, referenceImage ); } void mitk::SegTool2D::WriteBackSegmentationResult (const InteractionPositionEvent* positionEvent, Image* slice) { if(!positionEvent) return; const PlaneGeometry* planeGeometry( dynamic_cast (positionEvent->GetSender()->GetCurrentWorldPlaneGeometry() ) ); const AbstractTransformGeometry* abstractTransformGeometry( dynamic_cast (positionEvent->GetSender()->GetCurrentWorldPlaneGeometry() ) ); if( planeGeometry && slice && !abstractTransformGeometry) { DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); Image* image = dynamic_cast(workingNode->GetData()); unsigned int timeStep = positionEvent->GetSender()->GetTimeStep( image ); this->WriteBackSegmentationResult(planeGeometry, slice, timeStep); } } void mitk::SegTool2D::WriteBackSegmentationResult (const PlaneGeometry* planeGeometry, Image* slice, unsigned int timeStep) { if(!planeGeometry || !slice) return; SliceInformation sliceInfo (slice, const_cast(planeGeometry), timeStep); this->WriteSliceToVolume(sliceInfo); DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); Image* image = dynamic_cast(workingNode->GetData()); this->UpdateSurfaceInterpolation(slice, image, planeGeometry, false); if (m_SurfaceInterpolationEnabled) this->AddContourmarker(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::SegTool2D::WriteBackSegmentationResult(std::vector sliceList, bool writeSliceToVolume) { std::vector contourList; contourList.reserve(sliceList.size()); ImageToContourFilter::Pointer contourExtractor = ImageToContourFilter::New(); DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); Image* image = dynamic_cast(workingNode->GetData()); + mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); + timeSelector->SetInput( image ); + timeSelector->SetTimeNr( 0 ); + timeSelector->SetChannelNr( 0 ); + timeSelector->Update(); + Image::Pointer dimRefImg = timeSelector->GetOutput(); for (unsigned int i = 0; i < sliceList.size(); ++i) { SliceInformation currentSliceInfo = sliceList.at(i); if(writeSliceToVolume) this->WriteSliceToVolume(currentSliceInfo); - if (m_SurfaceInterpolationEnabled && image->GetDimension() == 3) + if (m_SurfaceInterpolationEnabled && dimRefImg->GetDimension() == 3) { currentSliceInfo.slice->DisconnectPipeline(); contourExtractor->SetInput(currentSliceInfo.slice); contourExtractor->Update(); mitk::Surface::Pointer contour = contourExtractor->GetOutput(); contour->DisconnectPipeline(); contourList.push_back(contour); } } mitk::SurfaceInterpolationController::GetInstance()->AddNewContours(contourList); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::SegTool2D::WriteSliceToVolume(mitk::SegTool2D::SliceInformation sliceInfo) { DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); Image* image = dynamic_cast(workingNode->GetData()); //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer vtkSmartPointer reslice = vtkSmartPointer::New(); //Set the slice as 'input' reslice->SetInputSlice(sliceInfo.slice->GetVtkImageData()); //set overwrite mode to true to write back to the image volume reslice->SetOverwriteMode(true); reslice->Modified(); mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput( image ); extractor->SetTimeStep( sliceInfo.timestep ); extractor->SetWorldGeometry( sliceInfo.plane ); extractor->SetVtkOutputRequest(true); extractor->SetResliceTransformByGeometry( image->GetGeometry( sliceInfo.timestep ) ); extractor->Modified(); extractor->Update(); //the image was modified within the pipeline, but not marked so image->Modified(); image->GetVtkImageData()->Modified(); /*============= BEGIN undo feature block ========================*/ //specify the undo operation with the edited slice m_doOperation = new DiffSliceOperation(image, extractor->GetVtkOutput(),dynamic_cast(sliceInfo.slice->GetGeometry()), sliceInfo.timestep, sliceInfo.plane); //create an operation event for the undo stack OperationEvent* undoStackItem = new OperationEvent( DiffSliceOperationApplier::GetInstance(), m_doOperation, m_undoOperation, "Segmentation" ); //add it to the undo controller UndoController::GetCurrentUndoModel()->SetOperationEvent( undoStackItem ); //clear the pointers as the operation are stored in the undocontroller and also deleted from there m_undoOperation = NULL; m_doOperation = NULL; /*============= END undo feature block ========================*/ } void mitk::SegTool2D::SetShowMarkerNodes(bool status) { m_ShowMarkerNodes = status; } void mitk::SegTool2D::SetEnable3DInterpolation(bool enabled) { m_SurfaceInterpolationEnabled = enabled; } int mitk::SegTool2D::AddContourmarker() { if (m_LastEventSender == NULL) return -1; us::ServiceReference serviceRef = us::GetModuleContext()->GetServiceReference(); PlanePositionManagerService* service = us::GetModuleContext()->GetService(serviceRef); unsigned int slicePosition = m_LastEventSender->GetSliceNavigationController()->GetSlice()->GetPos(); // the first geometry is needed otherwise restoring the position is not working const mitk::PlaneGeometry* plane = dynamic_cast (dynamic_cast< const mitk::SlicedGeometry3D*>( m_LastEventSender->GetSliceNavigationController()->GetCurrentGeometry3D())->GetPlaneGeometry(0)); unsigned int size = service->GetNumberOfPlanePositions(); unsigned int id = service->AddNewPlanePosition(plane, slicePosition); mitk::PlanarCircle::Pointer contourMarker = mitk::PlanarCircle::New(); mitk::Point2D p1; plane->Map(plane->GetCenter(), p1); mitk::Point2D p2 = p1; p2[0] -= plane->GetSpacing()[0]; p2[1] -= plane->GetSpacing()[1]; contourMarker->PlaceFigure( p1 ); contourMarker->SetCurrentControlPoint( p1 ); contourMarker->SetPlaneGeometry( const_cast(plane)); std::stringstream markerStream; mitk::DataNode* workingNode (m_ToolManager->GetWorkingData(0)); markerStream << m_Contourmarkername ; markerStream << " "; markerStream << id+1; DataNode::Pointer rotatedContourNode = DataNode::New(); rotatedContourNode->SetData(contourMarker); rotatedContourNode->SetProperty( "name", StringProperty::New(markerStream.str()) ); rotatedContourNode->SetProperty( "isContourMarker", BoolProperty::New(true)); rotatedContourNode->SetBoolProperty( "PlanarFigureInitializedWindow", true, m_LastEventSender ); rotatedContourNode->SetProperty( "includeInBoundingBox", BoolProperty::New(false)); rotatedContourNode->SetProperty( "helper object", mitk::BoolProperty::New(!m_ShowMarkerNodes)); rotatedContourNode->SetProperty( "planarfigure.drawcontrolpoints", BoolProperty::New(false)); rotatedContourNode->SetProperty( "planarfigure.drawname", BoolProperty::New(false)); rotatedContourNode->SetProperty( "planarfigure.drawoutline", BoolProperty::New(false)); rotatedContourNode->SetProperty( "planarfigure.drawshadow", BoolProperty::New(false)); if (plane) { if ( id == size ) { m_ToolManager->GetDataStorage()->Add(rotatedContourNode, workingNode); } else { mitk::NodePredicateProperty::Pointer isMarker = mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true)); mitk::DataStorage::SetOfObjects::ConstPointer markers = m_ToolManager->GetDataStorage()->GetDerivations(workingNode,isMarker); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = markers->begin(); iter != markers->end(); ++iter) { std::string nodeName = (*iter)->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int markerId = atof(nodeName.substr(t+1).c_str())-1; if(id == markerId) { return id; } } m_ToolManager->GetDataStorage()->Add(rotatedContourNode, workingNode); } } return id; } void mitk::SegTool2D::InteractiveSegmentationBugMessage( const std::string& message ) { MITK_ERROR << "********************************************************************************" << std::endl << " " << message << std::endl << "********************************************************************************" << std::endl << " " << std::endl << " If your image is rotated or the 2D views don't really contain the patient image, try to press the button next to the image selection. " << std::endl << " " << std::endl << " Please file a BUG REPORT: " << std::endl << " http://bugs.mitk.org" << std::endl << " Contain the following information:" << std::endl << " - What image were you working on?" << std::endl << " - Which region of the image?" << std::endl << " - Which tool did you use?" << std::endl << " - What did you do?" << std::endl << " - What happened (not)? What did you expect?" << std::endl; } diff --git a/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp b/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp index 890a10bd18..7fd26252cc 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkSlicesInterpolator.cpp @@ -1,1163 +1,1178 @@ /*=================================================================== 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 "QmitkSlicesInterpolator.h" #include "QmitkStdMultiWidget.h" #include "QmitkSelectableGLWidget.h" #include "mitkToolManager.h" #include "mitkLevelWindowProperty.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkOverwriteSliceImageFilter.h" #include "mitkProgressBar.h" #include "mitkGlobalInteraction.h" #include "mitkOperationEvent.h" #include "mitkUndoController.h" #include "mitkInteractionConst.h" #include "mitkApplyDiffImageOperation.h" #include "mitkDiffImageApplier.h" #include "mitkSegTool2D.h" #include "mitkCoreObjectFactory.h" #include "mitkSurfaceToImageFilter.h" #include "mitkSliceNavigationController.h" #include #include #include #include +#include #include #include #include #include #include #include #include //#define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) float SURFACE_COLOR_RGB [3] = {0.49f, 1.0f, 0.16f}; const std::map QmitkSlicesInterpolator::createActionToSliceDimension() { std::map actionToSliceDimension; foreach(mitk::SliceNavigationController* slicer, m_ControllerToDeleteObserverTag.keys()) { actionToSliceDimension[new QAction(QString::fromStdString(slicer->GetViewDirectionAsString()),0)] = slicer; } return actionToSliceDimension; } QmitkSlicesInterpolator::QmitkSlicesInterpolator(QWidget* parent, const char* /*name*/) :QWidget(parent), // ACTION_TO_SLICEDIMENSION( createActionToSliceDimension() ), m_Interpolator( mitk::SegmentationInterpolationController::New() ), m_SurfaceInterpolator(mitk::SurfaceInterpolationController::GetInstance()), m_ToolManager(NULL), m_Initialized(false), m_LastSNC(0), m_LastSliceIndex(0), m_2DInterpolationEnabled(false), m_3DInterpolationEnabled(false) { m_GroupBoxEnableExclusiveInterpolationMode = new QGroupBox("Interpolation", this); QVBoxLayout* vboxLayout = new QVBoxLayout(m_GroupBoxEnableExclusiveInterpolationMode); m_CmbInterpolation = new QComboBox(m_GroupBoxEnableExclusiveInterpolationMode); m_CmbInterpolation->addItem("Disabled"); m_CmbInterpolation->addItem("2-Dimensional"); m_CmbInterpolation->addItem("3-Dimensional"); vboxLayout->addWidget(m_CmbInterpolation); m_BtnApply2D = new QPushButton("Confirm for single slice", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApply2D); m_BtnApplyForAllSlices2D = new QPushButton("Confirm for all slices", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApplyForAllSlices2D); m_BtnApply3D = new QPushButton("Confirm", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnApply3D); m_BtnReinit3DInterpolation = new QPushButton("Reinit Interpolation", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_BtnReinit3DInterpolation); m_ChkShowPositionNodes = new QCheckBox("Show Position Nodes", m_GroupBoxEnableExclusiveInterpolationMode); vboxLayout->addWidget(m_ChkShowPositionNodes); this->HideAllInterpolationControls(); connect(m_CmbInterpolation, SIGNAL(currentIndexChanged(int)), this, SLOT(OnInterpolationMethodChanged(int))); connect(m_BtnApply2D, SIGNAL(clicked()), this, SLOT(OnAcceptInterpolationClicked())); connect(m_BtnApplyForAllSlices2D, SIGNAL(clicked()), this, SLOT(OnAcceptAllInterpolationsClicked())); connect(m_BtnApply3D, SIGNAL(clicked()), this, SLOT(OnAccept3DInterpolationClicked())); connect(m_BtnReinit3DInterpolation, SIGNAL(clicked()), this, SLOT(OnReinit3DInterpolation())); connect(m_ChkShowPositionNodes, SIGNAL(toggled(bool)), this, SLOT(OnShowMarkers(bool))); connect(m_ChkShowPositionNodes, SIGNAL(toggled(bool)), this, SIGNAL(SignalShowMarkerNodes(bool))); QHBoxLayout* layout = new QHBoxLayout(this); layout->addWidget(m_GroupBoxEnableExclusiveInterpolationMode); this->setLayout(layout); itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); command->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnInterpolationInfoChanged ); InterpolationInfoChangedObserverTag = m_Interpolator->AddObserver( itk::ModifiedEvent(), command ); itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnSurfaceInterpolationInfoChanged ); SurfaceInterpolationInfoChangedObserverTag = m_SurfaceInterpolator->AddObserver( itk::ModifiedEvent(), command2 ); // feedback node and its visualization properties m_FeedbackNode = mitk::DataNode::New(); mitk::CoreObjectFactory::GetInstance()->SetDefaultProperties( m_FeedbackNode ); m_FeedbackNode->SetProperty( "binary", mitk::BoolProperty::New(true) ); m_FeedbackNode->SetProperty( "outline binary", mitk::BoolProperty::New(true) ); m_FeedbackNode->SetProperty( "color", mitk::ColorProperty::New(255.0, 255.0, 0.0) ); m_FeedbackNode->SetProperty( "texture interpolation", mitk::BoolProperty::New(false) ); m_FeedbackNode->SetProperty( "layer", mitk::IntProperty::New( 20 ) ); m_FeedbackNode->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( mitk::LevelWindow(0, 1) ) ); m_FeedbackNode->SetProperty( "name", mitk::StringProperty::New("Interpolation feedback") ); m_FeedbackNode->SetProperty( "opacity", mitk::FloatProperty::New(0.8) ); m_FeedbackNode->SetProperty( "helper object", mitk::BoolProperty::New(true) ); m_InterpolatedSurfaceNode = mitk::DataNode::New(); m_InterpolatedSurfaceNode->SetProperty( "color", mitk::ColorProperty::New(SURFACE_COLOR_RGB) ); m_InterpolatedSurfaceNode->SetProperty( "name", mitk::StringProperty::New("Surface Interpolation feedback") ); m_InterpolatedSurfaceNode->SetProperty( "opacity", mitk::FloatProperty::New(0.5) ); m_InterpolatedSurfaceNode->SetProperty( "line width", mitk::FloatProperty::New(4.0f) ); m_InterpolatedSurfaceNode->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(false)); m_InterpolatedSurfaceNode->SetProperty( "helper object", mitk::BoolProperty::New(true) ); m_InterpolatedSurfaceNode->SetVisibility(false); m_3DContourNode = mitk::DataNode::New(); m_3DContourNode->SetProperty( "color", mitk::ColorProperty::New(0.0, 0.0, 0.0) ); m_3DContourNode->SetProperty("hidden object", mitk::BoolProperty::New(true)); m_3DContourNode->SetProperty( "name", mitk::StringProperty::New("Drawn Contours") ); m_3DContourNode->SetProperty("material.representation", mitk::VtkRepresentationProperty::New(VTK_WIREFRAME)); m_3DContourNode->SetProperty("material.wireframeLineWidth", mitk::FloatProperty::New(2.0f)); m_3DContourNode->SetProperty("3DContourContainer", mitk::BoolProperty::New(true)); m_3DContourNode->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(false)); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget2"))); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))); m_3DContourNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); QWidget::setContentsMargins(0, 0, 0, 0); if ( QWidget::layout() != NULL ) { QWidget::layout()->setContentsMargins(0, 0, 0, 0); } //For running 3D Interpolation in background // create a QFuture and a QFutureWatcher connect(&m_Watcher, SIGNAL(started()), this, SLOT(StartUpdateInterpolationTimer())); connect(&m_Watcher, SIGNAL(finished()), this, SLOT(OnSurfaceInterpolationFinished())); connect(&m_Watcher, SIGNAL(finished()), this, SLOT(StopUpdateInterpolationTimer())); m_Timer = new QTimer(this); connect(m_Timer, SIGNAL(timeout()), this, SLOT(ChangeSurfaceColor())); } void QmitkSlicesInterpolator::SetDataStorage( mitk::DataStorage::Pointer storage ) { m_DataStorage = storage; m_SurfaceInterpolator->SetDataStorage(storage); } mitk::DataStorage* QmitkSlicesInterpolator::GetDataStorage() { if ( m_DataStorage.IsNotNull() ) { return m_DataStorage; } else { return NULL; } } void QmitkSlicesInterpolator::Initialize(mitk::ToolManager* toolManager, const QList &controllers) { Q_ASSERT(!controllers.empty()); if (m_Initialized) { // remove old observers Uninitialize(); } m_ToolManager = toolManager; if (m_ToolManager) { // set enabled only if a segmentation is selected mitk::DataNode* node = m_ToolManager->GetWorkingData(0); QWidget::setEnabled( node != NULL ); // react whenever the set of selected segmentation changes m_ToolManager->WorkingDataChanged += mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerWorkingDataModified ); m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate( this, &QmitkSlicesInterpolator::OnToolManagerReferenceDataModified ); // connect to the slice navigation controller. after each change, call the interpolator foreach(mitk::SliceNavigationController* slicer, controllers) { //Has to be initialized m_LastSNC = slicer; m_TimeStep.insert(slicer, slicer->GetTime()->GetPos()); itk::MemberCommand::Pointer deleteCommand = itk::MemberCommand::New(); deleteCommand->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnSliceNavigationControllerDeleted); m_ControllerToDeleteObserverTag.insert(slicer, slicer->AddObserver(itk::DeleteEvent(), deleteCommand)); itk::MemberCommand::Pointer timeChangedCommand = itk::MemberCommand::New(); timeChangedCommand->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnTimeChanged); m_ControllerToTimeObserverTag.insert(slicer, slicer->AddObserver(mitk::SliceNavigationController::TimeGeometryEvent(NULL,0), timeChangedCommand)); itk::MemberCommand::Pointer sliceChangedCommand = itk::MemberCommand::New(); sliceChangedCommand->SetCallbackFunction( this, &QmitkSlicesInterpolator::OnSliceChanged); m_ControllerToSliceObserverTag.insert(slicer, slicer->AddObserver(mitk::SliceNavigationController::GeometrySliceEvent(NULL,0), sliceChangedCommand)); } ACTION_TO_SLICEDIMENSION = createActionToSliceDimension(); } m_Initialized = true; } void QmitkSlicesInterpolator::Uninitialize() { if (m_ToolManager.IsNotNull()) { m_ToolManager->WorkingDataChanged -= mitk::MessageDelegate(this, &QmitkSlicesInterpolator::OnToolManagerWorkingDataModified); m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate(this, &QmitkSlicesInterpolator::OnToolManagerReferenceDataModified); } foreach(mitk::SliceNavigationController* slicer, m_ControllerToSliceObserverTag.keys()) { slicer->RemoveObserver(m_ControllerToDeleteObserverTag.take(slicer)); slicer->RemoveObserver(m_ControllerToTimeObserverTag.take(slicer)); slicer->RemoveObserver(m_ControllerToSliceObserverTag.take(slicer)); } ACTION_TO_SLICEDIMENSION.clear(); m_ToolManager = NULL; m_Initialized = false; } QmitkSlicesInterpolator::~QmitkSlicesInterpolator() { if (m_Initialized) { // remove old observers Uninitialize(); } if(m_DataStorage->Exists(m_3DContourNode)) m_DataStorage->Remove(m_3DContourNode); if(m_DataStorage->Exists(m_InterpolatedSurfaceNode)) m_DataStorage->Remove(m_InterpolatedSurfaceNode); // remove observer m_Interpolator->RemoveObserver( InterpolationInfoChangedObserverTag ); m_SurfaceInterpolator->RemoveObserver( SurfaceInterpolationInfoChangedObserverTag ); delete m_Timer; } /** External enableization... */ void QmitkSlicesInterpolator::setEnabled( bool enable ) { QWidget::setEnabled(enable); //Set the gui elements of the different interpolation modi enabled if (enable) { if (m_2DInterpolationEnabled) { this->Show2DInterpolationControls(true); m_Interpolator->Activate2DInterpolation(true); } else if (m_3DInterpolationEnabled) { this->Show3DInterpolationControls(true); this->Show3DInterpolationResult(true); } } //Set all gui elements of the interpolation disabled else { this->HideAllInterpolationControls(); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::On2DInterpolationEnabled(bool status) { OnInterpolationActivated(status); m_Interpolator->Activate2DInterpolation(status); } void QmitkSlicesInterpolator::On3DInterpolationEnabled(bool status) { On3DInterpolationActivated(status); } void QmitkSlicesInterpolator::OnInterpolationDisabled(bool status) { if (status) { OnInterpolationActivated(!status); On3DInterpolationActivated(!status); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::HideAllInterpolationControls() { this->Show2DInterpolationControls(false); this->Show3DInterpolationControls(false); } void QmitkSlicesInterpolator::Show2DInterpolationControls(bool show) { m_BtnApply2D->setVisible(show); m_BtnApplyForAllSlices2D->setVisible(show); } void QmitkSlicesInterpolator::Show3DInterpolationControls(bool show) { m_BtnApply3D->setVisible(show); m_ChkShowPositionNodes->setVisible(show); m_BtnReinit3DInterpolation->setVisible(show); } void QmitkSlicesInterpolator::OnInterpolationMethodChanged(int index) { switch(index) { case 0: // Disabled m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation"); this->HideAllInterpolationControls(); this->OnInterpolationActivated(false); this->On3DInterpolationActivated(false); this->Show3DInterpolationResult(false); m_Interpolator->Activate2DInterpolation(false); break; case 1: // 2D m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation (Enabled)"); this->HideAllInterpolationControls(); this->Show2DInterpolationControls(true); this->OnInterpolationActivated(true); this->On3DInterpolationActivated(false); m_Interpolator->Activate2DInterpolation(true); break; case 2: // 3D m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation (Enabled)"); this->HideAllInterpolationControls(); this->Show3DInterpolationControls(true); this->OnInterpolationActivated(false); this->On3DInterpolationActivated(true); m_Interpolator->Activate2DInterpolation(false); break; default: MITK_ERROR << "Unknown interpolation method!"; m_CmbInterpolation->setCurrentIndex(0); break; } } void QmitkSlicesInterpolator::OnShowMarkers(bool state) { mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = m_DataStorage->GetSubset(mitk::NodePredicateProperty::New("isContourMarker" , mitk::BoolProperty::New(true))); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { it->Value()->SetProperty("helper object", mitk::BoolProperty::New(!state)); } } void QmitkSlicesInterpolator::OnToolManagerWorkingDataModified() { if (m_ToolManager->GetWorkingData(0) != 0) { m_Segmentation = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); m_BtnReinit3DInterpolation->setEnabled(true); } else { //If no workingdata is set, remove the interpolation feedback this->GetDataStorage()->Remove(m_FeedbackNode); m_FeedbackNode->SetData(NULL); this->GetDataStorage()->Remove(m_3DContourNode); m_3DContourNode->SetData(NULL); this->GetDataStorage()->Remove(m_InterpolatedSurfaceNode); m_InterpolatedSurfaceNode->SetData(NULL); m_BtnReinit3DInterpolation->setEnabled(false); return; } //Updating the current selected segmentation for the 3D interpolation SetCurrentContourListID(); if (m_2DInterpolationEnabled) { OnInterpolationActivated( true ); // re-initialize if needed } this->CheckSupportedImageDimension(); } void QmitkSlicesInterpolator::OnToolManagerReferenceDataModified() { } void QmitkSlicesInterpolator::OnTimeChanged(itk::Object* sender, const itk::EventObject& e) { //Check if we really have a GeometryTimeEvent if (!dynamic_cast(&e)) return; mitk::SliceNavigationController* slicer = dynamic_cast(sender); Q_ASSERT(slicer); m_TimeStep[slicer] = slicer->GetTime()->GetPos(); + m_SurfaceInterpolator->SetCurrentTimeStep( slicer->GetTime()->GetPos() ); + if (m_LastSNC == slicer) { slicer->SendSlice();//will trigger a new interpolation } } void QmitkSlicesInterpolator::OnSliceChanged(itk::Object *sender, const itk::EventObject &e) { //Check whether we really have a GeometrySliceEvent if (!dynamic_cast(&e)) return; mitk::SliceNavigationController* slicer = dynamic_cast(sender); if (TranslateAndInterpolateChangedSlice(e, slicer)) { slicer->GetRenderer()->RequestUpdate(); } } bool QmitkSlicesInterpolator::TranslateAndInterpolateChangedSlice(const itk::EventObject& e, mitk::SliceNavigationController* slicer) { if (!m_2DInterpolationEnabled) return false; try { const mitk::SliceNavigationController::GeometrySliceEvent& event = dynamic_cast(e); mitk::TimeGeometry* tsg = event.GetTimeGeometry(); if (tsg && m_TimeStep.contains(slicer)) { mitk::SlicedGeometry3D* slicedGeometry = dynamic_cast(tsg->GetGeometryForTimeStep(m_TimeStep[slicer]).GetPointer()); if (slicedGeometry) { m_LastSNC = slicer; mitk::PlaneGeometry* plane = dynamic_cast(slicedGeometry->GetPlaneGeometry( event.GetPos() )); if (plane) Interpolate( plane, m_TimeStep[slicer], slicer ); return true; } } } catch(std::bad_cast) { return false; // so what } return false; } void QmitkSlicesInterpolator::Interpolate( mitk::PlaneGeometry* plane, unsigned int timeStep, mitk::SliceNavigationController* slicer ) { if (m_ToolManager) { mitk::DataNode* node = m_ToolManager->GetWorkingData(0); if (node) { m_Segmentation = dynamic_cast(node->GetData()); if (m_Segmentation) { int clickedSliceDimension(-1); int clickedSliceIndex(-1); // calculate real slice position, i.e. slice of the image and not slice of the TimeSlicedGeometry mitk::SegTool2D::DetermineAffectedImageSlice( m_Segmentation, plane, clickedSliceDimension, clickedSliceIndex ); mitk::Image::Pointer interpolation = m_Interpolator->Interpolate( clickedSliceDimension, clickedSliceIndex, plane, timeStep ); m_FeedbackNode->SetData( interpolation ); m_LastSNC = slicer; m_LastSliceIndex = clickedSliceIndex; } } } } void QmitkSlicesInterpolator::OnSurfaceInterpolationFinished() { mitk::Surface::Pointer interpolatedSurface = m_SurfaceInterpolator->GetInterpolationResult(); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); if(interpolatedSurface.IsNotNull() && workingNode && workingNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3")))) { m_BtnApply3D->setEnabled(true); m_InterpolatedSurfaceNode->SetData(interpolatedSurface); m_3DContourNode->SetData(m_SurfaceInterpolator->GetContoursAsSurface()); this->Show3DInterpolationResult(true); if( !m_DataStorage->Exists(m_InterpolatedSurfaceNode) ) { m_DataStorage->Add(m_InterpolatedSurfaceNode); } if (!m_DataStorage->Exists(m_3DContourNode)) { m_DataStorage->Add(m_3DContourNode, workingNode); } } else if (interpolatedSurface.IsNull()) { m_BtnApply3D->setEnabled(false); if (m_DataStorage->Exists(m_InterpolatedSurfaceNode)) { this->Show3DInterpolationResult(false); } } m_BtnReinit3DInterpolation->setEnabled(true); foreach (mitk::SliceNavigationController* slicer, m_ControllerToTimeObserverTag.keys()) { slicer->GetRenderer()->RequestUpdate(); } } void QmitkSlicesInterpolator::OnAcceptInterpolationClicked() { if (m_Segmentation && m_FeedbackNode->GetData()) { //making interpolation separately undoable mitk::UndoStackItem::IncCurrObjectEventId(); mitk::UndoStackItem::IncCurrGroupEventId(); mitk::UndoStackItem::ExecuteIncrement(); //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer vtkSmartPointer reslice = vtkSmartPointer::New(); // Set slice as input mitk::Image::Pointer slice = dynamic_cast(m_FeedbackNode->GetData()); reslice->SetInputSlice(slice->GetSliceData()->GetVtkImageAccessor(slice)->GetVtkImageData()); //set overwrite mode to true to write back to the image volume reslice->SetOverwriteMode(true); reslice->Modified(); mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput( m_Segmentation ); unsigned int timestep = m_LastSNC->GetTime()->GetPos(); extractor->SetTimeStep( timestep ); extractor->SetWorldGeometry( m_LastSNC->GetCurrentPlaneGeometry() ); extractor->SetVtkOutputRequest(true); extractor->SetResliceTransformByGeometry( m_Segmentation->GetTimeGeometry()->GetGeometryForTimeStep( timestep ) ); extractor->Modified(); extractor->Update(); //the image was modified within the pipeline, but not marked so m_Segmentation->Modified(); m_Segmentation->GetVtkImageData()->Modified(); m_FeedbackNode->SetData(NULL); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSlicesInterpolator::AcceptAllInterpolations(mitk::SliceNavigationController* slicer) { /* * What exactly is done here: * 1. We create an empty diff image for the current segmentation * 2. All interpolated slices are written into the diff image * 3. Then the diffimage is applied to the original segmentation */ if (m_Segmentation) { //making interpolation separately undoable mitk::UndoStackItem::IncCurrObjectEventId(); mitk::UndoStackItem::IncCurrGroupEventId(); mitk::UndoStackItem::ExecuteIncrement(); mitk::Image::Pointer image3D = m_Segmentation; unsigned int timeStep( slicer->GetTime()->GetPos() ); if (m_Segmentation->GetDimension() == 4) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput( m_Segmentation ); timeSelector->SetTimeNr( timeStep ); timeSelector->Update(); image3D = timeSelector->GetOutput(); } // create a empty diff image for the undo operation mitk::Image::Pointer diffImage = mitk::Image::New(); diffImage->Initialize( image3D ); // Create scope for ImageWriteAccessor so that the accessor is destroyed // after the image is initialized. Otherwise later image access will lead to an error { mitk::ImageWriteAccessor imAccess(diffImage); // Set all pixels to zero mitk::PixelType pixelType( mitk::MakeScalarPixelType() ); memset( imAccess.GetData(), 0, (pixelType.GetBpe() >> 3) * diffImage->GetDimension(0) * diffImage->GetDimension(1) * diffImage->GetDimension(2) ); } // Since we need to shift the plane it must be clone so that the original plane isn't altered mitk::PlaneGeometry::Pointer reslicePlane = slicer->GetCurrentPlaneGeometry()->Clone(); int sliceDimension(-1); int sliceIndex(-1); mitk::SegTool2D::DetermineAffectedImageSlice( m_Segmentation, reslicePlane, sliceDimension, sliceIndex ); unsigned int zslices = m_Segmentation->GetDimension( sliceDimension ); mitk::ProgressBar::GetInstance()->AddStepsToDo(zslices); mitk::Point3D origin = reslicePlane->GetOrigin(); unsigned int totalChangedSlices(0); for (unsigned int sliceIndex = 0; sliceIndex < zslices; ++sliceIndex) { // Transforming the current origin of the reslice plane // so that it matches the one of the next slice m_Segmentation->GetSlicedGeometry()->WorldToIndex(origin, origin); origin[sliceDimension] = sliceIndex; m_Segmentation->GetSlicedGeometry()->IndexToWorld(origin, origin); reslicePlane->SetOrigin(origin); //Set the slice as 'input' mitk::Image::Pointer interpolation = m_Interpolator->Interpolate( sliceDimension, sliceIndex, reslicePlane, timeStep ); if (interpolation.IsNotNull()) // we don't check if interpolation is necessary/sensible - but m_Interpolator does { //Setting up the reslicing pipeline which allows us to write the interpolation results back into //the image volume vtkSmartPointer reslice = vtkSmartPointer::New(); //set overwrite mode to true to write back to the image volume reslice->SetInputSlice(interpolation->GetSliceData()->GetVtkImageAccessor(interpolation)->GetVtkImageData()); reslice->SetOverwriteMode(true); reslice->Modified(); mitk::ExtractSliceFilter::Pointer diffslicewriter = mitk::ExtractSliceFilter::New(reslice); diffslicewriter->SetInput( diffImage ); diffslicewriter->SetTimeStep( 0 ); diffslicewriter->SetWorldGeometry(reslicePlane); diffslicewriter->SetVtkOutputRequest(true); diffslicewriter->SetResliceTransformByGeometry( diffImage->GetTimeGeometry()->GetGeometryForTimeStep( 0 ) ); diffslicewriter->Modified(); diffslicewriter->Update(); ++totalChangedSlices; } mitk::ProgressBar::GetInstance()->Progress(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (totalChangedSlices > 0) { // store undo stack items if ( true ) { // create do/undo operations mitk::ApplyDiffImageOperation* doOp = new mitk::ApplyDiffImageOperation( mitk::OpTEST, m_Segmentation, diffImage, timeStep ); mitk::ApplyDiffImageOperation* undoOp = new mitk::ApplyDiffImageOperation( mitk::OpTEST, m_Segmentation, diffImage, timeStep ); undoOp->SetFactor( -1.0 ); std::stringstream comment; comment << "Confirm all interpolations (" << totalChangedSlices << ")"; mitk::OperationEvent* undoStackItem = new mitk::OperationEvent( mitk::DiffImageApplier::GetInstanceForUndo(), doOp, undoOp, comment.str() ); mitk::UndoController::GetCurrentUndoModel()->SetOperationEvent( undoStackItem ); // acutally apply the changes here to the original image mitk::DiffImageApplier::GetInstanceForUndo()->ExecuteOperation( doOp ); } } m_FeedbackNode->SetData(NULL); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSlicesInterpolator::FinishInterpolation(mitk::SliceNavigationController* slicer) { //this redirect is for calling from outside if (slicer == NULL) OnAcceptAllInterpolationsClicked(); else AcceptAllInterpolations( slicer ); } void QmitkSlicesInterpolator::OnAcceptAllInterpolationsClicked() { QMenu orientationPopup(this); std::map::const_iterator it; for(it = ACTION_TO_SLICEDIMENSION.begin(); it != ACTION_TO_SLICEDIMENSION.end(); it++) orientationPopup.addAction(it->first); connect( &orientationPopup, SIGNAL(triggered(QAction*)), this, SLOT(OnAcceptAllPopupActivated(QAction*)) ); orientationPopup.exec( QCursor::pos() ); } void QmitkSlicesInterpolator::OnAccept3DInterpolationClicked() { if (m_InterpolatedSurfaceNode.IsNotNull() && m_InterpolatedSurfaceNode->GetData()) { mitk::SurfaceToImageFilter::Pointer s2iFilter = mitk::SurfaceToImageFilter::New(); s2iFilter->MakeOutputBinaryOn(); s2iFilter->SetInput(dynamic_cast(m_InterpolatedSurfaceNode->GetData())); // check if ToolManager holds valid ReferenceData if (m_ToolManager->GetReferenceData(0) == NULL || m_ToolManager->GetWorkingData(0) == NULL) { return; } s2iFilter->SetImage(dynamic_cast(m_ToolManager->GetReferenceData(0)->GetData())); s2iFilter->Update(); mitk::DataNode* segmentationNode = m_ToolManager->GetWorkingData(0); - mitk::Image* oldSeg = dynamic_cast(segmentationNode->GetData()); mitk::Image::Pointer newSeg = s2iFilter->GetOutput(); - if (oldSeg) - m_SurfaceInterpolator->ReplaceInterpolationSession(oldSeg, newSeg); + mitk::Image* currSeg = dynamic_cast(segmentationNode->GetData()); + + unsigned int timestep = m_LastSNC->GetTime()->GetPos(); + mitk::ImageReadAccessor readAccess(newSeg, newSeg->GetVolumeData(timestep)); + const void* cPointer = readAccess.GetData(); + + if (currSeg && cPointer) + { + currSeg->SetVolume( cPointer, timestep, 0 ); + } else + { return; + } - segmentationNode->SetData(newSeg); m_CmbInterpolation->setCurrentIndex(0); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); mitk::DataNode::Pointer segSurface = mitk::DataNode::New(); float rgb[3]; segmentationNode->GetColor(rgb); segSurface->SetColor(rgb); segSurface->SetData(m_InterpolatedSurfaceNode->GetData()); std::stringstream stream; stream << segmentationNode->GetName(); stream << "_"; stream << "3D-interpolation"; segSurface->SetName(stream.str()); segSurface->SetProperty( "opacity", mitk::FloatProperty::New(0.7) ); segSurface->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(true)); segSurface->SetProperty( "3DInterpolationResult", mitk::BoolProperty::New(true)); + segSurface->SetVisibility(false); m_DataStorage->Add(segSurface, segmentationNode); this->Show3DInterpolationResult(false); } } void QmitkSlicesInterpolator::OnReinit3DInterpolation() { mitk::NodePredicateProperty::Pointer pred = mitk::NodePredicateProperty::New("3DContourContainer", mitk::BoolProperty::New(true)); mitk::DataStorage::SetOfObjects::ConstPointer contourNodes = m_DataStorage->GetDerivations( m_ToolManager->GetWorkingData(0), pred); if (contourNodes->Size() != 0) { m_3DContourNode = contourNodes->at(0); } else { QMessageBox errorInfo; errorInfo.setWindowTitle("Reinitialize surface interpolation"); errorInfo.setIcon(QMessageBox::Information); errorInfo.setText("No contours available for the selected segmentation!"); errorInfo.exec(); } mitk::Surface::Pointer contours = dynamic_cast(m_3DContourNode->GetData()); if (contours) mitk::SurfaceInterpolationController::GetInstance()->ReinitializeInterpolation(contours); m_BtnReinit3DInterpolation->setEnabled(false); } void QmitkSlicesInterpolator::OnAcceptAllPopupActivated(QAction* action) { try { std::map::const_iterator iter = ACTION_TO_SLICEDIMENSION.find( action ); if (iter != ACTION_TO_SLICEDIMENSION.end()) { mitk::SliceNavigationController* slicer = iter->second; AcceptAllInterpolations( slicer ); } } catch(...) { /* Showing message box with possible memory error */ QMessageBox errorInfo; errorInfo.setWindowTitle("Interpolation Process"); errorInfo.setIcon(QMessageBox::Critical); errorInfo.setText("An error occurred during interpolation. Possible cause: Not enough memory!"); errorInfo.exec(); //additional error message on std::cerr std::cerr << "Ill construction in " __FILE__ " l. " << __LINE__ << std::endl; } } void QmitkSlicesInterpolator::OnInterpolationActivated(bool on) { m_2DInterpolationEnabled = on; try { if ( m_DataStorage.IsNotNull() ) { if (on && !m_DataStorage->Exists(m_FeedbackNode)) { m_DataStorage->Add( m_FeedbackNode ); } } } catch(...) { // don't care (double add/remove) } if (m_ToolManager) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); QWidget::setEnabled( workingNode != NULL ); m_BtnApply2D->setEnabled( on ); m_FeedbackNode->SetVisibility( on ); if (!on) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return; } if (workingNode) { mitk::Image* segmentation = dynamic_cast(workingNode->GetData()); if (segmentation) { m_Interpolator->SetSegmentationVolume( segmentation ); if (referenceNode) { mitk::Image* referenceImage = dynamic_cast(referenceNode->GetData()); m_Interpolator->SetReferenceVolume( referenceImage ); // may be NULL } } } } UpdateVisibleSuggestion(); } void QmitkSlicesInterpolator::Run3DInterpolation() { m_SurfaceInterpolator->Interpolate(); } void QmitkSlicesInterpolator::StartUpdateInterpolationTimer() { m_Timer->start(500); } void QmitkSlicesInterpolator::StopUpdateInterpolationTimer() { m_Timer->stop(); m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB)); mitk::RenderingManager::GetInstance()->RequestUpdate(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetRenderWindow()); } void QmitkSlicesInterpolator::ChangeSurfaceColor() { float currentColor[3]; m_InterpolatedSurfaceNode->GetColor(currentColor); if( currentColor[2] == SURFACE_COLOR_RGB[2]) { m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(1.0f,1.0f,1.0f)); } else { m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB)); } m_InterpolatedSurfaceNode->Update(); mitk::RenderingManager::GetInstance()->RequestUpdate(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))->GetRenderWindow()); } void QmitkSlicesInterpolator::On3DInterpolationActivated(bool on) { m_3DInterpolationEnabled = on; this->CheckSupportedImageDimension(); try { if ( m_DataStorage.IsNotNull() && m_ToolManager && m_3DInterpolationEnabled) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); if (workingNode) { bool isInterpolationResult(false); workingNode->GetBoolProperty("3DInterpolationResult",isInterpolationResult); mitk::NodePredicateAnd::Pointer pred = mitk::NodePredicateAnd::New(mitk::NodePredicateProperty::New("3DInterpolationResult", mitk::BoolProperty::New(true)), mitk::NodePredicateDataType::New("Surface")); mitk::DataStorage::SetOfObjects::ConstPointer interpolationResults = m_DataStorage->GetDerivations(workingNode, pred); for (unsigned int i = 0; i < interpolationResults->Size(); ++i) { mitk::DataNode::Pointer currNode = interpolationResults->at(i); if (currNode.IsNotNull()) m_DataStorage->Remove(currNode); } if ((workingNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3")))) && !isInterpolationResult && m_3DInterpolationEnabled) { int ret = QMessageBox::Yes; if (m_SurfaceInterpolator->EstimatePortionOfNeededMemory() > 0.5) { QMessageBox msgBox; msgBox.setText("Due to short handed system memory the 3D interpolation may be very slow!"); msgBox.setInformativeText("Are you sure you want to activate the 3D interpolation?"); msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); ret = msgBox.exec(); } if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); if (ret == QMessageBox::Yes) { m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } else { m_CmbInterpolation->setCurrentIndex(0); } } else if (!m_3DInterpolationEnabled) { this->Show3DInterpolationResult(false); m_BtnApply3D->setEnabled(m_3DInterpolationEnabled); } } else { QWidget::setEnabled( false ); m_ChkShowPositionNodes->setEnabled(m_3DInterpolationEnabled); } } if (!m_3DInterpolationEnabled) { this->Show3DInterpolationResult(false); m_BtnApply3D->setEnabled(m_3DInterpolationEnabled); } } catch(...) { MITK_ERROR<<"Error with 3D surface interpolation!"; } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::EnableInterpolation(bool on) { // only to be called from the outside world // just a redirection to OnInterpolationActivated OnInterpolationActivated(on); } void QmitkSlicesInterpolator::Enable3DInterpolation(bool on) { // only to be called from the outside world // just a redirection to OnInterpolationActivated On3DInterpolationActivated(on); } void QmitkSlicesInterpolator::UpdateVisibleSuggestion() { if (m_2DInterpolationEnabled && m_LastSNC) { // determine which one is the current view, try to do an initial interpolation mitk::BaseRenderer* renderer = m_LastSNC->GetRenderer(); if (renderer && renderer->GetMapperID() == mitk::BaseRenderer::Standard2D) { //TODO 18735: This cast always returns NULL, cuase GetWorldGeometry returns a Base Geometry?!?!?! const mitk::TimeGeometry* timeGeometry = dynamic_cast( renderer->GetWorldGeometry() ); if (timeGeometry) { mitk::SliceNavigationController::GeometrySliceEvent event( const_cast(timeGeometry), renderer->GetSlice() ); TranslateAndInterpolateChangedSlice(event, m_LastSNC); } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::OnInterpolationInfoChanged(const itk::EventObject& /*e*/) { // something (e.g. undo) changed the interpolation info, we should refresh our display UpdateVisibleSuggestion(); } void QmitkSlicesInterpolator::OnSurfaceInterpolationInfoChanged(const itk::EventObject& /*e*/) { if(m_3DInterpolationEnabled) { if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } } void QmitkSlicesInterpolator:: SetCurrentContourListID() { // New ContourList = hide current interpolation Show3DInterpolationResult(false); if ( m_DataStorage.IsNotNull() && m_ToolManager && m_LastSNC ) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); if (workingNode) { bool isInterpolationResult(false); workingNode->GetBoolProperty("3DInterpolationResult",isInterpolationResult); if (!isInterpolationResult) { QWidget::setEnabled( true ); // In case the time is not valid use 0 to access the time geometry of the working node unsigned int time_position = 0; if( m_LastSNC->GetTime() != NULL ) time_position = m_LastSNC->GetTime()->GetPos(); mitk::Vector3D spacing = workingNode->GetData()->GetGeometry( time_position )->GetSpacing(); double minSpacing (100); double maxSpacing (0); for (int i =0; i < 3; i++) { if (spacing[i] < minSpacing) { minSpacing = spacing[i]; } - else if (spacing[i] > maxSpacing) + if (spacing[i] > maxSpacing) { maxSpacing = spacing[i]; } } m_SurfaceInterpolator->SetMaxSpacing(maxSpacing); m_SurfaceInterpolator->SetMinSpacing(minSpacing); m_SurfaceInterpolator->SetDistanceImageVolume(50000); mitk::Image* segmentationImage = dynamic_cast(workingNode->GetData()); - if (segmentationImage->GetDimension() == 3) + /*if (segmentationImage->GetDimension() == 3) + {*/ m_SurfaceInterpolator->SetCurrentInterpolationSession(segmentationImage); - else - MITK_INFO<<"3D Interpolation is only supported for 3D images at the moment!"; + m_SurfaceInterpolator->SetCurrentTimeStep( time_position ); + //} + /*else + MITK_INFO<<"3D Interpolation is only supported for 3D images at the moment!";*/ if (m_3DInterpolationEnabled) { if (m_Watcher.isRunning()) m_Watcher.waitForFinished(); m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation); m_Watcher.setFuture(m_Future); } } } else { QWidget::setEnabled(false); } } } void QmitkSlicesInterpolator::Show3DInterpolationResult(bool status) { if (m_InterpolatedSurfaceNode.IsNotNull()) m_InterpolatedSurfaceNode->SetVisibility(status); if (m_3DContourNode.IsNotNull()) m_3DContourNode->SetVisibility(status, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSlicesInterpolator::CheckSupportedImageDimension() { if (m_ToolManager->GetWorkingData(0)) m_Segmentation = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); - if (m_3DInterpolationEnabled && m_Segmentation && m_Segmentation->GetDimension() != 3) + /*if (m_3DInterpolationEnabled && m_Segmentation && m_Segmentation->GetDimension() != 3) { QMessageBox info; info.setWindowTitle("3D Interpolation Process"); info.setIcon(QMessageBox::Information); info.setText("3D Interpolation is only supported for 3D images at the moment!"); info.exec(); m_CmbInterpolation->setCurrentIndex(0); - } + }*/ } void QmitkSlicesInterpolator::OnSliceNavigationControllerDeleted(const itk::Object *sender, const itk::EventObject& /*e*/) { //Don't know how to avoid const_cast here?! mitk::SliceNavigationController* slicer = dynamic_cast(const_cast(sender)); if (slicer) { m_ControllerToTimeObserverTag.remove(slicer); m_ControllerToSliceObserverTag.remove(slicer); m_ControllerToDeleteObserverTag.remove(slicer); } } diff --git a/Modules/SurfaceInterpolation/Testing/mitkSurfaceInterpolationControllerTest.cpp b/Modules/SurfaceInterpolation/Testing/mitkSurfaceInterpolationControllerTest.cpp index b22d421a5a..20f7865c7c 100644 --- a/Modules/SurfaceInterpolation/Testing/mitkSurfaceInterpolationControllerTest.cpp +++ b/Modules/SurfaceInterpolation/Testing/mitkSurfaceInterpolationControllerTest.cpp @@ -1,465 +1,764 @@ /*=================================================================== 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 +#include "mitkImageTimeSelector.h" +#include "mitkImagePixelWriteAccessor.h" + class mitkSurfaceInterpolationControllerTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkSurfaceInterpolationControllerTestSuite); MITK_TEST(TestSingleton); MITK_TEST(TestSetCurrentInterpolationSession); MITK_TEST(TestReplaceInterpolationSession); MITK_TEST(TestRemoveAllInterpolationSessions); MITK_TEST(TestRemoveInterpolationSession); MITK_TEST(TestOnSegmentationDeleted); + MITK_TEST(TestSetCurrentInterpolationSession4D); + MITK_TEST(TestReplaceInterpolationSession4D); + MITK_TEST(TestRemoveAllInterpolationSessions4D); + MITK_TEST(TestRemoveInterpolationSession4D); + MITK_TEST(TestOnSegmentationDeleted4D); + + /// \todo Workaround for memory leak in TestAddNewContour. Bug 18096. vtkDebugLeaks::SetExitError(0); MITK_TEST(TestAddNewContour); MITK_TEST(TestRemoveContour); CPPUNIT_TEST_SUITE_END(); private: mitk::SurfaceInterpolationController::Pointer m_Controller; public: mitk::Image::Pointer createImage(unsigned int *dimensions) { mitk::Image::Pointer newImage = mitk::Image::New(); mitk::PixelType p_type = mitk::MakeScalarPixelType(); newImage->Initialize(p_type, 3, dimensions); return newImage; } + mitk::Image::Pointer createImage4D(unsigned int *dimensions) + { + mitk::Image::Pointer newImage = mitk::Image::New(); + mitk::PixelType p_type = mitk::MakeScalarPixelType(); + newImage->Initialize(p_type, 4, dimensions); + return newImage; + } + void setUp() { m_Controller = mitk::SurfaceInterpolationController::GetInstance(); + m_Controller->SetCurrentTimeStep( 0 ); vtkSmartPointer polygonSource = vtkSmartPointer::New(); polygonSource->SetRadius(100); polygonSource->SetNumberOfSides(7); polygonSource->Update(); mitk::Surface::Pointer surface = mitk::Surface::New(); surface->SetVtkPolyData(polygonSource->GetOutput()); } void TestSingleton() { mitk::SurfaceInterpolationController::Pointer controller2 = mitk::SurfaceInterpolationController::GetInstance(); CPPUNIT_ASSERT_MESSAGE("SurfaceInterpolationController pointers are not equal!", m_Controller.GetPointer() == controller2.GetPointer()); } void TestSetCurrentInterpolationSession() { // Create image for testing unsigned int dimensions1[] = {10, 10, 10}; mitk::Image::Pointer segmentation_1 = createImage(dimensions1); unsigned int dimensions2[] = {20, 10, 30}; mitk::Image::Pointer segmentation_2 = createImage(dimensions2); // Test 1 m_Controller->SetCurrentInterpolationSession(segmentation_1); MITK_ASSERT_EQUAL(m_Controller->GetCurrentSegmentation(), segmentation_1->Clone(), "Segmentation images are not equal"); CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_1.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1", m_Controller->GetNumberOfInterpolationSessions() == 1); // Test 2 m_Controller->SetCurrentInterpolationSession(segmentation_2); MITK_ASSERT_EQUAL(m_Controller->GetCurrentSegmentation(), segmentation_2->Clone(), "Segmentation images are not equal"); CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_2.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); // Test 3 m_Controller->SetCurrentInterpolationSession(segmentation_1); MITK_ASSERT_EQUAL(m_Controller->GetCurrentSegmentation(), segmentation_1->Clone(), "Segmentation images are not equal"); CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_1.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); // Test 4 m_Controller->SetCurrentInterpolationSession(segmentation_1); MITK_ASSERT_EQUAL(m_Controller->GetCurrentSegmentation(), segmentation_1->Clone(), "Segmentation images are not equal"); CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_1.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); // Test 5 m_Controller->SetCurrentInterpolationSession(0); CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().IsNull()); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); } void TestReplaceInterpolationSession() { // Create segmentation image unsigned int dimensions1[] = {10, 10, 10}; mitk::Image::Pointer segmentation_1 = createImage(dimensions1); m_Controller->SetCurrentInterpolationSession(segmentation_1); // Create some contours double center_1[3] = {1.25f ,3.43f ,4.44f}; double normal_1[3] = {0.25f ,1.76f, 0.93f}; vtkSmartPointer p_source = vtkSmartPointer::New(); p_source->SetNumberOfSides(20); p_source->SetCenter(center_1); p_source->SetRadius(4); p_source->SetNormal(normal_1); p_source->Update(); vtkPolyData* poly_1 = p_source->GetOutput(); mitk::Surface::Pointer surf_1 = mitk::Surface::New(); surf_1->SetVtkPolyData(poly_1); double center_2[3] = {4.0f ,4.0f ,4.0f}; double normal_2[3] = {1.0f ,0.0f, 0.0f}; vtkSmartPointer p_source_2 = vtkSmartPointer::New(); p_source_2->SetNumberOfSides(80); p_source_2->SetCenter(center_2); p_source_2->SetRadius(4); p_source_2->SetNormal(normal_2); p_source_2->Update(); vtkPolyData* poly_2 = p_source_2->GetOutput(); mitk::Surface::Pointer surf_2 = mitk::Surface::New(); surf_2->SetVtkPolyData(poly_2); // Add contours m_Controller->AddNewContour(surf_1); m_Controller->AddNewContour(surf_2); // Check if all contours are there mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo1; contourInfo1.contourNormal = normal_1; contourInfo1.contourPoint = center_1; mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo2; contourInfo2.contourNormal = normal_2; contourInfo2.contourPoint = center_2; mitk::Image::Pointer segmentation_2 = createImage(dimensions1); bool success = m_Controller->ReplaceInterpolationSession(segmentation_1, segmentation_2); const mitk::Surface* contour_1 = m_Controller->GetContour(contourInfo1); const mitk::Surface* contour_2 = m_Controller->GetContour(contourInfo2); CPPUNIT_ASSERT_MESSAGE("Replace session failed!", success == true); CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 2); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_1->GetVtkPolyData()), *(contour_1->GetVtkPolyData()), 0.000001, true)); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_2->GetVtkPolyData()), *(contour_2->GetVtkPolyData()), 0.000001, true)); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1", m_Controller->GetNumberOfInterpolationSessions() == 1); CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_2.GetPointer()); unsigned int dimensions2[] = {10, 20, 10}; mitk::Image::Pointer segmentation_3 = createImage(dimensions2); success = m_Controller->ReplaceInterpolationSession(segmentation_2, segmentation_3); CPPUNIT_ASSERT_MESSAGE("Replace session failed!", success == false); CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 2); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1", m_Controller->GetNumberOfInterpolationSessions() == 1); CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_2.GetPointer()); } void TestRemoveAllInterpolationSessions() { // Create image for testing unsigned int dimensions1[] = {10, 10, 10}; mitk::Image::Pointer segmentation_1 = createImage(dimensions1); unsigned int dimensions2[] = {20, 10, 30}; mitk::Image::Pointer segmentation_2 = createImage(dimensions2); // Test 1 m_Controller->SetCurrentInterpolationSession(segmentation_1); m_Controller->SetCurrentInterpolationSession(segmentation_2); m_Controller->RemoveAllInterpolationSessions(); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 0", m_Controller->GetNumberOfInterpolationSessions() == 0); } void TestRemoveInterpolationSession() { // Create image for testing unsigned int dimensions1[] = {10, 10, 10}; mitk::Image::Pointer segmentation_1 = createImage(dimensions1); unsigned int dimensions2[] = {20, 10, 30}; mitk::Image::Pointer segmentation_2 = createImage(dimensions2); // Test 1 m_Controller->SetCurrentInterpolationSession(segmentation_1); m_Controller->SetCurrentInterpolationSession(segmentation_2); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); // Test current segmentation should not be null if another one was removed m_Controller->RemoveInterpolationSession(segmentation_1); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1", m_Controller->GetNumberOfInterpolationSessions() == 1); CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_2.GetPointer()); CPPUNIT_ASSERT_MESSAGE("Current segmentation is null after another one was removed", m_Controller->GetCurrentSegmentation().IsNotNull()); m_Controller->SetCurrentInterpolationSession(segmentation_1); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); // Test current segmentation should not be null if another one was removed m_Controller->RemoveInterpolationSession(segmentation_1); CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1", m_Controller->GetNumberOfInterpolationSessions() == 1); CPPUNIT_ASSERT_MESSAGE("Current segmentation is not null after session was removed", m_Controller->GetCurrentSegmentation().IsNull()); } void TestOnSegmentationDeleted() { { // Create image for testing unsigned int dimensions1[] = {10, 10, 10}; mitk::Image::Pointer segmentation_1 = createImage(dimensions1); m_Controller->SetCurrentInterpolationSession(segmentation_1); } CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 0", m_Controller->GetNumberOfInterpolationSessions() == 0); } void TestAddNewContour() { // Create segmentation image unsigned int dimensions1[] = {10, 10, 10}; mitk::Image::Pointer segmentation_1 = createImage(dimensions1); m_Controller->SetCurrentInterpolationSession(segmentation_1); // Create some contours double center_1[3] = {1.25f ,3.43f ,4.44f}; double normal_1[3] = {0.25f ,1.76f, 0.93f}; vtkSmartPointer p_source = vtkSmartPointer::New(); p_source->SetNumberOfSides(20); p_source->SetCenter(center_1); p_source->SetRadius(4); p_source->SetNormal(normal_1); p_source->Update(); vtkPolyData* poly_1 = p_source->GetOutput(); mitk::Surface::Pointer surf_1 = mitk::Surface::New(); surf_1->SetVtkPolyData(poly_1); double center_2[3] = {4.0f ,4.0f ,4.0f}; double normal_2[3] = {1.0f ,0.0f, 0.0f}; vtkSmartPointer p_source_2 = vtkSmartPointer::New(); p_source_2->SetNumberOfSides(80); p_source_2->SetCenter(center_2); p_source_2->SetRadius(4); p_source_2->SetNormal(normal_2); p_source_2->Update(); vtkPolyData* poly_2 = p_source_2->GetOutput(); mitk::Surface::Pointer surf_2 = mitk::Surface::New(); surf_2->SetVtkPolyData(poly_2); double center_3[3] = {4.0f ,4.0f ,3.0f}; double normal_3[3] = {0.0f ,0.0f, 1.0f}; vtkSmartPointer p_source_3 = vtkSmartPointer::New(); p_source_3->SetNumberOfSides(10); p_source_3->SetCenter(center_3); p_source_3->SetRadius(4); p_source_3->SetNormal(normal_3); p_source_3->Update(); vtkPolyData* poly_3 = p_source_3->GetOutput(); mitk::Surface::Pointer surf_3 = mitk::Surface::New(); surf_3->SetVtkPolyData(poly_3); // Add contours m_Controller->AddNewContour(surf_1); m_Controller->AddNewContour(surf_2); m_Controller->AddNewContour(surf_3); // Check if all contours are there mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo1; contourInfo1.contourNormal = normal_1; contourInfo1.contourPoint = center_1; mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo2; contourInfo2.contourNormal = normal_2; contourInfo2.contourPoint = center_2; mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo3; contourInfo3.contourNormal = normal_3; contourInfo3.contourPoint = center_3; const mitk::Surface* contour_1 = m_Controller->GetContour(contourInfo1); const mitk::Surface* contour_2 = m_Controller->GetContour(contourInfo2); const mitk::Surface* contour_3 = m_Controller->GetContour(contourInfo3); CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 3); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_1->GetVtkPolyData()), *(contour_1->GetVtkPolyData()), 0.000001, true)); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_2->GetVtkPolyData()), *(contour_2->GetVtkPolyData()), 0.000001, true)); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_3->GetVtkPolyData()), *(contour_3->GetVtkPolyData()), 0.000001, true)); // Create another segmentation image unsigned int dimensions2[] = {20, 20, 20}; mitk::Image::Pointer segmentation_2 = createImage(dimensions2); m_Controller->SetCurrentInterpolationSession(segmentation_2); // Create some contours double center_4[3] = {10.0f ,10.0f ,10.0f}; double normal_4[3] = {0.0f ,1.0f, 0.0f}; vtkSmartPointer p_source_4 = vtkSmartPointer::New(); p_source_4->SetNumberOfSides(8); p_source_4->SetCenter(center_4); p_source_4->SetRadius(5); p_source_4->SetNormal(normal_4); p_source_4->Update(); vtkPolyData* poly_4 = p_source_4->GetOutput(); mitk::Surface::Pointer surf_4 = mitk::Surface::New(); surf_4->SetVtkPolyData(poly_4); double center_5[3] = {3.0f ,10.0f ,10.0f}; double normal_5[3] = {1.0f ,0.0f, 0.0f}; vtkSmartPointer p_source_5 = vtkSmartPointer::New(); p_source_5->SetNumberOfSides(16); p_source_5->SetCenter(center_5); p_source_5->SetRadius(8); p_source_5->SetNormal(normal_5); p_source_5->Update(); vtkPolyData* poly_5 = p_source_5->GetOutput(); mitk::Surface::Pointer surf_5 = mitk::Surface::New(); surf_5->SetVtkPolyData(poly_5); double center_6[3] = {10.0f ,10.0f ,3.0f}; double normal_6[3] = {0.0f ,0.0f, 1.0f}; vtkSmartPointer p_source_6 = vtkSmartPointer::New(); p_source_6->SetNumberOfSides(100); p_source_6->SetCenter(center_6); p_source_6->SetRadius(5); p_source_6->SetNormal(normal_6); p_source_6->Update(); vtkPolyData* poly_6 = p_source_6->GetOutput(); mitk::Surface::Pointer surf_6 = mitk::Surface::New(); surf_6->SetVtkPolyData(poly_6); mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo4; contourInfo4.contourNormal = normal_4; contourInfo4.contourPoint = center_4; mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo5; contourInfo5.contourNormal = normal_5; contourInfo5.contourPoint = center_5; mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo6; contourInfo6.contourNormal = normal_6; contourInfo6.contourPoint = center_6; // Add contours m_Controller->AddNewContour(surf_4); m_Controller->AddNewContour(surf_5); m_Controller->AddNewContour(surf_6); // Check if all contours are there mitk::Surface* contour_4 = const_cast(m_Controller->GetContour(contourInfo4)); mitk::Surface* contour_5 = const_cast(m_Controller->GetContour(contourInfo5)); mitk::Surface* contour_6 = const_cast(m_Controller->GetContour(contourInfo6)); CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 3); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_4->GetVtkPolyData()), *(contour_4->GetVtkPolyData()), 0.000001, true)); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_5->GetVtkPolyData()), *(contour_5->GetVtkPolyData()), 0.000001, true)); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_6->GetVtkPolyData()), *(contour_6->GetVtkPolyData()), 0.000001, true)); // Modify some contours vtkSmartPointer p_source_7 = vtkSmartPointer::New(); p_source_7->SetNumberOfSides(200); p_source_7->SetCenter(3.0,10.0,10.0); p_source_7->SetRadius(5); p_source_7->SetNormal(1, 0, 0); p_source_7->Update(); vtkPolyData* poly_7 = p_source_7->GetOutput(); mitk::Surface::Pointer surf_7 = mitk::Surface::New(); surf_7->SetVtkPolyData(poly_7); m_Controller->AddNewContour(surf_7); mitk::Surface* contour_7 = const_cast(m_Controller->GetContour(contourInfo5)); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_7->GetVtkPolyData()), *(contour_7->GetVtkPolyData()), 0.000001, true)); // Change session and test if all contours are available m_Controller->SetCurrentInterpolationSession(segmentation_1); mitk::Surface* contour_8 = const_cast(m_Controller->GetContour(contourInfo1)); mitk::Surface* contour_9 = const_cast(m_Controller->GetContour(contourInfo2)); mitk::Surface* contour_10 = const_cast(m_Controller->GetContour(contourInfo3)); CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 3); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_1->GetVtkPolyData()), *(contour_8->GetVtkPolyData()), 0.000001, true)); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_2->GetVtkPolyData()), *(contour_9->GetVtkPolyData()), 0.000001, true)); CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_3->GetVtkPolyData()), *(contour_10->GetVtkPolyData()), 0.000001, true)); } void TestRemoveContour() { // Create segmentation image unsigned int dimensions1[] = {10, 10, 10}; mitk::Image::Pointer segmentation_1 = createImage(dimensions1); m_Controller->SetCurrentInterpolationSession(segmentation_1); // Create some contours double center_1[3] = {4.0f ,4.0f ,4.0f}; double normal_1[3] = {0.0f ,1.0f, 0.0f}; vtkSmartPointer p_source = vtkSmartPointer::New(); p_source->SetNumberOfSides(20); p_source->SetCenter(center_1); p_source->SetRadius(4); p_source->SetNormal(normal_1); p_source->Update(); vtkPolyData* poly_1 = p_source->GetOutput(); mitk::Surface::Pointer surf_1 = mitk::Surface::New(); surf_1->SetVtkPolyData(poly_1); double center_2[3] = {4.0f ,4.0f ,4.0f}; double normal_2[3] = {1.0f ,0.0f, 0.0f}; vtkSmartPointer p_source_2 = vtkSmartPointer::New(); p_source_2->SetNumberOfSides(80); p_source_2->SetCenter(center_2); p_source_2->SetRadius(4); p_source_2->SetNormal(normal_2); p_source_2->Update(); vtkPolyData* poly_2 = p_source_2->GetOutput(); mitk::Surface::Pointer surf_2 = mitk::Surface::New(); surf_2->SetVtkPolyData(poly_2); // Add contours m_Controller->AddNewContour(surf_1); m_Controller->AddNewContour(surf_2); CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 2); mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo3; contourInfo3.contour = surf_1->Clone(); contourInfo3.contourNormal = normal_1; contourInfo3.contourPoint = center_1; // Shift the new contour so that it is different contourInfo3.contourPoint += 0.5; bool success = m_Controller->RemoveContour(contourInfo3); CPPUNIT_ASSERT_MESSAGE("Remove failed - contour was unintentionally removed!", (m_Controller->GetNumberOfContours() == 2) && !success); mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo2; contourInfo2.contourNormal = normal_2; contourInfo2.contourPoint = center_2; contourInfo2.contour = surf_2; success = m_Controller->RemoveContour(contourInfo2); CPPUNIT_ASSERT_MESSAGE("Remove failed - contour was not removed!", (m_Controller->GetNumberOfContours() == 1) && success); // Let's see if the other contour No. 1 is still there contourInfo3.contourPoint -= 0.5; const mitk::Surface* remainingContour = m_Controller->GetContour(contourInfo3); CPPUNIT_ASSERT_MESSAGE("Remove failed - contour was accidentally removed!", (m_Controller->GetNumberOfContours() == 1) && mitk::Equal(*(surf_1->GetVtkPolyData()), *(remainingContour->GetVtkPolyData()), 0.000001, true) &&success); } + + bool AssertImagesEqual4D( mitk::Image* img1, mitk::Image* img2 ) + { + mitk::ImageTimeSelector::Pointer selector1 = mitk::ImageTimeSelector::New(); + selector1->SetInput( img1 ); + selector1->SetChannelNr( 0 ); + mitk::ImageTimeSelector::Pointer selector2= mitk::ImageTimeSelector::New(); + selector2->SetInput( img2 ); + selector2->SetChannelNr( 0 ); + + int numTs1 = img1->GetTimeSteps(); + int numTs2 = img2->GetTimeSteps(); + if ( numTs1 != numTs2 ) + { + return false; + } + + /*mitk::ImagePixelWriteAccessor accessor( img1 ); + itk::Index<4> ind; + ind[0] = 5; + ind[1] = 5; + ind[2] = 5; + ind[3] = 2; + accessor.SetPixelByIndex( ind, 7 );*/ + + for ( int ts = 0; ts < numTs1; ++ts ) + { + selector1->SetTimeNr( ts ); + selector2->SetTimeNr( ts ); + + selector1->Update(); + selector2->Update(); + + mitk::Image::Pointer imgSel1 = selector1->GetOutput(); + mitk::Image::Pointer imgSel2 = selector2->GetOutput(); + + MITK_ASSERT_EQUAL(imgSel1, imgSel2, "Segmentation images are not equal"); + } + + return true; + } + + void TestSetCurrentInterpolationSession4D() + { + /*unsigned int testDimensions[] = {10, 10, 10, 5}; + mitk::Image::Pointer testSeg = createImage4D(testDimensions); + mitk::Image::Pointer testSegClone = testSeg->Clone(); + int testTs = testSeg->GetTimeSteps(); + + MITK_ASSERT_EQUAL(testSeg, testSegClone, "Segmentation images are not equal");*/ + + // Create image for testing + unsigned int dimensions1[] = {10, 10, 10, 5}; + mitk::Image::Pointer segmentation_1 = createImage4D(dimensions1); + + unsigned int dimensions2[] = {20, 10, 30, 4}; + mitk::Image::Pointer segmentation_2 = createImage4D(dimensions2); + + // Test 1 + m_Controller->SetCurrentInterpolationSession(segmentation_1); + bool equal = AssertImagesEqual4D( m_Controller->GetCurrentSegmentation(), segmentation_1->Clone() ); + CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_1.GetPointer()); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1", m_Controller->GetNumberOfInterpolationSessions() == 1); + + // Test 2 + m_Controller->SetCurrentInterpolationSession(segmentation_2); + //MITK_ASSERT_EQUAL(m_Controller->GetCurrentSegmentation(), segmentation_2->Clone(), "Segmentation images are not equal"); + equal = AssertImagesEqual4D( m_Controller->GetCurrentSegmentation(), segmentation_2->Clone() ); + CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_2.GetPointer()); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); + + // Test 3 + m_Controller->SetCurrentInterpolationSession(segmentation_1); + //MITK_ASSERT_EQUAL(m_Controller->GetCurrentSegmentation(), segmentation_1->Clone(), "Segmentation images are not equal"); + equal = AssertImagesEqual4D( m_Controller->GetCurrentSegmentation(), segmentation_1->Clone() ); + CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_1.GetPointer()); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); + + // Test 4 + m_Controller->SetCurrentInterpolationSession(segmentation_1); + //MITK_ASSERT_EQUAL(m_Controller->GetCurrentSegmentation(), segmentation_1->Clone(), "Segmentation images are not equal"); + equal = AssertImagesEqual4D( m_Controller->GetCurrentSegmentation(), segmentation_1->Clone() ); + CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_1.GetPointer()); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); + + // Test 5 + m_Controller->SetCurrentInterpolationSession(0); + CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().IsNull()); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); + } + + void TestReplaceInterpolationSession4D() + { + // Create segmentation image + unsigned int dimensions1[] = {10, 10, 10, 5}; + mitk::Image::Pointer segmentation_1 = createImage4D(dimensions1); + m_Controller->SetCurrentInterpolationSession(segmentation_1); + + // Create some contours + double center_1[3] = {1.25f ,3.43f ,4.44f}; + double normal_1[3] = {0.25f ,1.76f, 0.93f}; + vtkSmartPointer p_source = vtkSmartPointer::New(); + p_source->SetNumberOfSides(20); + p_source->SetCenter(center_1); + p_source->SetRadius(4); + p_source->SetNormal(normal_1); + p_source->Update(); + vtkPolyData* poly_1 = p_source->GetOutput(); + mitk::Surface::Pointer surf_1 = mitk::Surface::New(); + surf_1->SetVtkPolyData(poly_1); + + double center_2[3] = {4.0f ,4.0f ,4.0f}; + double normal_2[3] = {1.0f ,0.0f, 0.0f}; + vtkSmartPointer p_source_2 = vtkSmartPointer::New(); + p_source_2->SetNumberOfSides(80); + p_source_2->SetCenter(center_2); + p_source_2->SetRadius(4); + p_source_2->SetNormal(normal_2); + p_source_2->Update(); + vtkPolyData* poly_2 = p_source_2->GetOutput(); + mitk::Surface::Pointer surf_2 = mitk::Surface::New(); + surf_2->SetVtkPolyData(poly_2); + + // Add contours + m_Controller->AddNewContour(surf_1); + m_Controller->AddNewContour(surf_2); + + // Add contours for another timestep + m_Controller->SetCurrentTimeStep( 2 ); + + double center_3[3] = {1.3f ,3.5f ,4.6f}; + double normal_3[3] = {0.20f ,1.6f, 0.8f}; + vtkSmartPointer p_source_3 = vtkSmartPointer::New(); + p_source_3->SetNumberOfSides(20); + p_source_3->SetCenter(center_3); + p_source_3->SetRadius(4); + p_source_3->SetNormal(normal_3); + p_source_3->Update(); + vtkPolyData* poly_3 = p_source_3->GetOutput(); + mitk::Surface::Pointer surf_3 = mitk::Surface::New(); + surf_3->SetVtkPolyData(poly_3); + + double center_4[3] = {1.32f ,3.53f ,4.8f}; + double normal_4[3] = {0.22f ,1.5f, 0.85f}; + vtkSmartPointer p_source_4 = vtkSmartPointer::New(); + p_source_4->SetNumberOfSides(20); + p_source_4->SetCenter(center_4); + p_source_4->SetRadius(4); + p_source_4->SetNormal(normal_4); + p_source_4->Update(); + vtkPolyData* poly_4 = p_source_4->GetOutput(); + mitk::Surface::Pointer surf_4 = mitk::Surface::New(); + surf_4->SetVtkPolyData(poly_4); + + m_Controller->AddNewContour(surf_3); + m_Controller->AddNewContour(surf_4); + + m_Controller->SetCurrentTimeStep( 0 ); + + // Check if all contours are there + mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo1; + contourInfo1.contourNormal = normal_1; + contourInfo1.contourPoint = center_1; + + mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo2; + contourInfo2.contourNormal = normal_2; + contourInfo2.contourPoint = center_2; + + mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo3; + contourInfo3.contourNormal = normal_3; + contourInfo3.contourPoint = center_3; + + mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo4; + contourInfo4.contourNormal = normal_4; + contourInfo4.contourPoint = center_4; + + mitk::Image::Pointer segmentation_2 = createImage4D(dimensions1); + bool success = m_Controller->ReplaceInterpolationSession(segmentation_1, segmentation_2); + + CPPUNIT_ASSERT_MESSAGE("Replace session failed!", success == true); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1", m_Controller->GetNumberOfInterpolationSessions() == 1); + CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_2.GetPointer()); + + const mitk::Surface* contour_1 = m_Controller->GetContour(contourInfo1); + const mitk::Surface* contour_2 = m_Controller->GetContour(contourInfo2); + + CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 2); + CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_1->GetVtkPolyData()), *(contour_1->GetVtkPolyData()), 0.000001, true)); + CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_2->GetVtkPolyData()), *(contour_2->GetVtkPolyData()), 0.000001, true)); + + m_Controller->SetCurrentTimeStep( 2 ); + + //CPPUNIT_ASSERT_MESSAGE("Contour accessed from outside of timestep!", m_Controller->GetNumberOfContours() == 0); + contour_1 = m_Controller->GetContour(contourInfo1); + contour_2 = m_Controller->GetContour(contourInfo2); + CPPUNIT_ASSERT_MESSAGE("Contour accessed from outside of timestep!", contour_1 == 0 && contour_2 == 0); + + const mitk::Surface* contour_3 = m_Controller->GetContour(contourInfo3); + const mitk::Surface* contour_4 = m_Controller->GetContour(contourInfo4); + + CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 2); + CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_3->GetVtkPolyData()), *(contour_3->GetVtkPolyData()), 0.000001, true)); + CPPUNIT_ASSERT_MESSAGE("Contours not equal!", mitk::Equal(*(surf_4->GetVtkPolyData()), *(contour_4->GetVtkPolyData()), 0.000001, true)); + + unsigned int dimensions2[] = {10, 20, 10, 4}; + mitk::Image::Pointer segmentation_3 = createImage4D(dimensions2); + success = m_Controller->ReplaceInterpolationSession(segmentation_2, segmentation_3); + CPPUNIT_ASSERT_MESSAGE("Replace session failed!", success == false); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1", m_Controller->GetNumberOfInterpolationSessions() == 1); + CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_2.GetPointer()); + + m_Controller->SetCurrentTimeStep( 1 ); + CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 0); + + m_Controller->SetCurrentTimeStep( 0 ); + CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 2); + + m_Controller->SetCurrentTimeStep( 4 ); + CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 0); + + m_Controller->SetCurrentTimeStep( 2 ); + CPPUNIT_ASSERT_MESSAGE("Wrong number of contours!", m_Controller->GetNumberOfContours() == 2); + } + + void TestRemoveAllInterpolationSessions4D() + { + // Create image for testing + unsigned int dimensions1[] = {10, 10, 10, 4}; + mitk::Image::Pointer segmentation_1 = createImage4D(dimensions1); + + unsigned int dimensions2[] = {20, 10, 30, 5}; + mitk::Image::Pointer segmentation_2 = createImage4D(dimensions2); + + // Test 1 + m_Controller->SetCurrentInterpolationSession(segmentation_1); + m_Controller->SetCurrentInterpolationSession(segmentation_2); + m_Controller->RemoveAllInterpolationSessions(); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 0", m_Controller->GetNumberOfInterpolationSessions() == 0); + } + + void TestRemoveInterpolationSession4D() + { + // Create image for testing + unsigned int dimensions1[] = {10, 10, 10, 3}; + mitk::Image::Pointer segmentation_1 = createImage4D(dimensions1); + + unsigned int dimensions2[] = {20, 10, 30, 6}; + mitk::Image::Pointer segmentation_2 = createImage4D(dimensions2); + + // Test 1 + m_Controller->SetCurrentInterpolationSession(segmentation_1); + m_Controller->SetCurrentInterpolationSession(segmentation_2); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); + + // Test current segmentation should not be null if another one was removed + m_Controller->RemoveInterpolationSession(segmentation_1); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1", m_Controller->GetNumberOfInterpolationSessions() == 1); + CPPUNIT_ASSERT_MESSAGE("Segmentation images are not equal", m_Controller->GetCurrentSegmentation().GetPointer() == segmentation_2.GetPointer()); + CPPUNIT_ASSERT_MESSAGE("Current segmentation is null after another one was removed", m_Controller->GetCurrentSegmentation().IsNotNull()); + + m_Controller->SetCurrentInterpolationSession(segmentation_1); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 2", m_Controller->GetNumberOfInterpolationSessions() == 2); + + // Test current segmentation should not be null if another one was removed + m_Controller->RemoveInterpolationSession(segmentation_1); + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 1", m_Controller->GetNumberOfInterpolationSessions() == 1); + CPPUNIT_ASSERT_MESSAGE("Current segmentation is not null after session was removed", m_Controller->GetCurrentSegmentation().IsNull()); + } + + void TestOnSegmentationDeleted4D() + { + { + // Create image for testing + unsigned int dimensions1[] = {10, 10, 10, 7}; + mitk::Image::Pointer segmentation_1 = createImage4D(dimensions1); + m_Controller->SetCurrentInterpolationSession(segmentation_1); + m_Controller->SetCurrentTimeStep( 3 ); + } + CPPUNIT_ASSERT_MESSAGE("Number of interpolation session not 0", m_Controller->GetNumberOfInterpolationSessions() == 0); + } }; MITK_TEST_SUITE_REGISTRATION(mitkSurfaceInterpolationController) diff --git a/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp b/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp index 26a47d713b..6077e449dd 100644 --- a/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp +++ b/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp @@ -1,331 +1,334 @@ /*=================================================================== 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 "mitkComputeContourSetNormalsFilter.h" #include "mitkImagePixelReadAccessor.h" +#include "mitkIOUtil.h" mitk::ComputeContourSetNormalsFilter::ComputeContourSetNormalsFilter() : m_SegmentationBinaryImage(NULL) , m_MaxSpacing(5) , m_NegativeNormalCounter(0) , m_PositiveNormalCounter(0) , m_UseProgressBar(false) , m_ProgressStepSize(1) { mitk::Surface::Pointer output = mitk::Surface::New(); this->SetNthOutput(0, output.GetPointer()); } mitk::ComputeContourSetNormalsFilter::~ComputeContourSetNormalsFilter() { } void mitk::ComputeContourSetNormalsFilter::GenerateData() { unsigned int numberOfInputs = this->GetNumberOfIndexedInputs(); //Iterating over each input for(unsigned int i = 0; i < numberOfInputs; i++) { //Getting the inputs polydata and polygons Surface* currentSurface = const_cast( this->GetInput(i) ); vtkPolyData* polyData = currentSurface->GetVtkPolyData(); vtkSmartPointer existingPolys = polyData->GetPolys(); vtkSmartPointer existingPoints = polyData->GetPoints(); existingPolys->InitTraversal(); vtkIdType* cell (NULL); vtkIdType cellSize (0); //The array that contains all the vertex normals of the current polygon vtkSmartPointer normals = vtkSmartPointer::New(); normals->SetNumberOfComponents(3); normals->SetNumberOfTuples(polyData->GetNumberOfPoints()); //If the current contour is an inner contour then the direction is -1 //A contour lies inside another one if the pixel values in the direction of the normal is 1 m_NegativeNormalCounter = 0; m_PositiveNormalCounter = 0; vtkIdType offSet (0); //Iterating over each polygon for( existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);) { if(cellSize < 3)continue; //First we calculate the current polygon's normal double polygonNormal[3] = {0.0}; double p1[3]; double p2[3]; double v1[3]; double v2[3]; existingPoints->GetPoint(cell[0], p1); unsigned int index = cellSize*0.5; existingPoints->GetPoint(cell[index], p2); v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; for (vtkIdType k = 2; k < cellSize; k++) { index = cellSize*0.25; existingPoints->GetPoint(cell[index], p1); index = cellSize*0.75; existingPoints->GetPoint(cell[index], p2); v2[0] = p2[0]-p1[0]; v2[1] = p2[1]-p1[1]; v2[2] = p2[2]-p1[2]; vtkMath::Cross(v1,v2,polygonNormal); if (vtkMath::Norm(polygonNormal) != 0) break; } vtkMath::Normalize(polygonNormal); //Now we start computing the normal for each vertex double vertexNormalTemp[3]; existingPoints->GetPoint(cell[0], p1); existingPoints->GetPoint(cell[1], p2); v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; vtkMath::Cross(v1,polygonNormal,vertexNormalTemp); vtkMath::Normalize(vertexNormalTemp); double vertexNormal[3]; for (vtkIdType j = 0; j < cellSize-2; j++) { existingPoints->GetPoint(cell[j+1], p1); existingPoints->GetPoint(cell[j+2], p2); v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; vtkMath::Cross(v1,polygonNormal,vertexNormal); vtkMath::Normalize(vertexNormal); double finalNormal[3]; finalNormal[0] = (vertexNormal[0] + vertexNormalTemp[0])*0.5; finalNormal[1] = (vertexNormal[1] + vertexNormalTemp[1])*0.5; finalNormal[2] = (vertexNormal[2] + vertexNormalTemp[2])*0.5; vtkMath::Normalize(finalNormal); //Here we determine the direction of the normal if (m_SegmentationBinaryImage) { Point3D worldCoord; worldCoord[0] = p1[0]+finalNormal[0]*m_MaxSpacing; worldCoord[1] = p1[1]+finalNormal[1]*m_MaxSpacing; worldCoord[2] = p1[2]+finalNormal[2]*m_MaxSpacing; double val = 0.0; mitk::ImagePixelReadAccessor readAccess(m_SegmentationBinaryImage); itk::Index<3> idx; m_SegmentationBinaryImage->GetGeometry()->WorldToIndex(worldCoord, idx); try { val = readAccess.GetPixelByIndexSafe(idx); } catch (mitk::Exception e) { // If value is outside the image's region ignore it } if (val == 0.0) { + //MITK_INFO << "val equals zero."; ++m_PositiveNormalCounter; } else { + //MITK_INFO << "val does not equal zero."; ++m_NegativeNormalCounter; } } vertexNormalTemp[0] = vertexNormal[0]; vertexNormalTemp[1] = vertexNormal[1]; vertexNormalTemp[2] = vertexNormal[2]; vtkIdType id = cell[j+1]; normals->SetTuple(id,finalNormal); } existingPoints->GetPoint(cell[0], p1); existingPoints->GetPoint(cell[1], p2); v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; vtkMath::Cross(v1,polygonNormal,vertexNormal); vtkMath::Normalize(vertexNormal); vertexNormal[0] = (vertexNormal[0] + vertexNormalTemp[0])*0.5; vertexNormal[1] = (vertexNormal[1] + vertexNormalTemp[1])*0.5; vertexNormal[2] = (vertexNormal[2] + vertexNormalTemp[2])*0.5; vtkMath::Normalize(vertexNormal); vtkIdType id = cell[0]; normals->SetTuple(id,vertexNormal); id = cell[cellSize-1]; normals->SetTuple(id,vertexNormal); if(m_NegativeNormalCounter > m_PositiveNormalCounter) { for(vtkIdType n = 0; n < cellSize; n++) { double normal[3]; normals->GetTuple(offSet+n, normal); normal[0] = (-1)*normal[0]; normal[1] = (-1)*normal[1]; normal[2] = (-1)*normal[2]; normals->SetTuple(offSet+n, normal); } } m_NegativeNormalCounter = 0; m_PositiveNormalCounter = 0; offSet += cellSize; }//end for all cells Surface::Pointer surface = this->GetOutput(i); surface->GetVtkPolyData()->GetCellData()->SetNormals(normals); }//end for all inputs //Setting progressbar if (this->m_UseProgressBar) mitk::ProgressBar::GetInstance()->Progress(this->m_ProgressStepSize); } mitk::Surface::Pointer mitk::ComputeContourSetNormalsFilter::GetNormalsAsSurface() { //Just for debugging: vtkSmartPointer newPolyData = vtkSmartPointer::New(); vtkSmartPointer newLines = vtkSmartPointer::New(); vtkSmartPointer newPoints = vtkSmartPointer::New(); unsigned int idCounter (0); //Debug end for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs(); i++) { Surface* currentSurface = const_cast( this->GetOutput(i) ); vtkPolyData* polyData = currentSurface->GetVtkPolyData(); vtkSmartPointer currentCellNormals = vtkDoubleArray::SafeDownCast(polyData->GetCellData()->GetNormals()); vtkSmartPointer existingPolys = polyData->GetPolys(); vtkSmartPointer existingPoints = polyData->GetPoints(); existingPolys->InitTraversal(); vtkIdType* cell (NULL); vtkIdType cellSize (0); for( existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);) { for ( vtkIdType j = 0; j < cellSize; j++ ) { double currentNormal[3]; currentCellNormals->GetTuple(cell[j], currentNormal); vtkSmartPointer line = vtkSmartPointer::New(); line->GetPointIds()->SetNumberOfIds(2); double newPoint[3]; double p0[3]; existingPoints->GetPoint(cell[j], p0); newPoint[0] = p0[0] + currentNormal[0]; newPoint[1] = p0[1] + currentNormal[1]; newPoint[2] = p0[2] + currentNormal[2]; line->GetPointIds()->SetId(0, idCounter); newPoints->InsertPoint(idCounter, p0); idCounter++; line->GetPointIds()->SetId(1, idCounter); newPoints->InsertPoint(idCounter, newPoint); idCounter++; newLines->InsertNextCell(line); }//end for all points }//end for all cells }//end for all outputs newPolyData->SetPoints(newPoints); newPolyData->SetLines(newLines); newPolyData->BuildCells(); mitk::Surface::Pointer surface = mitk::Surface::New(); surface->SetVtkPolyData(newPolyData); return surface; } void mitk::ComputeContourSetNormalsFilter::SetMaxSpacing(double maxSpacing) { m_MaxSpacing = maxSpacing; } void mitk::ComputeContourSetNormalsFilter::GenerateOutputInformation() { Superclass::GenerateOutputInformation(); } void mitk::ComputeContourSetNormalsFilter::Reset() { for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); i++) { this->PopBackInput(); } this->SetNumberOfIndexedInputs(0); this->SetNumberOfIndexedOutputs(0); mitk::Surface::Pointer output = mitk::Surface::New(); this->SetNthOutput(0, output.GetPointer()); } void mitk::ComputeContourSetNormalsFilter::SetUseProgressBar(bool status) { this->m_UseProgressBar = status; } void mitk::ComputeContourSetNormalsFilter::SetProgressStepSize(unsigned int stepSize) { this->m_ProgressStepSize = stepSize; } diff --git a/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.h b/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.h index 09d29156b5..73fbe99ed8 100644 --- a/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.h +++ b/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.h @@ -1,113 +1,113 @@ /*=================================================================== 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 mitkComputeContourSetNormalsFilter_h_Included #define mitkComputeContourSetNormalsFilter_h_Included #include #include "mitkSurfaceToSurfaceFilter.h" #include "mitkProgressBar.h" #include "mitkSurface.h" #include "vtkCellArray.h" #include "vtkPolyData.h" #include "vtkSmartPointer.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkCellData.h" #include "vtkLine.h" #include "mitkImage.h" namespace mitk { /** \brief Filter to compute the normales for contours based on vtkPolygons This filter takes a number of extracted contours and computes the normals for each contour edge point. The normals can be accessed by calling: filter->GetOutput(i)->GetVtkPolyData()->GetCellData()->GetNormals(); See also the method GetNormalsAsSurface() Note: If a segmentation binary image is provided this filter assures that the computed normals do not point into the segmentation image $Author: fetzer$ */ class MITKSURFACEINTERPOLATION_EXPORT ComputeContourSetNormalsFilter : public SurfaceToSurfaceFilter { public: mitkClassMacro(ComputeContourSetNormalsFilter,SurfaceToSurfaceFilter); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /* \brief Returns the computed normals as a surface */ mitk::Surface::Pointer GetNormalsAsSurface(); //Resets the filter, i.e. removes all inputs and outputs void Reset(); void SetMaxSpacing(double); /** \brief Set whether the mitkProgressBar should be used \a Parameter true for using the progress bar, false otherwise */ void SetUseProgressBar(bool); /** \brief Set the stepsize which the progress bar should proceed \a Parameter The stepsize for progressing */ void SetProgressStepSize(unsigned int stepSize); void SetSegmentationBinaryImage(mitk::Image* segmentationImage) { m_SegmentationBinaryImage = segmentationImage; } protected: ComputeContourSetNormalsFilter(); virtual ~ComputeContourSetNormalsFilter(); virtual void GenerateData(); virtual void GenerateOutputInformation(); private: //The segmentation out of which the contours were extracted. Can be used to determine the direction of the normals - mitk::Image* m_SegmentationBinaryImage; + mitk::Image::Pointer m_SegmentationBinaryImage; double m_MaxSpacing; unsigned int m_NegativeNormalCounter; unsigned int m_PositiveNormalCounter; bool m_UseProgressBar; unsigned int m_ProgressStepSize; };//class }//namespace #endif diff --git a/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp b/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp index e30950bea3..c620d3f0d5 100644 --- a/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp +++ b/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.cpp @@ -1,579 +1,670 @@ /*=================================================================== 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 "mitkSurfaceInterpolationController.h" #include "mitkMemoryUtilities.h" #include "mitkImageAccessByItk.h" #include "mitkImageCast.h" #include "mitkImageToSurfaceFilter.h" +//#include "vtkXMLPolyDataWriter.h" +#include "vtkPolyDataWriter.h" // Check whether the given contours are coplanar bool ContoursCoplanar(mitk::SurfaceInterpolationController::ContourPositionInformation leftHandSide, mitk::SurfaceInterpolationController::ContourPositionInformation rightHandSide) { // Here we check two things: // 1. Whether the normals of both contours are at least parallel // 2. Whether both contours lie in the same plane // Check for coplanarity: // a. Span a vector between two points one from each contour // b. Calculate dot product for the vector and one of the normals // c. If the dot is zero the two vectors are orthogonal and the contours are coplanar double vec[3]; vec[0] = leftHandSide.contourPoint[0] - rightHandSide.contourPoint[0]; vec[1] = leftHandSide.contourPoint[1] - rightHandSide.contourPoint[1]; vec[2] = leftHandSide.contourPoint[2] - rightHandSide.contourPoint[2]; double n[3]; n[0] = rightHandSide.contourNormal[0]; n[1] = rightHandSide.contourNormal[1]; n[2] = rightHandSide.contourNormal[2]; double dot = vtkMath::Dot(n, vec); double n2[3]; n2[0] = leftHandSide.contourNormal[0]; n2[1] = leftHandSide.contourNormal[1]; n2[2] = leftHandSide.contourNormal[2]; // The normals of both contours have to be parallel but not of the same orientation double lengthLHS = leftHandSide.contourNormal.GetNorm(); double lengthRHS = rightHandSide.contourNormal.GetNorm(); double dot2 = vtkMath::Dot(n, n2); bool contoursParallel = mitk::Equal(fabs(lengthLHS*lengthRHS), fabs(dot2), 0.001); if (mitk::Equal(dot, 0.0, 0.001) && contoursParallel) return true; else return false; } mitk::SurfaceInterpolationController::ContourPositionInformation CreateContourPositionInformation(mitk::Surface::Pointer contour) { mitk::SurfaceInterpolationController::ContourPositionInformation contourInfo; contourInfo.contour = contour; double n[3]; double p[3]; contour->GetVtkPolyData()->GetPoints()->GetPoint(0, p); vtkPolygon::ComputeNormal(contour->GetVtkPolyData()->GetPoints(), n); contourInfo.contourNormal = n; contourInfo.contourPoint = p; return contourInfo; } mitk::SurfaceInterpolationController::SurfaceInterpolationController() - :m_SelectedSegmentation(0) + :m_SelectedSegmentation(0), m_CurrentTimeStep(0) { m_ReduceFilter = ReduceContourSetFilter::New(); m_NormalsFilter = ComputeContourSetNormalsFilter::New(); m_InterpolateSurfaceFilter = CreateDistanceImageFromSurfaceFilter::New(); + //m_TimeSelector = ImageTimeSelector::New(); m_ReduceFilter->SetUseProgressBar(false); // m_ReduceFilter->SetProgressStepSize(1); m_NormalsFilter->SetUseProgressBar(true); m_NormalsFilter->SetProgressStepSize(1); m_InterpolateSurfaceFilter->SetUseProgressBar(true); m_InterpolateSurfaceFilter->SetProgressStepSize(7); m_Contours = Surface::New(); m_PolyData = vtkSmartPointer::New(); vtkSmartPointer points = vtkSmartPointer::New(); m_PolyData->SetPoints(points); m_InterpolationResult = 0; m_CurrentNumberOfReducedContours = 0; } mitk::SurfaceInterpolationController::~SurfaceInterpolationController() { //Removing all observers std::map::iterator dataIter = m_SegmentationObserverTags.begin(); for (; dataIter != m_SegmentationObserverTags.end(); ++dataIter ) { (*dataIter).first->RemoveObserver( (*dataIter).second ); } m_SegmentationObserverTags.clear(); } mitk::SurfaceInterpolationController* mitk::SurfaceInterpolationController::GetInstance() { static mitk::SurfaceInterpolationController::Pointer m_Instance; if ( m_Instance.IsNull() ) { m_Instance = SurfaceInterpolationController::New(); } return m_Instance; } void mitk::SurfaceInterpolationController::AddNewContour (mitk::Surface::Pointer newContour) { if( newContour->GetVtkPolyData()->GetNumberOfPoints() > 0) { ContourPositionInformation contourInfo = CreateContourPositionInformation(newContour); this->AddToInterpolationPipeline(contourInfo); this->Modified(); } } void mitk::SurfaceInterpolationController::AddNewContours(std::vector newContours) { for (unsigned int i = 0; i < newContours.size(); ++i) { if( newContours.at(i)->GetVtkPolyData()->GetNumberOfPoints() > 0) { ContourPositionInformation contourInfo = CreateContourPositionInformation(newContours.at(i)); this->AddToInterpolationPipeline(contourInfo); } } this->Modified(); } -void mitk::SurfaceInterpolationController::AddToInterpolationPipeline(ContourPositionInformation contourInfo) +void mitk::SurfaceInterpolationController::AddToInterpolationPipeline(ContourPositionInformation contourInfo ) { int pos (-1); - ContourPositionInformationList currentContourList = m_ListOfInterpolationSessions[m_SelectedSegmentation]; + unsigned int numTimeSteps = m_SelectedSegmentation->GetTimeSteps(); + if ( m_CurrentTimeStep >= numTimeSteps ) + { + MITK_ERROR << "Invalid time step requested for interpolation pipeline."; + return; + } + + ContourPositionInformationVec2D currentContours = m_ListOfInterpolationSessions[m_SelectedSegmentation]; + ContourPositionInformationList currentContourList = currentContours[m_CurrentTimeStep]; + mitk::Surface* newContour = contourInfo.contour; for (unsigned int i = 0; i < currentContourList.size(); i++) { ContourPositionInformation contourFromList = currentContourList.at(i); if (ContoursCoplanar(contourInfo, contourFromList)) { pos = i; break; } } //Don't save a new empty contour if (pos == -1 && newContour->GetVtkPolyData()->GetNumberOfPoints() > 0) { - m_ReduceFilter->SetInput(m_ListOfInterpolationSessions[m_SelectedSegmentation].size(), newContour); - m_ListOfInterpolationSessions[m_SelectedSegmentation].push_back(contourInfo); + m_ReduceFilter->SetInput(m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep].size(), newContour); + m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep].push_back(contourInfo); } else if (pos != -1 && newContour->GetVtkPolyData()->GetNumberOfPoints() > 0) { - m_ListOfInterpolationSessions[m_SelectedSegmentation].at(pos) = contourInfo; + m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep].at(pos) = contourInfo; m_ReduceFilter->SetInput(pos, newContour); } else if (newContour->GetVtkPolyData()->GetNumberOfPoints() == 0) { this->RemoveContour(contourInfo); } + + m_ReduceFilter->Update(); + m_CurrentNumberOfReducedContours = m_ReduceFilter->GetNumberOfOutputs(); + + mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); + timeSelector->SetInput( m_SelectedSegmentation ); + timeSelector->SetTimeNr( m_CurrentTimeStep ); + timeSelector->SetChannelNr( 0 ); + timeSelector->Update(); + mitk::Image::Pointer refSegImage = timeSelector->GetOutput(); + + m_NormalsFilter->SetSegmentationBinaryImage(refSegImage); + for (unsigned int i = 0; i < m_CurrentNumberOfReducedContours; i++) + { + m_NormalsFilter->SetInput(i, m_ReduceFilter->GetOutput(i)); + m_InterpolateSurfaceFilter->SetInput(i, m_NormalsFilter->GetOutput(i)); + } } -bool mitk::SurfaceInterpolationController::RemoveContour(ContourPositionInformation contourInfo) +bool mitk::SurfaceInterpolationController::RemoveContour(ContourPositionInformation contourInfo ) { if(!m_SelectedSegmentation) + { return false; - ContourPositionInformationList::iterator it = m_ListOfInterpolationSessions[m_SelectedSegmentation].begin(); - while (it != m_ListOfInterpolationSessions[m_SelectedSegmentation].end()) + } + + unsigned int numTimeSteps = m_SelectedSegmentation->GetTimeSteps(); + if ( m_CurrentTimeStep >= numTimeSteps ) + { + return false; + } + + ContourPositionInformationList::iterator it = m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep].begin(); + while (it != m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep].end()) { ContourPositionInformation currentContour = (*it); if (ContoursCoplanar(currentContour, contourInfo)) { - m_ListOfInterpolationSessions[m_SelectedSegmentation].erase(it); + m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep].erase(it); this->ReinitializeInterpolation(); return true; } ++it; } return false; } -const mitk::Surface* mitk::SurfaceInterpolationController::GetContour(ContourPositionInformation contourInfo) +const mitk::Surface* mitk::SurfaceInterpolationController::GetContour(ContourPositionInformation contourInfo ) { - ContourPositionInformationList contourList = m_ListOfInterpolationSessions[m_SelectedSegmentation]; + if(!m_SelectedSegmentation) + { + return 0; + } + + unsigned int numTimeSteps = m_SelectedSegmentation->GetTimeSteps(); + if ( m_CurrentTimeStep >= numTimeSteps ) + { + return 0; + } + + ContourPositionInformationList contourList = m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep]; for (unsigned int i = 0; i < contourList.size(); ++i) { ContourPositionInformation currentContour = contourList.at(i); if (ContoursCoplanar(contourInfo, currentContour)) return currentContour.contour; } return 0; } unsigned int mitk::SurfaceInterpolationController::GetNumberOfContours() { - return m_ListOfInterpolationSessions[m_SelectedSegmentation].size(); + if(!m_SelectedSegmentation) + { + return -1; + } + + unsigned int numTimeSteps = m_SelectedSegmentation->GetTimeSteps(); + if ( m_CurrentTimeStep >= numTimeSteps ) + { + return -1; + } + + return m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep].size(); } void mitk::SurfaceInterpolationController::Interpolate() { m_ReduceFilter->Update(); m_CurrentNumberOfReducedContours = m_ReduceFilter->GetNumberOfOutputs(); for (unsigned int i = 0; i < m_CurrentNumberOfReducedContours; i++) { mitk::Surface::Pointer reducedContour = m_ReduceFilter->GetOutput(i); reducedContour->DisconnectPipeline(); m_NormalsFilter->SetInput(i, reducedContour); m_InterpolateSurfaceFilter->SetInput(i, m_NormalsFilter->GetOutput(i)); } if (m_CurrentNumberOfReducedContours< 2) { //If no interpolation is possible reset the interpolation result m_InterpolationResult = 0; return; } //Setting up progress bar mitk::ProgressBar::GetInstance()->AddStepsToDo(10); // create a surface from the distance-image mitk::ImageToSurfaceFilter::Pointer imageToSurfaceFilter = mitk::ImageToSurfaceFilter::New(); imageToSurfaceFilter->SetInput( m_InterpolateSurfaceFilter->GetOutput() ); imageToSurfaceFilter->SetThreshold( 0 ); imageToSurfaceFilter->SetSmooth(true); imageToSurfaceFilter->SetSmoothIteration(20); imageToSurfaceFilter->Update(); - m_InterpolationResult = imageToSurfaceFilter->GetOutput(); + + mitk::Surface::Pointer interpolationResult = mitk::Surface::New(); + interpolationResult->SetVtkPolyData( imageToSurfaceFilter->GetOutput()->GetVtkPolyData(), m_CurrentTimeStep ); + m_InterpolationResult = interpolationResult; vtkSmartPointer polyDataAppender = vtkSmartPointer::New(); - for (unsigned int i = 0; i < m_ListOfInterpolationSessions[m_SelectedSegmentation].size(); i++) + for (unsigned int i = 0; i < m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep].size(); i++) { - polyDataAppender->AddInputData(m_ListOfInterpolationSessions[m_SelectedSegmentation].at(i).contour->GetVtkPolyData()); + polyDataAppender->AddInputData(m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep].at(i).contour->GetVtkPolyData()); } polyDataAppender->Update(); m_Contours->SetVtkPolyData(polyDataAppender->GetOutput()); //Last progress step mitk::ProgressBar::GetInstance()->Progress(20); m_InterpolationResult->DisconnectPipeline(); } mitk::Surface::Pointer mitk::SurfaceInterpolationController::GetInterpolationResult() { return m_InterpolationResult; } mitk::Surface* mitk::SurfaceInterpolationController::GetContoursAsSurface() { return m_Contours; } void mitk::SurfaceInterpolationController::SetDataStorage(DataStorage::Pointer ds) { m_DataStorage = ds; } void mitk::SurfaceInterpolationController::SetMinSpacing(double minSpacing) { m_ReduceFilter->SetMinSpacing(minSpacing); } void mitk::SurfaceInterpolationController::SetMaxSpacing(double maxSpacing) { m_ReduceFilter->SetMaxSpacing(maxSpacing); m_NormalsFilter->SetMaxSpacing(maxSpacing); } void mitk::SurfaceInterpolationController::SetDistanceImageVolume(unsigned int distImgVolume) { m_InterpolateSurfaceFilter->SetDistanceImageVolume(distImgVolume); } mitk::Image::Pointer mitk::SurfaceInterpolationController::GetCurrentSegmentation() { return m_SelectedSegmentation; } mitk::Image* mitk::SurfaceInterpolationController::GetImage() { return m_InterpolateSurfaceFilter->GetOutput(); } double mitk::SurfaceInterpolationController::EstimatePortionOfNeededMemory() { double numberOfPointsAfterReduction = m_ReduceFilter->GetNumberOfPointsAfterReduction()*3; double sizeOfPoints = pow(numberOfPointsAfterReduction,2)*sizeof(double); double totalMem = mitk::MemoryUtilities::GetTotalSizeOfPhysicalRam(); double percentage = sizeOfPoints/totalMem; return percentage; } unsigned int mitk::SurfaceInterpolationController::GetNumberOfInterpolationSessions() { return m_ListOfInterpolationSessions.size(); } template void mitk::SurfaceInterpolationController::GetImageBase(itk::Image* input, itk::ImageBase<3>::Pointer& result) { result->Graft(input); } void mitk::SurfaceInterpolationController::SetCurrentSegmentationInterpolationList(mitk::Image::Pointer segmentation) { this->SetCurrentInterpolationSession(segmentation); } void mitk::SurfaceInterpolationController::SetCurrentInterpolationSession(mitk::Image::Pointer currentSegmentationImage) { if (currentSegmentationImage.GetPointer() == m_SelectedSegmentation) return; if (currentSegmentationImage.IsNull()) { m_SelectedSegmentation = 0; return; } m_SelectedSegmentation = currentSegmentationImage.GetPointer(); ContourListMap::iterator it = m_ListOfInterpolationSessions.find(currentSegmentationImage.GetPointer()); // If the session does not exist yet create a new ContourPositionPairList otherwise reinitialize the interpolation pipeline if (it == m_ListOfInterpolationSessions.end()) { - ContourPositionInformationList newList; - m_ListOfInterpolationSessions.insert(std::pair(m_SelectedSegmentation, newList)); + ContourPositionInformationVec2D newList; + m_ListOfInterpolationSessions.insert(std::pair(m_SelectedSegmentation, newList)); m_InterpolationResult = 0; m_CurrentNumberOfReducedContours = 0; itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction(this, &SurfaceInterpolationController::OnSegmentationDeleted); m_SegmentationObserverTags.insert( std::pair( m_SelectedSegmentation, m_SelectedSegmentation->AddObserver( itk::DeleteEvent(), command ) ) ); } this->ReinitializeInterpolation(); } bool mitk::SurfaceInterpolationController::ReplaceInterpolationSession(mitk::Image::Pointer oldSession, mitk::Image::Pointer newSession) { if (oldSession.IsNull() || newSession.IsNull()) return false; if (oldSession.GetPointer() == newSession.GetPointer()) return false; if (!mitk::Equal(*(oldSession->GetGeometry()), *(newSession->GetGeometry()), mitk::eps, false)) return false; ContourListMap::iterator it = m_ListOfInterpolationSessions.find(oldSession.GetPointer()); if (it == m_ListOfInterpolationSessions.end()) return false; - ContourPositionInformationList oldList = (*it).second; - m_ListOfInterpolationSessions.insert(std::pair(newSession.GetPointer(), oldList)); + ContourPositionInformationVec2D oldList = (*it).second; + m_ListOfInterpolationSessions.insert(std::pair(newSession.GetPointer(), oldList)); itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction(this, &SurfaceInterpolationController::OnSegmentationDeleted); m_SegmentationObserverTags.insert( std::pair( newSession, newSession->AddObserver( itk::DeleteEvent(), command ) ) ); if (m_SelectedSegmentation == oldSession) m_SelectedSegmentation = newSession; - m_NormalsFilter->SetSegmentationBinaryImage(m_SelectedSegmentation); + + mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); + timeSelector->SetInput( m_SelectedSegmentation ); + timeSelector->SetTimeNr( m_CurrentTimeStep ); + timeSelector->SetChannelNr( 0 ); + timeSelector->Update(); + mitk::Image::Pointer refSegImage = timeSelector->GetOutput(); + m_NormalsFilter->SetSegmentationBinaryImage(refSegImage); this->RemoveInterpolationSession(oldSession); return true; } void mitk::SurfaceInterpolationController::RemoveSegmentationFromContourList(mitk::Image *segmentation) { this->RemoveInterpolationSession(segmentation); } void mitk::SurfaceInterpolationController::RemoveInterpolationSession(mitk::Image::Pointer segmentationImage) { if (segmentationImage) { if (m_SelectedSegmentation == segmentationImage) { m_NormalsFilter->SetSegmentationBinaryImage(NULL); m_SelectedSegmentation = 0; } m_ListOfInterpolationSessions.erase(segmentationImage); // Remove observer std::map::iterator pos = m_SegmentationObserverTags.find(segmentationImage); if (pos != m_SegmentationObserverTags.end()) { segmentationImage->RemoveObserver((*pos).second); m_SegmentationObserverTags.erase(pos); } } } void mitk::SurfaceInterpolationController::RemoveAllInterpolationSessions() { //Removing all observers std::map::iterator dataIter = m_SegmentationObserverTags.begin(); while (dataIter != m_SegmentationObserverTags.end()) { mitk::Image* image = (*dataIter).first; image->RemoveObserver((*dataIter).second); ++dataIter; } m_SegmentationObserverTags.clear(); m_SelectedSegmentation = 0; m_ListOfInterpolationSessions.clear(); } void mitk::SurfaceInterpolationController::ReinitializeInterpolation(mitk::Surface::Pointer contours) { // 1. detect coplanar contours // 2. merge coplanar contours into a single surface // 4. add contour to pipeline // Split the surface into separate polygons vtkSmartPointer existingPolys; vtkSmartPointer existingPoints; existingPolys = contours->GetVtkPolyData()->GetPolys(); existingPoints = contours->GetVtkPolyData()->GetPoints(); existingPolys->InitTraversal(); vtkSmartPointer ids = vtkSmartPointer::New(); typedef std::pair PointNormalPair; std::vector list; std::vector > pointsList; int count (0); for( existingPolys->InitTraversal(); existingPolys->GetNextCell(ids);) { // Get the points vtkSmartPointer points = vtkSmartPointer::New(); existingPoints->GetPoints(ids, points); ++count; pointsList.push_back(points); PointNormalPair p_n; double n[3]; vtkPolygon::ComputeNormal(points, n); p_n.first = n; double p[3]; existingPoints->GetPoint(ids->GetId(0), p); p_n.second = p; ContourPositionInformation p_info; p_info.contourNormal = n; p_info.contourPoint = p; list.push_back(p_info); continue; } // Detect and sort coplanar polygons std::vector::iterator outer = list.begin(); std::vector< std::vector< vtkSmartPointer > > relatedPoints; while (outer != list.end()) { std::vector::iterator inner = outer; ++inner; std::vector< vtkSmartPointer > rel; std::vector< vtkSmartPointer >::iterator pointsIter = pointsList.begin(); rel.push_back((*pointsIter)); pointsIter = pointsList.erase(pointsIter); while (inner != list.end()) { if(ContoursCoplanar((*outer),(*inner))) { inner = list.erase(inner); rel.push_back((*pointsIter)); pointsIter = pointsList.erase(pointsIter); } else { ++inner; ++pointsIter; } } relatedPoints.push_back(rel); ++outer; } // Build the separate surfaces again std::vector finalSurfaces; for (unsigned int i = 0; i < relatedPoints.size(); ++i) { vtkSmartPointer contourSurface = vtkSmartPointer::New(); vtkSmartPointer points = vtkSmartPointer::New(); vtkSmartPointer polygons = vtkSmartPointer::New(); unsigned int pointId (0); for (unsigned int j = 0; j < relatedPoints.at(i).size(); ++j) { unsigned int numPoints = relatedPoints.at(i).at(j)->GetNumberOfPoints(); vtkSmartPointer polygon = vtkSmartPointer::New(); polygon->GetPointIds()->SetNumberOfIds(numPoints); polygon->GetPoints()->SetNumberOfPoints(numPoints); vtkSmartPointer currentPoints = relatedPoints.at(i).at(j); for (unsigned k = 0; k < numPoints; ++k) { points->InsertPoint(pointId, currentPoints->GetPoint(k)); polygon->GetPointIds()->SetId(k, pointId); ++pointId; } polygons->InsertNextCell(polygon); } contourSurface->SetPoints(points); contourSurface->SetPolys(polygons); contourSurface->BuildLinks(); mitk::Surface::Pointer surface = mitk::Surface::New(); surface->SetVtkPolyData(contourSurface); finalSurfaces.push_back(surface); } // Add detected contours to interpolation pipeline this->AddNewContours(finalSurfaces); } void mitk::SurfaceInterpolationController::OnSegmentationDeleted(const itk::Object *caller, const itk::EventObject &/*event*/) { mitk::Image* tempImage = dynamic_cast(const_cast(caller)); if (tempImage) { if (m_SelectedSegmentation == tempImage) { m_NormalsFilter->SetSegmentationBinaryImage(NULL); m_SelectedSegmentation = 0; } m_SegmentationObserverTags.erase(tempImage); m_ListOfInterpolationSessions.erase(tempImage); } } void mitk::SurfaceInterpolationController::ReinitializeInterpolation() { - m_NormalsFilter->SetSegmentationBinaryImage(m_SelectedSegmentation); - // If session has changed reset the pipeline m_ReduceFilter->Reset(); m_NormalsFilter->Reset(); m_InterpolateSurfaceFilter->Reset(); itk::ImageBase<3>::Pointer itkImage = itk::ImageBase<3>::New(); - AccessFixedDimensionByItk_1( m_SelectedSegmentation, GetImageBase, 3, itkImage ); - m_InterpolateSurfaceFilter->SetReferenceImage(itkImage.GetPointer()); - for (unsigned int i = 0; i < m_ListOfInterpolationSessions[m_SelectedSegmentation].size(); i++) + if ( m_SelectedSegmentation ) { - m_ReduceFilter->SetInput(i, m_ListOfInterpolationSessions[m_SelectedSegmentation].at(i).contour); - } + mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); + timeSelector->SetInput( m_SelectedSegmentation ); + timeSelector->SetTimeNr( m_CurrentTimeStep ); + timeSelector->SetChannelNr( 0 ); + timeSelector->Update(); + mitk::Image::Pointer refSegImage = timeSelector->GetOutput(); + AccessFixedDimensionByItk_1( refSegImage, GetImageBase, 3, itkImage ); + m_InterpolateSurfaceFilter->SetReferenceImage(itkImage.GetPointer()); + + unsigned int numTimeSteps = m_SelectedSegmentation->GetTimeSteps(); + unsigned int size = m_ListOfInterpolationSessions[m_SelectedSegmentation].size(); + if ( size != numTimeSteps ) + { + m_ListOfInterpolationSessions[m_SelectedSegmentation].resize( numTimeSteps ); + } - m_ReduceFilter->Update(); + if ( m_CurrentTimeStep < numTimeSteps ) + { + unsigned int numContours = m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep].size(); + for ( unsigned int c = 0; c < numContours; ++c ) + { + m_ReduceFilter->SetInput(c, m_ListOfInterpolationSessions[m_SelectedSegmentation][m_CurrentTimeStep][c].contour); + } - m_CurrentNumberOfReducedContours = m_ReduceFilter->GetNumberOfOutputs(); + m_ReduceFilter->Update(); + + m_CurrentNumberOfReducedContours = m_ReduceFilter->GetNumberOfOutputs(); + + for (unsigned int i = 0; i < m_CurrentNumberOfReducedContours; i++) + { + m_NormalsFilter->SetInput(i, m_ReduceFilter->GetOutput(i)); + m_InterpolateSurfaceFilter->SetInput(i, m_NormalsFilter->GetOutput(i)); + } + } + + Modified(); - for (unsigned int i = 0; i < m_CurrentNumberOfReducedContours; i++) - { - m_NormalsFilter->SetInput(i, m_ReduceFilter->GetOutput(i)); - m_InterpolateSurfaceFilter->SetInput(i, m_NormalsFilter->GetOutput(i)); } - Modified(); } diff --git a/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.h b/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.h index ee46b27ba6..97cef67f84 100644 --- a/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.h +++ b/Modules/SurfaceInterpolation/mitkSurfaceInterpolationController.h @@ -1,236 +1,264 @@ /*=================================================================== 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 mitkSurfaceInterpolationController_h_Included #define mitkSurfaceInterpolationController_h_Included #include "mitkCommon.h" #include #include "mitkRestorePlanePositionOperation.h" #include "mitkSurface.h" #include "mitkInteractionConst.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkCreateDistanceImageFromSurfaceFilter.h" #include "mitkReduceContourSetFilter.h" #include "mitkComputeContourSetNormalsFilter.h" #include "mitkDataNode.h" #include "mitkDataStorage.h" #include "mitkWeakPointer.h" #include "vtkPolygon.h" #include "vtkPoints.h" #include "vtkCellArray.h" #include "vtkPolyData.h" #include "vtkSmartPointer.h" #include "vtkAppendPolyData.h" #include "vtkMarchingCubes.h" #include "vtkImageData.h" #include "mitkVtkRepresentationProperty.h" #include "vtkProperty.h" +#include "mitkImageTimeSelector.h" #include "mitkProgressBar.h" namespace mitk { class MITKSURFACEINTERPOLATION_EXPORT SurfaceInterpolationController : public itk::Object { public: - mitkClassMacro(SurfaceInterpolationController, itk::Object) - itkFactorylessNewMacro(Self) - itkCloneMacro(Self) + mitkClassMacro(SurfaceInterpolationController, itk::Object); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); struct ContourPositionInformation { Surface::Pointer contour; Vector3D contourNormal; Point3D contourPoint; }; typedef std::vector ContourPositionInformationList; - typedef std::map ContourListMap; + typedef std::vector ContourPositionInformationVec2D; + //typedef std::map ContourListMap; + typedef std::map ContourListMap; static SurfaceInterpolationController* GetInstance(); + void SetCurrentTimeStep( int ts ) + { + if ( m_CurrentTimeStep != ts ) + { + m_CurrentTimeStep = ts; + + if ( m_SelectedSegmentation ) + { + /*m_TimeSelector->SetInput( m_SelectedSegmentation ); + m_TimeSelector->SetTimeNr( m_CurrentTimeStep ); + m_TimeSelector->SetChannelNr( 0 ); + m_TimeSelector->Update();*/ + + this->ReinitializeInterpolation(); + } + } + }; + + unsigned int GetCurrentTimeStep() + { + return m_CurrentTimeStep; + }; + /** * @brief Adds a new extracted contour to the list * @param newContour the contour to be added. If a contour at that position * already exists the related contour will be updated */ void AddNewContour (Surface::Pointer newContour); /** * @brief Removes the contour for a given plane for the current selected segmenation * @param contourInfo the contour which should be removed * @return true if a contour was found and removed, false if no contour was found */ - bool RemoveContour (ContourPositionInformation contourInfo); + bool RemoveContour (ContourPositionInformation contourInfo ); /** * @brief Adds new extracted contours to the list. If one or more contours at a given position * already exist they will be updated respectively * @param newContours the list of the contours */ void AddNewContours (std::vector newContours); /** * @brief Returns the contour for a given plane for the current selected segmenation * @param ontourInfo the contour which should be returned * @return the contour as an mitk::Surface. If no contour is available at the give position NULL is returned */ - const mitk::Surface* GetContour (ContourPositionInformation contourInfo); + const mitk::Surface* GetContour (ContourPositionInformation contourInfo ); /** * @brief Returns the number of available contours for the current selected segmentation * @return the number of contours */ unsigned int GetNumberOfContours(); /** * Interpolates the 3D surface from the given extracted contours */ void Interpolate (); mitk::Surface::Pointer GetInterpolationResult(); /** * Sets the minimum spacing of the current selected segmentation * This is needed since the contour points we reduced before they are used to interpolate the surface */ void SetMinSpacing(double minSpacing); /** * Sets the minimum spacing of the current selected segmentation * This is needed since the contour points we reduced before they are used to interpolate the surface */ void SetMaxSpacing(double maxSpacing); /** * Sets the volume i.e. the number of pixels that the distance image should have * By evaluation we found out that 50.000 pixel delivers a good result */ void SetDistanceImageVolume(unsigned int distImageVolume); /** * @brief Get the current selected segmentation for which the interpolation is performed * @return the current segmentation image */ mitk::Image::Pointer GetCurrentSegmentation(); Surface* GetContoursAsSurface(); void SetDataStorage(DataStorage::Pointer ds); /** * Sets the current list of contourpoints which is used for the surface interpolation * @param segmentation The current selected segmentation * \deprecatedSince{2014_03} */ DEPRECATED (void SetCurrentSegmentationInterpolationList(mitk::Image::Pointer segmentation)); /** * Sets the current list of contourpoints which is used for the surface interpolation * @param segmentation The current selected segmentation */ void SetCurrentInterpolationSession(mitk::Image::Pointer currentSegmentationImage); /** * Removes the segmentation and all its contours from the list * @param segmentation The segmentation to be removed * \deprecatedSince{2014_03} */ DEPRECATED (void RemoveSegmentationFromContourList(mitk::Image* segmentation)); /** * @brief Remove interpolation session * @param segmentationImage the session to be removed */ void RemoveInterpolationSession(mitk::Image::Pointer segmentationImage); /** * Replaces the current interpolation session with a new one. All contours form the old * session will be applied to the new session. This only works if the two images have the * geometry * @param oldSession the session which should be replaced * @param newSession the new session which replaces the old one * @return true it the the replacement was successful, false if not (e.g. the image's geometry differs) */ bool ReplaceInterpolationSession(mitk::Image::Pointer oldSession, mitk::Image::Pointer newSession); /** * @brief Removes all sessions */ void RemoveAllInterpolationSessions(); /** * @brief Reinitializes the interpolation using the provided contour data * @param contours a mitk::Surface which contains the contours as polys in the vtkPolyData */ void ReinitializeInterpolation(mitk::Surface::Pointer contours); mitk::Image* GetImage(); /** * Estimates the memory which is needed to build up the equationsystem for the interpolation. * \returns The percentage of the real memory which will be used by the interpolation */ double EstimatePortionOfNeededMemory(); unsigned int GetNumberOfInterpolationSessions(); protected: SurfaceInterpolationController(); ~SurfaceInterpolationController(); template void GetImageBase(itk::Image* input, itk::ImageBase<3>::Pointer& result); private: - void OnSegmentationDeleted(const itk::Object *caller, const itk::EventObject &event); - void ReinitializeInterpolation(); - void AddToInterpolationPipeline(ContourPositionInformation contourInfo); + void OnSegmentationDeleted(const itk::Object *caller, const itk::EventObject &event); + + void AddToInterpolationPipeline(ContourPositionInformation contourInfo ); ReduceContourSetFilter::Pointer m_ReduceFilter; ComputeContourSetNormalsFilter::Pointer m_NormalsFilter; CreateDistanceImageFromSurfaceFilter::Pointer m_InterpolateSurfaceFilter; Surface::Pointer m_Contours; vtkSmartPointer m_PolyData; mitk::DataStorage::Pointer m_DataStorage; ContourListMap m_ListOfInterpolationSessions; mitk::Surface::Pointer m_InterpolationResult; unsigned int m_CurrentNumberOfReducedContours; mitk::Image* m_SelectedSegmentation; std::map m_SegmentationObserverTags; + + int m_CurrentTimeStep; }; } #endif