3#include "NodeDecisionMasks.hpp"
4#include "../trees/TreeAltitudeAlgorithms.hpp"
5#include "../trees/ValuedMorphologicalTree.hpp"
6#include "../trees/ValuedMorphologicalTreeView.hpp"
7#include "../trees/detail/CommittedTreeAccess.hpp"
8#include "../utils/CommittedImageAccess.hpp"
9#include "../utils/Contract.hpp"
28namespace detail::attribute_filtering {
33 throw std::invalid_argument(std::string(
context) +
" nodePreservationMask size must match the internal node slot count."));
36template <std::
floating_po
int Real>
37inline void requireNodePreservationScores(
const MorphologicalTree& tree, std::span<const Real> nodePreservationScores,
const char* context) {
39 nodePreservationScores.size() ==
static_cast<std::size_t
>(tree.numInternalNodeSlots()),
40 throw std::invalid_argument(std::string(context) +
" nodePreservationScores size must match the internal node slot count."));
41 if constexpr (contract::validationsEnabled) {
42 for (std::size_t index = 0; index < nodePreservationScores.size(); ++index) {
43 const Real score = nodePreservationScores[index];
44 if (!std::isfinite(score) || score < Real{0} || score > Real{1}) {
45 throw std::invalid_argument(std::string(context) +
" requires every nodePreservationScore to be finite and in [0, 1].");
51template <AltitudeValue T>
52inline void applyDirectReconstruction(ValuedMorphologicalTreeView<T> valuedTree,
const NodePreservationMask& nodePreservationMask, ImagePtr<T> output) {
53 const char* context =
"DirectAttributeFilter::applyDirectAttributeFilter";
54 valuedTree.requireTopologyUnchanged(context);
55 const MorphologicalTree& tree = valuedTree.topology();
56 requireNodePreservationMaskShape(tree, nodePreservationMask, context);
58 throw std::invalid_argument(std::string(context) +
" requires the root node to be preserved."));
59 MMCFILTERS_CONTRACT_REQUIRE(output !=
nullptr,
throw std::invalid_argument(std::string(context) +
" requires a non-null output image."));
61 throw std::invalid_argument(std::string(context) +
" output image shape must match the tree image domain."));
63 const std::span<const T> nodeAltitudes = valuedTree.nodeAltitudes();
64 std::vector<T> reconstructedNodeAltitudes(
static_cast<std::size_t
>(tree.numInternalNodeSlots()), T{});
65 const NodeId root = tree.root();
66 reconstructedNodeAltitudes[
static_cast<std::size_t
>(root)] = nodeAltitudes[
static_cast<std::size_t
>(root)];
68 std::stack<NodeId> pending;
70 while (!pending.empty()) {
71 const NodeId nodeId = pending.top();
73 for (NodeId childId : detail::CommittedTreeAccess::children(tree, nodeId)) {
74 reconstructedNodeAltitudes[
static_cast<std::size_t
>(childId)] =
75 nodePreservationMask[
static_cast<std::size_t
>(childId)] ? nodeAltitudes[
static_cast<std::size_t
>(childId)]
76 : reconstructedNodeAltitudes[static_cast<std::size_t>(nodeId)];
77 pending.push(childId);
81 T* pixels = output->rawData();
82 for (NodeId nodeId : tree.aliveNodeIds()) {
83 for (PixelId pixel : detail::CommittedTreeAccess::properParts(tree, nodeId)) {
84 pixels[pixel] = reconstructedNodeAltitudes[
static_cast<std::size_t
>(nodeId)];
89template <AltitudeValue T>
90[[nodiscard]]
inline std::vector<AltitudeDifference<T>> computeHardNodeContributions(
91 ValuedMorphologicalTreeView<T> valuedTree,
const NodePreservationMask& nodePreservationMask) {
92 const MorphologicalTree& tree = valuedTree.topology();
93 requireNodePreservationMaskShape(tree, nodePreservationMask,
"HardSubtractiveAttributeFilter::applyHardSubtractiveAttributeFilter");
94 std::vector<AltitudeDifference<T>> nodeContributions(
static_cast<std::size_t
>(tree.numInternalNodeSlots()), AltitudeDifference<T>{});
95 for (NodeId nodeId : tree.aliveNodeIds()) {
96 if (nodePreservationMask[
static_cast<std::size_t
>(nodeId)]) {
97 nodeContributions[
static_cast<std::size_t
>(nodeId)] = valuedTree.nodeResidue(nodeId);
100 return nodeContributions;
103template <AltitudeValue T, std::
floating_po
int Real>
104[[nodiscard]]
inline std::vector<Real> computeSoftNodeContributions(ValuedMorphologicalTreeView<T> valuedTree,
105 std::span<const Real> nodePreservationScores) {
106 const MorphologicalTree& tree = valuedTree.topology();
107 requireNodePreservationScores(tree, nodePreservationScores,
"SoftSubtractiveAttributeFilter::applySoftSubtractiveAttributeFilter");
108 std::vector<Real> nodeContributions(
static_cast<std::size_t
>(tree.numInternalNodeSlots()), Real{});
109 for (NodeId nodeId : tree.aliveNodeIds()) {
110 nodeContributions[
static_cast<std::size_t
>(nodeId)] =
111 static_cast<Real
>(valuedTree.nodeResidue(nodeId)) * nodePreservationScores[
static_cast<std::size_t
>(nodeId)];
113 return nodeContributions;
148 ImagePtr<T> output = detail::CommittedImageAccess::create<T>(valuedTree_.topology().numRows(), valuedTree_.topology().numColumns());
187 valuedTree_.requireTopologyUnchanged(
"HardSubtractiveAttributeFilter::applyHardSubtractiveAttributeFilter");
191 "HardSubtractiveAttributeFilter::applyHardSubtractiveAttributeFilter");
226 valuedTree_.requireTopologyUnchanged(
"SoftSubtractiveAttributeFilter::applySoftSubtractiveAttributeFilter");
230 "SoftSubtractiveAttributeFilter::applySoftSubtractiveAttributeFilter");
234template <AltitudeValue T>
235[[nodiscard]]
inline ImagePtr<T> applyDirectAttributeFilter(ValuedMorphologicalTreeView<T> valuedTree,
236 const NodePreservationMask& nodePreservationMask) {
237 return DirectAttributeFilter<T>(valuedTree).applyDirectAttributeFilter(nodePreservationMask);
240template <AltitudeValue T>
241[[nodiscard]]
inline ImagePtr<T> applyDirectAttributeFilter(
const ValuedMorphologicalTree<T>& valuedTree,
242 const NodePreservationMask& nodePreservationMask) {
243 return DirectAttributeFilter<T>(valuedTree).applyDirectAttributeFilter(nodePreservationMask);
246template <AltitudeValue T>
247[[nodiscard]]
inline ImagePtr<AltitudeDifference<T>> applyHardSubtractiveAttributeFilter(
248 ValuedMorphologicalTreeView<T> valuedTree,
const NodePreservationMask& nodePreservationMask) {
249 return HardSubtractiveAttributeFilter<T>(valuedTree).applyHardSubtractiveAttributeFilter(nodePreservationMask);
252template <AltitudeValue T>
253[[nodiscard]]
inline ImagePtr<AltitudeDifference<T>> applyHardSubtractiveAttributeFilter(
254 const ValuedMorphologicalTree<T>& valuedTree,
const NodePreservationMask& nodePreservationMask) {
255 return HardSubtractiveAttributeFilter<T>(valuedTree).applyHardSubtractiveAttributeFilter(nodePreservationMask);
258template <AltitudeValue T, std::
floating_po
int Real>
259[[nodiscard]]
inline ImagePtr<Real> applySoftSubtractiveAttributeFilter(ValuedMorphologicalTreeView<T> valuedTree,
260 std::span<const Real> nodePreservationScores) {
261 return SoftSubtractiveAttributeFilter<T, Real>(valuedTree).applySoftSubtractiveAttributeFilter(nodePreservationScores);
264template <AltitudeValue T, std::
floating_po
int Real>
265[[nodiscard]]
inline ImagePtr<Real> applySoftSubtractiveAttributeFilter(
const ValuedMorphologicalTree<T>& valuedTree,
266 std::span<const Real> nodePreservationScores) {
267 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.
Hard subtractive filter using independently gated zero-baseline residues.
ImagePtr< OutputValue > applyHardSubtractiveAttributeFilter(const NodePreservationMask &nodePreservationMask) const
Reconstructs from residues selected by preservation decisions.
HardSubtractiveAttributeFilter(ValuedMorphologicalTreeView< T > valuedTree)
Creates a hard subtractive filter over a valued-tree view.
HardSubtractiveAttributeFilter(const ValuedMorphologicalTree< T > &valuedTree)
Creates a hard subtractive 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.
static ImagePtr< Contribution > reconstructFromNodeContributions(const MorphologicalTree &tree, std::span< const Contribution > nodeContributions, const char *context="TreeAltitudeAlgorithms::reconstructFromNodeContributions")
Reconstructs an image by summing node contributions on every root-to-node branch.
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.