20 const T*
ptr = std::get_if<T>(&p);
22 error<std::logic_error>(
24 std::source_location::current(),
25 "VisionExecutor: parameter type mismatch for op {}",
31 void render_labels(std::vector<float>&
pixels, std::span<const uint32_t> labels)
33 pixels.resize(labels.size() * 4);
34 std::for_each(std::execution::par_unseq,
35 std::views::iota(
size_t { 0 }, labels.size()).begin(),
36 std::views::iota(
size_t { 0 }, labels.size()).end(),
38 const uint32_t
color = labels[i] * 2654435761U;
39 const size_t pixel = i * 4;
48 std::vector<float>&
pixels, std::span<const Contour> contours,
49 uint32_t w, uint32_t
h)
51 pixels.assign(
static_cast<size_t>(w) *
h * 4, 0.0F);
52 for (
size_t i = 3; i <
pixels.size(); i += 4)
55 const glm::vec2 extent(
static_cast<float>(w),
static_cast<float>(
h));
56 for (
const auto& contour : contours) {
57 for (
size_t i = 0; i < contour.points.size(); ++i) {
58 const glm::vec2
a = contour.points[i] * extent;
59 const glm::vec2
b = contour.points[(i + 1) % contour.points.size()] * extent;
60 int32_t x =
static_cast<int32_t
>(std::round(
a.x));
61 int32_t y =
static_cast<int32_t
>(std::round(
a.y));
62 const auto end_x =
static_cast<int32_t
>(std::round(
b.x));
63 const auto end_y =
static_cast<int32_t
>(std::round(
b.y));
64 const int32_t dx = std::abs(end_x - x);
65 const int32_t dy = -std::abs(end_y - y);
66 const int32_t sx = x < end_x ? 1 : -1;
67 const int32_t sy = y < end_y ? 1 : -1;
68 int32_t
error = dx + dy;
71 if (x >= 0 && y >= 0 &&
static_cast<uint32_t
>(x) < w &&
static_cast<uint32_t
>(y) <
h) {
72 const size_t pixel = (
static_cast<size_t>(y) * w +
static_cast<uint32_t
>(x)) * 4;
75 if (x == end_x && y == end_y)
77 const int32_t twice_error = 2 *
error;
78 if (twice_error >= dy) {
82 if (twice_error <= dx) {
103 const size_t n =
static_cast<size_t>(w) *
h;
106 m_slots[i] = std::vector<float>(n, 0.0F);
118 const auto key = std::bit_cast<uint32_t>(sigma);
123 const auto radius =
static_cast<int32_t
>(std::ceil(3.0F * sigma));
125 const float inv_2s2 = 1.0F / (2.0F * sigma * sigma);
127 std::vector<float> k(
static_cast<size_t>(
size));
130 const float v = std::exp(-
static_cast<float>(i * i) * inv_2s2);
131 k[
static_cast<size_t>(i +
radius)] = v;
135 auto kmap = Eigen::Map<Eigen::ArrayXf>(k.data(),
static_cast<Eigen::Index
>(k.size()));
158 std::span<const float> frame,
159 uint32_t w, uint32_t
h)
169 cur_vec.assign(frame.begin(), frame.end());
177 std::vector<Keypoint> current_keypoints;
184 uint32_t new_w = 0, new_h = 0;
200 if (wants_tracking) {
226 const auto& p = get_params<ThresholdParams>(step.params, step.op);
233 const auto& p = get_params<ThresholdAdaptiveParams>(step.params, step.op);
244 std::span<float>(
slot_vec(nxt)).first(n));
252 const float mn = m.minCoeff();
253 const float mx = m.maxCoeff();
255 m = (m - mn) / (mx - mn);
261 const auto& p = get_params<NormalizeRangeParams>(step.params, step.op);
264 m = ((m - p.lo) / (p.hi - p.lo)).
max(0.0F).min(1.0F);
271 const auto& p = get_params<GaussianBlurParams>(step.params, step.op);
280 const auto& p = get_params<FilterSeparableParams>(step.params, step.op);
294 slot_map_mut(nxt, en) = (dx.square() + dy.square()).sqrt();
295 const float peak =
slot_map(nxt, en).maxCoeff();
303 grad.
angle.resize(
static_cast<size_t>(en));
305 std::transform(std::execution::par_unseq,
308 [](
float gx,
float gy) { return std::atan2(gy, gx); });
322 slot_map_mut(nxt, en) = (dx.square() + dy.square()).sqrt();
324 const float peak =
slot_map(nxt, en).maxCoeff();
331 grad.
angle.resize(
static_cast<size_t>(en));
333 std::transform(std::execution::par_unseq,
336 [](
float gx,
float gy) { return std::atan2(gy, gx); });
344 const auto& p = get_params<CannyParams>(step.params, step.op);
352 const auto& p = get_params<MorphParams>(step.params, step.op);
360 const auto& p = get_params<MorphParams>(step.params, step.op);
368 const auto& p = get_params<MorphParams>(step.params, step.op);
376 const auto& p = get_params<MorphParams>(step.params, step.op);
384 const auto& p = get_params<MorphParams>(step.params, step.op);
392 const auto& p = get_params<ConnectedComponentsParams>(step.params, step.op);
404 }
else if (!contours_follow) {
410 if (!p.export_labels && !contours_follow)
411 components.label_map.clear();
420 "VisionExecutor: FindContours requires ConnectedComponents as the immediately preceding step");
427 "VisionExecutor: FindContours requires a connected-component result");
431 const auto& p = get_params<FindContoursParams>(step.params, step.op);
433 p.min_area, p.max_contours, p.max_points_per_contour);
449 const auto& p = get_params<HarrisParams>(step.params, step.op);
463 const auto& p = get_params<ExtractPeaksParams>(step.params, step.op);
467 if (peaks_feed_track)
468 current_keypoints = kpts;
472 if (wants_tracking && !peaks_feed_track)
476 if (!peaks_feed_track) {
485 const auto& p = get_params<TrackKeypointsParams>(step.params, step.op);
488 const auto curr_gray = peaks_feed_track
491 auto& prev_vec = std::get<std::vector<float>>(
m_prev_gray);
492 std::vector<TrackResult> tracked;
494 std::vector<glm::vec2> prev_pos;
497 prev_pos.push_back(kp.position);
502 p.window_radius, p.max_iterations,
503 p.eigen_threshold, p.error_threshold,
504 p.forward_backward_threshold);
507 if (peaks_feed_track) {
535 "VisionExecutor: OpticalFlowDense has no CPU implementation");
#define MF_ERROR(comp, ctx,...)
Contour extraction from binary float masks.
const std::vector< float > * pixels
Gradient and edge detection on normalised float image spans.
Harris corner detection and non-maximum suppression.
2D spatial filtering on normalised float image spans.
Sparse optical flow via Lucas-Kanade tracker.
Pointwise pixel operations for MayaFlux::Kinesis::Vision.
std::vector< float > * out
Dispatch engine for VisionSequence execution.
Binary morphological operations on normalised float masks.
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.
void reset()
Clear stored inter-frame state.
static constexpr size_t k_slot_sxy
std::unordered_map< uint32_t, std::vector< float > > m_kernel_cache
Kakshya::DataVariant m_prev_gray
CpuVisionPass m_pass
Walk state for the current run: sequence position, geometry, working slot index, and the result under...
VisionResult run(const VisionSequence &sequence, std::span< const float > frame, uint32_t w, uint32_t h)
Execute a VisionSequence on one frame.
static constexpr size_t k_slot_count
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.
@ Runtime
General runtime operations (default fallback)
void error(Component component, Context context, std::source_location location, std::string_view message)
Log an error message and optionally throw an exception.
@ Kinesis
General mathematical and physics algorithns.
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.
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.
std::vector< Contour > find_contours(std::span< const float > mask, uint32_t w, uint32_t h, float min_area, uint32_t max_contours, uint32_t max_points_per_contour)
Extract outer and hole contours from a binary mask.
void dilate(std::span< const float > mask, std::span< float > dst, uint32_t w, uint32_t h, uint32_t radius)
Dilation writing into dst.
bool tracks_keypoints(const VisionSequence &seq)
True when any step tracks keypoints.
VisionOp
Named operations available in a VisionSequence.
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.
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, float forward_backward_threshold)
Track keypoints from prev_gray to curr_gray via Lucas-Kanade.
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.
std::variant< std::monostate, ThresholdParams, ThresholdAdaptiveParams, OtsuParams, NormalizeRangeParams, GaussianBlurParams, FilterSeparableParams, CannyParams, MorphParams, HarrisParams, ExtractPeaksParams, TrackKeypointsParams, ConnectedComponentsParams, FindContoursParams, OpticalFlowDenseParams, ConfineParams > VisionParams
Parameter variant covering all ops that carry parameters.
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.
constexpr std::string_view enum_to_string(EnumType value) noexcept
Universal enum to string converter using magic_enum (original case)
std::vector< float > angle
Gradient angle in radians, [-pi, pi].
std::vector< float > magnitude
Gradient magnitude, normalised to [0, 1].
std::vector< float > dx
Horizontal gradient component.
std::vector< float > dy
Vertical gradient component.
Gradient maps produced by Sobel and Scharr operators.
std::vector< float > pixels
Image captured mid-pipeline by a Snapshot step.
void begin(const VisionSequence &seq, uint32_t width, uint32_t height)
Reset the walk band for a fresh run.
const VisionStep & step() const noexcept
size_t plane_size() const noexcept
const VisionStep * behind(size_t offset=1) const noexcept
Op at offset steps back, or nullptr before the start.
const VisionStep * ahead(size_t offset=1) const noexcept
Op at offset steps ahead, or nullptr past the end.
void set_geometry(uint32_t width, uint32_t height) noexcept
std::vector< SnapshotEntry > snapshots
Kakshya::DataVariant pixel_image
StructuredOutput structured
Result of executing a VisionSequence on one frame.
Ordered VisionSteps and the backend chosen to execute them.