diff --git a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp index 33c9d9100f..57e4636d0a 100644 --- a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp +++ b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp @@ -1,444 +1,444 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkImageLiveWireContourModelFilter.h" #include <itkCastImageFilter.h> #include <itkGradientMagnitudeImageFilter.h> #include <itkImageRegionIterator.h> #include "mitkIOUtil.h" mitk::ImageLiveWireContourModelFilter::ImageLiveWireContourModelFilter() { OutputType::Pointer output = dynamic_cast<OutputType *>(this->MakeOutput(0).GetPointer()); this->SetNumberOfRequiredInputs(1); this->SetNumberOfIndexedOutputs(1); this->SetNthOutput(0, output.GetPointer()); m_CostFunction = CostFunctionType::New(); m_ShortestPathFilter = ShortestPathImageFilterType::New(); m_ShortestPathFilter->SetCostFunction(m_CostFunction); m_UseDynamicCostMap = false; m_TimeStep = 0; } mitk::ImageLiveWireContourModelFilter::~ImageLiveWireContourModelFilter() { } mitk::ImageLiveWireContourModelFilter::OutputType *mitk::ImageLiveWireContourModelFilter::GetOutput() { return Superclass::GetOutput(); } void mitk::ImageLiveWireContourModelFilter::SetInput(const mitk::ImageLiveWireContourModelFilter::InputType *input) { this->SetInput(0, input); } void mitk::ImageLiveWireContourModelFilter::SetInput(unsigned int idx, const mitk::ImageLiveWireContourModelFilter::InputType *input) { if (idx + 1 > this->GetNumberOfInputs()) { this->SetNumberOfRequiredInputs(idx + 1); } if (input != static_cast<InputType *>(this->ProcessObject::GetInput(idx))) { this->ProcessObject::SetNthInput(idx, const_cast<InputType *>(input)); this->Modified(); AccessFixedDimensionByItk(input, ItkPreProcessImage, 2); } } const mitk::ImageLiveWireContourModelFilter::InputType *mitk::ImageLiveWireContourModelFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) return nullptr; return static_cast<const mitk::ImageLiveWireContourModelFilter::InputType *>(this->ProcessObject::GetInput(0)); } const mitk::ImageLiveWireContourModelFilter::InputType *mitk::ImageLiveWireContourModelFilter::GetInput( unsigned int idx) { if (this->GetNumberOfInputs() < 1) return nullptr; return static_cast<const mitk::ImageLiveWireContourModelFilter::InputType *>(this->ProcessObject::GetInput(idx)); } void mitk::ImageLiveWireContourModelFilter::GenerateData() { mitk::Image::ConstPointer input = dynamic_cast<const mitk::Image *>(this->GetInput()); if (!input) { MITK_ERROR << "No input available."; - itkExceptionMacro("mitk::ImageToLiveWireContourFilter: No input available. Please set the input!"); + itkExceptionMacro("mitk::ImageToLiveWireContourModelFilter: No input available. Please set the input!"); return; } if (input->GetDimension() != 2) { MITK_ERROR << "Filter is only working on 2D images."; - itkExceptionMacro("mitk::ImageToLiveWireContourFilter: Filter is only working on 2D images.. Please make sure that " + itkExceptionMacro("mitk::ImageToLiveWireContourModelFilter: Filter is only working on 2D images.. Please make sure that " "the input is 2D!"); return; } input->GetGeometry()->WorldToIndex(m_StartPoint, m_StartPointInIndex); input->GetGeometry()->WorldToIndex(m_EndPoint, m_EndPointInIndex); m_StartPointInIndex[0] = std::round(m_StartPointInIndex[0]); m_StartPointInIndex[1] = std::round(m_StartPointInIndex[1]); m_StartPointInIndex[2] = std::round(m_StartPointInIndex[2]); m_EndPointInIndex[0] = std::round(m_EndPointInIndex[0]); m_EndPointInIndex[1] = std::round(m_EndPointInIndex[1]); m_EndPointInIndex[2] = std::round(m_EndPointInIndex[2]); // only start calculating if both indices are inside image geometry if (input->GetGeometry()->IsIndexInside(this->m_StartPointInIndex) && input->GetGeometry()->IsIndexInside(this->m_EndPointInIndex)) { try { this->UpdateLiveWire(); } catch (itk::ExceptionObject &e) { MITK_INFO << "Exception caught during live wiring calculation: " << e; return; } } } template <typename TPixel, unsigned int VImageDimension> void mitk::ImageLiveWireContourModelFilter::ItkPreProcessImage(const itk::Image<TPixel, VImageDimension> *inputImage) { typedef itk::Image<TPixel, VImageDimension> InputImageType; typedef itk::CastImageFilter<InputImageType, InternalImageType> CastFilterType; typename CastFilterType::Pointer castFilter = CastFilterType::New(); castFilter->SetInput(inputImage); castFilter->Update(); m_InternalImage = castFilter->GetOutput(); m_CostFunction->SetImage(m_InternalImage); m_ShortestPathFilter->SetInput(m_InternalImage); } void mitk::ImageLiveWireContourModelFilter::ClearRepulsivePoints() { m_CostFunction->ClearRepulsivePoints(); } void mitk::ImageLiveWireContourModelFilter::AddRepulsivePoint(const itk::Index<2> &idx) { m_CostFunction->AddRepulsivePoint(idx); } void mitk::ImageLiveWireContourModelFilter::DumpMaskImage() { mitk::Image::Pointer mask = mitk::Image::New(); mask->InitializeByItk(this->m_CostFunction->GetMaskImage()); mask->SetVolume(this->m_CostFunction->GetMaskImage()->GetBufferPointer()); mitk::IOUtil::Save(mask, "G:\\Data\\mask.nrrd"); } void mitk::ImageLiveWireContourModelFilter::RemoveRepulsivePoint(const itk::Index<2> &idx) { m_CostFunction->RemoveRepulsivePoint(idx); } void mitk::ImageLiveWireContourModelFilter::SetRepulsivePoints(const ShortestPathType &points) { m_CostFunction->ClearRepulsivePoints(); auto iter = points.begin(); for (; iter != points.end(); iter++) { m_CostFunction->AddRepulsivePoint((*iter)); } } void mitk::ImageLiveWireContourModelFilter::UpdateLiveWire() { // compute the requested region for itk filters InternalImageType::IndexType startPoint, endPoint; startPoint[0] = m_StartPointInIndex[0]; startPoint[1] = m_StartPointInIndex[1]; endPoint[0] = m_EndPointInIndex[0]; endPoint[1] = m_EndPointInIndex[1]; // minimum value in each direction for startRegion InternalImageType::IndexType startRegion; startRegion[0] = startPoint[0] < endPoint[0] ? startPoint[0] : endPoint[0]; startRegion[1] = startPoint[1] < endPoint[1] ? startPoint[1] : endPoint[1]; // maximum value in each direction for size InternalImageType::SizeType size; size[0] = std::abs(startPoint[0] - endPoint[0]) + 1; size[1] = std::abs(startPoint[1] - endPoint[1]) + 1; CostFunctionType::RegionType region; region.SetSize(size); region.SetIndex(startRegion); // inputImage->SetRequestedRegion(region); // extracts features from image and calculates costs // m_CostFunction->SetImage(m_InternalImage); m_CostFunction->SetStartIndex(startPoint); m_CostFunction->SetEndIndex(endPoint); m_CostFunction->SetRequestedRegion(region); m_CostFunction->SetUseCostMap(m_UseDynamicCostMap); // calculate shortest path between start and end point m_ShortestPathFilter->SetFullNeighborsMode(true); // m_ShortestPathFilter->SetInput( m_CostFunction->SetImage(m_InternalImage) ); m_ShortestPathFilter->SetMakeOutputImage(false); // m_ShortestPathFilter->SetCalcAllDistances(true); m_ShortestPathFilter->SetStartIndex(startPoint); m_ShortestPathFilter->SetEndIndex(endPoint); m_ShortestPathFilter->Update(); // construct contour from path image // get the shortest path as vector ShortestPathType shortestPath = m_ShortestPathFilter->GetVectorPath(); // fill the output contour with control points from the path OutputType::Pointer output = dynamic_cast<OutputType *>(this->MakeOutput(0).GetPointer()); this->SetNthOutput(0, output.GetPointer()); // OutputType::Pointer output = dynamic_cast<OutputType*> ( this->GetOutput() ); output->Expand(m_TimeStep + 1); // output->Clear(); mitk::Image::ConstPointer input = dynamic_cast<const mitk::Image *>(this->GetInput()); ShortestPathType::const_iterator pathIterator = shortestPath.begin(); while (pathIterator != shortestPath.end()) { mitk::Point3D currentPoint; currentPoint[0] = static_cast<mitk::ScalarType>((*pathIterator)[0]); currentPoint[1] = static_cast<mitk::ScalarType>((*pathIterator)[1]); currentPoint[2] = 0.0; input->GetGeometry()->IndexToWorld(currentPoint, currentPoint); output->AddVertex(currentPoint, false, m_TimeStep); pathIterator++; } } bool mitk::ImageLiveWireContourModelFilter::CreateDynamicCostMap(mitk::ContourModel *path) { mitk::Image::ConstPointer input = dynamic_cast<const mitk::Image *>(this->GetInput()); if (!input) return false; try { AccessFixedDimensionByItk_1(input, CreateDynamicCostMapByITK, 2, path); } catch (itk::ExceptionObject &e) { MITK_INFO << "Exception caught during dynamic cost map alculation: " << e; return false; } return true; } template <typename TPixel, unsigned int VImageDimension> void mitk::ImageLiveWireContourModelFilter::CreateDynamicCostMapByITK( const itk::Image<TPixel, VImageDimension> *inputImage, mitk::ContourModel *path) { /*++++++++++ create dynamic cost transfer map ++++++++++*/ /* Compute the costs of the gradient magnitude dynamically. * using a map of the histogram of gradient magnitude image. * Use the histogram gradient map to interpolate the costs * with gaussing function including next two bins right and left * to current position x. With the histogram gradient costs are interpolated * with a gaussing function summation of next two bins right and left * to current position x. */ std::vector<itk::Index<VImageDimension>> shortestPath; mitk::Image::ConstPointer input = dynamic_cast<const mitk::Image *>(this->GetInput()); if (path == nullptr) { OutputType::Pointer output = this->GetOutput(); auto it = output->IteratorBegin(); while (it != output->IteratorEnd()) { itk::Index<VImageDimension> cur; mitk::Point3D c = (*it)->Coordinates; input->GetGeometry()->WorldToIndex(c, c); cur[0] = c[0]; cur[1] = c[1]; shortestPath.push_back(cur); it++; } } else { auto it = path->IteratorBegin(); while (it != path->IteratorEnd()) { itk::Index<VImageDimension> cur; mitk::Point3D c = (*it)->Coordinates; input->GetGeometry()->WorldToIndex(c, c); cur[0] = c[0]; cur[1] = c[1]; shortestPath.push_back(cur); it++; } } // filter image gradient magnitude typedef itk::GradientMagnitudeImageFilter<itk::Image<TPixel, VImageDimension>, itk::Image<TPixel, VImageDimension>> GradientMagnitudeFilterType; typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New(); gradientFilter->SetInput(inputImage); gradientFilter->Update(); typename itk::Image<TPixel, VImageDimension>::Pointer gradientMagnImage = gradientFilter->GetOutput(); // get the path // iterator of path auto pathIterator = shortestPath.begin(); std::map<int, int> histogram; // create histogram within path while (pathIterator != shortestPath.end()) { // count pixel values // use scale factor to avoid mapping gradients between 0.0 and 1.0 to same bin histogram[static_cast<int>(gradientMagnImage->GetPixel((*pathIterator)) * ImageLiveWireContourModelFilter::CostFunctionType::MAPSCALEFACTOR)] += 1; pathIterator++; } double max = 1.0; if (!histogram.empty()) { std::map<int, int>::iterator itMAX; // get max of histogramm int currentMaxValue = 0; auto it = histogram.begin(); while (it != histogram.end()) { if ((*it).second > currentMaxValue) { itMAX = it; currentMaxValue = (*it).second; } it++; } std::map<int, int>::key_type keyOfMax = itMAX->first; // compute the to max of gaussian summation auto end = histogram.end(); auto last = --(histogram.end()); std::map<int, int>::iterator left2; std::map<int, int>::iterator left1; std::map<int, int>::iterator right1; std::map<int, int>::iterator right2; right1 = itMAX; if (right1 == end || right1 == last) { right2 = end; } else //( right1 <= last ) { auto temp = right1; right2 = ++right1; // rght1 + 1 right1 = temp; } if (right1 == histogram.begin()) { left1 = end; left2 = end; } else if (right1 == (++(histogram.begin()))) { auto temp = right1; left1 = --right1; // rght1 - 1 right1 = temp; left2 = end; } else { auto temp = right1; left1 = --right1; // rght1 - 1 left2 = --right1; // rght1 - 2 right1 = temp; } double partRight1, partRight2, partLeft1, partLeft2; partRight1 = partRight2 = partLeft1 = partLeft2 = 0.0; /* f(x) = v(bin) * e^ ( -1/2 * (|x-k(bin)| / sigma)^2 ) gaussian approximation where v(bin) is the value in the map k(bin) is the key */ if (left2 != end) { partLeft2 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, left2->first, left2->second); } if (left1 != end) { partLeft1 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, left1->first, left1->second); } if (right1 != end) { partRight1 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, right1->first, right1->second); } if (right2 != end) { partRight2 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, right2->first, right2->second); } max = (partRight1 + partRight2 + partLeft1 + partLeft2); } this->m_CostFunction->SetDynamicCostMap(histogram); this->m_CostFunction->SetCostMapMaximum(max); } diff --git a/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.cpp b/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.cpp deleted file mode 100644 index f62050ebc7..0000000000 --- a/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ - -#include "mitkImageToLiveWireContourFilter.h" - -#include <itkImageRegionIterator.h> -#include <itkShortestPathCostFunctionLiveWire.h> -#include <itkShortestPathImageFilter.h> - -mitk::ImageToLiveWireContourFilter::ImageToLiveWireContourFilter() -{ - OutputType::Pointer output = dynamic_cast<OutputType *>(this->MakeOutput(0).GetPointer()); - this->SetNumberOfRequiredInputs(1); - this->SetNumberOfIndexedOutputs(1); - this->SetNthOutput(0, output.GetPointer()); -} - -mitk::ImageToLiveWireContourFilter::~ImageToLiveWireContourFilter() -{ -} - -void mitk::ImageToLiveWireContourFilter::SetInput(const mitk::ImageToLiveWireContourFilter::InputType *input) -{ - this->SetInput(0, input); -} - -void mitk::ImageToLiveWireContourFilter::SetInput(unsigned int idx, - const mitk::ImageToLiveWireContourFilter::InputType *input) -{ - if (idx + 1 > this->GetNumberOfInputs()) - { - this->SetNumberOfRequiredInputs(idx + 1); - } - if (input != static_cast<InputType *>(this->ProcessObject::GetInput(idx))) - { - this->ProcessObject::SetNthInput(idx, const_cast<InputType *>(input)); - this->Modified(); - } -} - -const mitk::ImageToLiveWireContourFilter::InputType *mitk::ImageToLiveWireContourFilter::GetInput(void) -{ - if (this->GetNumberOfInputs() < 1) - return nullptr; - return static_cast<const mitk::ImageToLiveWireContourFilter::InputType *>(this->ProcessObject::GetInput(0)); -} - -const mitk::ImageToLiveWireContourFilter::InputType *mitk::ImageToLiveWireContourFilter::GetInput(unsigned int idx) -{ - if (this->GetNumberOfInputs() < 1) - return nullptr; - return static_cast<const mitk::ImageToLiveWireContourFilter::InputType *>(this->ProcessObject::GetInput(idx)); -} - -void mitk::ImageToLiveWireContourFilter::GenerateData() -{ - mitk::Image::ConstPointer input = dynamic_cast<const mitk::Image *>(this->GetInput()); - - if (!input) - { - MITK_ERROR << "No input available."; - itkExceptionMacro("mitk::ImageToLiveWireContourFilter: No input available. Please set the input!"); - return; - } - - if (input->GetDimension() != 2) - { - MITK_ERROR << "Filter is only working on 2D images."; - itkExceptionMacro("mitk::ImageToLiveWireContourFilter: Filter is only working on 2D images.. Please make sure that " - "the input is 2D!"); - return; - } - - input->GetGeometry()->WorldToIndex(m_StartPoint, m_StartPointInIndex); - input->GetGeometry()->WorldToIndex(m_EndPoint, m_EndPointInIndex); - - AccessFixedDimensionByItk(input, ItkProcessImage, 2); -} - -template <typename TPixel, unsigned int VImageDimension> -void mitk::ImageToLiveWireContourFilter::ItkProcessImage(const itk::Image<TPixel, VImageDimension> *) -{ - // typedef itk::Image< TPixel, VImageDimension > InputImageType; - // typedef itk::Image< float, 2 > FloatImageType; - - // typedef typename itk::ShortestPathImageFilter< InputImageType, InputImageType > ShortestPathImageFilterType; - // typedef typename itk::ShortestPathCostFunctionLiveWire< InputImageType > CostFunctionType; - - // typedef InputImageType::IndexType IndexType; - - ///* compute the requested region for itk filters */ - - // typename IndexType startPoint, endPoint; - // - // startPoint[0] = m_StartPointInIndex[0]; - // startPoint[1] = m_StartPointInIndex[1]; - - // endPoint[0] = m_EndPointInIndex[0]; - // endPoint[1] = m_EndPointInIndex[1]; - - ////minimum value in each direction for startRegion - // typename IndexType startRegion; - // startRegion[0] = startPoint[0] < endPoint[0] ? startPoint[0] : endPoint[0]; - // startRegion[1] = startPoint[1] < endPoint[1] ? startPoint[1] : endPoint[1]; - - ////maximum value in each direction for size - // typename InputImageType::SizeType size; - // size[0] = startPoint[0] > endPoint[0] ? startPoint[0] : endPoint[0]; - // size[1] = startPoint[1] > endPoint[1] ? startPoint[1] : endPoint[1]; - - // typename InputImageType::RegionType region; - // region.SetSize( size ); - // region.SetIndex( startRegion ); - ///*---------------------------------------------*/ - - ///* extracts features from image and calculates costs */ - // typename CostFunctionType::Pointer costFunction = CostFunctionType::New(); - // costFunction->SetImage(inputImage); - // costFunction->SetStartIndex(startPoint); - // costFunction->SetEndIndex(endPoint); - // costFunction->SetRequestedRegion(region); - ///*---------------------------------------------*/ - - ///* calculate shortest path between start and end point */ - // ShortestPathImageFilterType::Pointer shortestPathFilter = ShortestPathImageFilterType::New(); - // shortestPathFilter->SetFullNeighborsMode(true); - // shortestPathFilter->SetInput(inputImage); - // shortestPathFilter->SetMakeOutputImage(true); - // shortestPathFilter->SetStoreVectorOrder(false); - ////shortestPathFilter->SetActivateTimeOut(true); - // shortestPathFilter->SetStartIndex(startPoint); - // shortestPathFilter->SetEndIndex(endPoint); - - // shortestPathFilter->Update(); - - ///*---------------------------------------------*/ - - ///* construct contour from path image */ - ////get the shortest path as vector - // std::vector< itk::Index<3> > shortestPath = shortestPathFilter->GetVectorPath(); - - ////fill the output contour with controll points from the path - // OutputType::Pointer outputContour = this->GetOutput(); - // mitk::Image::ConstPointer input = dynamic_cast<const mitk::Image*>(this->GetInput()); - - // std::vector< itk::Index<3> >::iterator pathIterator = shortestPath.begin(); - - // while(pathIterator != shortestPath.end()) - //{ - // mitk::Point3D currentPoint; - // currentPoint[0] = (*pathIterator)[0]; - // currentPoint[1] = (*pathIterator)[1]; - - // input->GetGeometry(0)->IndexToWorld(currentPoint, currentPoint); - // outputContour->AddVertex(currentPoint); - // - // pathIterator++; - //} - /*---------------------------------------------*/ -} diff --git a/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.h b/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.h deleted file mode 100644 index b8e4f2c779..0000000000 --- a/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.h +++ /dev/null @@ -1,80 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ - -#ifndef mitkImageToLiveWireContourFilter_h -#define mitkImageToLiveWireContourFilter_h - -#include "mitkCommon.h" -#include "mitkContourModel.h" -#include "mitkContourModelSource.h" -#include <MitkSegmentationExports.h> - -#include <mitkImage.h> -#include <mitkImageAccessByItk.h> -#include <mitkImageCast.h> - -namespace mitk -{ - /** - * - * \brief - * - * \ingroup ContourModelFilters - * \ingroup Process - */ - class MITKSEGMENTATION_EXPORT ImageToLiveWireContourFilter : public ContourModelSource - { - public: - mitkClassMacro(ImageToLiveWireContourFilter, ContourModelSource); - itkFactorylessNewMacro(Self); - itkCloneMacro(Self); - - typedef ContourModel OutputType; - typedef OutputType::Pointer OutputTypePointer; - typedef mitk::Image InputType; - - itkSetMacro(StartPoint, mitk::Point3D); - itkGetMacro(StartPoint, mitk::Point3D); - - itkSetMacro(EndPoint, mitk::Point3D); - itkGetMacro(EndPoint, mitk::Point3D); - - virtual void SetInput(const InputType *input); - - using Superclass::SetInput; - virtual void SetInput(unsigned int idx, const InputType *input); - - const InputType *GetInput(void); - - const InputType *GetInput(unsigned int idx); - - protected: - ImageToLiveWireContourFilter(); - - ~ImageToLiveWireContourFilter() override; - - void GenerateData() override; - - void GenerateOutputInformation() override{}; - - mitk::Point3D m_StartPoint; - mitk::Point3D m_EndPoint; - - mitk::Point3D m_StartPointInIndex; - mitk::Point3D m_EndPointInIndex; - - private: - template <typename TPixel, unsigned int VImageDimension> - void ItkProcessImage(const itk::Image<TPixel, VImageDimension> *inputImage); - }; -} -#endif diff --git a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp index 7754a8e450..8c2903ef39 100644 --- a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp +++ b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp @@ -1,262 +1,262 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include <mitkContourModelUtils.h> #include <mitkLiveWireTool2D.h> #include <mitkLiveWireTool2D.xpm> #include <mitkToolManager.h> #include <mitkTimeNavigationController.h> #include <usGetModuleContext.h> #include <usModuleResource.h> #include <type_traits> namespace mitk { MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, LiveWireTool2D, "LiveWire tool"); } mitk::LiveWireTool2D::LiveWireTool2D() : EditableContourTool(), m_CreateAndUseDynamicCosts(false) { } mitk::LiveWireTool2D::~LiveWireTool2D() { } void mitk::LiveWireTool2D::ConnectActionsAndFunctions() { mitk::EditableContourTool::ConnectActionsAndFunctions(); CONNECT_FUNCTION("MovePoint", OnMouseMoveNoDynamicCosts); } const char **mitk::LiveWireTool2D::GetXPM() const { return mitkLiveWireTool2D_xpm; } us::ModuleResource mitk::LiveWireTool2D::GetIconResource() const { return us::GetModuleContext()->GetModule()->GetResource("LiveWire.svg"); } us::ModuleResource mitk::LiveWireTool2D::GetCursorIconResource() const { return us::GetModuleContext()->GetModule()->GetResource("LiveWire_Cursor.svg"); } const char *mitk::LiveWireTool2D::GetName() const { return "Live Wire"; } void mitk::LiveWireTool2D::UpdateLiveWireContour() { auto contour = this->GetContour(); if (nullptr != contour) { auto timeGeometry = contour->GetTimeGeometry()->Clone(); m_PreviewContour = this->m_LiveWireFilter->GetOutput(); // needed because the results of the filter are always from 0 ms // to 1 ms and the filter also resets its outputs. // generate a time geometry that is always visible as the working contour should always be. auto contourTimeGeometry = ProportionalTimeGeometry::New(); contourTimeGeometry->SetStepDuration(std::numeric_limits<TimePointType>::max()); contourTimeGeometry->SetTimeStepGeometry(contour->GetTimeGeometry()->GetGeometryForTimeStep(0)->Clone(), 0); m_PreviewContour->SetTimeGeometry(contourTimeGeometry); m_PreviewContourNode->SetData(this->m_PreviewContour); } } void mitk::LiveWireTool2D::OnTimePointChanged() { auto reference = this->GetReferenceData(); if (nullptr == reference || m_PlaneGeometry.IsNull() || m_LiveWireFilter.IsNull() || m_PreviewContourNode.IsNull()) return; auto timeStep = reference->GetTimeGeometry()->TimePointToTimeStep(this->GetLastTimePointTriggered()); m_ReferenceDataSlice = GetAffectedImageSliceAs2DImageByTimePoint(m_PlaneGeometry, reference, timeStep); m_LiveWireFilter->SetInput(m_ReferenceDataSlice); m_LiveWireFilter->Update(); this->UpdateLiveWireContour(); RenderingManager::GetInstance()->RequestUpdateAll(); }; mitk::Point3D mitk::LiveWireTool2D::PrepareInitContour(const mitk::Point3D& clickedPoint) { - // Set current slice as input for ImageToLiveWireContourFilter + // Set current slice as input for ImageToLiveWireContourModelFilter m_LiveWireFilter = ImageLiveWireContourModelFilter::New(); m_LiveWireFilter->SetUseCostFunction(true); m_LiveWireFilter->SetInput(m_ReferenceDataSlice); itk::Index<3> idx; m_ReferenceDataSlice->GetGeometry()->WorldToIndex(clickedPoint, idx); // Get the pixel with the highest gradient in a 7x7 region itk::Index<3> indexWithHighestGradient; AccessFixedDimensionByItk_2(m_ReferenceDataSlice, FindHighestGradientMagnitudeByITK, 2, idx, indexWithHighestGradient); Point3D adaptedClick; m_ReferenceDataSlice->GetGeometry()->IndexToWorld(indexWithHighestGradient, adaptedClick); m_CreateAndUseDynamicCosts = true; return adaptedClick; } void mitk::LiveWireTool2D::FinalizePreviewContour(const Point3D& clickedPoint) { // Add repulsive points to avoid getting the same path again std::for_each(m_PreviewContour->IteratorBegin(), m_PreviewContour->IteratorEnd(), [this](ContourElement::VertexType* vertex) { ImageLiveWireContourModelFilter::InternalImageType::IndexType idx; this->m_ReferenceDataSlice->GetGeometry()->WorldToIndex(vertex->Coordinates, idx); this->m_LiveWireFilter->AddRepulsivePoint(idx); }); EditableContourTool::FinalizePreviewContour(clickedPoint); } void mitk::LiveWireTool2D::InitializePreviewContour(const Point3D& clickedPoint) { m_PreviewContour->Clear(); // Set new start point m_LiveWireFilter->SetStartPoint(clickedPoint); if (m_CreateAndUseDynamicCosts) { auto contour = this->GetContour(); // Use dynamic cost map for next update m_LiveWireFilter->CreateDynamicCostMap(contour); m_LiveWireFilter->SetUseDynamicCostMap(true); } } void mitk::LiveWireTool2D::UpdatePreviewContour(const Point3D& clickedPoint) { // Compute LiveWire segment from last control point to current mouse position m_LiveWireFilter->SetEndPoint(clickedPoint); m_LiveWireFilter->Update(); this->UpdateLiveWireContour(); } void mitk::LiveWireTool2D::OnMouseMoveNoDynamicCosts(StateMachineAction *, InteractionEvent *interactionEvent) { m_LiveWireFilter->SetUseDynamicCostMap(false); this->OnMouseMoved(nullptr, interactionEvent); m_LiveWireFilter->SetUseDynamicCostMap(true); } void mitk::LiveWireTool2D::FinishTool() { m_LiveWireFilter->SetUseDynamicCostMap(false); m_ContourInteractor = mitk::ContourModelLiveWireInteractor::New(); m_ContourInteractor->SetDataNode(m_ContourNode); m_ContourInteractor->LoadStateMachine("ContourModelModificationInteractor.xml", us::GetModuleContext()->GetModule()); m_ContourInteractor->SetEventConfig("ContourModelModificationConfig.xml", us::GetModuleContext()->GetModule()); m_ContourInteractor->SetWorkingImage(this->m_ReferenceDataSlice); m_ContourInteractor->SetRestrictedArea(this->m_CurrentRestrictedArea); m_ContourNode->SetDataInteractor(m_ContourInteractor.GetPointer()); } template <typename TPixel, unsigned int VImageDimension> void mitk::LiveWireTool2D::FindHighestGradientMagnitudeByITK(itk::Image<TPixel, VImageDimension> *inputImage, itk::Index<3> &index, itk::Index<3> &returnIndex) { typedef itk::Image<TPixel, VImageDimension> InputImageType; typedef typename InputImageType::IndexType IndexType; const auto MAX_X = inputImage->GetLargestPossibleRegion().GetSize()[0]; const auto MAX_Y = 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 (MAX_X - index[0] < 7) startRegion[0] = MAX_X - 7; if (MAX_Y - index[1] < 7) startRegion[1] = MAX_Y - 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 gradientMagnitudeImage; gradientMagnitudeImage = 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 = gradientMagnitudeImage->GetPixel(currentIndex); // Check for new max if (maxGradientMagnitude < gradientMagnitude) { maxGradientMagnitude = gradientMagnitude; returnIndex[0] = currentIndex[0]; returnIndex[1] = currentIndex[1]; returnIndex[2] = 0.0; } } currentIndex[1] = index[1]; } } diff --git a/Modules/Segmentation/files.cmake b/Modules/Segmentation/files.cmake index 26317aa6b3..31b461d399 100644 --- a/Modules/Segmentation/files.cmake +++ b/Modules/Segmentation/files.cmake @@ -1,118 +1,117 @@ set(CPP_FILES Algorithms/mitkCalculateSegmentationVolume.cpp Algorithms/mitkContourModelSetToImageFilter.cpp Algorithms/mitkContourSetToPointSetFilter.cpp Algorithms/mitkContourUtils.cpp Algorithms/mitkCorrectorAlgorithm.cpp Algorithms/mitkDiffImageApplier.cpp Algorithms/mitkDiffSliceOperation.cpp Algorithms/mitkDiffSliceOperationApplier.cpp Algorithms/mitkGrowCutSegmentationFilter.cpp Algorithms/mitkImageLiveWireContourModelFilter.cpp Algorithms/mitkImageToContourFilter.cpp - Algorithms/mitkImageToLiveWireContourFilter.cpp Algorithms/mitkManualSegmentationToSurfaceFilter.cpp Algorithms/mitkOtsuSegmentationFilter.cpp Algorithms/mitkSegmentationHelper.cpp Algorithms/mitkSegmentationObjectFactory.cpp Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp Algorithms/mitkShowSegmentationAsSurface.cpp Algorithms/mitkVtkImageOverwrite.cpp Controllers/mitkSegmentationInterpolationController.cpp Controllers/mitkToolManager.cpp Controllers/mitkSegmentationModuleActivator.cpp Controllers/mitkToolManagerProvider.cpp DataManagement/mitkContour.cpp DataManagement/mitkContourSet.cpp DataManagement/mitkExtrudedContour.cpp Interactions/mitkAddContourTool.cpp Interactions/mitkAutoCropTool.cpp Interactions/mitkSegWithPreviewTool.cpp Interactions/mitkBinaryThresholdBaseTool.cpp Interactions/mitkBinaryThresholdTool.cpp Interactions/mitkBinaryThresholdULTool.cpp Interactions/mitkCloseRegionTool.cpp Interactions/mitkContourModelInteractor.cpp Interactions/mitkContourModelLiveWireInteractor.cpp Interactions/mitkEditableContourTool.cpp Interactions/mitkLiveWireTool2D.cpp Interactions/mitkLassoTool.cpp Interactions/mitkContourTool.cpp Interactions/mitkDrawPaintbrushTool.cpp Interactions/mitkErasePaintbrushTool.cpp Interactions/mitkEraseRegionTool.cpp Interactions/mitkFeedbackContourTool.cpp Interactions/mitkFillRegionBaseTool.cpp Interactions/mitkFillRegionTool.cpp Interactions/mitkGrowCutTool.cpp Interactions/mitkOtsuTool3D.cpp Interactions/mitkPaintbrushTool.cpp Interactions/mitkRegionGrowingTool.cpp Interactions/mitkSegmentationsProcessingTool.cpp Interactions/mitkSegTool2D.cpp Interactions/mitkSubtractContourTool.cpp Interactions/mitkTool.cpp Interactions/mitkToolCommand.cpp Interactions/mitkPickingTool.cpp Interactions/mitknnUnetTool.cpp Interactions/mitkProcessExecutor.cpp Interactions/mitkSegmentAnythingProcessExecutor.cpp Interactions/mitkTotalSegmentatorTool.cpp Interactions/mitkSegmentAnythingTool.cpp Interactions/mitkMedSAMTool.cpp Interactions/mitkSegmentAnythingPythonService.cpp Rendering/mitkContourMapper2D.cpp Rendering/mitkContourSetMapper2D.cpp Rendering/mitkContourSetVtkMapper3D.cpp Rendering/mitkContourVtkMapper3D.cpp SegmentationUtilities/BooleanOperations/mitkBooleanOperation.cpp SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp #Added from ML Algorithms/mitkSurfaceStampImageFilter.cpp ) set(RESOURCE_FILES Add.svg Add_Cursor.svg AI.svg AI_Cursor.svg Close.svg Close_Cursor.svg Erase.svg Erase_Cursor.svg Fill.svg Fill_Cursor.svg LiveWire.svg LiveWire_Cursor.svg Lasso.svg GrowCut.svg Lasso_Cursor.svg Otsu.svg Paint.svg Paint_Cursor.svg Picking.svg RegionGrowing.svg RegionGrowing_Cursor.svg Subtract.svg Subtract_Cursor.svg Threshold.svg ULThreshold.svg Wipe.svg Wipe_Cursor.svg Interactions/dummy.xml Interactions/EditableContourTool.xml Interactions/PickingTool.xml Interactions/MouseReleaseOnly.xml Interactions/PressMoveRelease.xml Interactions/PressMoveReleaseAndPointSetting.xml Interactions/PressMoveReleaseWithCTRLInversion.xml Interactions/PressMoveReleaseWithCTRLInversionAllMouseMoves.xml Interactions/SegmentationConfig.xml Interactions/SegmentationInteraction.xml Interactions/SegmentationToolsConfig.xml Interactions/ContourModelModificationConfig.xml Interactions/ContourModelModificationInteractor.xml )