/*========================================================================= * * 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 itkWatershedSegmentTreeGenerator_h #define itkWatershedSegmentTreeGenerator_h #include "itkWatershedSegmentTable.h" #include "itkWatershedSegmentTree.h" #include "itkEquivalencyTable.h" #include #include namespace itk { namespace watershed { /** * \class SegmentTreeGenerator * This filter is a process object class that implements a step in the N-d * watershed segmentation algorithm. It produces an ordered list (SegmentTree) * of binary merges between segments at increasing saliency levels. This * filter is used in conjunction with WatershedSegmenter and WatershedRelabeler * to process an initial segmentation into a final relabeled volume. See * itk::WatershedImageFilter for an overview of watershed segmentation. * * \par Inputs * There are two inputs to this filter, the second is optional. * (1) A table of segments (SegmentTable) derived from a labeled image. * (2) Optionally, a table of predetermined equivalencies among segments * (EquivalencyTable), necessary for streaming applications where * segments may be joined across streamed chunk boundaries. The flag * Merge must be set to true to enable this functionality. * * \par Outputs * The output of this filter is a list of binary merges of segments at * increasing saliency. This is the data structure * itk::watershed::SegmentTree referred to as a "merge tree" in the * itk::WatershedImageFilter documentation. * * \par Parameters * There are two parameters to this filter described below. * * \par * FloodLevel is specified as a percentage (0.0 - 1.0) of the maximum possible * saliency value in the initial image from which the segment table was * derived. A value of 0.0 calculates no merges. A value of 1.0 calculates * all of the potential merges that can occur as the FloodLevel is increased to * the maximum saliency value. Typically, there is no need to calculate merges * past about 40% of the total depth. Because this is the most computationally * intensive piece of the watershed segmentation algorithm, it is a good idea * to tune this parameter as low as possible on larger volumes. * * \par * Merge is a boolean flag indicating whether or not to pre-merge the segments * marked as equivalent in the EquivalencyTable. This is only useful for * streaming applications and is turned off by default. (TRUE == merge, FALSE * == do not merge). * \sa itk::WatershedImageFilter * \ingroup WatershedSegmentation * \ingroup ITKWatersheds */ template class ITK_TEMPLATE_EXPORT SegmentTreeGenerator : public ProcessObject { public: ITK_DISALLOW_COPY_AND_MOVE(SegmentTreeGenerator); /** Standard itk smart pointer declarations */ using Self = SegmentTreeGenerator; using Superclass = ProcessObject; using Pointer = SmartPointer; using ConstPointer = SmartPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); itkOverrideGetNameOfClassMacro(SegmentTreeGenerator); /** Convenient type definitions */ using ScalarType = TScalar; using SegmentTableType = SegmentTable; using SegmentTreeType = SegmentTree; using EquivalencyTableType = EquivalencyTable; using OneWayEquivalencyTableType = OneWayEquivalencyTable; using DataObjectPointer = DataObject::Pointer; /** Typedefs to avoid internal compiler error bug on Microsoft VC++ */ using SegmentTableTypePointer = typename SegmentTableType::Pointer; using OneWayEquivalencyTableTypePointer = typename OneWayEquivalencyTableType::Pointer; using SegmentTreeTypePointer = typename SegmentTreeType::Pointer; /** Get/Set the input table of segments to process */ SegmentTableType * GetInputSegmentTable() { return static_cast(this->ProcessObject::GetInput(0)); } void SetInputSegmentTable(SegmentTableType * st) { // Reset the highest calculated flood level if we are given a // different input image. if (st != this->GetInput(0)) { m_HighestCalculatedFloodLevel = 0.0; } this->ProcessObject::SetNthInput(0, st); } /** Get/Set input table of equivalencies to pre-merge before * running the tree generator algorithm. Only useful for * streaming applications */ void SetInputEquivalencyTable(EquivalencyTableType * eq) { this->ProcessObject::SetNthInput(1, eq); } EquivalencyTableType * GetInputEquivalencyTable() { return static_cast(this->ProcessObject::GetInput(1)); } /** Get/Set the output data */ SegmentTreeType * GetOutputSegmentTree() { return static_cast(this->ProcessObject::GetOutput(0)); } /** Standard non-threaded itk pipeline method */ void GenerateData() override; /** Get/Set a boolean flag indicating whether or not to pre-merge the segments marked as equivalent in the EquivalencyTable. This is only useful for streaming applications and is turned off by default. (TRUE == merge, FALSE == do not merge). */ itkSetMacro(Merge, bool); itkGetConstMacro(Merge, bool); /** Get/Set FloodLevel. FloodLevel is specified as a percentage (0.0 - 1.0) of the maximum possible saliency value in the initial image from which the segment table was derived. A value of 0.0 calculates no merges. A value of 1.0 calculates all of the potential merges that can occur as the FloodLevel is increased to the maximum saliency value. */ void SetFloodLevel(double); itkGetConstMacro(FloodLevel, double); /** Get/Set HighestCalculatedFloodLevel. HighestCalculatedFloodLevel keeps * track of the highest level this filter has computed. It is * used to prevent unnecessary re-execution of the filter. */ itkSetMacro(HighestCalculatedFloodLevel, double); itkGetConstMacro(HighestCalculatedFloodLevel, double); /** Get/Set a flag that prevents the filter from copying its input * segment table before executing. This can be enabled to conserve * memory, especially in streaming applications where memory is a * concern. If enabled, the input to this filter must always be * re-executed on updates. Default is false. */ itkSetMacro(ConsumeInput, bool); itkGetConstMacro(ConsumeInput, bool); /** Performs a merge of two segments in a SegmentTable according * to criteria specific to this algorithm. */ static void MergeSegments(SegmentTableTypePointer, OneWayEquivalencyTableTypePointer, const IdentifierType, const IdentifierType); /** This method should not be used. It will be removed in future versions * of this filter. */ static void PruneMergeSegments(SegmentTableTypePointer, OneWayEquivalencyTableTypePointer, const IdentifierType, const IdentifierType, ScalarType); /** Standard itk::ProcessObject subclass method. */ using DataObjectPointerArraySizeType = ProcessObject::DataObjectPointerArraySizeType; using Superclass::MakeOutput; DataObjectPointer MakeOutput(DataObjectPointerArraySizeType idx) override; protected: SegmentTreeGenerator(); ~SegmentTreeGenerator() override = default; void PrintSelf(std::ostream & os, Indent indent) const override; /** Generates an initial list of all potential merges in * the segment table. */ void CompileMergeList(SegmentTableTypePointer, SegmentTreeTypePointer); /** Compiles a list of all the actual segment merges up to the specified * flood level, recomputing new potential merges as it goes. */ void ExtractMergeHierarchy(SegmentTableTypePointer, SegmentTreeTypePointer); void MergeEquivalencies(); /** Methods required by the itk pipeline */ void GenerateOutputRequestedRegion(DataObject * output) override; void GenerateInputRequestedRegion() override; private: bool m_Merge{ false }; double m_FloodLevel{ 0.0 }; bool m_ConsumeInput{ false }; using HashMapType = std::unordered_map; OneWayEquivalencyTableType::Pointer m_MergedSegmentsTable{}; /** This value keeps track of the highest level this filter has been * calculated. m_FloodLevel can be manipulated anywhere below this * level without re-executing the filter, preventing unnecessary * updates. */ double m_HighestCalculatedFloodLevel{ 0.0 }; }; } // end namespace watershed } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION # include "itkWatershedSegmentTreeGenerator.hxx" #endif #endif