mmcfilters
Public API documentation
Loading...
Searching...
No Matches
DistanceTransformComputation.hpp
1#pragma once
2
3#include "DistanceTransformProfiles.hpp"
4#include "NodeDistanceField.hpp"
5#include "../attributes/computers/detail/distance_transform/DistanceFieldHistogram.hpp"
6#include "../attributes/computers/detail/distance_transform/MorphologicalTreeDistanceTransform.hpp"
7#include "../attributes/computers/detail/distance_transform_approx/MorphologicalTreeApproximateDistanceTransform.hpp"
8#include "../trees/MorphologicalTree.hpp"
9
10#include <cstdint>
11#include <span>
12#include <stdexcept>
13#include <utility>
14#include <vector>
15
16namespace mmcfilters {
17
28 private:
29 using InternalHistogram = attributes::computers::detail::distance_transform::DistanceFieldHistogram;
30 using ExactTransform = attributes::computers::detail::distance_transform::ExactNodeDistanceFieldProvider;
31 using ApproximateTransform = attributes::computers::detail::distance_transform_approx::MorphologicalTreeApproximateDistanceTransform;
34 public:
46 DistanceTransformAccuracy accuracy = DistanceTransformAccuracy::Exact) {
47 requireTreeAndNode(tree, node);
48 requireAccuracy(accuracy);
49 std::vector<PixelId> supportPixels;
50 std::vector<std::int64_t> squaredDistances;
51 bool found = false;
52 if (accuracy == DistanceTransformAccuracy::Exact) {
53 static_cast<void>(ExactTransform::forNode(tree, node, [&](const auto& frame) {
54 supportPixels.reserve(frame.supportSize());
55 squaredDistances.reserve(frame.supportSize());
56 frame.forEachSample([&](PixelId pixel, std::int64_t squaredDistance) {
57 supportPixels.push_back(pixel);
58 squaredDistances.push_back(squaredDistance);
59 });
60 found = true;
61 }));
62 } else {
63 static_cast<void>(
64 ApproximateTransform::forEachNodeField(tree, [&](NodeId currentNode, std::span<const PixelId> pixels, const auto& squaredDistanceAt) {
65 if (currentNode != node) {
66 return;
67 }
68 supportPixels.assign(pixels.begin(), pixels.end());
69 squaredDistances.reserve(pixels.size());
70 for (PixelId pixel : pixels) {
71 squaredDistances.push_back(squaredDistanceAt(pixel));
72 }
73 found = true;
74 }));
75 }
76 if (!found || supportPixels.empty() || supportPixels.size() != squaredDistances.size()) {
77 throw std::logic_error("Distance-transform computation did not materialize the requested live-node field.");
78 }
79 return NodeDistanceField(node, tree.numRows(), tree.numColumns(), accuracy, std::move(supportPixels), std::move(squaredDistances));
80 }
81
92 DistanceTransformAccuracy accuracy = DistanceTransformAccuracy::Exact) {
93 requireTree(tree);
94 requireAccuracy(accuracy);
95 std::vector<DistanceTransformHistogramBin> bins;
96 std::vector<DistanceTransformProfiles::Span> spans(static_cast<std::size_t>(tree.numInternalNodeSlots()));
97 std::vector<std::uint8_t> alive(static_cast<std::size_t>(tree.numInternalNodeSlots()), std::uint8_t{0});
98 for (NodeId node : tree.aliveNodeIds()) {
99 alive[static_cast<std::size_t>(node)] = 1;
100 }
101
102 const auto appendHistogram = [&](NodeId node, const InternalHistogram& histogram) {
103 DistanceTransformProfiles::Span& span = spans[static_cast<std::size_t>(node)];
104 span.offset = bins.size();
105 span.size = histogram.levelCount();
106 for (const auto& [squaredDistance, count] : histogram.bins()) {
107 bins.push_back({squaredDistance, count});
108 }
109 };
110
111 if (accuracy == DistanceTransformAccuracy::Exact) {
112 static_cast<void>(ExactTransform::forEachNode(tree, [&](const auto& frame) {
113 InternalHistogram histogram;
114 frame.forEachSample([&](PixelId, std::int64_t squaredDistance) { histogram.add<false>(squaredDistance); });
115 appendHistogram(frame.node(), histogram);
116 }));
117 } else {
118 static_cast<void>(ApproximateTransform::template forEachNodeSelectedStatistics<false, true, false>(
119 tree, [&](NodeId node, const auto&, const auto&, const auto& observer, PixelId representative) {
120 appendHistogram(node, observer.histogramFor(representative));
121 }));
122 }
123 return DistanceTransformProfiles(accuracy, std::move(bins), std::move(spans), std::move(alive));
124 }
125
127 private:
128 static void requireTree(const MorphologicalTree& tree) {
129 tree.requireNotEditing("DistanceTransformComputation");
130 if (!tree.hasGridDomain2D() || tree.numRows() <= 0 || tree.numColumns() <= 0) {
131 throw std::invalid_argument("Distance-transform computation requires a non-empty regular 2D tree domain.");
132 }
133 }
134
135 static void requireTreeAndNode(const MorphologicalTree& tree, NodeId node) {
136 requireTree(tree);
137 if (!tree.isAlive(node)) {
138 throw std::out_of_range("Distance-transform field computation requires a live internal node id.");
139 }
140 }
141
142 static void requireAccuracy(DistanceTransformAccuracy accuracy) {
143 if (accuracy != DistanceTransformAccuracy::Exact && accuracy != DistanceTransformAccuracy::Approximate) {
144 throw std::invalid_argument("Distance-transform computation requires Exact or Approximate accuracy.");
145 }
146 }
148};
149
150} // namespace mmcfilters
Public topology-only computation of node distance fields and profiles.
static NodeDistanceField computeNodeField(const MorphologicalTree &tree, NodeId node, DistanceTransformAccuracy accuracy=DistanceTransformAccuracy::Exact)
Materializes the compact field of one live node.
static DistanceTransformProfiles computeProfiles(const MorphologicalTree &tree, DistanceTransformAccuracy accuracy=DistanceTransformAccuracy::Exact)
Computes sorted sparse histograms for every live node.
Compact CSR-like sparse distance histograms for every live tree node.
Mutable connected-subset tree on a finite pixel domain.
int numRows() const
Returns the number of rows in the regular 2D pixel domain.
int numInternalNodeSlots() const
Returns the size of the dense internal-node id domain.
bool hasGridDomain2D() const noexcept
Tests whether pixel ids have an attached row/column layout.
AliveNodeRange aliveNodeIds() const
Returns a fail-fast range over all live node ids.
void requireNotEditing(const char *context) const
Rejects operations that require a committed connected topology.
int numColumns() const
Returns the number of columns in the regular 2D pixel domain.
Self-contained compact per-pixel distance field for one live node.
Owning result for one computed scalar attribute layout and buffer.
Offset and length of one node histogram in the flat bin array.