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

◆ run()

VisionResult MayaFlux::Kinesis::Vision::VisionExecutor::run ( const VisionSequence sequence,
std::span< const float >  frame,
uint32_t  w,
uint32_t  h 
)

Execute a VisionSequence on one frame.

Parameters
sequenceOrdered steps to execute.
frameNormalised float input. RGBA (4 floats/pixel) for RgbaToGray/RgbaToHsv; single-channel otherwise.
wFrame width in pixels.
hFrame height in pixels.
Returns
VisionResult with pixel_image (DataVariant) and/or structured output.

Definition at line 97 of file VisionExecutor.cpp.

101{
102 ensure_slots(w, h);
103 const size_t slot_min = static_cast<size_t>(m_slot_w) * m_slot_h * 4;
104 if (slot_vec(k_slot_nxt).size() < slot_min)
105 slot_vec(k_slot_nxt).resize(slot_min);
106 if (slot_vec(k_slot_cur).capacity() < slot_min)
107 slot_vec(k_slot_cur).reserve(slot_min);
108
109 uint32_t channels = 4;
110
111 auto& cur_vec = slot_vec(k_slot_cur);
112 cur_vec.assign(frame.begin(), frame.end());
113
114 size_t cur = k_slot_cur;
115 size_t nxt = k_slot_nxt;
116 auto en = static_cast<Eigen::Index>(static_cast<size_t>(w) * h);
117
118 VisionResult result;
119 result.w = w;
120 result.h = h;
121
122 for (const auto& step : sequence.steps) {
123 switch (step.op) {
124
126 uint32_t new_w = 0, new_h = 0;
127 downsample_2x(slot_vec(cur), slot_vec(nxt), w, h, channels, new_w, new_h);
128 w = new_w;
129 h = new_h;
130 result.w = w;
131 result.h = h;
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
139 rgba_to_gray(slot_vec(cur), slot_vec(nxt), w, h);
140 channels = 1;
141 std::swap(cur, nxt);
142
143 if (sequence.tracks_keypoints && !sequence.track_follows_peaks) {
144 m_curr_gray_cache.assign(slot_vec(cur).begin(),
145 slot_vec(cur).begin() + static_cast<size_t>(w) * h);
146 }
147
148 result.structured = std::monostate {};
149 break;
150 }
151
152 case VisionOp::RgbaToHsv: {
153 rgba_to_hsv(slot_vec(cur), slot_vec(nxt), w, h);
154 channels = 3;
155 std::swap(cur, nxt);
156 result.structured = std::monostate {};
157 break;
158 }
159
161 gray_to_rgba(slot_vec(cur), slot_vec(nxt), w, h);
162 channels = 4;
163 std::swap(cur, nxt);
164 result.structured = std::monostate {};
165 break;
166 }
167
168 case VisionOp::Threshold: {
169 const auto& p = get_params<ThresholdParams>(step.params, step.op);
170 slot_map_mut(cur, en) = (slot_map(cur, en) >= p.value).cast<float>();
171 result.structured = std::monostate {};
172 break;
173 }
174
176 const auto& p = get_params<ThresholdAdaptiveParams>(step.params, step.op);
177 threshold_adaptive(slot_vec(cur), slot_vec(nxt), w, h, p.block_size, p.offset);
178 std::swap(cur, nxt);
179 result.structured = std::monostate {};
180 break;
181 }
182
184 threshold_otsu(slot_vec(cur), slot_vec(nxt));
185 std::swap(cur, nxt);
186 result.structured = std::monostate {};
187 break;
188 }
189
191 auto m = slot_map_mut(cur, en);
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) {
203 auto m = slot_map_mut(cur, en);
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);
212 const auto& kern = gaussian_kernel(p.sigma);
213 filter_separable(slot_vec(cur), slot_vec(k_slot_tmp), slot_vec(nxt), w, h, kern, kern);
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);
221 filter_separable(slot_vec(cur), slot_vec(k_slot_tmp), slot_vec(nxt), w, h, p.kernel_x, p.kernel_y);
222 std::swap(cur, nxt);
223 result.structured = std::monostate {};
224 break;
225 }
226
227 case VisionOp::Sobel: {
228 GradientResult grad;
230 slot_vec(k_slot_tmp), w, h);
231
232 auto dx = slot_map(k_slot_dx, en);
233 auto dy = slot_map(k_slot_dy, en);
234 slot_map_mut(nxt, en) = (dx.square() + dy.square()).sqrt();
235 const float peak = slot_map(nxt, en).maxCoeff();
236
237 if (peak > 0.0F)
238 slot_map_mut(nxt, en) /= peak;
239
240 grad.dx.assign(slot_vec(k_slot_dx).begin(), slot_vec(k_slot_dx).begin() + en);
241 grad.dy.assign(slot_vec(k_slot_dy).begin(), slot_vec(k_slot_dy).begin() + en);
242 grad.magnitude.assign(slot_vec(nxt).begin(), slot_vec(nxt).begin() + en);
243 grad.angle.resize(static_cast<size_t>(en));
244
245 P::transform(P::par_unseq,
246 slot_vec(k_slot_dx).begin(), slot_vec(k_slot_dx).begin() + en,
247 slot_vec(k_slot_dy).begin(), grad.angle.begin(),
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
255 case VisionOp::Scharr: {
256 GradientResult grad;
258 slot_vec(k_slot_tmp), w, h);
259
260 auto dx = slot_map(k_slot_dx, en);
261 auto dy = slot_map(k_slot_dy, en);
262 slot_map_mut(nxt, en) = (dx.square() + dy.square()).sqrt();
263
264 const float peak = slot_map(nxt, en).maxCoeff();
265 if (peak > 0.0F)
266 slot_map_mut(nxt, en) /= peak;
267
268 grad.dx.assign(slot_vec(k_slot_dx).begin(), slot_vec(k_slot_dx).begin() + en);
269 grad.dy.assign(slot_vec(k_slot_dy).begin(), slot_vec(k_slot_dy).begin() + en);
270 grad.magnitude.assign(slot_vec(nxt).begin(), slot_vec(nxt).begin() + en);
271 grad.angle.resize(static_cast<size_t>(en));
272
273 P::transform(P::par_unseq,
274 slot_vec(k_slot_dx).begin(), slot_vec(k_slot_dx).begin() + en,
275 slot_vec(k_slot_dy).begin(), grad.angle.begin(),
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
283 case VisionOp::Canny: {
284 const auto& p = get_params<CannyParams>(step.params, step.op);
285 canny(slot_vec(cur), slot_vec(nxt), w, h, p.sigma, p.low_threshold, p.high_threshold);
286 std::swap(cur, nxt);
287 result.structured = std::monostate {};
288 break;
289 }
290
291 case VisionOp::Erode: {
292 const auto& p = get_params<MorphParams>(step.params, step.op);
293 erode(slot_vec(cur), slot_vec(nxt), w, h, p.radius);
294 std::swap(cur, nxt);
295 result.structured = std::monostate {};
296 break;
297 }
298
299 case VisionOp::Dilate: {
300 const auto& p = get_params<MorphParams>(step.params, step.op);
301 dilate(slot_vec(cur), slot_vec(nxt), w, h, p.radius);
302 std::swap(cur, nxt);
303 result.structured = std::monostate {};
304 break;
305 }
306
307 case VisionOp::Open: {
308 const auto& p = get_params<MorphParams>(step.params, step.op);
309 open(slot_vec(cur), slot_vec(k_slot_tmp), slot_vec(nxt), w, h, p.radius);
310 std::swap(cur, nxt);
311 result.structured = std::monostate {};
312 break;
313 }
314
315 case VisionOp::Close: {
316 const auto& p = get_params<MorphParams>(step.params, step.op);
317 close(slot_vec(cur), slot_vec(k_slot_tmp), slot_vec(nxt), w, h, p.radius);
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);
325 morph_gradient(slot_vec(cur), slot_vec(k_slot_tmp), slot_vec(nxt), w, h, p.radius);
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;
333 result.structured = connected_components(
334 std::span<const float>(slot_vec(cur)).subspan(0, n),
335 w, h);
336 slot_vec(cur).clear();
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;
345 result.structured = find_contours(
346 std::span<const float>(slot_vec(cur)).subspan(0, n),
347 w, h, p.min_area, p.max_contours);
348 slot_vec(cur).clear();
349 result.w = 0;
350 result.h = 0;
351 break;
352 }
353
355 const auto& p = get_params<HarrisParams>(step.params, step.op);
357 slot_vec(cur),
361 slot_vec(nxt),
362 w, h, p.k, gaussian_kernel(p.sigma));
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);
370 auto kpts = extract_peaks(slot_vec(cur), w, h, p.threshold, p.nms_radius);
371 m_prev_keypoints = kpts;
372
373 if (sequence.tracks_keypoints && !sequence.track_follows_peaks)
374 std::swap(std::get<std::vector<float>>(m_prev_gray), m_curr_gray_cache);
375
376 result.structured = std::move(kpts);
377 if (!sequence.track_follows_peaks) {
378 slot_vec(cur).clear();
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);
389 if (prev_vec.empty() || m_prev_keypoints.empty()) {
390 std::swap(prev_vec, slot_vec(cur));
391 result.structured = std::vector<TrackResult> {};
392 slot_vec(cur).clear();
393 result.w = 0;
394 result.h = 0;
395 break;
396 }
397
398 std::vector<glm::vec2> prev_pos;
399 prev_pos.reserve(m_prev_keypoints.size());
400 for (const auto& kp : m_prev_keypoints)
401 prev_pos.push_back(kp.position);
402
403 auto tracked = track_keypoints(
404 prev_vec, slot_vec(cur),
405 w, h, prev_pos,
406 p.window_radius, p.max_iterations,
407 p.eigen_threshold, p.error_threshold);
408
409 std::swap(prev_vec, slot_vec(cur));
410 result.structured = std::move(tracked);
411 slot_vec(cur).clear();
412 result.w = 0;
413 result.h = 0;
414 break;
415 }
416
417 case VisionOp::Snapshot: {
418 if (slot_vec(cur).empty())
419 break;
420 const size_t n = static_cast<size_t>(w) * h * channels;
421 SnapshotEntry entry;
422 entry.pixels.assign(slot_vec(cur).begin(), slot_vec(cur).begin() + n);
423 entry.w = w;
424 entry.h = h;
425 entry.channels = channels;
426 result.snapshots.push_back(std::move(entry));
427 break;
428 }
429 } // switch
430 }
431
432 result.pixel_image = std::move(m_slots[cur]);
433 slot_vec(cur).reserve(static_cast<size_t>(m_slot_w) * m_slot_h * 4);
434 return result;
435}
uint32_t h
Definition InkPress.cpp:28
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 > & slot_vec(size_t i) noexcept
Mutable reference to the vector<float> inside slot i.
void ensure_slots(uint32_t w, uint32_t h)
Ensure all slots are sized to n_pixels floats.
const std::vector< float > & gaussian_kernel(float sigma)
Return a reference to the precomputed 1D Gaussian kernel for sigma.
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.
Definition Analysis.cpp:436
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.
Definition PixelOps.cpp:18
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.
Definition Gradient.cpp:132
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.
Definition PixelOps.cpp:138
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.
Definition Harris.cpp:184
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.
Definition Harris.cpp:19
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.
Definition PixelOps.cpp:94
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.
Definition Contours.cpp:70
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.
Definition Gradient.cpp:66
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.
Definition Gradient.cpp:99
void threshold_otsu(std::span< const float > gray, std::span< float > dst)
Otsu threshold writing into caller-supplied buffer.
Definition PixelOps.cpp:299
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.
Definition PixelOps.cpp:258
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.
Definition PixelOps.cpp:443
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.
Definition Tasks.cpp:36
double peak(const std::vector< double > &data)
Find peak amplitude in single-channel data.
Definition Yantra.cpp:268

