#ifndef itkSkeletonizationImageFilter_txx #define itkSkeletonizationImageFilter_txx #include #include #include #include #include "itkHierarchicalQueue.h" #include "itkLineTerminalityImageFunction.h" #include "itkSimplicityByTopologicalNumbersImageFunction.h" #include "itkSkeletonizeImageFilter.h" namespace itk { template void SkeletonizeImageFilter ::SetOrderingImage(OrderingImageType *input) { // Process object is not const-correct so the const casting is required. this->SetNthInput( 1, const_cast(input) ); } template typename SkeletonizeImageFilter::OrderingImageType * SkeletonizeImageFilter ::GetOrderingImage() { return static_cast( const_cast(this->ProcessObject::GetInput(1)) ); } template SkeletonizeImageFilter ::SkeletonizeImageFilter() : m_SimplicityCriterion(0), m_TerminalityCriterion(0) { this->SetNumberOfRequiredInputs(2); } 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 ::GenerateInputRequestedRegion() { // call the superclass' implementation of this method Superclass::GenerateInputRequestedRegion(); // get pointers to the inputs typename OrderingImageType::Pointer orderingPtr = this->GetOrderingImage(); typename TImage::Pointer inputPtr = const_cast(this->GetInput()); if ( !orderingPtr || !inputPtr ) { return; } // We need to // configure the inputs such that all the data is available. // orderingPtr->SetRequestedRegion(orderingPtr->GetLargestPossibleRegion()); inputPtr->SetRequestedRegion(inputPtr->GetLargestPossibleRegion()); } template void SkeletonizeImageFilter ::GenerateData() { this->AllocateOutputs(); typename OrderingImageType::Pointer orderingImage = this->GetOrderingImage(); 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 HierarchicalQueue > q; bool* inQueue = new bool[outputImage->GetRequestedRegion().GetNumberOfPixels()]; // set up progress reporter. There is 2 steps, but we can't know how many // pixels will be in the second one, so use the maximum ProgressReporter progress(this, 0, outputImage->GetRequestedRegion().GetNumberOfPixels()*2); for(ImageRegionConstIteratorWithIndex it(orderingImage, 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; } progress.CompletedPixel(); } ForegroundConnectivity const & connectivity = ForegroundConnectivity::GetInstance(); while(!q.IsEmpty()) { typename InputImageType::IndexType const current = q.GetFront(); 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( /* currentNeighbor is in image */ outputImage->GetPixel(currentNeighbor) != NumericTraits::Zero && /* and not in queue */ !inQueue[outputImage->ComputeOffset(currentNeighbor)] && /*and has not 0 priority*/ orderingImage->GetPixel(currentNeighbor) != NumericTraits::Zero ) { q.Push(orderingImage->GetPixel(currentNeighbor), currentNeighbor); inQueue[outputImage->ComputeOffset(currentNeighbor)] = true; } } } progress.CompletedPixel(); } delete[] inQueue; } } // namespace itk #endif // itkSkeletonizationImageFilter_txx