/*========================================================================= * * 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 itkLevelSetEvolution_hxx #define itkLevelSetEvolution_hxx namespace itk { template LevelSetEvolution>::LevelSetEvolution() : m_IdListToProcessWhenThreading(nullptr) { this->m_SplitLevelSetComputeIterationThreader = SplitLevelSetComputeIterationThreaderType::New(); this->m_SplitDomainMapComputeIterationThreader = SplitDomainMapComputeIterationThreaderType::New(); this->m_SplitLevelSetUpdateLevelSetsThreader = SplitLevelSetUpdateLevelSetsThreaderType::New(); } template void LevelSetEvolution>::AllocateUpdateBuffer() { this->m_UpdateBuffer = LevelSetContainerType::New(); this->m_UpdateBuffer->CopyInformationAndAllocate(this->m_LevelSetContainer, true); } template void LevelSetEvolution>::SetNumberOfWorkUnits( const ThreadIdType numberOfThreads) { this->m_SplitLevelSetComputeIterationThreader->SetMaximumNumberOfThreads(numberOfThreads); this->m_SplitDomainMapComputeIterationThreader->SetMaximumNumberOfThreads(numberOfThreads); this->m_SplitLevelSetUpdateLevelSetsThreader->SetMaximumNumberOfThreads(numberOfThreads); } template ThreadIdType LevelSetEvolution>::GetNumberOfWorkUnits() const { return this->m_SplitDomainMapComputeIterationThreader->GetMaximumNumberOfThreads(); } template void LevelSetEvolution>::ComputeIteration() { InputImageConstPointer inputImage = this->m_EquationContainer->GetInput(); if (this->m_LevelSetContainer->HasDomainMap()) { typename DomainMapImageFilterType::ConstPointer domainMapFilter = this->m_LevelSetContainer->GetDomainMapFilter(); using DomainMapType = typename DomainMapImageFilterType::DomainMapType; const DomainMapType domainMap = domainMapFilter->GetDomainMap(); auto mapIt = domainMap.begin(); auto mapEnd = domainMap.end(); const ThreadIdType maximumNumberOfThreads = this->m_SplitDomainMapComputeIterationThreader->GetMaximumNumberOfThreads(); using DomainMapDomainType = typename SplitDomainMapComputeIterationThreaderType::DomainType; DomainMapDomainType subdomain; DomainMapDomainType completeDomain(mapIt, mapEnd); const typename SplitDomainMapComputeIterationThreaderType::DomainPartitionerType * domainParitioner = this->m_SplitDomainMapComputeIterationThreader->GetDomainPartitioner(); const ThreadIdType numberOfThreadsThatWillBeUsed = domainParitioner->PartitionDomain(0, maximumNumberOfThreads, completeDomain, subdomain); // If we do not have enough domains to process one per thread. if (numberOfThreadsThatWillBeUsed < maximumNumberOfThreads) { // split up each level set individually while (mapIt != mapEnd) { using LevelSetListImageDomainType = typename DomainMapImageFilterType::LevelSetDomain; const LevelSetListImageDomainType & levelSetListImageDomain = mapIt->second; this->m_IdListToProcessWhenThreading = levelSetListImageDomain.GetIdList(); this->m_SplitLevelSetComputeIterationThreader->Execute(this, *(levelSetListImageDomain.GetRegion())); ++mapIt; } } else { // process a level set domain in every thread this->m_SplitDomainMapComputeIterationThreader->Execute(this, completeDomain); } } else // assume there is one level set that covers the RequestedRegion of the InputImage { this->m_SplitLevelSetComputeIterationThreader->Execute(this, inputImage->GetRequestedRegion()); } } template void LevelSetEvolution>::ComputeTimeStepForNextIteration() { // if the time step is not globally set if (!this->m_UserGloballyDefinedTimeStep) { if ((this->m_Alpha > LevelSetOutputRealType{}) && (this->m_Alpha < NumericTraits::OneValue())) { LevelSetOutputRealType contribution = this->m_EquationContainer->ComputeCFLContribution(); contribution = 1; if (contribution > NumericTraits::epsilon()) { this->m_Dt = this->m_Alpha / contribution; } else { if (Math::ExactlyEquals(contribution, NumericTraits::max())) { itkGenericExceptionMacro("contribution is " << contribution); } else { itkGenericExceptionMacro("contribution is too low"); } } } else { itkGenericExceptionMacro("m_Alpha should be in ]0,1["); } } } template void LevelSetEvolution>::UpdateLevelSets() { this->m_LevelSetContainerIteratorToProcessWhenThreading = this->m_LevelSetContainer->Begin(); this->m_LevelSetUpdateContainerIteratorToProcessWhenThreading = this->m_UpdateBuffer->Begin(); while (this->m_LevelSetContainerIteratorToProcessWhenThreading != this->m_LevelSetContainer->End()) { typename LevelSetType::Pointer levelSet = this->m_LevelSetContainerIteratorToProcessWhenThreading->GetLevelSet(); typename LevelSetImageType::ConstPointer levelSetImage = levelSet->GetImage(); this->m_SplitLevelSetUpdateLevelSetsThreader->Execute(this, levelSetImage->GetRequestedRegion()); ++(this->m_LevelSetContainerIteratorToProcessWhenThreading); ++(this->m_LevelSetUpdateContainerIteratorToProcessWhenThreading); } this->ReinitializeToSignedDistance(); } template void LevelSetEvolution>::UpdateEquations() { this->InitializeIteration(); } template void LevelSetEvolution>::ReinitializeToSignedDistance() { typename LevelSetContainerType::Iterator it = this->m_LevelSetContainer->Begin(); while (it != this->m_LevelSetContainer->End()) { typename LevelSetImageType::Pointer image = it->GetLevelSet()->GetModifiableImage(); ThresholdFilterPointer thresh = ThresholdFilterType::New(); thresh->SetLowerThreshold(NumericTraits::NonpositiveMin()); thresh->SetUpperThreshold(LevelSetOutputType{}); thresh->SetInsideValue(NumericTraits::OneValue()); thresh->SetOutsideValue(LevelSetOutputType{}); thresh->SetInput(image); thresh->Update(); MaurerPointer maurer = MaurerType::New(); maurer->SetInput(thresh->GetOutput()); maurer->SetSquaredDistance(false); maurer->SetUseImageSpacing(true); maurer->SetInsideIsPositive(false); maurer->Update(); image->Graft(maurer->GetOutput()); ++it; } } // Whitaker -------------------------------------------------------------------- template LevelSetEvolution>::LevelSetEvolution() { this->m_SplitLevelSetComputeIterationThreader = SplitLevelSetComputeIterationThreaderType::New(); } template LevelSetEvolution>::~LevelSetEvolution() { typename LevelSetContainerType::ConstIterator it = this->m_LevelSetContainer->Begin(); while (it != this->m_LevelSetContainer->End()) { delete this->m_UpdateBuffer[it->GetIdentifier()]; ++it; } } template void LevelSetEvolution>::SetNumberOfWorkUnits( const ThreadIdType numberOfWorkUnits) { this->m_SplitLevelSetComputeIterationThreader->SetNumberOfWorkUnits(numberOfWorkUnits); } template ThreadIdType LevelSetEvolution>::GetNumberOfWorkUnits() const { return this->m_SplitLevelSetComputeIterationThreader->GetNumberOfWorkUnits(); } template void LevelSetEvolution>::AllocateUpdateBuffer() { typename LevelSetContainerType::Iterator it = this->m_LevelSetContainer->Begin(); while (it != this->m_LevelSetContainer->End()) { const IdentifierType identifier = it->GetIdentifier(); if (this->m_UpdateBuffer.find(identifier) == this->m_UpdateBuffer.end()) { this->m_UpdateBuffer[identifier] = new LevelSetLayerType; } else { if (this->m_UpdateBuffer[identifier]) { this->m_UpdateBuffer[identifier]->clear(); } else { this->m_UpdateBuffer[identifier] = new LevelSetLayerType; } } ++it; } } template void LevelSetEvolution>::ComputeIteration() { this->m_LevelSetContainerIteratorToProcessWhenThreading = this->m_LevelSetContainer->Begin(); while (this->m_LevelSetContainerIteratorToProcessWhenThreading != this->m_LevelSetContainer->End()) { typename LevelSetType::ConstPointer levelSet = this->m_LevelSetContainerIteratorToProcessWhenThreading->GetLevelSet(); const LevelSetLayerType zeroLayer = levelSet->GetLayer(0); auto layerBegin = zeroLayer.begin(); auto layerEnd = zeroLayer.end(); typename SplitLevelSetPartitionerType::DomainType completeDomain(layerBegin, layerEnd); this->m_SplitLevelSetComputeIterationThreader->Execute(this, completeDomain); ++(this->m_LevelSetContainerIteratorToProcessWhenThreading); } } template void LevelSetEvolution>::ComputeTimeStepForNextIteration() { if (!this->m_UserGloballyDefinedTimeStep) { if ((this->m_Alpha > LevelSetOutputRealType{}) && (this->m_Alpha < NumericTraits::OneValue())) { LevelSetOutputRealType contribution = this->m_EquationContainer->ComputeCFLContribution(); if (contribution > NumericTraits::epsilon()) { this->m_Dt = this->m_Alpha / contribution; } else { if (Math::ExactlyEquals(contribution, NumericTraits::max())) { itkGenericExceptionMacro("contribution is " << contribution); } else { itkGenericExceptionMacro("contribution is too low " << contribution); } } } else { itkGenericExceptionMacro("m_Alpha should be in ]0,1["); } } } template void LevelSetEvolution>::UpdateLevelSets() { typename LevelSetContainerType::Iterator it = this->m_LevelSetContainer->Begin(); while (it != this->m_LevelSetContainer->End()) { typename LevelSetType::Pointer levelSet = it->GetLevelSet(); UpdateLevelSetFilterPointer updateLevelSet = UpdateLevelSetFilterType::New(); updateLevelSet->SetInputLevelSet(levelSet); updateLevelSet->SetUpdate(*this->m_UpdateBuffer[it->GetIdentifier()]); updateLevelSet->SetEquationContainer(this->m_EquationContainer); updateLevelSet->SetTimeStep(this->m_Dt); updateLevelSet->SetCurrentLevelSetId(it->GetIdentifier()); updateLevelSet->Update(); levelSet->Graft(updateLevelSet->GetOutputLevelSet()); this->m_RMSChangeAccumulator = updateLevelSet->GetRMSChangeAccumulator(); this->m_UpdateBuffer[it->GetIdentifier()]->clear(); ++it; } } template void LevelSetEvolution>::UpdateEquations() { this->m_EquationContainer->UpdateInternalEquationTerms(); } // Shi template void LevelSetEvolution>::UpdateLevelSets() { typename LevelSetContainerType::Iterator it = this->m_LevelSetContainer->Begin(); while (it != this->m_LevelSetContainer->End()) { typename LevelSetType::Pointer levelSet = it->GetLevelSet(); UpdateLevelSetFilterPointer updateLevelSet = UpdateLevelSetFilterType::New(); updateLevelSet->SetInputLevelSet(levelSet); updateLevelSet->SetCurrentLevelSetId(it->GetIdentifier()); updateLevelSet->SetEquationContainer(this->m_EquationContainer); updateLevelSet->Update(); levelSet->Graft(updateLevelSet->GetOutputLevelSet()); this->m_RMSChangeAccumulator = updateLevelSet->GetRMSChangeAccumulator(); ++it; } } template void LevelSetEvolution>::UpdateEquations() { this->m_EquationContainer->UpdateInternalEquationTerms(); } // Malcolm template void LevelSetEvolution>::UpdateLevelSets() { typename LevelSetContainerType::Iterator it = this->m_LevelSetContainer->Begin(); while (it != this->m_LevelSetContainer->End()) { typename LevelSetType::Pointer levelSet = it->GetLevelSet(); LevelSetIdentifierType levelSetId = it->GetIdentifier(); UpdateLevelSetFilterPointer updateLevelSet = UpdateLevelSetFilterType::New(); updateLevelSet->SetInputLevelSet(levelSet); updateLevelSet->SetCurrentLevelSetId(levelSetId); updateLevelSet->SetEquationContainer(this->m_EquationContainer); updateLevelSet->Update(); levelSet->Graft(updateLevelSet->GetOutputLevelSet()); this->m_RMSChangeAccumulator = updateLevelSet->GetRMSChangeAccumulator(); ++it; } } template void LevelSetEvolution>::UpdateEquations() { this->m_EquationContainer->UpdateInternalEquationTerms(); } } // namespace itk #endif // itkLevelSetEvolution_hxx