3#include "MorphologicalTree.hpp"
4#include "NativeHierarchy.hpp"
5#include "TreeOfShapesProducer.hpp"
6#include "TreeAltitudeAlgorithms.hpp"
7#include "ValuedMorphologicalTree.hpp"
8#include "detail/ComponentTreeProducerDetail.hpp"
9#include "detail/HigraHierarchyAdapterDetail.hpp"
10#include "detail/MorphologicalTreeConstructionTag.hpp"
11#include "detail/NativeHierarchyValidationDetail.hpp"
15#include "../utils/Image.hpp"
16#include "../utils/Contract.hpp"
61 template <AltitudeValue T>
static void validateComponentTreeImage(
const ImagePtr<T>&
img,
const char*
context) {
64 throw std::invalid_argument(std::string(
context) +
" requires a non-empty 2D image."));
74 std::vector<std::uint8_t>
visited(
static_cast<std::size_t
>(numPixels), 0);
76 pending.reserve(
static_cast<std::size_t
>(numPixels));
92 throw std::invalid_argument(
"Component-tree adjacency must induce one connected image-domain graph.");
103 enum class MaterializedVersionPolicy { CanonicalNative, PreserveLinkedConstruction };
114 static constexpr detail::MorphologicalTreeConstructionTag tag()
noexcept {
return detail::MorphologicalTreeConstructionTag{}; }
123 throw std::invalid_argument(
"MorphologicalTreeFactory::createTreeOfShapes requires a non-null image.");
125 if (
img->getNumRows() <= 0 ||
img->getNumColumns() <= 0 ||
img->getSize() <= 0) {
126 throw std::invalid_argument(
"MorphologicalTreeFactory::createTreeOfShapes requires a non-empty 2D image.");
142 static void resolveTopographicImmersion(
TopographicConvention& convention,
int numRows,
int numColumns) {
143 const auto*
canonical = std::get_if<CanonicalComplementaryGridImmersion>(&convention.
immersion);
163 template <AltitudeValue T>
165 materializeNativeHierarchy(detail::ValidatedNativeHierarchy<T>&&
hierarchy, std::optional<NodeId> preservedExternalNodeIdOffset = std::nullopt,
166 MaterializedVersionPolicy
versionPolicy = MaterializedVersionPolicy::CanonicalNative) {
168 const std::size_t numNodes =
storage.parent.size();
171 if (
versionPolicy == MaterializedVersionPolicy::PreserveLinkedConstruction) {
173 topology.mutationVersion_ = numNodes + 1;
175 if (preservedExternalNodeIdOffset) {
176 topology.preserveExternalNodeIdOffset(*preservedExternalNodeIdOffset);
196 validateComponentTreeImage(
img,
"MorphologicalTreeFactory::createMaxTree");
199 throw std::invalid_argument(
"Component-tree adjacency must induce one connected image-domain graph."));
201 detail::kernel::ComponentTreeProducer<T>(detail::kernel::ComponentTreePolarity::MaxTree, std::move(adjacency)).build(
img), std::nullopt,
202 MaterializedVersionPolicy::PreserveLinkedConstruction);
216 validateComponentTreeImage(
img,
"MorphologicalTreeFactory::createMaxTree");
218 throw std::invalid_argument(
"Component-tree adjacency domain must match the input image domain."));
221 detail::kernel::ComponentTreeProducer<T>(detail::kernel::ComponentTreePolarity::MaxTree, std::move(adjacency)).build(
img), std::nullopt,
222 MaterializedVersionPolicy::PreserveLinkedConstruction);
239 validateComponentTreeImage(
img,
"MorphologicalTreeFactory::createMinTree");
242 throw std::invalid_argument(
"Component-tree adjacency must induce one connected image-domain graph."));
244 detail::kernel::ComponentTreeProducer<T>(detail::kernel::ComponentTreePolarity::MinTree, std::move(adjacency)).build(
img), std::nullopt,
245 MaterializedVersionPolicy::PreserveLinkedConstruction);
256 validateComponentTreeImage(
img,
"MorphologicalTreeFactory::createMinTree");
258 throw std::invalid_argument(
"Component-tree adjacency domain must match the input image domain."));
261 detail::kernel::ComponentTreeProducer<T>(detail::kernel::ComponentTreePolarity::MinTree, std::move(adjacency)).build(
img), std::nullopt,
262 MaterializedVersionPolicy::PreserveLinkedConstruction);
277 template <AltitudeValue T>
284 builder.build(
img, std::move(minTree), std::move(maxTree));
298 template <AltitudeValue T>
299 [[nodiscard]]
static ValuedMorphologicalTree<T>
319 template <AltitudeValue T>
320 [[nodiscard]]
static ValuedMorphologicalTree<T>
326 builder.build(
img, std::move(minTree), std::move(maxTree));
341 template <AltitudeValue T>
342 [[nodiscard]]
static ValuedMorphologicalTree<T>
372 template <
class Altitude = std::u
int8_t>
374 validateTreeOfShapesImage(
img);
375 resolveTopographicImmersion(convention,
img->getNumRows(),
img->getNumColumns());
408 template <AltitudeValue T>
429 template <AltitudeValue T>
431 std::span<const T> nodeAltitudes,
NodeId root,
int rows,
int columns,
463 template <AltitudeValue T>
466 std::optional<RegularGridAdjacency2D> adjacency = std::nullopt) {
467 auto imported = detail::adaptHigraHierarchy<T>(parent, nodeAltitudes, rows, columns, kind, std::move(adjacency));
#define MMCFILTERS_CONTRACT_REQUIRE(condition,...)
Evaluates a caller precondition and its failure action only in checked builds.
#define MMCFILTERS_CONTRACT_CHECKED_ONLY(...)
Executes validation statements only when defensive checks are enabled.
std::shared_ptr< ImageUInt8 > ImageUInt8Ptr
Shared pointer to an 8-bit unsigned image.
MorphologicalTreeSemantics makeMorphologicalTreeSemantics(MorphologicalTreeKind kind, MorphologicalTreeConstructionContext constructionContext=NoConstructionContext{})
Constructs semantics using the conventional altitude order of kind.
MorphologicalTreeKind
Declared construction family of one morphological tree.
Normative values used by self-dual residual-tree evolution.
Builder dedicated to the saturated self-dual residual tree.
Builder dedicated to the unrestricted self-dual residual tree.
Public construction facade for all high-level morphological trees.
static ValuedMorphologicalTree< T > createUnrestrictedResidualTree(ImagePtr< T > img, RegularGridAdjacency2D adjacency, sdrt::UnrestrictedResidualTreeOptions options={})
Builds the unrestricted residual tree.
static ValuedMorphologicalTree< T > createSaturatedResidualTree(ImagePtr< T > img, PixelId infinityPixel, double radius=1.5, sdrt::SaturatedResidualTreeOptions options={})
Builds the saturated residual tree with a radius adjacency.
static ValuedMorphologicalTree< T > createMaxTree(ImagePtr< T > img, double radius=1.5)
Builds a typed valuedTree max-tree from an image.
static ValuedMorphologicalTree< T > createUnrestrictedResidualTree(ImagePtr< T > img, double radius=1.5, sdrt::UnrestrictedResidualTreeOptions options={})
Builds the unrestricted residual tree with a radius adjacency.
static ValuedMorphologicalTree< T > createFromHigraParent(std::span< const NodeId > parent, std::span< const T > nodeAltitudes, int rows, int columns, MorphologicalTreeKind kind, std::optional< RegularGridAdjacency2D > adjacency=std::nullopt)
Imports a static Higra parent/altitude hierarchy.
static ValuedMorphologicalTree< T > createFromNativeHierarchy(NativeHierarchyView< T > hierarchy)
Materializes the common output contract of a native producer.
static ValuedMorphologicalTree< T > createSaturatedResidualTree(ImagePtr< T > img, RegularGridAdjacency2D adjacency, PixelId infinityPixel, sdrt::SaturatedResidualTreeOptions options={})
Builds the saturated residual tree.
static ValuedMorphologicalTree< Altitude > createTreeOfShapes(ImageUInt8Ptr img, TopographicConvention convention={})
Builds a valued tree of shapes from an 8-bit image.
static ValuedMorphologicalTree< T > createFromNativeTopology(std::span< const NodeId > parent, std::span< const NodeId > smallestNodeMap, std::span< const T > nodeAltitudes, NodeId root, int rows, int columns, MorphologicalTreeSemantics semantics)
Imports a native hierarchy with a regular 2D pixel layout.
static ValuedMorphologicalTree< T > createFromNativeTopology(std::span< const NodeId > parent, std::span< const NodeId > smallestNodeMap, std::span< const T > nodeAltitudes, NodeId root, MorphologicalTreeSemantics semantics)
Imports a valued connected-subset tree from native buffers.
static ValuedMorphologicalTree< T > createMinTree(ImagePtr< T > img, RegularGridAdjacency2D adjacency)
Builds a min-tree with an explicit regular-grid 2D adjacency.
static ValuedMorphologicalTree< T > createMinTree(ImagePtr< T > img, double radius=1.5)
Builds a typed valuedTree min-tree from an image.
static ValuedMorphologicalTree< T > createMaxTree(ImagePtr< T > img, RegularGridAdjacency2D adjacency)
Builds a max-tree with an explicit regular-grid 2D adjacency.
Mutable connected-subset tree on a finite pixel domain.
Immutable regular-grid 2D adjacency with allocation-free traversal.
int getNumColumns() const noexcept
Returns the number of columns in the attached grid domain.
int getNumRows() const noexcept
Returns the number of rows in the attached grid domain.
NeighborIndexRange getNeighborIndices(int row, int column) const
Returns valid neighbouring grid indices excluding the origin.
static void validateFiniteImageAltitudes(const ImagePtr< T > &image, const char *context)
Rejects non-finite floating-point pixels before using an image as altitude source.
Builds trees of shapes (ToS) using a union-find construction.
Builds the saturated residual tree from synchronized component trees.
Builds the unrestricted residual tree from synchronized component trees.
Ordered pair of complementary minimum and maximum adjacencies.
Selects the optimized complementary-grid immersion.
Owning result for one computed scalar attribute layout and buffer.
Shape metadata optionally attached to the pixel domain.
Immutable scientific interpretation attached to one morphological tree.
Records the shared adjacency and infinity pixel of a saturated residual construction.
Records one adjacency shared by both construction polarities.
Complete discrete convention retained by a tree-of-shapes result.
TreeOfShapesImmersion immersion
Selected topographic immersion.
Options that affect saturated residual-tree construction.
Options that affect unrestricted residual-tree construction.