3#include "../utils/Image.hpp"
4#include "../utils/Common.hpp"
5#include "../trees/TreeAltitudeAlgorithms.hpp"
6#include "../trees/WeightedMorphologicalTree.hpp"
7#include "../trees/WeightedTreeView.hpp"
8#include "../trees/detail/TreeTraversalDetail.hpp"
9#include "DepthStableRegionComputer.hpp"
10#include "MSERComputer.hpp"
11#include "detail/VariationMeasure.hpp"
12#include "detail/ViterbiDecision.hpp"
65template<AltitudeValue T>
74 std::size_t treeMutationVersion_ = 0;
77 return weighted_ !=
nullptr ? weighted_->asView() :
view_;
80 void requireStableTree(
const char*
context)
const {
84 template <std::
floating_po
int Real>
86 if (attribute ==
nullptr) {
87 throw std::invalid_argument(std::string(
context) +
" requires a non-null attribute buffer.");
93 throw std::invalid_argument(std::string(
context) +
" criterion size must match the internal node slot count.");
99 throw std::invalid_argument(std::string(
context) +
" score size must match the internal node slot count.");
103 template <
typename TImagePtr>
106 throw std::invalid_argument(std::string(
context) +
" requires a non-null output image.");
109 throw std::invalid_argument(std::string(
context) +
" output image shape must match the tree image domain.");
129 template <
typename TValue>
143 template <
typename TValue>
159 view.requireTopologyUnchanged(
"AttributeFilters::filteringBySubtractiveScoreRule");
171 std::stack<NodeId>
stack;
173 while (!
stack.empty()) {
197 const char*
context =
"AttributeFilters::filteringBySubtractiveRule";
208 std::stack<NodeId>
stack;
210 while (!
stack.empty()) {
235 const char*
context =
"AttributeFilters::filteringByDirectRule";
246 std::stack<NodeId>
stack;
248 while (!
stack.empty()) {
272 const char*
context =
"AttributeFilters::filteringByPruningMin";
277 std::stack<NodeId>
stack;
281 while (!
stack.empty()) {
304 const char*
context =
"AttributeFilters::filteringByPruningMax";
313 detail::traversePostOrder(
317 criterion[nodeId] = !keepCriterion[nodeId];
320 criterion[parentNodeId] = (criterion[parentNodeId] & criterion[childNodeId]);
325 std::stack<NodeId>
stack;
327 while (!
stack.empty()) {
349 template <std::
floating_po
int Real>
351 const char*
context =
"AttributeFilters::filteringByPruningMin";
357 std::stack<NodeId>
stack;
359 while (!
stack.empty()) {
380 template <std::
floating_po
int Real>
382 const char*
context =
"AttributeFilters::filteringByPruningMax";
391 detail::traversePostOrder(
395 if (attribute[nodeId] <= threshold) {
396 criterion[nodeId] = true;
405 std::stack<NodeId>
stack;
407 while (!
stack.empty()) {
421 template <std::
floating_po
int Real,
class StabilityComputer>
424 const Real* attribute,
436 if (!detail::isFiniteVariation(variation[
static_cast<std::size_t
>(
nodeId)])) {
439 isPruned[stabilityComputer.nodeWithMinimumVariationInWindow(nodeId)] =
true;
446 template <std::
floating_po
int Real,
class StabilityComputer>
447 static std::vector<bool> adaptiveCriterionFromMaskStability(
448 const MorphologicalTree& tree,
449 std::vector<bool>& criterion,
450 StabilityComputer& stabilityComputer,
451 const char* context) {
452 requireCriterionSize(tree, criterion, context);
453 const std::vector<Real>& variation = stabilityComputer.getVariations();
454 std::vector<bool> isPruned(tree.getNumInternalNodeSlots(),
false);
455 for (NodeId nodeId : tree.getAliveNodeIds()) {
456 if (!criterion[nodeId]) {
460 if (!detail::isFiniteVariation(variation[
static_cast<std::size_t
>(nodeId)])) {
461 isPruned[nodeId] =
true;
463 isPruned[stabilityComputer.nodeWithMinimumVariationInWindow(nodeId)] =
true;
470 template <std::
floating_po
int Real>
471 static std::vector<bool> getAdaptiveCriterionImpl(
const WeightedMorphologicalTree<T>& weighted,
const Real* attribute, Real threshold, AltitudeDiff<T> delta) {
472 const MorphologicalTree& tree = weighted.topology();
473 MSERComputer<T, Real> mser(weighted);
474 (void)mser.computeMSER(delta);
475 return adaptiveCriterionFromAttributeStability<Real>(
480 "AttributeFilters::getAdaptiveCriterion");
483 static std::vector<bool> getAdaptiveCriterionImpl(
const WeightedMorphologicalTree<T>& weighted, std::vector<bool>& criterion, AltitudeDiff<T> delta) {
484 const MorphologicalTree& tree = weighted.topology();
485 MSERComputer<T> mser(weighted);
486 (void)mser.computeMSER(delta);
487 return adaptiveCriterionFromMaskStability<float>(
491 "AttributeFilters::getAdaptiveCriterion");
494 template <std::
floating_po
int Real>
495 static std::vector<bool> getAdaptiveCriterionByDepthImpl(
const MorphologicalTree& tree,
const Real* attribute, Real threshold,
int depthDelta) {
496 DepthStableRegionComputer<Real> stabilityComputer(tree);
497 (void)stabilityComputer.computeByDepth(depthDelta);
498 return adaptiveCriterionFromAttributeStability<Real>(
503 "AttributeFilters::getAdaptiveCriterionByDepth");
506 static std::vector<bool> getAdaptiveCriterionByDepthImpl(
const MorphologicalTree& tree, std::vector<bool>& criterion,
int depthDelta) {
507 DepthStableRegionComputer<float> stabilityComputer(tree);
508 (void)stabilityComputer.computeByDepth(depthDelta);
509 return adaptiveCriterionFromMaskStability<float>(
513 "AttributeFilters::getAdaptiveCriterionByDepth");
526 tree{
view_.topology()},
527 treeMutationVersion_{tree.getMutationVersion()} {
528 view_.requireTopologyUnchanged(
"AttributeFilters");
554 requireStableTree(
"AttributeFilters::getAdaptiveCriterion");
555 if (weighted_ ==
nullptr) {
556 throw std::logic_error(
"AttributeFilters::getAdaptiveCriterion requires a WeightedMorphologicalTree owner because MSER uses the tree-owned altitude.");
558 return AttributeFilters::getAdaptiveCriterionImpl(*weighted_,
criterion, delta);
569 requireStableTree(
"AttributeFilters::getAdaptiveCriterionByDepth");
570 return AttributeFilters::getAdaptiveCriterionByDepthImpl(this->tree,
criterion,
depthDelta);
580 template <std::
floating_po
int Real>
582 return filteringByPruningMin(attr.get(),
threshold);
588 template <std::
floating_po
int Real>
590 requireStableTree(
"AttributeFilters::filteringByPruningMin");
603 template <std::
floating_po
int Real>
605 return filteringByPruningMax(attr.get(),
threshold);
611 template <std::
floating_po
int Real>
613 requireStableTree(
"AttributeFilters::filteringByPruningMax");
630 template <std::
floating_po
int Real>
632 requireStableTree(
"AttributeFilters::filteringByViterbiRule");
633 auto costs = detail::makeThresholdViterbiCosts(tree, attr,
threshold);
634 std::vector<bool>
criterion = detail::computeViterbiKeepCriterion(tree,
costs);
645 requireStableTree(
"AttributeFilters::filteringByPruningMin");
655 requireStableTree(
"AttributeFilters::filteringByPruningMax");
668 requireStableTree(
"AttributeFilters::filteringByDirectRule");
681 requireStableTree(
"AttributeFilters::filteringBySubtractiveRule");
694 requireStableTree(
"AttributeFilters::filteringBySubtractiveScoreRule");
773 template <std::
floating_po
int Real>
781 template <std::
floating_po
int Real>
789 template <std::
floating_po
int Real>
797 template <std::
floating_po
int Real>
805 template <std::
floating_po
int Real>
813 template <std::
floating_po
int Real>
821 template <std::
floating_po
int Real>
829 template <std::
floating_po
int Real>
837 template <std::
floating_po
int Real>
845 template <std::
floating_po
int Real>
860 template <std::
floating_po
int Real>
868 template <std::
floating_po
int Real>
std::shared_ptr< ImageFloat > ImageFloatPtr
Shared pointer to a single-precision floating-point image.
Family of attribute-based image filtering operators on morphological trees.
static void filteringByPruningMin(const WeightedMorphologicalTree< T > &weighted, std::vector< bool > &criterion, ImagePtr< T > imgOutputPtr)
Writes pruning-min filtering from a weighted owner into an output image.
static void filteringByDirectRule(const WeightedTreeView< T > &weighted, std::vector< bool > &criterion, ImagePtr< T > imgOutputPtr)
Writes direct-rule filtering into a caller-owned output image.
static void filteringByPruningMax(const WeightedTreeView< T > &weighted, const std::shared_ptr< Real[]> &attribute, Real threshold, ImagePtr< T > imgOutputPtr)
Writes pruning-max filtering from an owned attribute buffer into an output image.
static void filteringByPruningMax(const WeightedMorphologicalTree< T > &weighted, const Real *attribute, Real threshold, ImagePtr< T > imgOutputPtr)
Writes pruning-max filtering from a weighted owner and raw attribute buffer.
static void filteringByPruningMin(const WeightedTreeView< T > &weighted, const Real *attribute, Real threshold, ImagePtr< T > imgOutputPtr)
Writes pruning-min filtering from a raw attribute buffer into an output image.
static void filteringByPruningMax(const WeightedTreeView< T > &weighted, std::vector< bool > &criterion, ImagePtr< T > imgOutputPtr)
Writes pruning-max filtering from a criterion into an output image.
AttributeFilters(const WeightedMorphologicalTree< T > &weighted)
Creates filtering operators over an owned weighted tree.
static void filteringByPruningMax(const WeightedMorphologicalTree< T > &weighted, const std::shared_ptr< Real[]> &attribute, Real threshold, ImagePtr< T > imgOutputPtr)
Writes pruning-max filtering from a weighted owner and owned attribute buffer.
static std::vector< bool > getAdaptiveCriterion(const WeightedMorphologicalTree< T > &weighted, std::vector< bool > &criterion, AltitudeDiff< T > delta)
Builds an MSER-assisted pruning criterion from an existing criterion mask.
static std::vector< bool > getAdaptiveCriterionByDepth(const WeightedMorphologicalTree< T > &weighted, std::vector< bool > &criterion, int depthDelta)
Builds a depth-stability pruning criterion from an existing criterion mask.
ImagePtr< T > filteringByPruningMax(std::vector< bool > &criterion)
Applies pruning-max filtering from a dense internal-node criterion.
static void filteringByDirectRule(const WeightedMorphologicalTree< T > &weighted, std::vector< bool > &criterion, ImagePtr< T > imgOutputPtr)
Writes direct-rule filtering from a weighted owner into an output image.
static void filteringByPruningMax(const WeightedMorphologicalTree< T > &weighted, std::vector< bool > &criterion, ImagePtr< T > imgOutputPtr)
Writes pruning-max filtering from a weighted owner into an output image.
static std::vector< bool > getAdaptiveCriterion(const WeightedMorphologicalTree< T > &weighted, const std::shared_ptr< Real[]> &attribute, Real threshold, AltitudeDiff< T > delta)
Builds an MSER-assisted pruning criterion from an attribute threshold.
std::vector< bool > getAdaptiveCriterion(std::vector< bool > &criterion, AltitudeDiff< T > delta)
Builds an MSER-assisted pruning criterion from an existing keep/reject mask.
ImagePtr< T > filteringByViterbiRule(const Real *attr, Real threshold)
Applies Salembier-style Viterbi filtering from a raw attribute buffer.
std::vector< bool > getAdaptiveCriterionByDepth(std::vector< bool > &criterion, int depthDelta)
Builds a depth-stability pruning criterion from an existing mask.
static void filteringBySubtractiveRule(const WeightedMorphologicalTree< T > &weighted, std::vector< bool > &criterion, ImagePtr< T > imgOutputPtr)
Writes subtractive-rule filtering from a weighted owner into an output image.
AttributeFilters(AltitudeView view)
Creates filtering operators over a non-owning weighted tree view.
ImagePtr< T > filteringByPruningMin(std::vector< bool > &criterion)
Applies pruning-min filtering from a dense internal-node criterion.
static void filteringByPruningMax(const WeightedTreeView< T > &weighted, const Real *attribute, Real threshold, ImagePtr< T > imgOutputPtr)
Writes pruning-max filtering from a raw attribute buffer into an output image.
static void filteringByPruningMin(const WeightedMorphologicalTree< T > &weighted, const std::shared_ptr< Real[]> &attribute, Real threshold, ImagePtr< T > imgOutputPtr)
Writes pruning-min filtering from a weighted owner and owned attribute buffer.
static std::vector< bool > getAdaptiveCriterionByDepth(const WeightedMorphologicalTree< T > &weighted, const Real *attribute, Real threshold, int depthDelta)
Builds a depth-stability pruning criterion from a raw attribute buffer.
ImageFloatPtr filteringBySubtractiveScoreRule(std::vector< float > &prob)
Applies the subtractive score rule from dense per-node scores.
static std::vector< bool > getAdaptiveCriterionByDepth(const WeightedMorphologicalTree< T > &weighted, const std::shared_ptr< Real[]> &attribute, Real threshold, int depthDelta)
Builds a depth-stability pruning criterion from an attribute threshold.
static void filteringByPruningMin(const WeightedTreeView< T > &weighted, const std::shared_ptr< Real[]> &attribute, Real threshold, ImagePtr< T > imgOutputPtr)
Writes pruning-min filtering from an owned attribute buffer into an output image.
ImagePtr< T > filteringByPruningMin(const std::shared_ptr< Real[]> &attr, Real threshold)
Applies pruning-min filtering from an attribute buffer.
ImagePtr< T > filteringByPruningMax(const Real *attr, Real threshold)
Applies pruning-max filtering from a raw internal-node attribute buffer.
static void filteringBySubtractiveRule(const WeightedTreeView< T > &weighted, std::vector< bool > &criterion, ImagePtr< T > imgOutputPtr)
Writes subtractive-rule filtering into a caller-owned output image.
static void filteringBySubtractiveScoreRule(const WeightedTreeView< T > &weighted, std::vector< float > &prob, ImageFloatPtr imgOutputPtr)
Writes subtractive-score filtering into a caller-owned output image.
static void filteringBySubtractiveScoreRule(const WeightedMorphologicalTree< T > &weighted, std::vector< float > &prob, ImageFloatPtr imgOutputPtr)
Writes subtractive-score filtering from a weighted owner into an output image.
static void filteringByPruningMin(const WeightedTreeView< T > &weighted, std::vector< bool > &criterion, ImagePtr< T > imgOutputPtr)
Writes pruning-min filtering from a criterion into an output image.
ImagePtr< T > filteringByPruningMin(const Real *attr, Real threshold)
Applies pruning-min filtering from a raw internal-node attribute buffer.
ImagePtr< T > filteringByPruningMax(const std::shared_ptr< Real[]> &attr, Real threshold)
Applies pruning-max filtering from an attribute buffer.
static std::vector< bool > getAdaptiveCriterion(const WeightedMorphologicalTree< T > &weighted, const Real *attribute, Real threshold, AltitudeDiff< T > delta)
Builds an MSER-assisted pruning criterion from a raw attribute buffer.
static void filteringByPruningMin(const WeightedMorphologicalTree< T > &weighted, const Real *attribute, Real threshold, ImagePtr< T > imgOutputPtr)
Writes pruning-min filtering from a weighted owner and raw attribute buffer.
ImagePtr< T > filteringBySubtractiveRule(std::vector< bool > &criterion)
Applies the subtractive filtering rule from a dense internal-node criterion.
ImagePtr< T > filteringByDirectRule(std::vector< bool > &criterion)
Applies the direct filtering rule from a dense internal-node criterion.
static Ptr create(int rows, int cols)
Creates an owned image with uninitialised pixel values.
Mutable morphological tree built directly on proper parts and dense node ids.
ChildrenRange getChildren(NodeId nodeId) const
Returns a fail-fast range over the direct children of nodeId.
void requireMutationVersion(std::size_t expectedVersion, const char *context) const
Rejects stale read-only views that captured an older mutation version.
int getNumInternalNodeSlots() const
Returns the size of the dense internal-node id domain.
SubtreeNodeRange getNodeSubtree(NodeId nodeId) const
Returns a pre-order traversal range over the subtree of nodeId.
NodeId getRoot() const
Returns the current hierarchy root.
ProperPartsRange getProperParts(NodeId nodeId) const
Returns a fail-fast range over the direct proper parts of nodeId.
int getNumColsOfImage() const
Returns the number of image columns in the attached 2D domain.
AliveNodeRange getAliveNodeIds() const
Returns a fail-fast range over all live node ids.
int getNumRowsOfImage() const
Returns the number of image rows in the attached 2D domain.
Owning result for one computed scalar attribute layout and buffer.