3#include "NodeDecisionMasks.hpp"
4#include "../trees/TreeAltitudeAlgorithms.hpp"
5#include "../trees/ValuedMorphologicalTree.hpp"
6#include "../trees/ValuedMorphologicalTreeView.hpp"
7#include "../trees/detail/TreeKernelAccess.hpp"
8#include "../utils/CommittedImageAccess.hpp"
9#include "../utils/Contract.hpp"
29namespace detail::attribute_filtering {
34 throw std::invalid_argument(std::string(
context) +
" nodePreservationMask size must match the internal node slot count."));
37template <std::
floating_po
int Real>
38inline void requireNodePreservationScores(
const MorphologicalTree& tree, std::span<const Real> nodePreservationScores,
const char* context) {
40 nodePreservationScores.size() ==
static_cast<std::size_t
>(tree.numInternalNodeSlots()),
41 throw std::invalid_argument(std::string(context) +
" nodePreservationScores size must match the internal node slot count."));
42 if constexpr (contract::validationsEnabled) {
43 for (std::size_t index = 0; index < nodePreservationScores.size(); ++index) {
44 const Real score = nodePreservationScores[index];
45 if (!std::isfinite(score) || score < Real{0} || score > Real{1}) {
46 throw std::invalid_argument(std::string(context) +
" requires every nodePreservationScore to be finite and in [0, 1].");
52template <AltitudeValue T>
53[[nodiscard]]
inline ImagePtr<T> applyDirectReconstruction(ValuedMorphologicalTreeView<T> valuedTree,
54 const NodePreservationMask& nodePreservationMask) {
55 const char* context =
"DirectAttributeFilter::applyDirectAttributeFilter";
56 valuedTree.requireTopologyUnchanged(context);
57 const MorphologicalTree& tree = valuedTree.topology();
58 tree.requireNotEditing(context);
59 requireNodePreservationMaskShape(tree, nodePreservationMask, context);
61 throw std::invalid_argument(std::string(context) +
" requires the root node to be preserved."));
62 const std::span<const T> nodeAltitudes = valuedTree.nodeAltitudes();
63 std::vector<T> reconstructedNodeAltitudes(
static_cast<std::size_t
>(tree.numInternalNodeSlots()), T{});
64 const NodeId root = tree.root();
65 reconstructedNodeAltitudes[
static_cast<std::size_t
>(root)] = nodeAltitudes[
static_cast<std::size_t
>(root)];
67 std::stack<NodeId> pending;
69 while (!pending.empty()) {
70 const NodeId nodeId = pending.top();
72 for (NodeId childId : detail::TreeKernelAccess::children(tree, nodeId)) {
73 reconstructedNodeAltitudes[
static_cast<std::size_t
>(childId)] =
74 nodePreservationMask[
static_cast<std::size_t
>(childId)] ? nodeAltitudes[
static_cast<std::size_t
>(childId)]
75 : reconstructedNodeAltitudes[static_cast<std::size_t>(nodeId)];
76 pending.push(childId);
80 ImagePtr<T> output = CommittedImageAccess::create<T>(tree.numRows(), tree.numColumns());
81 T* pixels = output->rawData();
82 for (NodeId nodeId : tree.aliveNodeIds()) {
83 for (PixelId pixel : detail::TreeKernelAccess::properParts(tree, nodeId)) {
84 pixels[pixel] = reconstructedNodeAltitudes[
static_cast<std::size_t
>(nodeId)];
91template <AltitudeValue T>
92[[nodiscard]]
inline AltitudeDifference<T> nodeResidueEstablished(
const MorphologicalTree& tree, std::span<const T> nodeAltitudes, NodeId nodeId) {
93 const auto altitude =
static_cast<AltitudeDifference<T>
>(nodeAltitudes[
static_cast<std::size_t
>(nodeId)]);
94 if (nodeId == tree.root()) {
97 const NodeId parent = TreeKernelAccess::nodeParent(tree, nodeId);
98 return altitude -
static_cast<AltitudeDifference<T>
>(nodeAltitudes[
static_cast<std::size_t
>(parent)]);
102template <
class Contribution>
103[[nodiscard]]
inline ImagePtr<Contribution> reconstructNodeContributionsEstablished(
const MorphologicalTree& tree,
104 std::span<const Contribution> nodeContributions) {
105 const auto pixelValues = tree_altitude::reconstructNodeContributionValuesEstablished(tree, nodeContributions);
106 ImagePtr<Contribution> output = CommittedImageAccess::create<Contribution>(tree.numRows(), tree.numColumns());
107 std::copy(pixelValues.begin(), pixelValues.end(), output->rawData());
111template <AltitudeValue T>
112[[nodiscard]]
inline std::vector<AltitudeDifference<T>> computeGatedNodeContributions(
113 ValuedMorphologicalTreeView<T> valuedTree,
const NodePreservationMask& nodePreservationMask) {
114 const char* context =
"SubtractiveAttributeFilter::applySubtractiveAttributeFilter";
115 const MorphologicalTree& tree = valuedTree.topology();
116 tree.requireNotEditing(context);
117 requireNodePreservationMaskShape(tree, nodePreservationMask, context);
118 const auto nodeAltitudes = valuedTree.nodeAltitudes();
119 std::vector<AltitudeDifference<T>> nodeContributions(
static_cast<std::size_t
>(tree.numInternalNodeSlots()), AltitudeDifference<T>{});
120 for (NodeId nodeId : tree.aliveNodeIds()) {
121 if (nodePreservationMask[
static_cast<std::size_t
>(nodeId)]) {
122 const auto contribution = nodeResidueEstablished(tree, nodeAltitudes, nodeId);
123 tree_altitude::requireFiniteNodeContribution(contribution, context);
124 nodeContributions[
static_cast<std::size_t
>(nodeId)] = contribution;
127 return nodeContributions;
130template <AltitudeValue T, std::
floating_po
int Real>
131[[nodiscard]]
inline std::vector<Real> computeSoftNodeContributions(ValuedMorphologicalTreeView<T> valuedTree,
132 std::span<const Real> nodePreservationScores) {
133 const char* context =
"SoftSubtractiveAttributeFilter::applySoftSubtractiveAttributeFilter";
134 const MorphologicalTree& tree = valuedTree.topology();
135 tree.requireNotEditing(context);
136 requireNodePreservationScores(tree, nodePreservationScores, context);
137 const auto nodeAltitudes = valuedTree.nodeAltitudes();
138 std::vector<Real> nodeContributions(
static_cast<std::size_t
>(tree.numInternalNodeSlots()), Real{});
139 for (NodeId nodeId : tree.aliveNodeIds()) {
140 const Real contribution =
141 static_cast<Real
>(nodeResidueEstablished(tree, nodeAltitudes, nodeId)) * nodePreservationScores[
static_cast<std::size_t
>(nodeId)];
142 tree_altitude::requireFiniteNodeContribution(contribution, context);
143 nodeContributions[
static_cast<std::size_t
>(nodeId)] = contribution;
145 return nodeContributions;
180 return detail::attribute_filtering::applyDirectReconstruction(valuedTree_,
nodePreservationMask);
217 valuedTree_.requireTopologyUnchanged(
"SubtractiveAttributeFilter::applySubtractiveAttributeFilter");
219 return detail::attribute_filtering::reconstructNodeContributionsEstablished(
255 valuedTree_.requireTopologyUnchanged(
"SoftSubtractiveAttributeFilter::applySoftSubtractiveAttributeFilter");
257 return detail::attribute_filtering::reconstructNodeContributionsEstablished(
262template <AltitudeValue T>
263[[nodiscard]]
inline ImagePtr<T> applyDirectAttributeFilter(ValuedMorphologicalTreeView<T> valuedTree,
264 const NodePreservationMask& nodePreservationMask) {
265 return DirectAttributeFilter<T>(valuedTree).applyDirectAttributeFilter(nodePreservationMask);
268template <AltitudeValue T>
269[[nodiscard]]
inline ImagePtr<T> applyDirectAttributeFilter(
const ValuedMorphologicalTree<T>& valuedTree,
270 const NodePreservationMask& nodePreservationMask) {
271 return DirectAttributeFilter<T>(valuedTree).applyDirectAttributeFilter(nodePreservationMask);
274template <AltitudeValue T>
275[[nodiscard]]
inline ImagePtr<AltitudeDifference<T>> applySubtractiveAttributeFilter(
276 ValuedMorphologicalTreeView<T> valuedTree,
const NodePreservationMask& nodePreservationMask) {
277 return SubtractiveAttributeFilter<T>(valuedTree).applySubtractiveAttributeFilter(nodePreservationMask);
280template <AltitudeValue T>
281[[nodiscard]]
inline ImagePtr<AltitudeDifference<T>> applySubtractiveAttributeFilter(
282 const ValuedMorphologicalTree<T>& valuedTree,
const NodePreservationMask& nodePreservationMask) {
283 return SubtractiveAttributeFilter<T>(valuedTree).applySubtractiveAttributeFilter(nodePreservationMask);
286template <AltitudeValue T, std::
floating_po
int Real>
287[[nodiscard]]
inline ImagePtr<Real> applySoftSubtractiveAttributeFilter(ValuedMorphologicalTreeView<T> valuedTree,
288 std::span<const Real> nodePreservationScores) {
289 return SoftSubtractiveAttributeFilter<T, Real>(valuedTree).applySoftSubtractiveAttributeFilter(nodePreservationScores);
292template <AltitudeValue T, std::
floating_po
int Real>
293[[nodiscard]]
inline ImagePtr<Real> applySoftSubtractiveAttributeFilter(
const ValuedMorphologicalTree<T>& valuedTree,
294 std::span<const Real> nodePreservationScores) {
295 return SoftSubtractiveAttributeFilter<T, Real>(valuedTree).applySoftSubtractiveAttributeFilter(nodePreservationScores);
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.
Direct attribute filter using reconstructed-parent altitude propagation.
DirectAttributeFilter(ValuedMorphologicalTreeView< T > valuedTree)
Creates a direct filter over a valued-tree view.
ImagePtr< T > applyDirectAttributeFilter(const NodePreservationMask &nodePreservationMask) const
Applies direct reconstruction under node-preservation decisions.
DirectAttributeFilter(const ValuedMorphologicalTree< T > &valuedTree)
Creates a direct filter over an owning valued tree.
Mutable connected-subset tree on a finite pixel domain.
int numInternalNodeSlots() const
Returns the size of the dense internal-node id domain.
Dense Boolean decisions where true means preserve the node.
Soft subtractive filter using scores in [0,1] to gate zero-baseline residues.
SoftSubtractiveAttributeFilter(ValuedMorphologicalTreeView< T > valuedTree)
Creates a soft subtractive filter over a valued-tree view.
SoftSubtractiveAttributeFilter(const ValuedMorphologicalTree< T > &valuedTree)
Creates a soft subtractive filter over an owning valued tree.
ImagePtr< Real > applySoftSubtractiveAttributeFilter(std::span< const Real > nodePreservationScores) const
Reconstructs from residues modulated by preservation scores.
Subtractive filter using independently gated zero-baseline residues.
SubtractiveAttributeFilter(const ValuedMorphologicalTree< T > &valuedTree)
Creates a subtractive filter over an owning valued tree.
ImagePtr< OutputValue > applySubtractiveAttributeFilter(const NodePreservationMask &nodePreservationMask) const
Reconstructs from residues selected by preservation decisions.
SubtractiveAttributeFilter(ValuedMorphologicalTreeView< T > valuedTree)
Creates a subtractive filter over a valued-tree view.
Owning result for one computed scalar attribute layout and buffer.
Policy tag for parent-altitude propagation after node rejection.
Policy tag for independent zero-baseline modulation of node residues.