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"
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;
46 DistanceTransformAccuracy accuracy = DistanceTransformAccuracy::Exact) {
49 std::vector<PixelId> supportPixels;
50 std::vector<std::int64_t> squaredDistances;
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);
68 supportPixels.assign(pixels.begin(), pixels.end());
69 squaredDistances.reserve(pixels.size());
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.");
92 DistanceTransformAccuracy accuracy = DistanceTransformAccuracy::Exact) {
95 std::vector<DistanceTransformHistogramBin>
bins;
97 std::vector<std::uint8_t> alive(
static_cast<std::size_t
>(tree.
numInternalNodeSlots()), std::uint8_t{0});
99 alive[
static_cast<std::size_t
>(node)] = 1;
105 span.size = histogram.levelCount();
106 for (
const auto& [squaredDistance, count] : histogram.bins()) {
107 bins.push_back({squaredDistance, count});
111 if (accuracy == DistanceTransformAccuracy::Exact) {
112 static_cast<void>(ExactTransform::forEachNode(tree, [&](
const auto&
frame) {
114 frame.forEachSample([&](
PixelId, std::int64_t squaredDistance) { histogram.add<
false>(squaredDistance); });
131 throw std::invalid_argument(
"Distance-transform computation requires a non-empty regular 2D tree domain.");
135 static void requireTreeAndNode(
const MorphologicalTree& tree, NodeId node) {
137 if (!tree.isAlive(node)) {
138 throw std::out_of_range(
"Distance-transform field computation requires a live internal node id.");
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.");
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.