diff --git a/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp b/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp index f7b33aa3a0..f66952caa9 100755 --- a/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp +++ b/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp @@ -1,210 +1,236 @@ /*=================================================================== 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 "mitkContourModelUtils.h" #include "mitkImageCast.h" #include "mitkImageAccessByItk.h" #include "mitkContourModel.h" #include "itkCastImageFilter.h" #include "mitkImage.h" #include "mitkSurface.h" #include "vtkPolyData.h" #include "mitkContourModelToSurfaceFilter.h" #include "vtkPolyDataToImageStencil.h" #include "vtkImageStencil.h" #include "mitkImageVtkAccessor.h" #include "vtkSmartPointer.h" #include "vtkImageData.h" #include "vtkImageLogic.h" #include "vtkPointData.h" - +#include "mitkLabelSetImage.h" mitk::ContourModelUtils::ContourModelUtils() { } mitk::ContourModelUtils::~ContourModelUtils() { } mitk::ContourModel::Pointer mitk::ContourModelUtils::ProjectContourTo2DSlice(Image* slice, ContourModel* contourIn3D, bool itkNotUsed( correctionForIpSegmentation ), bool constrainToInside) { if ( !slice || !contourIn3D ) return NULL; ContourModel::Pointer projectedContour = ContourModel::New(); projectedContour->Initialize(*contourIn3D); const BaseGeometry* sliceGeometry = slice->GetGeometry(); int numberOfTimesteps = contourIn3D->GetTimeGeometry()->CountTimeSteps(); for(int currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++) { ContourModel::VertexIterator iter = contourIn3D->Begin(currentTimestep); ContourModel::VertexIterator end = contourIn3D->End(currentTimestep); while( iter != end) { Point3D currentPointIn3D = (*iter)->Coordinates; Point3D projectedPointIn2D; projectedPointIn2D.Fill(0.0); sliceGeometry->WorldToIndex( currentPointIn3D, projectedPointIn2D ); // MITK_INFO << "world point " << currentPointIn3D << " in index is " << projectedPointIn2D; if ( !sliceGeometry->IsIndexInside( projectedPointIn2D ) && constrainToInside ) { MITK_INFO << "**" << currentPointIn3D << " is " << projectedPointIn2D << " --> correct it (TODO)" << std::endl; } projectedContour->AddVertex( projectedPointIn2D, currentTimestep ); iter++; } } return projectedContour; } mitk::ContourModel::Pointer mitk::ContourModelUtils::BackProjectContourFrom2DSlice(const BaseGeometry* sliceGeometry, ContourModel* contourIn2D, bool itkNotUsed( correctionForIpSegmentation ) ) { if ( !sliceGeometry || !contourIn2D ) return NULL; ContourModel::Pointer worldContour = ContourModel::New(); worldContour->Initialize(*contourIn2D); int numberOfTimesteps = contourIn2D->GetTimeGeometry()->CountTimeSteps(); for(int currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++) { ContourModel::VertexIterator iter = contourIn2D->Begin(currentTimestep); ContourModel::VertexIterator end = contourIn2D->End(currentTimestep); while( iter != end) { Point3D currentPointIn2D = (*iter)->Coordinates; Point3D worldPointIn3D; worldPointIn3D.Fill(0.0); sliceGeometry->IndexToWorld( currentPointIn2D, worldPointIn3D ); //MITK_INFO << "index " << currentPointIn2D << " world " << worldPointIn3D << std::endl; worldContour->AddVertex( worldPointIn3D, currentTimestep ); iter++; } } return worldContour; } -void mitk::ContourModelUtils::FillContourInSlice( ContourModel* projectedContour, Image* sliceImage, int paintingPixelValue ) +void mitk::ContourModelUtils::FillContourInSlice( ContourModel* projectedContour, Image* sliceImage, mitk::Image::Pointer workingImage, int paintingPixelValue ) { - mitk::ContourModelUtils::FillContourInSlice(projectedContour, 0, sliceImage, paintingPixelValue); + mitk::ContourModelUtils::FillContourInSlice(projectedContour, 0, sliceImage,workingImage, paintingPixelValue); } -void mitk::ContourModelUtils::FillContourInSlice( ContourModel* projectedContour, unsigned int timeStep, Image* sliceImage, int paintingPixelValue ) +void mitk::ContourModelUtils::FillContourInSlice( ContourModel* projectedContour, unsigned int timeStep, Image* sliceImage, mitk::Image::Pointer workingImage , int eraseMode) { //create a surface of the input ContourModel mitk::Surface::Pointer surface = mitk::Surface::New(); mitk::ContourModelToSurfaceFilter::Pointer contourModelFilter = mitk::ContourModelToSurfaceFilter::New(); contourModelFilter->SetInput(projectedContour); contourModelFilter->Update(); surface = contourModelFilter->GetOutput(); // that's our vtkPolyData-Surface vtkSmartPointer surface2D = vtkSmartPointer::New(); if (surface->GetVtkPolyData(timeStep) == NULL) { MITK_WARN << "No surface has been created from contour model. Add more points to fill contour in slice."; return; } surface2D->SetPoints(surface->GetVtkPolyData(timeStep)->GetPoints()); surface2D->SetLines(surface->GetVtkPolyData(timeStep)->GetLines()); surface2D->Modified(); //surface2D->Update(); // prepare the binary image's voxel grid vtkSmartPointer whiteImage = vtkSmartPointer::New(); whiteImage->DeepCopy(sliceImage->GetVtkImageData()); // fill the image with foreground voxels: unsigned char inval = 255; unsigned char outval = 0; vtkIdType count = whiteImage->GetNumberOfPoints(); for (vtkIdType i = 0; i < count; ++i) { whiteImage->GetPointData()->GetScalars()->SetTuple1(i, inval); } // polygonal data --> image stencil: vtkSmartPointer pol2stenc = vtkSmartPointer::New(); pol2stenc->SetTolerance(0); pol2stenc->SetInputData(surface2D); pol2stenc->Update(); // cut the corresponding white image and set the background: vtkSmartPointer imgstenc = vtkSmartPointer::New(); imgstenc->SetInputData(whiteImage); imgstenc->SetStencilConnection(pol2stenc->GetOutputPort()); imgstenc->ReverseStencilOff(); imgstenc->SetBackgroundValue(outval); imgstenc->Update(); + mitk::LabelSetImage* labelImage; // Todo: Get the working Image + int activePixelValue = eraseMode; + labelImage = dynamic_cast(workingImage.GetPointer()); + if (workingImage) + { + activePixelValue = labelImage->GetActiveLabel()->GetValue(); + } - //Fill according to painting value - vtkSmartPointer booleanOperation = vtkSmartPointer::New(); - - booleanOperation->SetInput2Data(sliceImage->GetVtkImageData()); - booleanOperation->SetOperationToOr(); - booleanOperation->SetOutputTrueValue(1.0); + // Fill according to the Color Team + vtkSmartPointer filledImage = imgstenc->GetOutput(); + vtkSmartPointer resultImage = sliceImage->GetVtkImageData(); - if(paintingPixelValue == 1) + count = filledImage->GetNumberOfPoints(); + if (activePixelValue == 0) { - //COMBINE - //slice or stencil - booleanOperation->SetInputConnection(imgstenc->GetOutputPort()); - booleanOperation->SetOperationToOr(); - } else + for (vtkIdType i = 0; i < count; ++i) + { + if (filledImage->GetPointData()->GetScalars()->GetTuple1(i) > 1) + { + resultImage->GetPointData()->GetScalars()->SetTuple1(i, eraseMode); + } + } + } + else if (eraseMode != 0) // We are not erasing... + { + for (vtkIdType i = 0; i < count; ++i) + { + if (filledImage->GetPointData()->GetScalars()->GetTuple1(i) > 1) + { + int targetValue = resultImage->GetPointData()->GetScalars()->GetTuple1(i); + if (labelImage) + { + if (!labelImage->GetLabel(targetValue)->GetLocked()) + { + resultImage->GetPointData()->GetScalars()->SetTuple1(i, eraseMode); + } + } else + { + resultImage->GetPointData()->GetScalars()->SetTuple1(i, eraseMode); + } + } + } + } + else { - //CUT - //slice and not(stencil) - vtkSmartPointer booleanOperationNOT = vtkSmartPointer::New(); - booleanOperationNOT->SetInputConnection(imgstenc->GetOutputPort()); - booleanOperationNOT->SetOperationToNot(); - booleanOperationNOT->Update(); - booleanOperation->SetInputConnection(booleanOperationNOT->GetOutputPort()); - booleanOperation->SetOperationToAnd(); + for (vtkIdType i = 0; i < count; ++i) + { + if ((resultImage->GetPointData()->GetScalars()->GetTuple1(i) == activePixelValue) & (filledImage->GetPointData()->GetScalars()->GetTuple1(i) > 1)) + { + resultImage->GetPointData()->GetScalars()->SetTuple1(i, eraseMode); + } + } } - booleanOperation->Update(); - //copy scalars to output image slice - sliceImage->SetVolume(booleanOperation->GetOutput()->GetScalarPointer()); + sliceImage->SetVolume(resultImage->GetScalarPointer()); } diff --git a/Modules/ContourModel/Algorithms/mitkContourModelUtils.h b/Modules/ContourModel/Algorithms/mitkContourModelUtils.h index a8d55a564c..0db17da919 100644 --- a/Modules/ContourModel/Algorithms/mitkContourModelUtils.h +++ b/Modules/ContourModel/Algorithms/mitkContourModelUtils.h @@ -1,77 +1,77 @@ /*=================================================================== 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 mitkContourModelUtilshIncludett #define mitkContourModelUtilshIncludett #include "mitkImage.h" #include #include "mitkContourModel.h" #include namespace mitk { /** * \brief Helpful methods for working with contours and images * * */ class MitkContourModel_EXPORT ContourModelUtils : public itk::Object { public: mitkClassMacro(ContourModelUtils, itk::Object); /** \brief Projects a contour onto an image point by point. Converts from world to index coordinates. \param correctionForIpSegmentation adds 0.5 to x and y index coordinates (difference between ipSegmentation and MITK contours) */ static ContourModel::Pointer ProjectContourTo2DSlice(Image* slice, ContourModel* contourIn3D, bool correctionForIpSegmentation, bool constrainToInside); /** \brief Projects a slice index coordinates of a contour back into world coordinates. \param correctionForIpSegmentation subtracts 0.5 to x and y index coordinates (difference between ipSegmentation and MITK contours) */ static ContourModel::Pointer BackProjectContourFrom2DSlice(const BaseGeometry* sliceGeometry, ContourModel* contourIn2D, bool correctionForIpSegmentation = false); /** \brief Fill a contour in a 2D slice with a specified pixel value at time step 0. */ - static void FillContourInSlice( ContourModel* projectedContour, Image* sliceImage, int paintingPixelValue = 1 ); + static void FillContourInSlice( ContourModel* projectedContour, Image* sliceImage, mitk::Image::Pointer workingImage, int paintingPixelValue = 1 ); /** \brief Fill a contour in a 2D slice with a specified pixel value at a given time step. */ - static void FillContourInSlice( ContourModel* projectedContour, unsigned int timeStep, Image* sliceImage, int paintingPixelValue = 1 ); + static void FillContourInSlice( ContourModel* projectedContour, unsigned int timeStep, Image* sliceImage, mitk::Image::Pointer workingImage, int paintingPixelValue = 1 ); protected: ContourModelUtils(); virtual ~ContourModelUtils(); }; } #endif diff --git a/Modules/ContourModel/CMakeLists.txt b/Modules/ContourModel/CMakeLists.txt index bd9168e7a9..400ebef8ed 100644 --- a/Modules/ContourModel/CMakeLists.txt +++ b/Modules/ContourModel/CMakeLists.txt @@ -1,8 +1,8 @@ MITK_CREATE_MODULE( INCLUDE_DIRS Algorithms DataManagement IO Rendering - DEPENDS MitkCore MitkSceneSerializationBase MitkLegacyGL MitkOverlays + DEPENDS MitkCore MitkSceneSerializationBase MitkLegacyGL MitkOverlays MitkMultilabel PACKAGE_DEPENDS ITK|ITKReview WARNINGS_AS_ERRORS ) add_subdirectory(Testing) diff --git a/Modules/Segmentation/Algorithms/mitkContourModelSetToImageFilter.cpp b/Modules/Segmentation/Algorithms/mitkContourModelSetToImageFilter.cpp index 1ce117afb9..9236a937af 100644 --- a/Modules/Segmentation/Algorithms/mitkContourModelSetToImageFilter.cpp +++ b/Modules/Segmentation/Algorithms/mitkContourModelSetToImageFilter.cpp @@ -1,272 +1,272 @@ /*=================================================================== 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 "mitkContourModelSetToImageFilter.h" #include #include #include #include #include #include #include mitk::ContourModelSetToImageFilter::ContourModelSetToImageFilter() : m_MakeOutputBinary( true ), m_TimeStep( 0 ), m_ReferenceImage( 0 ) { // Create the output. itk::DataObject::Pointer output = this->MakeOutput(0); Superclass::SetNumberOfRequiredInputs(1); Superclass::SetNumberOfRequiredOutputs(1); Superclass::SetNthOutput(0, output); } mitk::ContourModelSetToImageFilter::~ContourModelSetToImageFilter() { } void mitk::ContourModelSetToImageFilter::GenerateInputRequestedRegion() { mitk::Image* output = this->GetOutput(); if((output->IsInitialized()==false) ) return; GenerateTimeInInputRegion(output, const_cast< mitk::Image * > ( m_ReferenceImage )); } void mitk::ContourModelSetToImageFilter::GenerateOutputInformation() { mitk::Image::Pointer output = this->GetOutput(); itkDebugMacro(<<"GenerateOutputInformation()"); if((m_ReferenceImage == NULL) || (m_ReferenceImage->IsInitialized() == false) || (m_ReferenceImage->GetTimeGeometry() == NULL)) return; if (m_MakeOutputBinary) { output->Initialize(mitk::MakeScalarPixelType() , *m_ReferenceImage->GetTimeGeometry(),1,1); } else { output->Initialize(m_ReferenceImage->GetPixelType(), *m_ReferenceImage->GetTimeGeometry()); } output->SetPropertyList(m_ReferenceImage->GetPropertyList()->Clone()); } itk::DataObject::Pointer mitk::ContourModelSetToImageFilter::MakeOutput ( DataObjectPointerArraySizeType /*idx*/ ) { return OutputType::New().GetPointer(); } itk::DataObject::Pointer mitk::ContourModelSetToImageFilter::MakeOutput( const DataObjectIdentifierType & name ) { itkDebugMacro("MakeOutput(" << name << ")"); if( this->IsIndexedOutputName(name) ) { return this->MakeOutput( this->MakeIndexFromOutputName(name) ); } return OutputType::New().GetPointer(); } const mitk::ContourModelSet* mitk::ContourModelSetToImageFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) { return 0; } return static_cast< const mitk::ContourModelSet* > ( this->ProcessObject::GetInput(0) ); } void mitk::ContourModelSetToImageFilter::SetInput(const ContourModelSet *input) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput(0, const_cast< mitk::ContourModelSet* >( input ) ); } void mitk::ContourModelSetToImageFilter::SetImage(const mitk::Image *refImage) { m_ReferenceImage = refImage; } const mitk::Image* mitk::ContourModelSetToImageFilter::GetImage(void) { return m_ReferenceImage; } void mitk::ContourModelSetToImageFilter::GenerateData() { mitk::ContourModelSet* contourSet = const_cast(this->GetInput()); // Assure that the volume data of the output is set (fill volume with zeros) this->InitializeOutputEmpty(); mitk::Image::Pointer outputImage = const_cast(this->GetOutput()); if(outputImage.IsNull() || outputImage->IsInitialized() == false || !outputImage->IsVolumeSet(m_TimeStep)) { MITK_ERROR<<"Error creating output for specified image!"; return; } if (!contourSet || contourSet->GetContourModelList()->size() == 0) { MITK_ERROR<<"No contours specified!"; return; } mitk::BaseGeometry* outputImageGeo = outputImage->GetGeometry(m_TimeStep); // Create mitkVtkImageOverwrite which is needed to write the slice back into the volume vtkSmartPointer reslice = vtkSmartPointer::New(); // Create ExtractSliceFilter for extracting the corresponding slices from the volume mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput( outputImage ); extractor->SetTimeStep( m_TimeStep ); extractor->SetResliceTransformByGeometry( outputImageGeo ); // Fill each contour of the contourmodelset into the image mitk::ContourModelSet::ContourModelSetIterator it = contourSet->Begin(); mitk::ContourModelSet::ContourModelSetIterator end = contourSet->End(); while (it != end) { mitk::ContourModel* contour = it->GetPointer(); // 1. Create slice geometry using the contour points mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); mitk::Point3D point3D, tempPoint; mitk::Vector3D normal; mitk::Image::Pointer slice; int sliceIndex; bool isFrontside = true; bool isRotated = false; // Determine plane orientation point3D = contour->GetVertexAt(0)->Coordinates; tempPoint = contour->GetVertexAt(contour->GetNumberOfVertices()*0.25)->Coordinates; mitk::Vector3D vec = point3D - tempPoint; vec.Normalize(); outputImageGeo->WorldToIndex(point3D, point3D); mitk::PlaneGeometry::PlaneOrientation orientation; if (mitk::Equal(vec[0], 0)) { orientation = mitk::PlaneGeometry::Sagittal; sliceIndex = point3D[0]; } else if (mitk::Equal(vec[1], 0)) { orientation = mitk::PlaneGeometry::Frontal; sliceIndex = point3D[1]; } else if (mitk::Equal(vec[2], 0)) { orientation = mitk::PlaneGeometry::Axial; sliceIndex = point3D[2]; } else { // TODO Maybe rotate geometry to extract slice? MITK_ERROR<<"Cannot detect correct slice number! Only axial, sagittal and frontal oriented contours are supported!"; return; } // Initialize plane using the detected orientation plane->InitializeStandardPlane(outputImageGeo, orientation, sliceIndex, isFrontside, isRotated); point3D = plane->GetOrigin(); normal = plane->GetNormal(); normal.Normalize(); point3D += normal * 0.5;//pixelspacing is 1, so half the spacing is 0.5 plane->SetOrigin(point3D); // 2. Extract slice at the given position extractor->SetWorldGeometry( plane ); extractor->SetVtkOutputRequest(false); reslice->SetOverwriteMode(false); extractor->Modified(); extractor->Update(); slice = extractor->GetOutput(); slice->DisconnectPipeline(); // 3. Fill contour into slice mitk::ContourModel::Pointer projectedContour = mitk::ContourModelUtils::ProjectContourTo2DSlice(slice, contour, true, false); - mitk::ContourModelUtils::FillContourInSlice(projectedContour, slice); + mitk::ContourModelUtils::FillContourInSlice(projectedContour, slice, outputImage); // 4. Write slice back into image volume reslice->SetInputSlice(slice->GetVtkImageData()); //set overwrite mode to true to write back to the image volume reslice->SetOverwriteMode(true); reslice->Modified(); extractor->Modified(); extractor->Update(); reslice->SetInputSlice(0); ++it; } outputImage->Modified(); outputImage->GetVtkImageData()->Modified(); } void mitk::ContourModelSetToImageFilter::InitializeOutputEmpty() { // Initialize the output's volume with zeros mitk::Image* output = this->GetOutput(); unsigned int byteSize = output->GetPixelType().GetSize(); if(output->GetDimension() < 4) { for (unsigned int dim = 0; dim < output->GetDimension(); ++dim) { byteSize *= output->GetDimension(dim); } mitk::ImageWriteAccessor writeAccess(output, output->GetVolumeData(0)); memset( writeAccess.GetData(), 0, byteSize ); } else { //if we have a time-resolved image we need to set memory to 0 for each time step for (unsigned int dim = 0; dim < 3; ++dim) { byteSize *= output->GetDimension(dim); } for( unsigned int volumeNumber = 0; volumeNumber < output->GetDimension(3); volumeNumber++) { mitk::ImageWriteAccessor writeAccess(output, output->GetVolumeData(volumeNumber)); memset( writeAccess.GetData(), 0, byteSize ); } } } diff --git a/Modules/Segmentation/Algorithms/mitkContourUtils.cpp b/Modules/Segmentation/Algorithms/mitkContourUtils.cpp index 80b9831cc1..8e06ff8047 100755 --- a/Modules/Segmentation/Algorithms/mitkContourUtils.cpp +++ b/Modules/Segmentation/Algorithms/mitkContourUtils.cpp @@ -1,79 +1,79 @@ /*=================================================================== 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 "mitkContourUtils.h" #include "mitkContourModelUtils.h" mitk::ContourUtils::ContourUtils() { } mitk::ContourUtils::~ContourUtils() { } mitk::ContourModel::Pointer mitk::ContourUtils::ProjectContourTo2DSlice(Image* slice, Contour* contourIn3D, bool itkNotUsed( correctionForIpSegmentation ), bool constrainToInside) { mitk::Contour::PointsContainerIterator it = contourIn3D->GetPoints()->Begin(); mitk::Contour::PointsContainerIterator end = contourIn3D->GetPoints()->End(); mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); while(it!=end) { contour->AddVertex(it.Value()); it++; } return mitk::ContourModelUtils::ProjectContourTo2DSlice(slice, contour, false/*not used*/, constrainToInside ); } mitk::ContourModel::Pointer mitk::ContourUtils::BackProjectContourFrom2DSlice(const BaseGeometry* sliceGeometry, Contour* contourIn2D, bool itkNotUsed( correctionForIpSegmentation ) ) { mitk::Contour::PointsContainerIterator it = contourIn2D->GetPoints()->Begin(); mitk::Contour::PointsContainerIterator end = contourIn2D->GetPoints()->End(); mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); while(it!=end) { contour->AddVertex(it.Value()); it++; } return mitk::ContourModelUtils::BackProjectContourFrom2DSlice(sliceGeometry, contour, false/*not used*/); } void mitk::ContourUtils::FillContourInSlice( Contour* projectedContour, Image* sliceImage, int paintingPixelValue ) { mitk::Contour::PointsContainerIterator it = projectedContour->GetPoints()->Begin(); mitk::Contour::PointsContainerIterator end = projectedContour->GetPoints()->End(); mitk::ContourModel::Pointer contour = mitk::ContourModel::New(); while(it!=end) { contour->AddVertex(it.Value()); it++; } - mitk::ContourModelUtils::FillContourInSlice(contour, sliceImage, paintingPixelValue); + mitk::ContourModelUtils::FillContourInSlice(contour, sliceImage, sliceImage, paintingPixelValue); } diff --git a/Modules/Segmentation/Interactions/mitkContourTool.cpp b/Modules/Segmentation/Interactions/mitkContourTool.cpp index ca1f04144b..e20fb3811b 100644 --- a/Modules/Segmentation/Interactions/mitkContourTool.cpp +++ b/Modules/Segmentation/Interactions/mitkContourTool.cpp @@ -1,200 +1,197 @@ /*=================================================================== 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 "mitkContourTool.h" #include "mitkToolManager.h" #include "mitkOverwriteSliceImageFilter.h" #include "mitkOverwriteDirectedPlaneImageFilter.h" #include "mitkAbstractTransformGeometry.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" //#include "mitkProperties.h" //#include "mitkPlanarCircle.h" #include "mitkLabelSetImage.h" #include "mitkStateMachineAction.h" #include "mitkInteractionEvent.h" mitk::ContourTool::ContourTool(int paintingPixelValue) :FeedbackContourTool("PressMoveReleaseWithCTRLInversion"), m_PaintingPixelValue(paintingPixelValue), m_CurrentLabelID(1) { } mitk::ContourTool::~ContourTool() { } void mitk::ContourTool::ConnectActionsAndFunctions() { CONNECT_FUNCTION( "PrimaryButtonPressed", OnMousePressed); CONNECT_FUNCTION( "Move", OnMouseMoved); CONNECT_FUNCTION( "Release", OnMouseReleased); CONNECT_FUNCTION( "InvertLogic", OnInvertLogic); } void mitk::ContourTool::Activated() { Superclass::Activated(); } void mitk::ContourTool::Deactivated() { Superclass::Deactivated(); } /** Just show the contour, insert the first point. */ bool mitk::ContourTool::OnMousePressed( StateMachineAction*, InteractionEvent* interactionEvent ) { mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if (!positionEvent) return false; m_LastEventSender = positionEvent->GetSender(); m_LastEventSlice = m_LastEventSender->GetSlice(); int timestep = positionEvent->GetSender()->GetTimeStep(); ContourModel* contour = FeedbackContourTool::GetFeedbackContour(); //Clear feedback contour contour->Initialize(); //expand time bounds because our contour was initialized contour->Expand( timestep + 1 ); //draw as a closed contour contour->SetClosed(true,timestep); //add first mouse position mitk::Point3D point = positionEvent->GetPositionInWorld(); contour->AddVertex( point, timestep ); FeedbackContourTool::SetFeedbackContourVisible(true); assert( positionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); return true; } /** Insert the point to the feedback contour. */ bool mitk::ContourTool::OnMouseMoved( StateMachineAction*, InteractionEvent* interactionEvent ) { mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if (!positionEvent) return false; int timestep = positionEvent->GetSender()->GetTimeStep(); ContourModel* contour = FeedbackContourTool::GetFeedbackContour(); mitk::Point3D point = positionEvent->GetPositionInWorld(); contour->AddVertex( point, timestep ); assert( positionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); return true; } /** Close the contour, project it to the image slice and fill it in 2D. */ bool mitk::ContourTool::OnMouseReleased( StateMachineAction*, InteractionEvent* interactionEvent ) { // 1. Hide the feedback contour, find out which slice the user clicked, find out which slice of the toolmanager's working image corresponds to that FeedbackContourTool::SetFeedbackContourVisible(false); mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); //const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) return false; assert( positionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); if (!workingNode) return false; Image* image = dynamic_cast(workingNode->GetData()); const PlaneGeometry* planeGeometry( dynamic_cast (positionEvent->GetSender()->GetCurrentWorldPlaneGeometry() ) ); if ( !image || !planeGeometry ) return false; // Check if it is a multilabel-image // If yes, get the new drawing color from it. // Otherwise nothing happens. mitk::LabelSetImage* labelSetImage = dynamic_cast(image); if (labelSetImage) { mitk::Label* label = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer()); m_CurrentLabelID = label->GetValue(); } else { m_CurrentLabelID = 1; } const AbstractTransformGeometry* abstractTransformGeometry( dynamic_cast (positionEvent->GetSender()->GetCurrentWorldPlaneGeometry() ) ); if ( !image || abstractTransformGeometry ) return false; // 2. Slice is known, now we try to get it as a 2D image and project the contour into index coordinates of this slice Image::Pointer slice = SegTool2D::GetAffectedImageSliceAs2DImage( positionEvent, image ); if ( slice.IsNull() ) { MITK_ERROR << "Unable to extract slice." << std::endl; return false; } ContourModel* feedbackContour = FeedbackContourTool::GetFeedbackContour(); ContourModel::Pointer projectedContour = FeedbackContourTool::ProjectContourTo2DSlice( slice, feedbackContour, true, false ); // true: actually no idea why this is neccessary, but it works :-( if (projectedContour.IsNull()) return false; int timestep = positionEvent->GetSender()->GetTimeStep(); - MITK_INFO << "Fill Contour: " << m_PaintingPixelValue*m_CurrentLabelID; - FeedbackContourTool::FillContourInSlice( projectedContour, timestep, slice, (m_PaintingPixelValue * m_CurrentLabelID)); - //ContourUtils::Pointer util = ContourUtils::New(); - //util->FillContourInSlice(projectedContour, slice, (m_PaintingPixelValue * m_CurrentLabelID)); + mitk::ContourModelUtils::FillContourInSlice(projectedContour, timestep, slice, image, (m_PaintingPixelValue*m_CurrentLabelID)); //this->WriteBackSegmentationResult(positionEvent, slice); SegTool2D::WriteBackSegmentationResult(positionEvent,slice); // 4. Make sure the result is drawn again --> is visible then. assert( positionEvent->GetSender()->GetRenderWindow() ); return true; } /** Called when the CTRL key is pressed. Will change the painting pixel value from 0 to 1 or from 1 to 0. */ bool mitk::ContourTool::OnInvertLogic( StateMachineAction*, InteractionEvent* interactionEvent ) { // Inversion only for 0 and 1 as painting values if (m_PaintingPixelValue == 1) { m_PaintingPixelValue = 0; FeedbackContourTool::SetFeedbackContourColor( 1.0, 0.0, 0.0 ); } else if (m_PaintingPixelValue == 0) { m_PaintingPixelValue = 1; FeedbackContourTool::SetFeedbackContourColorDefault(); } return true; } diff --git a/Modules/Segmentation/Interactions/mitkFeedbackContourTool.cpp b/Modules/Segmentation/Interactions/mitkFeedbackContourTool.cpp index be7a8af186..6355daf2f8 100644 --- a/Modules/Segmentation/Interactions/mitkFeedbackContourTool.cpp +++ b/Modules/Segmentation/Interactions/mitkFeedbackContourTool.cpp @@ -1,136 +1,136 @@ /*=================================================================== 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 "mitkFeedbackContourTool.h" #include "mitkToolManager.h" #include "mitkProperties.h" #include "mitkStringProperty.h" #include "mitkColorProperty.h" #include "mitkDataStorage.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" mitk::FeedbackContourTool::FeedbackContourTool(const char* type) :SegTool2D(type), m_FeedbackContourVisible(false) { m_FeedbackContour = ContourModel::New(); m_FeedbackContour->SetClosed(true); m_FeedbackContourNode = DataNode::New(); m_FeedbackContourNode->SetData( m_FeedbackContour ); m_FeedbackContourNode->SetProperty("name", StringProperty::New("One of FeedbackContourTool's feedback nodes")); m_FeedbackContourNode->SetProperty("visible", BoolProperty::New(true)); m_FeedbackContourNode->SetProperty("helper object", BoolProperty::New(true)); m_FeedbackContourNode->SetProperty("layer", IntProperty::New(1000)); m_FeedbackContourNode->SetProperty("contour.project-onto-plane", BoolProperty::New(false)); m_FeedbackContourNode->SetProperty("contour.width", FloatProperty::New(1.0)); this->Disable3dRendering(); SetFeedbackContourColorDefault(); } mitk::FeedbackContourTool::~FeedbackContourTool() { } void mitk::FeedbackContourTool::SetFeedbackContourColor( float r, float g, float b ) { m_FeedbackContourNode->SetProperty("contour.color", ColorProperty::New(r, g, b)); } void mitk::FeedbackContourTool::SetFeedbackContourColorDefault() { m_FeedbackContourNode->SetProperty("contour.color", ColorProperty::New(0.0/255.0, 255.0/255.0, 0.0/255.0)); } mitk::ContourModel* mitk::FeedbackContourTool::GetFeedbackContour() { return m_FeedbackContour; } void mitk::FeedbackContourTool::SetFeedbackContour(ContourModel& contour) { // begin of temporary fix for 3m3 release this->Disable3dRendering(); //end of temporary fix for 3m3 release m_FeedbackContour = &contour; m_FeedbackContourNode->SetData( m_FeedbackContour ); } void mitk::FeedbackContourTool::SetFeedbackContourVisible(bool visible) { // begin of temporary fix for 3m3 release this->Disable3dRendering(); //end of temporary fix for 3m3 release if ( m_FeedbackContourVisible == visible ) return; // nothing changed if ( DataStorage* storage = m_ToolManager->GetDataStorage() ) { if (visible) { storage->Add( m_FeedbackContourNode ); } else { storage->Remove( m_FeedbackContourNode ); } } m_FeedbackContourVisible = visible; } mitk::ContourModel::Pointer mitk::FeedbackContourTool::ProjectContourTo2DSlice(Image* slice, ContourModel* contourIn3D, bool correctionForIpSegmentation, bool constrainToInside) { return mitk::ContourModelUtils::ProjectContourTo2DSlice(slice, contourIn3D, correctionForIpSegmentation, constrainToInside); } mitk::ContourModel::Pointer mitk::FeedbackContourTool::BackProjectContourFrom2DSlice(const BaseGeometry* sliceGeometry, ContourModel* contourIn2D, bool correctionForIpSegmentation) { return mitk::ContourModelUtils::BackProjectContourFrom2DSlice(sliceGeometry, contourIn2D, correctionForIpSegmentation); } void mitk::FeedbackContourTool::FillContourInSlice( ContourModel* projectedContour, Image* sliceImage, int paintingPixelValue ) { this->FillContourInSlice(projectedContour, 0, sliceImage, paintingPixelValue); } void mitk::FeedbackContourTool::FillContourInSlice( ContourModel* projectedContour, unsigned int timeStep, Image* sliceImage, int paintingPixelValue ) { - mitk::ContourModelUtils::FillContourInSlice(projectedContour, timeStep, sliceImage, paintingPixelValue); + mitk::ContourModelUtils::FillContourInSlice(projectedContour, timeStep, sliceImage, sliceImage, paintingPixelValue); } void mitk::FeedbackContourTool::Disable3dRendering() { // set explicitly visible=false for all 3D renderer (that exist already ...) const RenderingManager::RenderWindowVector& renderWindows = RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); for (RenderingManager::RenderWindowVector::const_iterator iter = renderWindows.begin(); iter != renderWindows.end(); ++iter) { if ( mitk::BaseRenderer::GetInstance((*iter))->GetMapperID() == BaseRenderer::Standard3D ) //if ( (*iter)->GetRenderer()->GetMapperID() == BaseRenderer::Standard3D ) { m_FeedbackContourNode->SetProperty("visible", BoolProperty::New(false), mitk::BaseRenderer::GetInstance((*iter))); } } } diff --git a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp index 2821f08945..b35eaa73b4 100644 --- a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp +++ b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp @@ -1,680 +1,680 @@ /*=================================================================== 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 #include #include #include #include #include #include #include #include "mitkLiveWireTool2D.h" #include "mitkLiveWireTool2D.xpm" namespace mitk { MITK_TOOL_MACRO(MitkSegmentation_EXPORT, LiveWireTool2D, "LiveWire tool"); } static void AddInteractorToGlobalInteraction(mitk::Interactor* interactor) { mitk::GlobalInteraction::GetInstance()->AddInteractor(interactor); } static void RemoveInteractorFromGlobalInteraction(mitk::Interactor* interactor) { mitk::GlobalInteraction::GetInstance()->RemoveInteractor(interactor); } class RemoveFromDataStorage { public: RemoveFromDataStorage(mitk::DataStorage::Pointer dataStorage) : m_DataStorage(dataStorage) { } void operator()(mitk::DataNode* dataNode) { m_DataStorage->Remove(dataNode); } void operator()(const std::pair& dataNode) { m_DataStorage->Remove(dataNode.first); } private: mitk::DataStorage::Pointer m_DataStorage; }; mitk::LiveWireTool2D::LiveWireTool2D() : SegTool2D("LiveWireTool"), m_PlaneGeometry(NULL) { } mitk::LiveWireTool2D::~LiveWireTool2D() { this->ClearSegmentation(); } void mitk::LiveWireTool2D::RemoveHelperObjects() { DataStorage* dataStorage = m_ToolManager->GetDataStorage(); if (!m_EditingContours.empty()) std::for_each(m_EditingContours.begin(), m_EditingContours.end(), RemoveFromDataStorage(dataStorage)); if (!m_WorkingContours.empty()) std::for_each(m_WorkingContours.begin(), m_WorkingContours.end(), RemoveFromDataStorage(dataStorage)); if (m_EditingContourNode.IsNotNull()) dataStorage->Remove(m_EditingContourNode); if (m_LiveWireContourNode.IsNotNull()) dataStorage->Remove(m_LiveWireContourNode); if (m_ContourModelNode.IsNotNull()) dataStorage->Remove(m_ContourModelNode); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::LiveWireTool2D::ReleaseHelperObjects() { this->RemoveHelperObjects(); if (!m_EditingContours.empty()) m_EditingContours.clear(); if (!m_WorkingContours.empty()) m_WorkingContours.clear(); m_EditingContourNode = NULL; m_EditingContour = NULL; m_LiveWireContourNode = NULL; m_LiveWireContour = NULL; m_ContourModelNode = NULL; m_Contour = NULL; } void mitk::LiveWireTool2D::ReleaseInteractors() { this->EnableContourLiveWireInteraction(false); m_LiveWireInteractors.clear(); } void mitk::LiveWireTool2D::ConnectActionsAndFunctions() { CONNECT_CONDITION("CheckContourClosed", OnCheckPoint); CONNECT_FUNCTION("InitObject", OnInitLiveWire); CONNECT_FUNCTION("AddPoint", OnAddPoint); CONNECT_FUNCTION("CtrlAddPoint", OnAddPoint); CONNECT_FUNCTION("MovePoint", OnMouseMoveNoDynamicCosts); CONNECT_FUNCTION("FinishContour", OnFinish); CONNECT_FUNCTION("DeletePoint", OnLastSegmentDelete); CONNECT_FUNCTION("CtrlMovePoint", OnMouseMoved); } const char** mitk::LiveWireTool2D::GetXPM() const { return mitkLiveWireTool2D_xpm; } us::ModuleResource mitk::LiveWireTool2D::GetIconResource() const { return us::GetModuleContext()->GetModule()->GetResource("LiveWire_48x48.png"); } us::ModuleResource mitk::LiveWireTool2D::GetCursorIconResource() const { return us::GetModuleContext()->GetModule()->GetResource("LiveWire_Cursor_32x32.png"); } const char* mitk::LiveWireTool2D::GetName() const { return "Live Wire"; } void mitk::LiveWireTool2D::Activated() { Superclass::Activated(); this->ResetToStartState(); this->EnableContourLiveWireInteraction(true); } void mitk::LiveWireTool2D::Deactivated() { Superclass::Deactivated(); this->ConfirmSegmentation(); } void mitk::LiveWireTool2D::EnableContourLiveWireInteraction(bool on) { std::for_each(m_LiveWireInteractors.begin(), m_LiveWireInteractors.end(), on ? AddInteractorToGlobalInteraction : RemoveInteractorFromGlobalInteraction); } void mitk::LiveWireTool2D::ConfirmSegmentation() { DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); if (!workingNode) return; Image* workingImage = dynamic_cast(workingNode->GetData()); if (!workingImage) return; // for all contours in list (currently created by tool) std::vector< std::pair >::iterator itWorkingContours = this->m_WorkingContours.begin(); std::vector sliceList; sliceList.reserve(m_WorkingContours.size()); while(itWorkingContours != this->m_WorkingContours.end() ) { // if node contains data if( itWorkingContours->first->GetData() ) { // if this is a contourModel mitk::ContourModel* contourModel = dynamic_cast(itWorkingContours->first->GetData()); if( contourModel ) { // for each timestep of this contourModel for( TimeStepType currentTimestep = 0; currentTimestep < contourModel->GetTimeGeometry()->CountTimeSteps(); ++currentTimestep) { //get the segmentation image slice at current timestep mitk::Image::Pointer workingSlice = this->GetAffectedImageSliceAs2DImage(itWorkingContours->second, workingImage, currentTimestep); mitk::ContourModel::Pointer projectedContour = mitk::ContourModelUtils::ProjectContourTo2DSlice(workingSlice, contourModel, true, false); - mitk::ContourModelUtils::FillContourInSlice(projectedContour, workingSlice, 1.0); + mitk::ContourModelUtils::FillContourInSlice(projectedContour, workingSlice, workingImage, 1.0); //write back to image volume SliceInformation sliceInfo (workingSlice, itWorkingContours->second, currentTimestep); sliceList.push_back(sliceInfo); this->WriteSliceToVolume(sliceInfo); } } } ++itWorkingContours; } this->WriteBackSegmentationResult(sliceList, false); this->ClearSegmentation(); } void mitk::LiveWireTool2D::ClearSegmentation() { this->ReleaseHelperObjects(); this->ReleaseInteractors(); this->ResetToStartState(); } bool mitk::LiveWireTool2D::OnInitLiveWire ( StateMachineAction*, InteractionEvent* interactionEvent ) { mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if (!positionEvent) return false; m_LastEventSender = positionEvent->GetSender(); m_LastEventSlice = m_LastEventSender->GetSlice(); int timestep = positionEvent->GetSender()->GetTimeStep(); m_Contour = mitk::ContourModel::New(); m_Contour->Expand(timestep+1); m_ContourModelNode = mitk::DataNode::New(); m_ContourModelNode->SetData( m_Contour ); m_ContourModelNode->SetName("working contour node"); m_ContourModelNode->SetProperty( "layer", IntProperty::New(100)); m_ContourModelNode->AddProperty( "fixedLayer", BoolProperty::New(true)); m_ContourModelNode->SetProperty( "helper object", mitk::BoolProperty::New(true)); m_ContourModelNode->AddProperty( "contour.color", ColorProperty::New(1, 1, 0), NULL, true ); m_ContourModelNode->AddProperty( "contour.points.color", ColorProperty::New(1.0, 0.0, 0.1), NULL, true ); m_ContourModelNode->AddProperty( "contour.controlpoints.show", BoolProperty::New(true), NULL, true ); m_LiveWireContour = mitk::ContourModel::New(); m_LiveWireContour->Expand(timestep+1); m_LiveWireContourNode = mitk::DataNode::New(); m_LiveWireContourNode->SetData( m_LiveWireContour ); m_LiveWireContourNode->SetName("active livewire node"); m_LiveWireContourNode->SetProperty( "layer", IntProperty::New(101)); m_LiveWireContourNode->AddProperty( "fixedLayer", BoolProperty::New(true)); m_LiveWireContourNode->SetProperty( "helper object", mitk::BoolProperty::New(true)); m_LiveWireContourNode->AddProperty( "contour.color", ColorProperty::New(0.1, 1.0, 0.1), NULL, true ); m_LiveWireContourNode->AddProperty( "contour.width", mitk::FloatProperty::New( 4.0 ), NULL, true ); m_EditingContour = mitk::ContourModel::New(); m_EditingContour->Expand(timestep+1); m_EditingContourNode = mitk::DataNode::New(); m_EditingContourNode->SetData( m_EditingContour ); m_EditingContourNode->SetName("editing node"); m_EditingContourNode->SetProperty( "layer", IntProperty::New(102)); m_EditingContourNode->AddProperty( "fixedLayer", BoolProperty::New(true)); m_EditingContourNode->SetProperty( "helper object", mitk::BoolProperty::New(true)); m_EditingContourNode->AddProperty( "contour.color", ColorProperty::New(0.1, 1.0, 0.1), NULL, true ); m_EditingContourNode->AddProperty( "contour.points.color", ColorProperty::New(0.0, 0.0, 1.0), NULL, true ); m_EditingContourNode->AddProperty( "contour.width", mitk::FloatProperty::New( 4.0 ), NULL, true ); mitk::DataNode* workingDataNode = m_ToolManager->GetWorkingData(0); m_ToolManager->GetDataStorage()->Add(m_ContourModelNode, workingDataNode); m_ToolManager->GetDataStorage()->Add(m_LiveWireContourNode, workingDataNode); m_ToolManager->GetDataStorage()->Add(m_EditingContourNode, workingDataNode); //set current slice as input for ImageToLiveWireContourFilter m_WorkingSlice = this->GetAffectedReferenceSlice(positionEvent); //Transfer LiveWire's center based contour output to corner based via the adaption of the input //slice image. Just in case someone stumbles across the 0.5 here I know what I'm doing ;-). mitk::Point3D newOrigin = m_WorkingSlice->GetSlicedGeometry()->GetOrigin(); m_WorkingSlice->GetSlicedGeometry()->WorldToIndex(newOrigin, newOrigin); newOrigin[0] -= 0.5; newOrigin[1] -= 0.5; m_WorkingSlice->GetSlicedGeometry()->IndexToWorld(newOrigin, newOrigin); m_WorkingSlice->GetSlicedGeometry()->SetOrigin(newOrigin); m_LiveWireFilter = mitk::ImageLiveWireContourModelFilter::New(); m_LiveWireFilter->SetInput(m_WorkingSlice); //map click to pixel coordinates mitk::Point3D click = positionEvent->GetPositionInWorld(); itk::Index<3> idx; m_WorkingSlice->GetGeometry()->WorldToIndex(click, idx); // get the pixel the gradient in region of 5x5 itk::Index<3> indexWithHighestGradient; AccessFixedDimensionByItk_2(m_WorkingSlice, FindHighestGradientMagnitudeByITK, 2, idx, indexWithHighestGradient); // itk::Index to mitk::Point3D click[0] = indexWithHighestGradient[0]; click[1] = indexWithHighestGradient[1]; click[2] = indexWithHighestGradient[2]; m_WorkingSlice->GetGeometry()->IndexToWorld(click, click); //set initial start point m_Contour->AddVertex( click, true, timestep ); m_LiveWireFilter->SetStartPoint(click); // remember plane geometry to determine if events were triggered in same plane m_PlaneGeometry = interactionEvent->GetSender()->GetCurrentWorldPlaneGeometry(); m_CreateAndUseDynamicCosts = true; //render assert( positionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); return true; } bool mitk::LiveWireTool2D::OnAddPoint ( StateMachineAction*, InteractionEvent* interactionEvent ) { //complete LiveWire interaction for last segment //add current LiveWire contour to the finished contour and reset //to start new segment and computation mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if (!positionEvent) return false; if (m_PlaneGeometry != NULL) { // this checks that the point is in the correct slice if (m_PlaneGeometry->DistanceFromPlane(positionEvent->GetPositionInWorld()) > mitk::eps) return false; } int timestep = positionEvent->GetSender()->GetTimeStep(); //add repulsive points to avoid to get the same path again typedef mitk::ImageLiveWireContourModelFilter::InternalImageType::IndexType IndexType; mitk::ContourModel::ConstVertexIterator iter = m_LiveWireContour->IteratorBegin(timestep); for (;iter != m_LiveWireContour->IteratorEnd(timestep); iter++) { IndexType idx; this->m_WorkingSlice->GetGeometry()->WorldToIndex((*iter)->Coordinates, idx); this->m_LiveWireFilter->AddRepulsivePoint( idx ); } //remove duplicate first vertex, it's already contained in m_Contour m_LiveWireContour->RemoveVertexAt(0, timestep); // set last added point as control point m_LiveWireContour->SetControlVertexAt(m_LiveWireContour->GetNumberOfVertices(timestep)-1, timestep); //merge contours m_Contour->Concatenate(m_LiveWireContour, timestep); //clear the livewire contour and reset the corresponding datanode m_LiveWireContour->Clear(timestep); //set new start point m_LiveWireFilter->SetStartPoint(positionEvent->GetPositionInWorld()); if( m_CreateAndUseDynamicCosts ) { //use dynamic cost map for next update m_LiveWireFilter->CreateDynamicCostMap(m_Contour); m_LiveWireFilter->SetUseDynamicCostMap(true); //m_CreateAndUseDynamicCosts = false; } //render assert( positionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); return true; } bool mitk::LiveWireTool2D::OnMouseMoved( StateMachineAction*, InteractionEvent* interactionEvent ) { //compute LiveWire segment from last control point to current mouse position mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if (!positionEvent) return false; // actual LiveWire computation int timestep = positionEvent->GetSender()->GetTimeStep(); m_LiveWireFilter->SetEndPoint(positionEvent->GetPositionInWorld()); m_LiveWireFilter->SetTimeStep( timestep ); m_LiveWireFilter->Update(); m_LiveWireContour = this->m_LiveWireFilter->GetOutput(); m_LiveWireContourNode->SetData( this->m_LiveWireContour ); //render assert( positionEvent->GetSender()->GetRenderWindow() ); positionEvent->GetSender()->GetRenderingManager()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); return true; } bool mitk::LiveWireTool2D::OnMouseMoveNoDynamicCosts( StateMachineAction*, InteractionEvent* interactionEvent ) { //do not use dynamic cost map m_LiveWireFilter->SetUseDynamicCostMap(false); OnMouseMoved( NULL, interactionEvent); m_LiveWireFilter->SetUseDynamicCostMap(true); return true; } bool mitk::LiveWireTool2D::OnCheckPoint( const InteractionEvent* interactionEvent) { //check double click on first control point to finish the LiveWire tool // //Check distance to first point. //Transition YES if click close to first control point // const mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if (positionEvent) { int timestep = positionEvent->GetSender()->GetTimeStep(); mitk::Point3D click = positionEvent->GetPositionInWorld(); mitk::Point3D first = this->m_Contour->GetVertexAt(0, timestep)->Coordinates; if (first.EuclideanDistanceTo(click) < 4.5) { // allow to finish return true; } else { return false; } } return false; } bool mitk::LiveWireTool2D::OnFinish( StateMachineAction*, InteractionEvent* interactionEvent ) { // finish livewire tool interaction mitk::InteractionPositionEvent* positionEvent = dynamic_cast( interactionEvent ); if (!positionEvent) return false; // Have to do that here so that the m_LastEventSender is set correctly mitk::SegTool2D::AddContourmarker(); // actual timestep int timestep = positionEvent->GetSender()->GetTimeStep(); // remove last control point being added by double click m_Contour->RemoveVertexAt(m_Contour->GetNumberOfVertices(timestep) - 1, timestep); // save contour and corresponding plane geometry to list std::pair cp(m_ContourModelNode, dynamic_cast(positionEvent->GetSender()->GetCurrentWorldPlaneGeometry()->Clone().GetPointer()) ); this->m_WorkingContours.push_back(cp); std::pair ecp(m_EditingContourNode, dynamic_cast(positionEvent->GetSender()->GetCurrentWorldPlaneGeometry()->Clone().GetPointer()) ); this->m_EditingContours.push_back(ecp); m_LiveWireFilter->SetUseDynamicCostMap(false); this->FinishTool(); return true; } void mitk::LiveWireTool2D::FinishTool() { TimeStepType numberOfTimesteps = m_Contour->GetTimeGeometry()->CountTimeSteps(); //close contour in each timestep for( int i = 0; i <= numberOfTimesteps; i++) { m_Contour->Close(i); } m_ToolManager->GetDataStorage()->Remove( m_LiveWireContourNode ); // clear live wire contour node m_LiveWireContourNode = NULL; m_LiveWireContour = NULL; //set the livewire interactor to edit control points m_ContourInteractor = mitk::ContourModelLiveWireInteractor::New(m_ContourModelNode); m_ContourInteractor->SetWorkingImage(this->m_WorkingSlice); m_ContourInteractor->SetEditingContourModelNode(this->m_EditingContourNode); m_ContourModelNode->SetInteractor(m_ContourInteractor); this->m_LiveWireInteractors.push_back( m_ContourInteractor ); //add interactor to globalInteraction instance mitk::GlobalInteraction::GetInstance()->AddInteractor(m_ContourInteractor); } bool mitk::LiveWireTool2D::OnLastSegmentDelete( StateMachineAction*, InteractionEvent* interactionEvent ) { int timestep = interactionEvent->GetSender()->GetTimeStep(); //if last point of current contour will be removed go to start state and remove nodes if( m_Contour->GetNumberOfVertices(timestep) <= 1 ) { m_ToolManager->GetDataStorage()->Remove( m_LiveWireContourNode ); m_ToolManager->GetDataStorage()->Remove( m_ContourModelNode ); m_ToolManager->GetDataStorage()->Remove( m_EditingContourNode ); m_LiveWireContour = mitk::ContourModel::New(); m_Contour = mitk::ContourModel::New(); m_ContourModelNode->SetData( m_Contour ); m_LiveWireContourNode->SetData( m_LiveWireContour ); this->ResetToStartState(); //go to start state } else //remove last segment from contour and reset livewire contour { m_LiveWireContour = mitk::ContourModel::New(); m_LiveWireContourNode->SetData(m_LiveWireContour); mitk::ContourModel::Pointer newContour = mitk::ContourModel::New(); newContour->Expand(m_Contour->GetTimeSteps()); mitk::ContourModel::VertexIterator begin = m_Contour->IteratorBegin(); //iterate from last point to next active point mitk::ContourModel::VertexIterator newLast = m_Contour->IteratorBegin() + (m_Contour->GetNumberOfVertices() - 1); //go at least one down if(newLast != begin) { newLast--; } //search next active control point while(newLast != begin && !((*newLast)->IsControlPoint) ) { newLast--; } //set position of start point for livewire filter to coordinates of the new last point m_LiveWireFilter->SetStartPoint((*newLast)->Coordinates); mitk::ContourModel::VertexIterator it = m_Contour->IteratorBegin(); //fill new Contour while(it <= newLast) { newContour->AddVertex((*it)->Coordinates, (*it)->IsControlPoint, timestep); it++; } newContour->SetClosed(m_Contour->IsClosed()); //set new contour visible m_ContourModelNode->SetData(newContour); m_Contour = newContour; assert( interactionEvent->GetSender()->GetRenderWindow() ); mitk::RenderingManager::GetInstance()->RequestUpdate( interactionEvent->GetSender()->GetRenderWindow() ); } return true; } template void mitk::LiveWireTool2D::FindHighestGradientMagnitudeByITK(itk::Image* inputImage, itk::Index<3> &index, itk::Index<3> &returnIndex) { typedef itk::Image InputImageType; typedef typename InputImageType::IndexType IndexType; unsigned long xMAX = inputImage->GetLargestPossibleRegion().GetSize()[0]; unsigned long yMAX = inputImage->GetLargestPossibleRegion().GetSize()[1]; returnIndex[0] = index[0]; returnIndex[1] = index[1]; returnIndex[2] = 0.0; double gradientMagnitude = 0.0; double maxGradientMagnitude = 0.0; /* the size and thus the region of 7x7 is only used to calculate the gradient magnitude in that region not for searching the maximum value */ //maximum value in each direction for size typename InputImageType::SizeType size; size[0] = 7; size[1] = 7; //minimum value in each direction for startRegion IndexType startRegion; startRegion[0] = index[0] - 3; startRegion[1] = index[1] - 3; if(startRegion[0] < 0) startRegion[0] = 0; if(startRegion[1] < 0) startRegion[1] = 0; if(xMAX - index[0] < 7) startRegion[0] = xMAX - 7; if(yMAX - index[1] < 7) startRegion[1] = yMAX - 7; index[0] = startRegion[0] + 3; index[1] = startRegion[1] + 3; typename InputImageType::RegionType region; region.SetSize( size ); region.SetIndex( startRegion ); typedef typename itk::GradientMagnitudeImageFilter< InputImageType, InputImageType> GradientMagnitudeFilterType; typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New(); gradientFilter->SetInput(inputImage); gradientFilter->GetOutput()->SetRequestedRegion(region); gradientFilter->Update(); typename InputImageType::Pointer gradientMagnImage; gradientMagnImage = gradientFilter->GetOutput(); IndexType currentIndex; currentIndex[0] = 0; currentIndex[1] = 0; // search max (approximate) gradient magnitude for( int x = -1; x <= 1; ++x) { currentIndex[0] = index[0] + x; for( int y = -1; y <= 1; ++y) { currentIndex[1] = index[1] + y; gradientMagnitude = gradientMagnImage->GetPixel(currentIndex); //check for new max if(maxGradientMagnitude < gradientMagnitude) { maxGradientMagnitude = gradientMagnitude; returnIndex[0] = currentIndex[0]; returnIndex[1] = currentIndex[1]; returnIndex[2] = 0.0; }//end if }//end for y currentIndex[1] = index[1]; }//end for x }