101{
108
109 uint32_t channels = 4;
110
112 cur_vec.assign(frame.begin(), frame.end());
113
116 auto en =
static_cast<Eigen::Index
>(
static_cast<size_t>(w) *
h);
117
118 VisionResult result;
119 result.w = w;
121
122 for (
const auto& step :
sequence.steps) {
123 switch (step.op) {
124
126 uint32_t new_w = 0, new_h = 0;
128 w = new_w;
130 result.w = w;
132 en =
static_cast<Eigen::Index
>(
static_cast<size_t>(w) *
h);
133 std::swap(cur, nxt);
134 result.structured = std::monostate {};
135 break;
136 }
137
140 channels = 1;
141 std::swap(cur, nxt);
142
145 slot_vec(cur).begin() +
static_cast<size_t>(w) *
h);
146 }
147
148 result.structured = std::monostate {};
149 break;
150 }
151
154 channels = 3;
155 std::swap(cur, nxt);
156 result.structured = std::monostate {};
157 break;
158 }
159
162 channels = 4;
163 std::swap(cur, nxt);
164 result.structured = std::monostate {};
165 break;
166 }
167
169 const auto& p = get_params<ThresholdParams>(step.params, step.op);
171 result.structured = std::monostate {};
172 break;
173 }
174
176 const auto& p = get_params<ThresholdAdaptiveParams>(step.params, step.op);
178 std::swap(cur, nxt);
179 result.structured = std::monostate {};
180 break;
181 }
182
185 std::swap(cur, nxt);
186 result.structured = std::monostate {};
187 break;
188 }
189
192 const float mn = m.minCoeff();
193 const float mx = m.maxCoeff();
194 if (mx > mn)
195 m = (m - mn) / (mx - mn);
196 result.structured = std::monostate {};
197 break;
198 }
199
201 const auto& p = get_params<NormalizeRangeParams>(step.params, step.op);
202 if (p.hi > p.lo) {
204 m = ((m - p.lo) / (p.hi - p.lo)).
max(0.0F).min(1.0F);
205 }
206 result.structured = std::monostate {};
207 break;
208 }
209
211 const auto& p = get_params<GaussianBlurParams>(step.params, step.op);
214 std::swap(cur, nxt);
215 result.structured = std::monostate {};
216 break;
217 }
218
220 const auto& p = get_params<FilterSeparableParams>(step.params, step.op);
222 std::swap(cur, nxt);
223 result.structured = std::monostate {};
224 break;
225 }
226
228 GradientResult grad;
231
234 slot_map_mut(nxt, en) = (dx.square() + dy.square()).sqrt();
236
239
243 grad.angle.resize(static_cast<size_t>(en));
244
245 P::transform(P::par_unseq,
248 [](float gx, float gy) { return std::atan2(gy, gx); });
249
250 result.structured = std::move(grad);
251 std::swap(cur, nxt);
252 break;
253 }
254
256 GradientResult grad;
259
262 slot_map_mut(nxt, en) = (dx.square() + dy.square()).sqrt();
263
267
271 grad.angle.resize(static_cast<size_t>(en));
272
273 P::transform(P::par_unseq,
276 [](float gx, float gy) { return std::atan2(gy, gx); });
277
278 result.structured = std::move(grad);
279 std::swap(cur, nxt);
280 break;
281 }
282
284 const auto& p = get_params<CannyParams>(step.params, step.op);
286 std::swap(cur, nxt);
287 result.structured = std::monostate {};
288 break;
289 }
290
292 const auto& p = get_params<MorphParams>(step.params, step.op);
294 std::swap(cur, nxt);
295 result.structured = std::monostate {};
296 break;
297 }
298
300 const auto& p = get_params<MorphParams>(step.params, step.op);
302 std::swap(cur, nxt);
303 result.structured = std::monostate {};
304 break;
305 }
306
308 const auto& p = get_params<MorphParams>(step.params, step.op);
310 std::swap(cur, nxt);
311 result.structured = std::monostate {};
312 break;
313 }
314
316 const auto& p = get_params<MorphParams>(step.params, step.op);
318 std::swap(cur, nxt);
319 result.structured = std::monostate {};
320 break;
321 }
322
324 const auto& p = get_params<MorphParams>(step.params, step.op);
326 std::swap(cur, nxt);
327 result.structured = std::monostate {};
328 break;
329 }
330
332 const size_t n =
static_cast<size_t>(w) *
h;
334 std::span<const float>(
slot_vec(cur)).subspan(0, n),
337 result.w = 0;
338 result.h = 0;
339 break;
340 }
341
343 const auto& p = get_params<FindContoursParams>(step.params, step.op);
344 const size_t n =
static_cast<size_t>(w) *
h;
346 std::span<const float>(
slot_vec(cur)).subspan(0, n),
347 w,
h, p.min_area, p.max_contours);
349 result.w = 0;
350 result.h = 0;
351 break;
352 }
353
355 const auto& p = get_params<HarrisParams>(step.params, step.op);
363 std::swap(cur, nxt);
364 result.structured = std::monostate {};
365 break;
366 }
367
369 const auto& p = get_params<ExtractPeaksParams>(step.params, step.op);
372
375
376 result.structured = std::move(kpts);
377 if (!
sequence.track_follows_peaks) {
379 result.w = 0;
380 result.h = 0;
381 }
382 break;
383 }
384
386 const auto& p = get_params<TrackKeypointsParams>(step.params, step.op);
387
388 auto& prev_vec = std::get<std::vector<float>>(
m_prev_gray);
391 result.structured = std::vector<TrackResult> {};
393 result.w = 0;
394 result.h = 0;
395 break;
396 }
397
398 std::vector<glm::vec2> prev_pos;
401 prev_pos.push_back(kp.position);
402
406 p.window_radius, p.max_iterations,
407 p.eigen_threshold, p.error_threshold);
408
410 result.structured = std::move(tracked);
412 result.w = 0;
413 result.h = 0;
414 break;
415 }
416
419 break;
420 const size_t n =
static_cast<size_t>(w) *
h * channels;
421 SnapshotEntry entry;
423 entry.w = w;
425 entry.channels = channels;
426 result.snapshots.push_back(std::move(entry));
427 break;
428 }
429 }
430 }
431
432 result.pixel_image = std::move(
m_slots[cur]);
434 return result;
435}
std::array< Kakshya::DataVariant, k_slot_count > m_slots
Eigen::Map< Eigen::ArrayXf > slot_map_mut(size_t i, Eigen::Index n) noexcept
Zero-copy mutable Eigen::Map<ArrayXf> over slot i.
std::vector< float > m_curr_gray_cache
static constexpr size_t k_slot_iyy
static constexpr size_t k_slot_syy
static constexpr size_t k_slot_dx
std::vector< float > & slot_vec(size_t i) noexcept
Mutable reference to the vector<float> inside slot i.
static constexpr size_t k_slot_sxy
Kakshya::DataVariant m_prev_gray
static constexpr size_t k_slot_dy
static constexpr size_t k_slot_ixy
static constexpr size_t k_slot_ixx
static constexpr size_t k_slot_tmp
void ensure_slots(uint32_t w, uint32_t h)
Ensure all slots are sized to n_pixels floats.
static constexpr size_t k_slot_cur
const std::vector< float > & gaussian_kernel(float sigma)
Return a reference to the precomputed 1D Gaussian kernel for sigma.
static constexpr size_t k_slot_sxx
static constexpr size_t k_slot_nxt
std::vector< Keypoint > m_prev_keypoints
Eigen::Map< const Eigen::ArrayXf > slot_map(size_t i, Eigen::Index n) const noexcept
Zero-copy read-only Eigen::Map<const ArrayXf> over slot i.
std::vector< double > max(std::span< const double > data, size_t n_windows, uint32_t hop_size, uint32_t window_size)
Maximum value per window.
void rgba_to_gray(std::span< const float > rgba, std::span< float > dst, uint32_t w, uint32_t h)
Convert RGBA to luminance gray using BT.601 coefficients.
std::vector< float > filter_separable(std::span< const float > src, uint32_t w, uint32_t h, std::span< const float > kernel_x, std::span< const float > kernel_y)
Apply a separable 2D filter via two 1D passes.
std::vector< float > canny(std::span< const float > gray, uint32_t w, uint32_t h, float sigma, float low_threshold, float high_threshold)
Canny edge detector.
void gray_to_rgba(std::span< const float > gray, std::span< float > dst, uint32_t w, uint32_t h)
Global threshold writing into caller-supplied buffer.
std::vector< Keypoint > extract_peaks(std::span< const float > response, uint32_t w, uint32_t h, float threshold, uint32_t nms_radius)
Extract peaks from a response map via non-maximum suppression.
void erode(std::span< const float > mask, std::span< float > dst, uint32_t w, uint32_t h, uint32_t radius)
Erosion writing into dst.
std::vector< float > harris_response(std::span< const float > gray, uint32_t w, uint32_t h, float k, float sigma)
Compute the Harris corner response map.
ComponentResult connected_components(std::span< const float > mask, uint32_t w, uint32_t h)
Label connected foreground components in a binary mask.
void rgba_to_hsv(std::span< const float > rgba, std::span< float > dst, uint32_t w, uint32_t h)
Convert RGBA to HSV writing into caller-supplied buffer.
std::vector< Contour > find_contours(std::span< const float > mask, uint32_t w, uint32_t h, float min_area, uint32_t max_contours)
Extract outer contours from a binary mask.
void close(std::span< const float > mask, std::span< float > tmp, std::span< float > dst, uint32_t w, uint32_t h, uint32_t radius)
Morphological closing writing into dst.
void sobel(std::span< const float > gray, std::span< float > dx, std::span< float > dy, std::span< float > tmp, uint32_t w, uint32_t h)
Sobel gradient writing dx and dy into caller-supplied buffers.
void dilate(std::span< const float > mask, std::span< float > dst, uint32_t w, uint32_t h, uint32_t radius)
Dilation writing into dst.
std::vector< TrackResult > track_keypoints(std::span< const float > prev_gray, std::span< const float > curr_gray, uint32_t w, uint32_t h, std::span< const glm::vec2 > prev_points, uint32_t window_radius, uint32_t max_iterations, float eigen_threshold, float error_threshold)
Track keypoints from prev_gray to curr_gray via Lucas-Kanade.
void scharr(std::span< const float > gray, std::span< float > dx, std::span< float > dy, std::span< float > tmp, uint32_t w, uint32_t h)
Scharr gradient writing dx and dy into caller-supplied buffers.
void threshold_otsu(std::span< const float > gray, std::span< float > dst)
Otsu threshold writing into caller-supplied buffer.
void threshold_adaptive(std::span< const float > gray, std::span< float > dst, uint32_t w, uint32_t h, uint32_t block_size, float offset)
Adaptive threshold writing into caller-supplied buffer.
void downsample_2x(std::span< const float > src, std::span< float > dst, uint32_t w, uint32_t h, uint32_t &new_w, uint32_t &new_h)
2x box-filter downsample writing into a caller-supplied buffer.
void morph_gradient(std::span< const float > mask, std::span< float > tmp, std::span< float > dst, uint32_t w, uint32_t h, uint32_t radius)
Morphological gradient (dilate - erode) writing into dst.
void open(std::span< const float > mask, std::span< float > tmp, std::span< float > dst, uint32_t w, uint32_t h, uint32_t radius)
Morphological opening writing into dst.
std::shared_ptr< Vruta::Routine > sequence(std::vector< std::pair< double, std::function< void()> > > sequence, Vruta::ProcessingToken token)
Creates a temporal sequence that executes callbacks at specified time offsets.
double peak(const std::vector< double > &data)
Find peak amplitude in single-channel data.