#ifndef itkSkeletonizationImageFilter_txx #define itkSkeletonizationImageFilter_txx #include #include #include #include "hierarchical_queue.h" #include "itkLineTerminalityImageFunction.h" #include "itkSimplicityByTopologicalNumbersImageFunction.h" namespace itk { template SkeletonizeImageFilter ::SkeletonizeImageFilter() : m_OrderingImage(0), m_SimplicityCriterion(0), m_TerminalityCriterion(0) { } template void SkeletonizeImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); os << indent << "Cell dimension used for foreground connectivity: " << ForegroundConnectivity::CellDimension << std::endl; } template void SkeletonizeImageFilter ::GenerateData() { this->AllocateOutputs(); if(m_OrderingImage.IsNull()) { itkExceptionMacro("No distance map available, cannot skeletonize image"); } if(m_SimplicityCriterion.IsNull()) { m_SimplicityCriterion = SimplicityByTopologicalNumbersImageFunction::New(); m_SimplicityCriterion->SetInputImage(this->GetInput()); } if(m_TerminalityCriterion.IsNull()) { m_TerminalityCriterion = LineTerminalityImageFunction::New(); m_TerminalityCriterion->SetInputImage(this->GetInput()); } typename OutputImageType::Pointer outputImage = this->GetOutput(0); // Initialize hierarchical queue hierarchical_queue > q; bool* inQueue = new bool[ outputImage->GetRequestedRegion().GetNumberOfPixels() ]; for(ImageRegionConstIteratorWithIndex it(m_OrderingImage, m_OrderingImage->GetRequestedRegion()); !it.IsAtEnd(); ++it) { if(it.Get() != NumericTraits::Zero ) { q.push(it.Get(), it.GetIndex()); inQueue[ outputImage->ComputeOffset(it.GetIndex()) ] = true; } else { inQueue[ outputImage->ComputeOffset(it.GetIndex()) ] = false; } } ForegroundConnectivity const & connectivity = ForegroundConnectivity::GetInstance(); while(!q.empty()) { typename InputImageType::IndexType const current = q.front(); q.pop(); inQueue[outputImage->ComputeOffset(current)] = false; bool const terminal = m_TerminalityCriterion->EvaluateAtIndex(current); bool const simple = m_SimplicityCriterion->EvaluateAtIndex(current); if( simple && !terminal ) { outputImage->SetPixel(current, NumericTraits::Zero); // Add neighbors that are not already in the queue for(unsigned int i = 0; i < connectivity.GetNumberOfNeighbors(); ++i) { typename InputImageType::IndexType currentNeighbor; for(unsigned int j = 0; j < ForegroundConnectivity::Dimension; ++j) { currentNeighbor[j] = current[j] + connectivity.GetNeighborsPoints()[i][j]; } if( /*outputImage->GetRequestedRegion().IsInside(currentNeighbor) &&*/ outputImage->GetPixel(currentNeighbor) != NumericTraits::Zero && /* currentNeighbor is in image */ !inQueue[outputImage->ComputeOffset(currentNeighbor)] /* and not in queue */ && m_OrderingImage->GetPixel(currentNeighbor) != NumericTraits::Zero /*and has not 0 priority*/) { q.push(m_OrderingImage->GetPixel(currentNeighbor), currentNeighbor); inQueue[outputImage->ComputeOffset(currentNeighbor)] = true; } } } } delete[] inQueue; } } // namespace itk #endif // itkSkeletonizationImageFilter_txx