3#include "DepthStableRegionComputer.hpp"
4#include "MSERComputer.hpp"
5#include "NodeDecisionMasks.hpp"
6#include "../trees/MorphologicalTree.hpp"
7#include "../trees/ValuedMorphologicalTree.hpp"
8#include "../utils/Altitude.hpp"
9#include "../utils/Contract.hpp"
22enum class IncompleteStabilityWindowPolicy {
33template <
class AttributeValue>
34 requires(std::is_arithmetic_v<AttributeValue> && !std::is_same_v<std::remove_cv_t<AttributeValue>,
bool>)
35[[nodiscard]] NodePreservationMask computeNodePreservationMask(std::span<const AttributeValue> nodeAttributes, AttributeValue threshold) {
36 std::vector<bool> nodePreservationDecisions(nodeAttributes.size(),
false);
37 for (std::size_t index = 0; index < nodeAttributes.size(); ++index) {
38 nodePreservationDecisions[index] = nodeAttributes[index] >= threshold;
40 return NodePreservationMask(std::move(nodePreservationDecisions));
43namespace detail::node_preservation_stability {
45inline void requireNodePreservationMaskShape(
const MorphologicalTree& tree,
const NodePreservationMask& nodePreservationMask,
46 const char* context) {
48 nodePreservationMask.size() ==
static_cast<std::size_t
>(tree.numInternalNodeSlots()),
49 throw std::invalid_argument(std::string(context) +
" nodePreservationMask size must match the internal node slot count."));
52template <std::
floating_po
int Real,
class StabilityComputer>
53[[nodiscard]] NodePreservationMask adjustNodePreservationMask(
const MorphologicalTree& tree,
54 const NodePreservationMask& nodePreservationMask,
55 StabilityComputer& stabilityComputer,
56 IncompleteStabilityWindowPolicy incompleteWindowPolicy,
57 const char* context) {
58 requireNodePreservationMaskShape(tree, nodePreservationMask, context);
59 const std::vector<Real>& variations = stabilityComputer.getVariations();
60 std::vector<bool> adjustedDecisions(
static_cast<std::size_t
>(tree.numInternalNodeSlots()),
true);
62 for (NodeId nodeId : tree.aliveNodeIds()) {
63 if (nodePreservationMask[
static_cast<std::size_t
>(nodeId)]) {
67 if (detail::isFiniteVariation(variations[
static_cast<std::size_t
>(nodeId)])) {
68 const NodeId adjustedRejection = stabilityComputer.nodeWithMinimumVariationInWindow(nodeId);
69 adjustedDecisions[
static_cast<std::size_t
>(adjustedRejection)] =
false;
73 switch (incompleteWindowPolicy) {
74 case IncompleteStabilityWindowPolicy::PreserveInputDecision:
75 adjustedDecisions[
static_cast<std::size_t
>(nodeId)] =
false;
80 return NodePreservationMask(std::move(adjustedDecisions));
90template <AltitudeValue T>
91[[nodiscard]] NodePreservationMask adjustNodePreservationMaskByAltitudeStability(
92 const ValuedMorphologicalTree<T>& valuedTree,
const NodePreservationMask& nodePreservationMask,
93 AltitudeDifference<T> altitudeWindowRadius,
94 IncompleteStabilityWindowPolicy incompleteWindowPolicy = IncompleteStabilityWindowPolicy::PreserveInputDecision) {
95 MSERComputer<T> stabilityComputer(valuedTree);
96 (void)stabilityComputer.computeMSER(altitudeWindowRadius);
97 return detail::node_preservation_stability::adjustNodePreservationMask<float>(
98 valuedTree.topology(), nodePreservationMask, stabilityComputer, incompleteWindowPolicy,
99 "adjustNodePreservationMaskByAltitudeStability");
103[[nodiscard]]
inline NodePreservationMask adjustNodePreservationMaskByDepthStability(
104 const MorphologicalTree& tree,
const NodePreservationMask& nodePreservationMask,
int depthWindowRadius,
105 IncompleteStabilityWindowPolicy incompleteWindowPolicy = IncompleteStabilityWindowPolicy::PreserveInputDecision) {
106 DepthStableRegionComputer<float> stabilityComputer(tree);
107 (void)stabilityComputer.computeByDepth(depthWindowRadius);
108 return detail::node_preservation_stability::adjustNodePreservationMask<float>(
109 tree, nodePreservationMask, stabilityComputer, incompleteWindowPolicy,
110 "adjustNodePreservationMaskByDepthStability");
114template <AltitudeValue T>
115[[nodiscard]]
inline NodePreservationMask adjustNodePreservationMaskByDepthStability(
116 const ValuedMorphologicalTree<T>& valuedTree,
const NodePreservationMask& nodePreservationMask,
int depthWindowRadius,
117 IncompleteStabilityWindowPolicy incompleteWindowPolicy = IncompleteStabilityWindowPolicy::PreserveInputDecision) {
118 return adjustNodePreservationMaskByDepthStability(valuedTree.topology(), nodePreservationMask, depthWindowRadius,
119 incompleteWindowPolicy);
int NodeId
Node identifier type used throughout the project.
#define MMCFILTERS_CONTRACT_REQUIRE(condition,...)
Evaluates a caller precondition and its failure action only in checked builds.