/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkShapedFloodFilledFunctionConditionalConstIterator_hxx #define itkShapedFloodFilledFunctionConditionalConstIterator_hxx #include "itkImageRegionConstIterator.h" namespace itk { template ShapedFloodFilledFunctionConditionalConstIterator::ShapedFloodFilledFunctionConditionalConstIterator( const ImageType * imagePtr, FunctionType * fnPtr, IndexType startIndex) : m_FullyConnected(false) { this->m_Image = imagePtr; m_Function = fnPtr; m_Seeds.push_back(startIndex); // Set up the temporary image this->InitializeIterator(); } template ShapedFloodFilledFunctionConditionalConstIterator::ShapedFloodFilledFunctionConditionalConstIterator( const ImageType * imagePtr, FunctionType * fnPtr, std::vector & startIndex) : m_Function(fnPtr) , m_FullyConnected(false) { this->m_Image = imagePtr; // can not be done in the initialization list unsigned int i; for (i = 0; i < startIndex.size(); ++i) { m_Seeds.push_back(startIndex[i]); } // Set up the temporary image this->InitializeIterator(); } template ShapedFloodFilledFunctionConditionalConstIterator::ShapedFloodFilledFunctionConditionalConstIterator( const ImageType * imagePtr, FunctionType * fnPtr) : m_FullyConnected(false) { this->m_Image = imagePtr; m_Function = fnPtr; // Set up the temporary image this->InitializeIterator(); } template void ShapedFloodFilledFunctionConditionalConstIterator::InitializeIterator() { // Get the origin and spacing from the image in simple arrays m_ImageOrigin = this->m_Image->GetOrigin(); m_ImageSpacing = this->m_Image->GetSpacing(); m_ImageRegion = this->m_Image->GetBufferedRegion(); // Build and setup the neighborhood iterator typename NeighborhoodIteratorType::RadiusType radius; radius.Fill(1); NeighborhoodIteratorType tmp_iter(radius, this->m_Image, m_ImageRegion); m_NeighborhoodIterator = tmp_iter; setConnectivity(&m_NeighborhoodIterator, m_FullyConnected); // Build a temporary image of chars for use in the flood algorithm m_TempPtr = TTempImage::New(); typename TTempImage::RegionType tempRegion = this->m_Image->GetBufferedRegion(); m_TempPtr->SetRegions(tempRegion); m_TempPtr->AllocateInitialized(); // Initialize the queue by adding the start index assuming one of // the m_Seeds is "inside" This might not be true, in which // case it's up to the programmer to specify a correct starting // position later (using FindSeedPixel). Must make sure that the // seed is inside the buffer before touching pixels. this->m_IsAtEnd = true; for (unsigned int i = 0; i < m_Seeds.size(); ++i) { if (m_ImageRegion.IsInside(m_Seeds[i])) { m_IndexStack.push(m_Seeds[i]); this->m_IsAtEnd = false; } } } template void ShapedFloodFilledFunctionConditionalConstIterator::FindSeedPixel() { // Create an iterator that will walk the input image using IRIType = typename itk::ImageRegionConstIterator; // Now we search the input image for the first pixel which is inside // the function of interest m_Seeds.clear(); for (IRIType it(this->m_Image, this->m_Image->GetBufferedRegion()); !it.IsAtEnd(); ++it) { if (this->IsPixelIncluded(it.GetIndex())) { m_Seeds.push_back(it.GetIndex()); // We need to reset the "beginning" now that we have a real seed this->GoToBegin(); return; } } } template void ShapedFloodFilledFunctionConditionalConstIterator::FindSeedPixels() { // Create an iterator that will walk the input image using IRIType = typename itk::ImageRegionConstIterator; // Now we search the input image for the first pixel which is inside // the function of interest m_Seeds.clear(); bool found = false; for (IRIType it(this->m_Image, this->m_Image->GetBufferedRegion()); !it.IsAtEnd(); ++it) { if (this->IsPixelIncluded(it.GetIndex())) { m_Seeds.push_back(it.GetIndex()); found = true; } } if (found) { // We need to reset the "beginning" now that we have a real seed this->GoToBegin(); } } template void ShapedFloodFilledFunctionConditionalConstIterator::DoFloodStep() { // The index in the front of the queue should always be // valid and be inside since this is what the iterator // uses in the Set/Get methods. This is ensured by the // GoToBegin() method. // Take the index in the front of the queue const IndexType & topIndex = m_IndexStack.front(); // We are explicitly not calling set location since only offsets of // the neighborhood iterator are accessed. typename NeighborhoodIteratorType::ConstIterator neighborIt = m_NeighborhoodIterator.Begin(); const typename NeighborhoodIteratorType::ConstIterator neighborEnd = m_NeighborhoodIterator.End(); for (; neighborIt != neighborEnd; ++neighborIt) { const OffsetType & offset = neighborIt.GetNeighborhoodOffset(); const IndexType tempIndex = topIndex + offset; // If this is a valid index and have not been tested, // then test it. if (m_ImageRegion.IsInside(tempIndex)) { if (m_TempPtr->GetPixel(tempIndex) == 0) { // if it is inside, push it into the queue if (this->IsPixelIncluded(tempIndex)) { m_IndexStack.push(tempIndex); m_TempPtr->SetPixel(tempIndex, 2); } else // If the pixel is outside { // Mark the pixel as outside and remove it from the queue. m_TempPtr->SetPixel(tempIndex, 1); } } } } // Finished traversing neighbors // Now that all the potential neighbors have been // inserted we can get rid of the pixel in the front m_IndexStack.pop(); if (m_IndexStack.empty()) { this->m_IsAtEnd = true; } } template void ShapedFloodFilledFunctionConditionalConstIterator::SetFullyConnected(const bool _arg) { if (this->m_FullyConnected != _arg) { this->m_FullyConnected = _arg; setConnectivity(&m_NeighborhoodIterator, m_FullyConnected); } } template bool ShapedFloodFilledFunctionConditionalConstIterator::GetFullyConnected() const { return this->m_FullyConnected; } } // end namespace itk #endif