References MayaFlux::Kinesis::Vision::GradientResult::angle, MayaFlux::Kinesis::Vision::canny(), MayaFlux::Kinesis::Vision::Canny, MayaFlux::Kinesis::Vision::SnapshotEntry::channels, MayaFlux::Kinesis::Vision::close(), MayaFlux::Kinesis::Vision::Close, MayaFlux::Kinesis::Vision::connected_components(), MayaFlux::Kinesis::Vision::ConnectedComponents, MayaFlux::Kinesis::Vision::dilate(), MayaFlux::Kinesis::Vision::Dilate, MayaFlux::Kinesis::Vision::Downsample2x, MayaFlux::Kinesis::Vision::downsample_2x(), MayaFlux::Kinesis::Vision::GradientResult::dx, MayaFlux::Kinesis::Vision::GradientResult::dy, ensure_slots(), MayaFlux::Kinesis::Vision::erode(), MayaFlux::Kinesis::Vision::Erode, MayaFlux::Kinesis::Vision::extract_peaks(), MayaFlux::Kinesis::Vision::ExtractPeaks, MayaFlux::Kinesis::Vision::filter_separable(), MayaFlux::Kinesis::Vision::FilterSeparable, MayaFlux::Kinesis::Vision::find_contours(), MayaFlux::Kinesis::Vision::FindContours, gaussian_kernel(), MayaFlux::Kinesis::Vision::GaussianBlur, MayaFlux::Kinesis::Vision::gray_to_rgba(), MayaFlux::Kinesis::Vision::GrayToRgba, MayaFlux::Kinesis::Vision::SnapshotEntry::h, MayaFlux::Kinesis::Vision::VisionResult::h, h, MayaFlux::Kinesis::Vision::harris_response(), MayaFlux::Kinesis::Vision::HarrisResponse, k_slot_cur, k_slot_dx, k_slot_dy, k_slot_ixx, k_slot_ixy, k_slot_iyy, k_slot_nxt, k_slot_sxx, k_slot_sxy, k_slot_syy, k_slot_tmp, m_curr_gray_cache, m_prev_gray, m_prev_keypoints, m_slot_h, m_slot_w, m_slots, MayaFlux::Kinesis::Vision::GradientResult::magnitude, MayaFlux::Kinesis::Vision::morph_gradient(), MayaFlux::Kinesis::Vision::MorphGradient, MayaFlux::Kinesis::Vision::NormalizeInplace, MayaFlux::Kinesis::Vision::NormalizeRange, MayaFlux::Kinesis::Vision::open(), MayaFlux::Kinesis::Vision::Open, MayaFlux::peak(), MayaFlux::Kinesis::Vision::VisionResult::pixel_image, MayaFlux::Kinesis::Vision::SnapshotEntry::pixels, MayaFlux::Kinesis::Vision::rgba_to_gray(), MayaFlux::Kinesis::Vision::rgba_to_hsv(), MayaFlux::Kinesis::Vision::RgbaToGray, MayaFlux::Kinesis::Vision::RgbaToHsv, MayaFlux::Kinesis::Vision::scharr(), MayaFlux::Kinesis::Vision::Scharr, slot_map(), slot_map_mut(), slot_vec(), MayaFlux::Kinesis::Vision::Snapshot, MayaFlux::Kinesis::Vision::VisionResult::snapshots, MayaFlux::Kinesis::Vision::sobel(), MayaFlux::Kinesis::Vision::Sobel, MayaFlux::Kinesis::Vision::VisionResult::structured, MayaFlux::Kinesis::Vision::Threshold, MayaFlux::Kinesis::Vision::threshold_adaptive(), MayaFlux::Kinesis::Vision::threshold_otsu(), MayaFlux::Kinesis::Vision::ThresholdAdaptive, MayaFlux::Kinesis::Vision::ThresholdOtsu, MayaFlux::Kinesis::Vision::track_keypoints(), MayaFlux::Kinesis::Vision::TrackKeypoints, MayaFlux::Kinesis::Vision::SnapshotEntry::w, and MayaFlux::Kinesis::Vision::VisionResult::w.

Referenced by MayaFlux::Yantra::VisionAnalyzer< InputType, OutputType >::analyze_implementation(), MayaFlux::Kakshya::VisionProcessor::process(), and MayaFlux::Buffers::ImageCVProcessor< T >::processing_function().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: