MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ find_contours() [1/2]

MAYAFLUX_API std::vector< Contour > MayaFlux::Kinesis::Vision::find_contours ( const ComponentResult &  components,
uint32_t  w,
uint32_t  h,
float  min_area = 0.0F,
uint32_t  max_contours = 0,
uint32_t  max_points_per_contour = 0 
)

Extract contours from an existing CPU component labeling.

Applies the same tracing, filtering, and measurement rules as mask-based extraction without repeating connected-component labeling.

Parameters
componentsCPU labeling with a complete w * h label_map and compact foreground labels in 1..count; zero labels are background.
wImage width in pixels.
hImage height in pixels.
min_areaMinimum normalised area to retain.
max_contoursMaximum number of contours to return; zero is unlimited.
max_points_per_contourMaximum trace length; zero is unlimited.
Returns
Outer and hole contours with normalized points and pixel perimeter.

Definition at line 122 of file Contours.cpp.

125{
126 if (w == 0 || h == 0 || cc.count == 0)
127 return {};
128
129 const size_t n = static_cast<size_t>(w) * h;
130 std::vector<TraceSeed> seeds(cc.count, TraceSeed { .pixel = n, .label = 0, .parent = 0 });
131 for (size_t i = 0; i < n; ++i) {
132 const uint32_t label = cc.label_map[i];
133 if (label != 0 && seeds[label - 1].pixel == n)
134 seeds[label - 1] = { .pixel = i, .label = label, .parent = 0 };
135 }
136
137 std::vector<uint32_t> background(n, 0);
138 std::vector<size_t> pending;
139 uint32_t region = 0;
140 for (size_t seed = 0; seed < n; ++seed) {
141 if (cc.label_map[seed] != 0 || background[seed] != 0)
142 continue;
143
144 ++region;
145 pending.clear();
146 pending.push_back(seed);
147 background[seed] = region;
148 bool exterior = false;
149 for (size_t head = 0; head < pending.size(); ++head) {
150 const size_t pixel = pending[head];
151 const auto x = static_cast<uint32_t>(pixel % w);
152 const auto y = static_cast<uint32_t>(pixel / w);
153 exterior = exterior || x == 0 || y == 0 || x + 1 == w || y + 1 == h;
154
155 const auto visit = [&](size_t neighbor) {
156 if (cc.label_map[neighbor] == 0 && background[neighbor] == 0) {
157 background[neighbor] = region;
158 pending.push_back(neighbor);
159 }
160 };
161 if (x > 0)
162 visit(pixel - 1);
163 if (x + 1 < w)
164 visit(pixel + 1);
165 if (y > 0)
166 visit(pixel - w);
167 if (y + 1 < h)
168 visit(pixel + w);
169 }
170
171 if (!exterior) {
172 const uint32_t parent = cc.label_map[seed - w];
173 seeds.push_back({ .pixel = seed, .label = region, .parent = parent });
174 }
175 }
176
177 std::vector<Contour> result(seeds.size());
178 std::vector<uint8_t> valid(seeds.size(), 0);
179 const size_t max_points = max_points_per_contour > 0
180 ? static_cast<size_t>(max_points_per_contour)
181 : n * 8;
182
183 std::for_each(std::execution::par_unseq,
184 std::views::iota(size_t { 0 }, seeds.size()).begin(),
185 std::views::iota(size_t { 0 }, seeds.size()).end(),
186 [&](size_t ci) {
187 const auto& seed = seeds[ci];
188 const glm::ivec2 start(static_cast<int32_t>(seed.pixel % w), static_cast<int32_t>(seed.pixel / w));
189 const auto inside = [&](glm::ivec2 p) {
190 if (p.x < 0 || p.y < 0 || static_cast<uint32_t>(p.x) >= w || static_cast<uint32_t>(p.y) >= h)
191 return false;
192 const size_t index = static_cast<size_t>(p.y) * w + static_cast<uint32_t>(p.x);
193 return seed.parent == 0 ? cc.label_map[index] == seed.label : background[index] == seed.label;
194 };
195 const auto points = walk_boundary(start, max_points, inside);
196 if (points.size() < 3)
197 return;
198
199 auto contour = measure_contour(points, w, h, seed.parent);
200 if (contour.area < min_area)
201 return;
202
203 result[ci] = std::move(contour);
204 valid[ci] = 1;
205 });
206
207 std::vector<Contour> out;
208 out.reserve(seeds.size());
209 for (size_t i = 0; i < seeds.size(); ++i) {
210 if (valid[i])
211 out.push_back(std::move(result[i]));
212 }
213
214 if (max_contours > 0) {
215 const size_t count = std::min(out.size(), static_cast<size_t>(max_contours));
216 std::partial_sort(out.begin(),
217 out.begin() + static_cast<ptrdiff_t>(count),
218 out.end(),
219 [](const Contour& a, const Contour& b) { return a.area > b.area; });
220 out.resize(count);
221 }
222
223 return out;
224}
uint32_t parent
Definition Contours.cpp:17
size_t pixel
Definition Contours.cpp:15
uint32_t label
Definition Contours.cpp:16
std::vector< glm::vec2 > * points
uint32_t h
Definition InkPress.cpp:29
size_t a
size_t b
std::vector< float > * out
uint32_t index
Definition VKDevice.cpp:122
size_t count
GeometryFn< float > background(Kinesis::AABB2D bounds, glm::vec3 color, const std::shared_ptr< Core::VKImage > &texture)
TRIANGLE_STRIP background quad for a plot area.
Definition PlotSpec.cpp:88

References a, b, count, MayaFlux::Kinesis::Vision::ComponentResult::count, h, index, label, MayaFlux::Kinesis::Vision::ComponentResult::label_map, out, parent, pixel, and points.