mmcfilters
Public API documentation
Loading...
Searching...
No Matches
MSERComputer.hpp
1#pragma once
2
3#include "../attributes/AttributeComputation.hpp"
4#include "../trees/detail/TreeNeighborhood.hpp"
5#include "../trees/MorphologicalTree.hpp"
6#include "../trees/TreeAltitudeAlgorithms.hpp"
7#include "../trees/ValuedMorphologicalTree.hpp"
8#include "../utils/Common.hpp"
9#include "../utils/Contract.hpp"
10#include "detail/VariationMeasure.hpp"
11
12#include <cassert>
13#include <cmath>
14#include <concepts>
15#include <limits>
16#include <memory>
17#include <span>
18#include <stdexcept>
19#include <string>
20#include <type_traits>
21#include <utility>
22#include <vector>
23
24namespace mmcfilters {
25
59template <AltitudeValue T, std::floating_point Real = float> class MSERComputer {
60 public:
63
64 private:
66 const ValuedMorphologicalTree<T>& valuedTree_;
68 const MorphologicalTree& tree;
70 const std::vector<T>& altitude_;
72 const Real* externalAttrMser_;
74 std::vector<Real> ownedAttrMser_;
76 Real maxVariation;
78 Real minAttr;
80 Real maxAttr;
82 int num = 0;
84 bool hasComputed_ = false;
86 std::vector<Real> variation;
88 std::vector<NodeId> ancestors;
90 std::vector<NodeId> descendants;
91
97 [[nodiscard]] const Real* attributeData() const noexcept { return ownedAttrMser_.empty() ? externalAttrMser_ : ownedAttrMser_.data(); }
98
104 void requireComputed(const char* context) const {
105 MMCFILTERS_CONTRACT_REQUIRE(hasComputed_, throw std::logic_error(std::string(context) + " requires computeMSER to run first."));
106 }
107
114 static void validateOwnedAttributeSize(const MorphologicalTree& tree, const std::vector<Real>& attr) {
115 MMCFILTERS_CONTRACT_REQUIRE(attr.size() == static_cast<std::size_t>(tree.numInternalNodeSlots()),
116 throw std::invalid_argument("MSERComputer attribute size must match the internal node slot count."));
117 }
118
126 MSERComputer(const ValuedMorphologicalTree<T>& valuedTree, const Real* attr_increasing, std::vector<Real> ownedAttr)
127 : valuedTree_(valuedTree), tree(valuedTree.topology()), altitude_(valuedTree.nodeAltitudes()), externalAttrMser_(attr_increasing),
128 ownedAttrMser_(std::move(ownedAttr)), maxVariation(Real{10}), minAttr(Real{0}),
129 maxAttr(static_cast<Real>(this->tree.numColumns() * this->tree.numRows())) {
130 TreeAltitudeAlgorithms::validateNodeAltitudeBufferShape(this->tree, std::span<const T>(this->altitude_));
132 }
133
134 public:
143 validateOwnedAttributeSize(valuedTree.topology(), attr_increasing);
144 return std::move(attr_increasing);
145 }()) {}
146
157 attr_increasing != nullptr,
158 throw std::invalid_argument("MSERComputer requires a non-null attribute buffer for the raw-pointer constructor."));
159 }
160
167
169 MSERComputer(const MSERComputer&) = default;
176
181
191 if constexpr (std::is_floating_point_v<AltitudeDifference<T>>) {
193 throw std::invalid_argument("MSERComputer requires a finite altitude window radius."));
194 }
196 throw std::invalid_argument("MSERComputer requires a positive altitude window radius."));
197 detail::TreeNeighborhood neighborhood(tree);
198 neighborhood.computeByAltitude(std::span<const T>(altitude_), altitudeWindowRadius);
199 this->ancestors = std::move(neighborhood.ancestors);
200 this->descendants = std::move(neighborhood.descendants);
201
202 auto attrAt = [this](NodeId node) -> Real { return this->getAttrMSER(node); };
203 this->variation = detail::computeVariationsFromNeighborhood<Real>(this->tree, this->ancestors, this->descendants, attrAt);
204 std::vector<uint8_t> selected = detail::selectStrictVariationMinima<Real>(this->tree, this->variation, this->ancestors, this->descendants, attrAt,
205 this->maxVariation, this->minAttr, this->maxAttr, this->num);
206 this->hasComputed_ = true;
207 return selected;
208 }
209
217 requireComputed("MSERComputer::getVariation");
218 detail::validateStabilityNeighborhoodShape(this->tree, this->ancestors, this->descendants, "MSERComputer::getVariation");
219 auto attrAt = [this](NodeId nodeId) -> Real { return this->getAttrMSER(nodeId); };
220 return detail::computeVariationValue<Real>(node, this->ancestors, this->descendants, attrAt);
221 }
222
230 [[nodiscard]] Real getAttrMSER(NodeId node) {
231 if (attributeData() == nullptr) {
232 auto area = AttributeComputation::computeSingleAttribute<Real>(valuedTree_, Area);
233 ownedAttrMser_ = std::move(area.second);
234 }
235 const Real* data = attributeData();
236 if (data == nullptr) {
237 throw std::logic_error("MSERComputer attribute storage is unavailable.");
238 }
239 return data[node];
240 }
241
250 requireComputed("MSERComputer::nodeWithMinimumVariationInWindow");
251 detail::validateStabilityNeighborhoodShape(this->tree, this->ancestors, this->descendants, "MSERComputer::nodeWithMinimumVariationInWindow");
252 return detail::nodeWithMinimumVariationInWindow<Real>(node, this->variation, this->ancestors, this->descendants);
253 }
254
262 requireComputed("MSERComputer::ancestorInStabilityWindow");
263 return this->ancestors[static_cast<std::size_t>(node)];
264 }
265
273 requireComputed("MSERComputer::descendantInStabilityWindow");
274 return this->descendants[node];
275 }
276
282 [[nodiscard]] std::vector<Real>& getVariations() {
283 requireComputed("MSERComputer::getVariations");
284 return this->variation;
285 }
286
292 [[nodiscard]] int numNodes() {
293 requireComputed("MSERComputer::numNodes");
294 return this->num;
295 }
296
302 void setMaxVariation(Real maxVariation) { this->maxVariation = maxVariation; }
308 void setMinAttribute(Real minAttr) { this->minAttr = minAttr; }
314 void setMaxAttribute(Real maxAttr) { this->maxAttr = maxAttr; }
315};
316
317} // namespace mmcfilters
typename detail::AltitudeDifferenceSelector< T >::type AltitudeDifference
Arithmetic result type for altitude differences.
Definition Altitude.hpp:72
int NodeId
Node identifier type used throughout the project.
Definition Common.hpp:17
#define MMCFILTERS_CONTRACT_REQUIRE(condition,...)
Evaluates a caller precondition and its failure action only in checked builds.
Definition Contract.hpp:53
Detects MSER-like nodes from a monotone increasing attribute defined on the hierarchy.
int numNodes()
Returns the number of nodes selected as MSER-like in the last run.
std::vector< uint8_t > computeMSER(AltitudeDifference< T > altitudeWindowRadius)
Computes the MSER indicator vector for an altitude-window radius.
MSERComputer(const ValuedMorphologicalTree< T > &valuedTree)
Creates an MSER detector that lazily falls back to AREA.
Real getVariation(NodeId node)
Returns the variation score currently associated with a node.
MSERComputer(const ValuedMorphologicalTree< T > &valuedTree, std::vector< Real > attr_increasing)
Creates an MSER detector backed by an owned attribute buffer.
NodeId descendantInStabilityWindow(NodeId node) const
Returns the descendant used in the current stability window.
MSERComputer(const MSERComputer &)=default
Copies the evaluator while preserving owned-buffer safety.
NodeId nodeWithMinimumVariationInWindow(NodeId node)
Returns the node with minimum variation among the current node and its altitude-window neighbours.
void setMaxVariation(Real maxVariation)
Sets the maximum accepted variation value.
void setMaxAttribute(Real maxAttr)
Sets the upper bound of the accepted attribute interval.
NodeId ancestorInStabilityWindow(NodeId node) const
Returns the ancestor used in the current stability window.
Real variation_value_type
Floating-point type used to store variation scores.
std::vector< Real > & getVariations()
Returns the current variation array, indexed by node slot.
MSERComputer(MSERComputer &&) noexcept=default
Moves the evaluator while preserving its referenced tree.
void setMinAttribute(Real minAttr)
Sets the lower bound of the accepted attribute interval.
Real getAttrMSER(NodeId node)
Returns the attribute used by the MSER stability measure, lazily computing AREA when no external buff...
MSERComputer(const ValuedMorphologicalTree< T > &valuedTree, const Real *attr_increasing)
Creates an MSER detector backed by a non-owning attribute view.
Mutable connected-subset tree on a finite pixel domain.
static void validateNodeAltitudeBufferShape(const MorphologicalTree &tree, std::span< const T > altitude)
Validates that an altitude buffer covers the dense internal-node domain.
static void requireGlobalMonotoneAltitudeOrder(const MorphologicalTree &tree, const char *context)
Requires a declared globally monotone altitude order.
Owning result for one computed scalar attribute layout and buffer.