diff --git a/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx index 19c8af5f6d..b319a7fdba 100644 --- a/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx +++ b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx @@ -1,408 +1,408 @@ /*=================================================================== 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 __itkShortestPathCostFunctionLiveWire_txx #define __itkShortestPathCostFunctionLiveWire_txx #include "itkShortestPathCostFunctionLiveWire.h" #include #include #include #include #include #include #include #include namespace itk { // Constructor template ShortestPathCostFunctionLiveWire::ShortestPathCostFunctionLiveWire() { m_UseRepulsivePoints = false; m_GradientMax = 0.0; m_Initialized = false; m_UseCostMap = false; m_MaxMapCosts = -1.0; } template void ShortestPathCostFunctionLiveWire::AddRepulsivePoint(const IndexType &index) { this->m_MaskImage->SetPixel(index, 255); m_UseRepulsivePoints = true; } template void ShortestPathCostFunctionLiveWire::RemoveRepulsivePoint(const IndexType &index) { this->m_MaskImage->SetPixel(index, 0); } template void ShortestPathCostFunctionLiveWire::SetImage(const TInputImageType *_arg) { if (this->m_Image != _arg) { this->m_Image = _arg; // initialize mask image this->m_MaskImage = UnsignedCharImageType::New(); this->m_MaskImage->SetRegions(this->m_Image->GetLargestPossibleRegion()); this->m_MaskImage->SetOrigin(this->m_Image->GetOrigin()); this->m_MaskImage->SetSpacing(this->m_Image->GetSpacing()); this->m_MaskImage->SetDirection(this->m_Image->GetDirection()); this->m_MaskImage->Allocate(); this->m_MaskImage->FillBuffer(0); this->Modified(); this->m_Initialized = false; } } template void ShortestPathCostFunctionLiveWire::ClearRepulsivePoints() { m_UseRepulsivePoints = false; this->m_MaskImage->FillBuffer(0); } template double ShortestPathCostFunctionLiveWire::GetCost(IndexType p1, IndexType p2) { // local component costs // weights double w1; double w2; double w3; double costs = 0.0; // if we are on the mask, return asap if (m_UseRepulsivePoints) { if ((this->m_MaskImage->GetPixel(p1) != 0) || (this->m_MaskImage->GetPixel(p2) != 0)) return 1000; } double gradientX, gradientY; gradientX = gradientY = 0.0; double gradientCost; double gradientMagnitude; // Gradient Magnitude costs gradientMagnitude = this->m_GradientMagnitudeImage->GetPixel(p2); gradientX = m_GradientImage->GetPixel(p2)[0]; gradientY = m_GradientImage->GetPixel(p2)[1]; if (m_UseCostMap && !m_CostMap.empty()) { std::map::iterator end = m_CostMap.end(); std::map::iterator last = --(m_CostMap.end()); // current position std::map::iterator x; // std::map< int, int >::key_type keyOfX = static_cast::key_type>(gradientMagnitude * 1000); int keyOfX = static_cast(gradientMagnitude /* ShortestPathCostFunctionLiveWire::MAPSCALEFACTOR*/); x = m_CostMap.find(keyOfX); std::map::iterator left2; std::map::iterator left1; std::map::iterator right1; std::map::iterator right2; if (x == end) { // x can also be == end if the key is not in the map but between two other keys // search next key within map from x upwards right1 = m_CostMap.lower_bound(keyOfX); } else { right1 = x; } if (right1 == end || right1 == last) { right2 = end; } else //( right1 != (end-1) ) { auto temp = right1; right2 = ++right1; // rght1 + 1 right1 = temp; } if (right1 == m_CostMap.begin()) { left1 = end; left2 = end; } else if (right1 == (++(m_CostMap.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 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, left2->first, left2->second); } if (left1 != end) { partLeft1 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, left1->first, left1->second); } if (right1 != end) { partRight1 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, right1->first, right1->second); } if (right2 != end) { partRight2 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, right2->first, right2->second); } if (m_MaxMapCosts > 0.0) { gradientCost = 1.0 - ((partRight1 + partRight2 + partLeft1 + partLeft2) / m_MaxMapCosts); } else { // use linear mapping gradientCost = 1.0 - (gradientMagnitude / m_GradientMax); } } else { // use linear mapping // value between 0 (good) and 1 (bad) gradientCost = 1.0 - (gradientMagnitude / m_GradientMax); } // Laplacian zero crossing costs // f(p) = 0; if I(p)=0 // or 1; if I(p)!=0 double laplacianCost; typename Superclass::PixelType laplaceImageValue; laplaceImageValue = m_EdgeImage->GetPixel(p2); if (laplaceImageValue < 0 || laplaceImageValue > 0) { laplacianCost = 1.0; } else { laplacianCost = 0.0; } // gradient vector at p1 double nGradientAtP1[2]; nGradientAtP1[0] = gradientX; // previously computed for gradient magnitude nGradientAtP1[1] = gradientY; // gradient direction unit vector of p1 nGradientAtP1[0] /= gradientMagnitude; nGradientAtP1[1] /= gradientMagnitude; //------- // gradient vector at p1 double nGradientAtP2[2]; nGradientAtP2[0] = m_GradientImage->GetPixel(p2)[0]; nGradientAtP2[1] = m_GradientImage->GetPixel(p2)[1]; nGradientAtP2[0] /= m_GradientMagnitudeImage->GetPixel(p2); nGradientAtP2[1] /= m_GradientMagnitudeImage->GetPixel(p2); double scalarProduct = (nGradientAtP1[0] * nGradientAtP2[0]) + (nGradientAtP1[1] * nGradientAtP2[1]); - if (abs(scalarProduct) >= 1.0) + if (std::abs(scalarProduct) >= 1.0) { // this should probably not happen; make sure the input for acos is valid scalarProduct = 0.999999999; } double gradientDirectionCost = acos(scalarProduct) / 3.14159265; if (this->m_UseCostMap) { w1 = 0.43; w2 = 0.43; w3 = 0.14; } else { w1 = 0.10; w2 = 0.85; w3 = 0.05; } costs = w1 * laplacianCost + w2 * gradientCost + w3 * gradientDirectionCost; // scale by euclidian distance double costScale; if (p1[0] == p2[0] || p1[1] == p2[1]) { // horizontal or vertical neighbor costScale = 1.0; } else { // diagonal neighbor costScale = sqrt(2.0); } costs *= costScale; return costs; } template double ShortestPathCostFunctionLiveWire::GetMinCost() { return minCosts; } template void ShortestPathCostFunctionLiveWire::Initialize() { if (!m_Initialized) { typedef itk::CastImageFilter CastFilterType; typename CastFilterType::Pointer castFilter = CastFilterType::New(); castFilter->SetInput(this->m_Image); // init gradient magnitude image typedef itk::GradientMagnitudeImageFilter GradientMagnitudeFilterType; typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New(); gradientFilter->SetInput(castFilter->GetOutput()); // gradientFilter->SetNumberOfThreads(4); // gradientFilter->GetOutput()->SetRequestedRegion(m_RequestedRegion); gradientFilter->Update(); this->m_GradientMagnitudeImage = gradientFilter->GetOutput(); typedef itk::StatisticsImageFilter StatisticsImageFilterType; typename StatisticsImageFilterType::Pointer statisticsImageFilter = StatisticsImageFilterType::New(); statisticsImageFilter->SetInput(this->m_GradientMagnitudeImage); statisticsImageFilter->Update(); m_GradientMax = statisticsImageFilter->GetMaximum(); typedef itk::GradientImageFilter GradientFilterType; typename GradientFilterType::Pointer filter = GradientFilterType::New(); // sigma is specified in millimeters // filter->SetSigma( 1.5 ); filter->SetInput(castFilter->GetOutput()); filter->Update(); m_GradientImage = filter->GetOutput(); // init zero crossings // typedef itk::ZeroCrossingImageFilter< TInputImageType, UnsignedCharImageType > ZeroCrossingImageFilterType; // ZeroCrossingImageFilterType::Pointer zeroCrossingImageFilter = ZeroCrossingImageFilterType::New(); // zeroCrossingImageFilter->SetInput(this->m_Image); // zeroCrossingImageFilter->SetBackgroundValue(1); // zeroCrossingImageFilter->SetForegroundValue(0); // zeroCrossingImageFilter->SetNumberOfThreads(4); // zeroCrossingImageFilter->Update(); // m_EdgeImage = zeroCrossingImageFilter->GetOutput(); // cast image to float to apply canny edge dection filter /*typedef itk::CastImageFilter< TInputImageType, FloatImageType > CastFilterType; CastFilterType::Pointer castFilter = CastFilterType::New(); castFilter->SetInput(this->m_Image);*/ // typedef itk::LaplacianImageFilter filterType; // filterType::Pointer laplacianFilter = filterType::New(); // laplacianFilter->SetInput( castFilter->GetOutput() ); // NOTE: input image type must be double or float // laplacianFilter->Update(); // m_EdgeImage = laplacianFilter->GetOutput(); // init canny edge detection typedef itk::CannyEdgeDetectionImageFilter CannyEdgeDetectionImageFilterType; typename CannyEdgeDetectionImageFilterType::Pointer cannyEdgeDetectionfilter = CannyEdgeDetectionImageFilterType::New(); cannyEdgeDetectionfilter->SetInput(castFilter->GetOutput()); cannyEdgeDetectionfilter->SetUpperThreshold(30); cannyEdgeDetectionfilter->SetLowerThreshold(15); cannyEdgeDetectionfilter->SetVariance(4); cannyEdgeDetectionfilter->SetMaximumError(.01f); cannyEdgeDetectionfilter->Update(); m_EdgeImage = cannyEdgeDetectionfilter->GetOutput(); // set minCosts minCosts = 0.0; // The lower, the more thouroughly! 0 = dijkstra. If estimate costs are lower than actual costs // everything is fine. If estimation is higher than actual costs, you might not get the shortest // but a different path. m_Initialized = true; } // check start/end point value startValue = this->m_Image->GetPixel(this->m_StartIndex); endValue = this->m_Image->GetPixel(this->m_EndIndex); } template double ShortestPathCostFunctionLiveWire::SigmoidFunction( double I, double max, double min, double alpha, double beta) { // Using the SIgmoid formula from ITK Software Guide 6.3.2 Non Linear Mappings double Exponent = -1 * ((I - beta) / alpha); double Factor = 1 / (1 + exp(Exponent)); double newI = (max - min) * Factor + min; return newI; } template double ShortestPathCostFunctionLiveWire::Gaussian(double x, double xOfGaussian, double yOfGaussian) { return yOfGaussian * exp(-0.5 * pow((x - xOfGaussian), 2)); } } // end namespace itk #endif // __itkShortestPathCostFunctionLiveWire_txx diff --git a/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp b/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp index 7e7e598cbe..5ee2941914 100644 --- a/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp +++ b/Modules/ImageStatistics/mitkImageStatisticsCalculator.cpp @@ -1,629 +1,629 @@ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "itkImageFileWriter.h" namespace mitk { void ImageStatisticsCalculator::SetInputImage(mitk::Image::Pointer image) { if (image != m_Image) { m_Image = image; m_StatisticsByTimeStep.resize(m_Image->GetTimeSteps()); m_StatisticsUpdateTimePerTimeStep.resize(m_Image->GetTimeSteps()); std::fill(m_StatisticsUpdateTimePerTimeStep.begin(), m_StatisticsUpdateTimePerTimeStep.end(), 0); this->Modified(); } } void ImageStatisticsCalculator::SetMask(mitk::MaskGenerator::Pointer mask) { if (mask != m_MaskGenerator) { m_MaskGenerator = mask; this->Modified(); } } void ImageStatisticsCalculator::SetSecondaryMask(mitk::MaskGenerator::Pointer mask) { if (mask != m_SecondaryMaskGenerator) { m_SecondaryMaskGenerator = mask; this->Modified(); } } void ImageStatisticsCalculator::SetNBinsForHistogramStatistics(unsigned int nBins) { if (nBins != m_nBinsForHistogramStatistics) { m_nBinsForHistogramStatistics = nBins; this->Modified(); this->m_UseBinSizeOverNBins = false; } if (m_UseBinSizeOverNBins) { this->Modified(); this->m_UseBinSizeOverNBins = false; } } unsigned int ImageStatisticsCalculator::GetNBinsForHistogramStatistics() const { return m_nBinsForHistogramStatistics; } void ImageStatisticsCalculator::SetBinSizeForHistogramStatistics(double binSize) { if (binSize != m_binSizeForHistogramStatistics) { m_binSizeForHistogramStatistics = binSize; this->Modified(); this->m_UseBinSizeOverNBins = true; } if (!m_UseBinSizeOverNBins) { this->Modified(); this->m_UseBinSizeOverNBins = true; } } double ImageStatisticsCalculator::GetBinSizeForHistogramStatistics() const { return m_binSizeForHistogramStatistics; } ImageStatisticsCalculator::StatisticsContainer::Pointer ImageStatisticsCalculator::GetStatistics(unsigned int timeStep, unsigned int label) { if (timeStep >= m_StatisticsByTimeStep.size()) { mitkThrow() << "invalid timeStep in ImageStatisticsCalculator_v2::GetStatistics"; } if (m_Image.IsNull()) { mitkThrow() << "no image"; } if (!m_Image->IsInitialized()) { mitkThrow() << "Image not initialized!"; } if (IsUpdateRequired(timeStep)) { if (m_MaskGenerator.IsNotNull()) { m_MaskGenerator->SetTimeStep(timeStep); m_InternalMask = m_MaskGenerator->GetMask(); if (m_MaskGenerator->GetReferenceImage().IsNotNull()) { m_InternalImageForStatistics = m_MaskGenerator->GetReferenceImage(); } else { m_InternalImageForStatistics = m_Image; } } else { m_InternalImageForStatistics = m_Image; } if (m_SecondaryMaskGenerator.IsNotNull()) { m_SecondaryMaskGenerator->SetTimeStep(timeStep); m_SecondaryMask = m_SecondaryMaskGenerator->GetMask(); } ImageTimeSelector::Pointer imgTimeSel = ImageTimeSelector::New(); imgTimeSel->SetInput(m_InternalImageForStatistics); imgTimeSel->SetTimeNr(timeStep); imgTimeSel->UpdateLargestPossibleRegion(); m_ImageTimeSlice = imgTimeSel->GetOutput(); // Calculate statistics with/without mask if (m_MaskGenerator.IsNull() && m_SecondaryMaskGenerator.IsNull()) { // 1) calculate statistics unmasked: AccessByItk_1(m_ImageTimeSlice, InternalCalculateStatisticsUnmasked, timeStep) } else { // 2) calculate statistics masked AccessByItk_1(m_ImageTimeSlice, InternalCalculateStatisticsMasked, timeStep) } //this->Modified(); } m_StatisticsUpdateTimePerTimeStep[timeStep] = m_StatisticsByTimeStep[timeStep][m_StatisticsByTimeStep[timeStep].size()-1]->GetMTime(); for (auto it = m_StatisticsByTimeStep[timeStep].begin(); it != m_StatisticsByTimeStep[timeStep].end(); ++it) { StatisticsContainer::Pointer statCont = *it; if (statCont->GetLabel() == label) { return statCont->Clone(); } } // these lines will ony be executed if the requested label could not be found! MITK_WARN << "Invalid label: " << label << " in time step: " << timeStep; return StatisticsContainer::New(); } template < typename TPixel, unsigned int VImageDimension > void ImageStatisticsCalculator::InternalCalculateStatisticsUnmasked( typename itk::Image< TPixel, VImageDimension >* image, unsigned int timeStep) { typedef typename itk::Image< TPixel, VImageDimension > ImageType; typedef typename itk::ExtendedStatisticsImageFilter ImageStatisticsFilterType; typedef typename itk::MinMaxImageFilterWithIndex MinMaxFilterType; StatisticsContainer::Pointer statisticsResult = StatisticsContainer::New(); typename ImageStatisticsFilterType::Pointer statisticsFilter = ImageStatisticsFilterType::New(); statisticsFilter->SetInput(image); statisticsFilter->SetCoordinateTolerance(0.001); statisticsFilter->SetDirectionTolerance(0.001); // TODO: this is single threaded. Implement our own image filter that does this multi threaded // typename itk::MinimumMaximumImageCalculator::Pointer imgMinMaxFilter = itk::MinimumMaximumImageCalculator::New(); // imgMinMaxFilter->SetImage(image); // imgMinMaxFilter->Compute(); vnl_vector minIndex, maxIndex; typename MinMaxFilterType::Pointer minMaxFilter = MinMaxFilterType::New(); minMaxFilter->SetInput(image); minMaxFilter->UpdateLargestPossibleRegion(); typename ImageType::PixelType minval = minMaxFilter->GetMin(); typename ImageType::PixelType maxval = minMaxFilter->GetMax(); typename ImageType::IndexType tmpMinIndex = minMaxFilter->GetMinIndex(); typename ImageType::IndexType tmpMaxIndex = minMaxFilter->GetMaxIndex(); // typename ImageType::IndexType tmpMinIndex = imgMinMaxFilter->GetIndexOfMinimum(); // typename ImageType::IndexType tmpMaxIndex = imgMinMaxFilter->GetIndexOfMaximum(); minIndex.set_size(tmpMaxIndex.GetIndexDimension()); maxIndex.set_size(tmpMaxIndex.GetIndexDimension()); for (unsigned int i=0; i < tmpMaxIndex.GetIndexDimension(); i++) { minIndex[i] = tmpMinIndex[i]; maxIndex[i] = tmpMaxIndex[i]; } statisticsResult->SetMinIndex(minIndex); statisticsResult->SetMaxIndex(maxIndex); //convert m_binSize in m_nBins if necessary unsigned int nBinsForHistogram; if (m_UseBinSizeOverNBins) { nBinsForHistogram = std::max(static_cast(std::ceil(maxval - minval)) / m_binSizeForHistogramStatistics, 10.); // do not allow less than 10 bins } else { nBinsForHistogram = m_nBinsForHistogramStatistics; } statisticsFilter->SetHistogramParameters(nBinsForHistogram, minval, maxval); try { statisticsFilter->Update(); } catch (const itk::ExceptionObject& e) { mitkThrow() << "Image statistics calculation failed due to following ITK Exception: \n " << e.what(); } // no mask, therefore just one label = the whole image m_StatisticsByTimeStep[timeStep].resize(1); statisticsResult->SetLabel(1); statisticsResult->SetN(image->GetLargestPossibleRegion().GetNumberOfPixels()); statisticsResult->SetMean(statisticsFilter->GetMean()); statisticsResult->SetMin(statisticsFilter->GetMinimum()); statisticsResult->SetMax(statisticsFilter->GetMaximum()); statisticsResult->SetVariance(statisticsFilter->GetVariance()); statisticsResult->SetStd(statisticsFilter->GetSigma()); statisticsResult->SetSkewness(statisticsFilter->GetSkewness()); statisticsResult->SetKurtosis(statisticsFilter->GetKurtosis()); statisticsResult->SetRMS(std::sqrt(std::pow(statisticsFilter->GetMean(), 2.) + statisticsFilter->GetVariance())); // variance = sigma^2 statisticsResult->SetMPP(statisticsFilter->GetMPP()); statisticsResult->SetEntropy(statisticsFilter->GetEntropy()); statisticsResult->SetMedian(statisticsFilter->GetMedian()); statisticsResult->SetUniformity(statisticsFilter->GetUniformity()); statisticsResult->SetUPP(statisticsFilter->GetUPP()); statisticsResult->SetHistogram(statisticsFilter->GetHistogram()); m_StatisticsByTimeStep[timeStep][0] = statisticsResult; } template < typename TPixel, unsigned int VImageDimension > void ImageStatisticsCalculator::InternalCalculateStatisticsMasked( typename itk::Image< TPixel, VImageDimension >* image, unsigned int timeStep) { typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< MaskPixelType, VImageDimension > MaskType; typedef typename MaskType::PixelType LabelPixelType; typedef itk::ExtendedLabelStatisticsImageFilter< ImageType, MaskType > ImageStatisticsFilterType; typedef MaskUtilities< TPixel, VImageDimension > MaskUtilType; typedef typename itk::MinMaxLabelImageFilterWithIndex MinMaxLabelFilterType; typedef typename ImageType::PixelType InputImgPixelType; // workaround: if m_SecondaryMaskGenerator ist not null but m_MaskGenerator is! (this is the case if we request a 'ignore zuero valued pixels' // mask in the gui but do not define a primary mask) bool swapMasks = false; if (m_SecondaryMask.IsNotNull() && m_InternalMask.IsNull()) { m_InternalMask = m_SecondaryMask; m_SecondaryMask = nullptr; swapMasks = true; } // maskImage has to have the same dimension as image typename MaskType::Pointer maskImage = MaskType::New(); try { // try to access the pixel values directly (no copying or casting). Only works if mask pixels are of pixelType unsigned short maskImage = ImageToItkImage< MaskPixelType, VImageDimension >(m_InternalMask); } catch (const itk::ExceptionObject &) { // if the pixel type of the mask is not short, then we have to make a copy of m_InternalMask (and cast the values) CastToItkImage(m_InternalMask, maskImage); } // if we have a secondary mask (say a ignoreZeroPixelMask) we need to combine the masks (corresponds to AND) if (m_SecondaryMask.IsNotNull()) { // dirty workaround for a bug when pf mask + any other mask is used in conjunction. We need a proper fix for this (Fabian Isensee is responsible and probably working on it!) if (m_InternalMask->GetDimension() == 2 && (m_SecondaryMask->GetDimension() == 3 || m_SecondaryMask->GetDimension() == 4)) { mitk::Image::Pointer old_img = m_SecondaryMaskGenerator->GetReferenceImage(); m_SecondaryMaskGenerator->SetInputImage(m_MaskGenerator->GetReferenceImage()); m_SecondaryMask = m_SecondaryMaskGenerator->GetMask(); m_SecondaryMaskGenerator->SetInputImage(old_img); } typename MaskType::Pointer secondaryMaskImage = MaskType::New(); secondaryMaskImage = ImageToItkImage< MaskPixelType, VImageDimension >(m_SecondaryMask); // secondary mask should be a ignore zero value pixel mask derived from image. it has to be cropped to the mask region (which may be planar or simply smaller) typename MaskUtilities::Pointer secondaryMaskMaskUtil = MaskUtilities::New(); secondaryMaskMaskUtil->SetImage(secondaryMaskImage.GetPointer()); secondaryMaskMaskUtil->SetMask(maskImage.GetPointer()); typename MaskType::Pointer adaptedSecondaryMaskImage = secondaryMaskMaskUtil->ExtractMaskImageRegion(); typename itk::MaskImageFilter2::Pointer maskFilter = itk::MaskImageFilter2::New(); maskFilter->SetInput1(maskImage); maskFilter->SetInput2(adaptedSecondaryMaskImage); maskFilter->SetMaskingValue(1); // all pixels of maskImage where secondaryMaskImage==1 will be kept, all the others are set to 0 maskFilter->UpdateLargestPossibleRegion(); maskImage = maskFilter->GetOutput(); } typename MaskUtilType::Pointer maskUtil = MaskUtilType::New(); maskUtil->SetImage(image); maskUtil->SetMask(maskImage.GetPointer()); // if mask is smaller than image, extract the image region where the mask is typename ImageType::Pointer adaptedImage = ImageType::New(); adaptedImage = maskUtil->ExtractMaskImageRegion(); // this also checks mask sanity // find min, max, minindex and maxindex typename MinMaxLabelFilterType::Pointer minMaxFilter = MinMaxLabelFilterType::New(); minMaxFilter->SetInput(adaptedImage); minMaxFilter->SetLabelInput(maskImage); minMaxFilter->UpdateLargestPossibleRegion(); // set histogram parameters for each label individually (min/max may be different for each label) typedef typename std::map MapType; typedef typename std::pair PairType; std::vector relevantLabels = minMaxFilter->GetRelevantLabels(); MapType minVals; MapType maxVals; std::map nBins; for (LabelPixelType label:relevantLabels) { minVals.insert(PairType(label, minMaxFilter->GetMin(label))); maxVals.insert(PairType(label, minMaxFilter->GetMax(label))); unsigned int nBinsForHistogram; if (m_UseBinSizeOverNBins) { nBinsForHistogram = std::max(static_cast(std::ceil(minMaxFilter->GetMax(label) - minMaxFilter->GetMin(label))) / m_binSizeForHistogramStatistics, 10.); // do not allow less than 10 bins } else { nBinsForHistogram = m_nBinsForHistogramStatistics; } nBins.insert(typename std::pair(label, nBinsForHistogram)); } typename ImageStatisticsFilterType::Pointer imageStatisticsFilter = ImageStatisticsFilterType::New(); imageStatisticsFilter->SetDirectionTolerance(0.001); imageStatisticsFilter->SetCoordinateTolerance(0.001); imageStatisticsFilter->SetInput(adaptedImage); imageStatisticsFilter->SetLabelInput(maskImage); imageStatisticsFilter->SetHistogramParametersForLabels(nBins, minVals, maxVals); imageStatisticsFilter->Update(); std::list labels = imageStatisticsFilter->GetRelevantLabels(); auto it = labels.begin(); m_StatisticsByTimeStep[timeStep].resize(0); while(it != labels.end()) { StatisticsContainer::Pointer statisticsResult = StatisticsContainer::New(); // find min, max, minindex and maxindex // make sure to only look in the masked region, use a masker for this vnl_vector minIndex, maxIndex; mitk::Point3D worldCoordinateMin; mitk::Point3D worldCoordinateMax; mitk::Point3D indexCoordinateMin; mitk::Point3D indexCoordinateMax; m_InternalImageForStatistics->GetGeometry()->IndexToWorld(minMaxFilter->GetMinIndex(*it), worldCoordinateMin); m_InternalImageForStatistics->GetGeometry()->IndexToWorld(minMaxFilter->GetMaxIndex(*it), worldCoordinateMax); m_Image->GetGeometry()->WorldToIndex(worldCoordinateMin, indexCoordinateMin); m_Image->GetGeometry()->WorldToIndex(worldCoordinateMax, indexCoordinateMax); minIndex.set_size(3); maxIndex.set_size(3); //for (unsigned int i=0; i < tmpMaxIndex.GetIndexDimension(); i++) for (unsigned int i=0; i < 3; i++) { minIndex[i] = indexCoordinateMin[i]; maxIndex[i] = indexCoordinateMax[i]; } statisticsResult->SetMinIndex(minIndex); statisticsResult->SetMaxIndex(maxIndex); - assert(abs(minMaxFilter->GetMax(*it) - imageStatisticsFilter->GetMaximum(*it)) < mitk::eps); - assert(abs(minMaxFilter->GetMin(*it) - imageStatisticsFilter->GetMinimum(*it)) < mitk::eps); + assert(std::abs(minMaxFilter->GetMax(*it) - imageStatisticsFilter->GetMaximum(*it)) < mitk::eps); + assert(std::abs(minMaxFilter->GetMin(*it) - imageStatisticsFilter->GetMinimum(*it)) < mitk::eps); statisticsResult->SetN(imageStatisticsFilter->GetSum(*it) / (double) imageStatisticsFilter->GetMean(*it)); statisticsResult->SetMean(imageStatisticsFilter->GetMean(*it)); statisticsResult->SetMin(imageStatisticsFilter->GetMinimum(*it)); statisticsResult->SetMax(imageStatisticsFilter->GetMaximum(*it)); statisticsResult->SetVariance(imageStatisticsFilter->GetVariance(*it)); statisticsResult->SetStd(imageStatisticsFilter->GetSigma(*it)); statisticsResult->SetSkewness(imageStatisticsFilter->GetSkewness(*it)); statisticsResult->SetKurtosis(imageStatisticsFilter->GetKurtosis(*it)); statisticsResult->SetRMS(std::sqrt(std::pow(imageStatisticsFilter->GetMean(*it), 2.) + imageStatisticsFilter->GetVariance(*it))); // variance = sigma^2 statisticsResult->SetMPP(imageStatisticsFilter->GetMPP(*it)); statisticsResult->SetLabel(*it); statisticsResult->SetEntropy(imageStatisticsFilter->GetEntropy(*it)); statisticsResult->SetMedian(imageStatisticsFilter->GetMedian(*it)); statisticsResult->SetUniformity(imageStatisticsFilter->GetUniformity(*it)); statisticsResult->SetUPP(imageStatisticsFilter->GetUPP(*it)); statisticsResult->SetHistogram(imageStatisticsFilter->GetHistogram(*it)); m_StatisticsByTimeStep[timeStep].push_back(statisticsResult); ++it; } // swap maskGenerators back if (swapMasks) { m_SecondaryMask = m_InternalMask; m_InternalMask = nullptr; } } bool ImageStatisticsCalculator::IsUpdateRequired(unsigned int timeStep) const { unsigned long thisClassTimeStamp = this->GetMTime(); unsigned long inputImageTimeStamp = m_Image->GetMTime(); unsigned long statisticsTimeStamp = m_StatisticsUpdateTimePerTimeStep[timeStep]; if (thisClassTimeStamp > statisticsTimeStamp) // inputs have changed { return true; } if (inputImageTimeStamp > statisticsTimeStamp) // image has changed { return true; } if (m_MaskGenerator.IsNotNull()) { unsigned long maskGeneratorTimeStamp = m_MaskGenerator->GetMTime(); if (maskGeneratorTimeStamp > statisticsTimeStamp) // there is a mask generator and it has changed { return true; } } if (m_SecondaryMaskGenerator.IsNotNull()) { unsigned long maskGeneratorTimeStamp = m_SecondaryMaskGenerator->GetMTime(); if (maskGeneratorTimeStamp > statisticsTimeStamp) // there is a secondary mask generator and it has changed { return true; } } return false; } ImageStatisticsCalculator::StatisticsContainer::StatisticsContainer(): m_N(0), m_Mean(nan("")), m_Min(nan("")), m_Max(nan("")), m_Std(nan("")), m_Variance(nan("")), m_Skewness(nan("")), m_Kurtosis(nan("")), m_RMS(nan("")), m_MPP(nan("")), m_Median(nan("")), m_Uniformity(nan("")), m_UPP(nan("")), m_Entropy(nan("")) { m_minIndex.set_size(0); m_maxIndex.set_size(0); } ImageStatisticsCalculator::statisticsMapType ImageStatisticsCalculator::StatisticsContainer::GetStatisticsAsMap() { ImageStatisticsCalculator::statisticsMapType statisticsAsMap; statisticsAsMap["N"] = m_N; statisticsAsMap["Mean"] = m_Mean; statisticsAsMap["Min"] = m_Min; statisticsAsMap["Max"] = m_Max; statisticsAsMap["StandardDeviation"] = m_Std; statisticsAsMap["Variance"] = m_Variance; statisticsAsMap["Skewness"] = m_Skewness; statisticsAsMap["Kurtosis"] = m_Kurtosis; statisticsAsMap["RMS"] = m_RMS; statisticsAsMap["MPP"] = m_MPP; statisticsAsMap["Median"] = m_Median; statisticsAsMap["Uniformity"] = m_Uniformity; statisticsAsMap["UPP"] = m_UPP; statisticsAsMap["Entropy"] = m_Entropy; statisticsAsMap["Label"] = m_Label; return statisticsAsMap; } void ImageStatisticsCalculator::StatisticsContainer::Reset() { m_N = 0; m_Mean = nan(""); m_Min = nan(""); m_Max = nan(""); m_Std = nan(""); m_Variance = nan(""); m_Skewness = nan(""); m_Kurtosis = nan(""); m_RMS = nan(""); m_MPP = nan(""); m_Median = nan(""); m_Uniformity = nan(""); m_UPP = nan(""); m_Entropy = nan(""); m_Histogram = HistogramType::New(); m_minIndex.set_size(0); m_maxIndex.set_size(0); m_Label = 0; } void ImageStatisticsCalculator::StatisticsContainer::Print() { ImageStatisticsCalculator::statisticsMapType statMap = this->GetStatisticsAsMap(); // print all map key value pairs // const auto& val:statMap for (auto it = statMap.begin(); it != statMap.end(); ++it) { std::cout << it->first << ": " << it->second << std::endl; } // print the min and max index std::cout << "Min Index:" << std::endl; for (auto it = this->GetMinIndex().begin(); it != this->GetMinIndex().end(); ++it) { std::cout << *it << " "; } std::cout << std::endl; // print the min and max index std::cout << "Max Index:" << std::endl; for (auto it = this->GetMaxIndex().begin(); it != this->GetMaxIndex().end(); ++it) { std::cout << *it << " "; } std::cout << std::endl; } std::string ImageStatisticsCalculator::StatisticsContainer::GetAsString() { std::string res = ""; ImageStatisticsCalculator::statisticsMapType statMap = this->GetStatisticsAsMap(); // print all map key value pairs // const auto& val:statMap for (auto it = statMap.begin(); it != statMap.end(); ++it) { res += std::string(it->first) + ": " + std::to_string(it->second) + "\n"; } // print the min and max index res += "Min Index:" + std::string("\n"); for (auto it = this->GetMinIndex().begin(); it != this->GetMinIndex().end(); it++) { res += std::to_string(*it) + std::string(" "); } res += "\n"; // print the min and max index res += "Max Index:" + std::string("\n"); for (auto it = this->GetMaxIndex().begin(); it != this->GetMaxIndex().end(); it++) { res += std::to_string(*it) + " "; } res += "\n"; return res; } } diff --git a/Modules/PhotoacousticsLib/src/Generator/mitkPASlicedVolumeGenerator.cpp b/Modules/PhotoacousticsLib/src/Generator/mitkPASlicedVolumeGenerator.cpp index a868e1317e..c310767c39 100644 --- a/Modules/PhotoacousticsLib/src/Generator/mitkPASlicedVolumeGenerator.cpp +++ b/Modules/PhotoacousticsLib/src/Generator/mitkPASlicedVolumeGenerator.cpp @@ -1,118 +1,118 @@ /*=================================================================== 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 "mitkPASlicedVolumeGenerator.h" #include mitk::pa::SlicedVolumeGenerator::SlicedVolumeGenerator(int centralYSlice, bool precorrect, Volume::Pointer precorrectionVolume, bool inverse) { m_CentralYSlice = centralYSlice; m_Precorrect = precorrect; m_Inverse = inverse; m_PrecorrectionVolume = nullptr; if (m_Precorrect) { m_PrecorrectionVolume = precorrectionVolume; } } mitk::pa::SlicedVolumeGenerator::~SlicedVolumeGenerator() { m_CentralYSlice = -1; m_Precorrect = false; m_PrecorrectionVolume = nullptr; } mitk::pa::Volume::Pointer mitk::pa::SlicedVolumeGenerator::GetSlicedFluenceImageFromComposedVolume( ComposedVolume::Pointer composedVolume) { int fluenceComponents = composedVolume->GetNumberOfFluenceComponents(); int xDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetXDim(); int zDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetZDim(); auto* imageArray = new double[xDim*zDim*fluenceComponents]; for (int fluenceComponentIdx = 0; fluenceComponentIdx < fluenceComponents; fluenceComponentIdx++) for (int z = 0; z < zDim; z++) for (int x = 0; x < xDim; x++) { int index = z * xDim * fluenceComponents + x * fluenceComponents + fluenceComponentIdx; imageArray[index] = composedVolume->GetFluenceValue(fluenceComponentIdx, x, m_CentralYSlice, z); if (m_Precorrect) { imageArray[index] = imageArray[index] / m_PrecorrectionVolume->GetData(x, m_CentralYSlice, z); } if (m_Inverse) { - if (abs(imageArray[index] - 0) >= mitk::eps) + if (std::abs(imageArray[index] - 0) >= mitk::eps) imageArray[index] = 1 / imageArray[index]; else imageArray[index] = INFINITY; } } return mitk::pa::Volume::New(imageArray, xDim, fluenceComponents, zDim); } mitk::pa::Volume::Pointer mitk::pa::SlicedVolumeGenerator::GetSlicedSignalImageFromComposedVolume( ComposedVolume::Pointer composedVolume) { int fluenceComponents = composedVolume->GetNumberOfFluenceComponents(); int xDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetXDim(); int zDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetZDim(); auto* imageArray = new double[xDim*zDim*fluenceComponents]; for (int fluenceComponentIdx = 0; fluenceComponentIdx < fluenceComponents; fluenceComponentIdx++) for (int z = 0; z < zDim; z++) for (int x = 0; x < xDim; x++) { int y = m_CentralYSlice + composedVolume->GetYOffsetForFluenceComponentInPixels(fluenceComponentIdx); imageArray[z * xDim * fluenceComponents + x * fluenceComponents + fluenceComponentIdx] = composedVolume->GetFluenceValue(fluenceComponentIdx, x, m_CentralYSlice, z) * composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetData(x, y, z); } return mitk::pa::Volume::New(imageArray, xDim, fluenceComponents, zDim); } mitk::pa::Volume::Pointer mitk::pa::SlicedVolumeGenerator::GetSlicedGroundTruthImageFromComposedVolume( ComposedVolume::Pointer composedVolume) { int fluenceComponents = composedVolume->GetNumberOfFluenceComponents(); int xDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetXDim(); int zDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetZDim(); auto* imageArray = new double[xDim*zDim*fluenceComponents]; for (int fluenceComponentIdx = 0; fluenceComponentIdx < fluenceComponents; fluenceComponentIdx++) for (int z = 0; z < zDim; z++) for (int x = 0; x < xDim; x++) { int y = m_CentralYSlice + composedVolume->GetYOffsetForFluenceComponentInPixels(fluenceComponentIdx); imageArray[z * xDim * fluenceComponents + x * fluenceComponents + fluenceComponentIdx] = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetData(x, y, z); } return mitk::pa::Volume::New(imageArray, xDim, fluenceComponents, zDim); } diff --git a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp index f645fe37f6..635af167d0 100644 --- a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp +++ b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp @@ -1,440 +1,440 @@ /*=================================================================== 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 "mitkImageLiveWireContourModelFilter.h" #include #include #include #include "mitkIOUtil.h" mitk::ImageLiveWireContourModelFilter::ImageLiveWireContourModelFilter() { OutputType::Pointer output = dynamic_cast(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(this->ProcessObject::GetInput(idx))) { this->ProcessObject::SetNthInput(idx, const_cast(input)); this->Modified(); AccessFixedDimensionByItk(input, ItkPreProcessImage, 2); } } const mitk::ImageLiveWireContourModelFilter::InputType *mitk::ImageLiveWireContourModelFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetInput(0)); } const mitk::ImageLiveWireContourModelFilter::InputType *mitk::ImageLiveWireContourModelFilter::GetInput( unsigned int idx) { if (this->GetNumberOfInputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetInput(idx)); } void mitk::ImageLiveWireContourModelFilter::GenerateData() { mitk::Image::ConstPointer input = dynamic_cast(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); // 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 void mitk::ImageLiveWireContourModelFilter::ItkPreProcessImage(const itk::Image *inputImage) { typedef itk::Image InputImageType; typedef itk::CastImageFilter 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] = abs(startPoint[0] - endPoint[0]) + 1; - size[1] = abs(startPoint[1] - endPoint[1]) + 1; + 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(this->MakeOutput(0).GetPointer()); this->SetNthOutput(0, output.GetPointer()); // OutputType::Pointer output = dynamic_cast ( this->GetOutput() ); output->Expand(m_TimeStep + 1); // output->Clear(); mitk::Image::ConstPointer input = dynamic_cast(this->GetInput()); ShortestPathType::const_iterator pathIterator = shortestPath.begin(); while (pathIterator != shortestPath.end()) { mitk::Point3D currentPoint; currentPoint[0] = static_cast((*pathIterator)[0]); currentPoint[1] = static_cast((*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(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 void mitk::ImageLiveWireContourModelFilter::CreateDynamicCostMapByITK( const itk::Image *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> shortestPath; mitk::Image::ConstPointer input = dynamic_cast(this->GetInput()); if (path == nullptr) { OutputType::Pointer output = this->GetOutput(); auto it = output->IteratorBegin(); while (it != output->IteratorEnd()) { itk::Index 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 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> GradientMagnitudeFilterType; typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New(); gradientFilter->SetInput(inputImage); gradientFilter->Update(); typename itk::Image::Pointer gradientMagnImage = gradientFilter->GetOutput(); // get the path // iterator of path auto pathIterator = shortestPath.begin(); std::map 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(gradientMagnImage->GetPixel((*pathIterator)) * ImageLiveWireContourModelFilter::CostFunctionType::MAPSCALEFACTOR)] += 1; pathIterator++; } double max = 1.0; if (!histogram.empty()) { std::map::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::key_type keyOfMax = itMAX->first; // compute the to max of gaussian summation auto end = histogram.end(); auto last = --(histogram.end()); std::map::iterator left2; std::map::iterator left1; std::map::iterator right1; std::map::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); }