53 std::vector<NodeId> parent_;
55 std::vector<int> size_;
63 explicit DisjointSet(
int count) : parent_(
static_cast<std::size_t
>(count)), size_(
static_cast<std::size_t
>(count), 1) {
64 std::iota(parent_.begin(), parent_.end(),
NodeId{0});
75 while (parent_[
static_cast<std::size_t
>(root)] != root) {
76 root = parent_[
static_cast<std::size_t
>(root)];
78 while (parent_[
static_cast<std::size_t
>(
id)] != id) {
79 const NodeId next = parent_[
static_cast<std::size_t
>(id)];
80 parent_[
static_cast<std::size_t
>(id)] = root;
99 if (size_[
static_cast<std::size_t
>(
lhs)] < size_[
static_cast<std::size_t
>(
rhs)]) {
102 parent_[
static_cast<std::size_t
>(
rhs)] =
lhs;
103 size_[
static_cast<std::size_t
>(
lhs)] += size_[
static_cast<std::size_t
>(
rhs)];
109 template <AltitudeValue T>
struct OrderedGraphEdge {
119 bool finestRegionEdge =
false;
121 std::size_t order = 0;
125 template <AltitudeValue T, std::
floating_po
int Real>
struct PersistenceEdge {
129 Real persistence = Real{0};
145 if (
lhs.finestRegionEdge !=
rhs.finestRegionEdge) {
146 return lhs.finestRegionEdge;
148 if (
lhs.altitude !=
rhs.altitude) {
149 if (nodeAltitudeOrder == NodeAltitudeOrder::Increasing) {
150 return rhs.altitude <
lhs.altitude;
152 return lhs.altitude <
rhs.altitude;
154 if (
lhs.source !=
rhs.source) {
155 return lhs.source <
rhs.source;
157 return lhs.target <
rhs.target;
173 template <std::
floating_po
int Real>
176 throw std::invalid_argument(std::string(
context) +
" requires one extinction slot per internal NodeId.");
179 const Real value =
leafExtinction[
static_cast<std::size_t
>(leaf)];
180 if (!std::isfinite(value) || value < Real{0}) {
181 throw std::invalid_argument(std::string(
context) +
" requires finite non-negative leaf extinction values.");
194 template <AltitudeValue T>
197 std::vector<OrderedGraphEdge<T>> edges;
198 std::size_t order = 0;
201 for (
int targetValue : detail::CommittedGridAccess::forwardNeighbors(adjacency, source)) {
206 edges.push_back(
OrderedGraphEdge<T>{source, target, lca,
valuedTree.nodeAltitudes()[
static_cast<std::size_t
>(lca)], finestRegionEdge, order++});
210 std::stable_sort(edges.begin(), edges.end(), [nodeAltitudeOrder](
const auto&
lhs,
const auto&
rhs) { return edgePrecedes(lhs, rhs, nodeAltitudeOrder); });
223 template <AltitudeValue T>
226 std::vector<OrderedGraphEdge<T>>
mst;
227 mst.reserve(
static_cast<std::size_t
>(std::max(0,
numVertices - 1)));
254 template <AltitudeValue T, std::
floating_po
int Real>
260 const auto properParts = detail::TreeKernelAccess::properParts(tree, leaf);
293 template <AltitudeValue T, std::
floating_po
int Real>
298 if (lhs.persistence != rhs.persistence) {
299 return lhs.persistence < rhs.persistence;
301 return lhs.graphEdge.order <
rhs.graphEdge.order;
305 std::vector<NodeId> parent(
static_cast<std::size_t
>(numNodes),
InvalidNode);
307 std::vector<Real> altitude(
static_cast<std::size_t
>(numNodes), Real{0});
309 parent[
static_cast<std::size_t
>(pixel)] = pixel;
310 smallestNodeMap[
static_cast<std::size_t
>(pixel)] = pixel;
325 altitude[
static_cast<std::size_t
>(
nextNode)] =
edge.persistence;
334 return detail::materializeNativeHierarchy<Real>(makeNativeHierarchyOwned(
335 std::move(parent), std::move(smallestNodeMap), std::move(altitude), root,
GridDomain2D{rows, columns}, std::move(semantics)));
367 template <AltitudeValue T, std::
floating_po
int Real>
370 constexpr const char*
context =
"HierarchicalWatershedSaliency::compute";
383 HierarchyValuationPolicy::AllowLevelCollapse, HierarchyLevelConvention::EdgeSaliencyValue,
384 HierarchyConnectivityPolicy::AssumeConnected);
400 template <AltitudeValue T, std::
floating_po
int Real>
static EdgeSaliencyMap< Value > computeSaliencyEdgeMap(const MorphologicalTree &tree, const RegularGridAdjacency2D &adjacency, std::span< const Value > valuation, HierarchyValuationPolicy policy=HierarchyValuationPolicy::AllowLevelCollapse, HierarchyLevelConvention levelConvention=HierarchyLevelConvention::EdgeSaliencyValue, HierarchyConnectivityPolicy connectivityPolicy=HierarchyConnectivityPolicy::ValidateConnected)
Computes the formal edge-indexed saliency map induced by a valuation.
Shape metadata optionally attached to the pixel domain.
Records one adjacency shared by both construction polarities.