MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
VisionExtractor.hpp
Go to the documentation of this file.
1#pragma once
2
4
7
10
11namespace MayaFlux::Yantra {
12
13/**
14 * @enum VisionExtractionMode
15 * @brief Selects the spatial mask used to crop pixels from a container.
16 */
17enum class VisionExtractionMode : uint8_t {
18 BBOX, ///< Crop the axis-aligned rectangle of a BoundingBox.
19 CONTOUR_TIGHT, ///< Crop the tight bounding rect of a Contour; no polygon mask.
20 CONTOUR_MASKED, ///< Crop the tight bounding rect of a Contour; zero pixels outside polygon.
21};
22
23/**
24 * @class VisionExtractor
25 * @brief Extracts a pixel sub-region guided by a VisionAnalysis in input metadata.
26 *
27 * Accepts any pixel-bearing InputType: vector<DataVariant>, shared_ptr<SignalSourceContainer>,
28 * Region, or RegionGroup. extract_structured_native handles all unwrapping.
29 * VisionAnalysis must be present in input.metadata["vision_analysis"].
30 *
31 * CPU path: reads pixel data via extract_structured_native, converts normalised
32 * bbox or contour rect to a pixel Region via CoordUtils, copies the sub-region,
33 * and optionally applies apply_contour_mask. Output data is vector<DataVariant>
34 * carrying the cropped float pixels with IMAGE_2D dimensions set.
35 *
36 * GPU path: attach a TextureExecutionContext configured with vision_crop.comp.
37 * Before calling apply_operation, use compute_normalised_rect() to get the crop
38 * rect, then call set_output_dimensions() and set_push_constants() on the context.
39 * apply_operation_internal routes to the backend automatically.
40 *
41 * @tparam InputType Any ComputeData type carrying pixel data.
42 * Defaults to shared_ptr<SignalSourceContainer>.
43 * @tparam OutputType Output pixel data type. Defaults to vector<DataVariant>.
44 */
45template <ComputeData InputType = std::shared_ptr<Kakshya::SignalSourceContainer>,
46 ComputeData OutputType = std::vector<Kakshya::DataVariant>>
48 : public UniversalExtractor<InputType, OutputType> {
49public:
52
53 /**
54 * @brief Construct with extraction mode and target index.
55 * @param mode Crop strategy to apply.
56 * @param index Zero-based index into boxes or contours in VisionAnalysis.
57 */
60 uint32_t index = 0)
61 : m_mode(mode)
62 , m_index(index)
63 {
64 }
65
66 void set_mode(VisionExtractionMode mode) { m_mode = mode; }
67 void set_index(uint32_t index) { m_index = index; }
68
69 [[nodiscard]] VisionExtractionMode get_mode() const { return m_mode; }
70 [[nodiscard]] uint32_t get_index() const { return m_index; }
71
72 [[nodiscard]] ExtractionType get_extraction_type() const override
73 {
75 }
76
77 [[nodiscard]] std::string get_extractor_name() const override
78 {
79 return "VisionExtractor";
80 }
81
82 [[nodiscard]] std::vector<std::string> get_available_methods() const override
83 {
84 return { "bbox", "contour_tight", "contour_masked" };
85 }
86
87 /**
88 * @brief Compute the normalised crop rectangle for a given VisionAnalysis.
89 *
90 * Returns { nx, ny, nw, nh } in image space [0,1]. Used by callers
91 * to configure a TextureExecutionContext before GPU dispatch:
92 * @code
93 * auto rect = extractor->compute_normalised_rect(analysis);
94 * ctx->set_output_dimensions(crop_w, crop_h);
95 * ctx->set_push_constants(CropPC { rect[0], rect[1], rect[2], rect[3], crop_w, crop_h });
96 * extractor->apply_operation(datum);
97 * @endcode
98 *
99 * @throws std::out_of_range if index exceeds the relevant detection collection.
100 */
101 [[nodiscard]] std::array<float, 4> compute_normalised_rect(
102 const VisionAnalysis& analysis) const
103 {
104 switch (m_mode) {
106 if (m_index >= analysis.frame.boxes.size()) {
107 error<std::out_of_range>(
110 std::source_location::current(),
111 "VisionExtractor: bbox index {} out of range ({})",
112 m_index, analysis.frame.boxes.size());
113 }
114 const auto& b = analysis.frame.boxes[m_index];
115 return { b.x, b.y, b.w, b.h };
116 }
119 if (m_index >= analysis.frame.contours.size()) {
120 error<std::out_of_range>(
123 std::source_location::current(),
124 "VisionExtractor: contour index {} out of range ({})",
125 m_index, analysis.frame.contours.size());
126 }
127 const auto& pts = analysis.frame.contours[m_index].points;
128 float min_x = pts[0].x, max_x = pts[0].x;
129 float min_y = pts[0].y, max_y = pts[0].y;
130 for (const auto& p : pts) {
131 if (p.x < min_x)
132 min_x = p.x;
133 if (p.x > max_x)
134 max_x = p.x;
135 if (p.y < min_y)
136 min_y = p.y;
137 if (p.y > max_y)
138 max_y = p.y;
139 }
140 return { min_x, min_y, max_x - min_x, max_y - min_y };
141 }
142 }
143 return { 0.F, 0.F, 1.F, 1.F };
144 }
145
146protected:
148 const input_type& input, const ExecutionContext& context) override
149 {
150 if (this->m_gpu_backend && this->m_gpu_backend->ensure_gpu_ready()) {
151 const auto analysis_it = input.metadata.find("vision_analysis");
152 if (analysis_it != input.metadata.end() && analysis_it->second.has_value()) {
153 const auto& analysis = safe_any_cast_or_throw<VisionAnalysis>(
154 analysis_it->second);
155
156 auto [nx, ny, nw, nh] = compute_normalised_rect(analysis);
157 const auto crop_w = static_cast<uint32_t>(
158 std::max(1.0F, std::round(nw * static_cast<float>(analysis.w))));
159 const auto crop_h = static_cast<uint32_t>(
160 std::max(1.0F, std::round(nh * static_cast<float>(analysis.h))));
161
162 auto* ctx = dynamic_cast<TextureExecutionContext*>(
163 this->m_gpu_backend.get());
164 if (ctx) {
165 ctx->set_output_dimensions(crop_w, crop_h);
166 ctx->set_push_constants(
167 CropPC { nx, ny, nw, nh, crop_w, crop_h });
168 }
169 }
170 }
171
173 }
174
176 {
177 const auto analysis_it = input.metadata.find("vision_analysis");
178 if (analysis_it == input.metadata.end() || !analysis_it->second.has_value()) {
179 error<std::runtime_error>(
182 std::source_location::current(),
183 "VisionExtractor: no vision_analysis in input metadata");
184 }
185
186 const auto& analysis = safe_any_cast_or_throw<VisionAnalysis>(
187 analysis_it->second);
188
189 if (analysis.pixel_image.empty()) {
190 error<std::runtime_error>(
193 std::source_location::current(),
194 "VisionExtractor: VisionAnalysis carries no pixel data");
195 }
196
197 const uint32_t w = analysis.w;
198 const uint32_t h = analysis.h;
199 const auto channels = static_cast<uint32_t>(
200 analysis.pixel_image.size() / (static_cast<size_t>(w) * h));
201
202 const auto [nx, ny, nw, nh] = compute_normalised_rect(analysis);
203
204 Kakshya::Region region = Kakshya::normalised_rect_to_region(nx, ny, nw, nh, w, h);
205
206 const auto crop_w = static_cast<uint32_t>(
207 region.end_coordinates[1] - region.start_coordinates[1] + 1);
208 const auto crop_h = static_cast<uint32_t>(
209 region.end_coordinates[0] - region.start_coordinates[0] + 1);
210
211 const uint32_t stride = w * channels;
212 const uint32_t crop_stride = crop_w * channels;
213 std::vector<float> cropped(static_cast<size_t>(crop_w) * crop_h * channels);
214
215 const float* src = analysis.pixel_image.data();
216 float* dst = cropped.data();
217
218 const auto y0 = static_cast<uint32_t>(region.start_coordinates[0]);
219 const auto x0 = static_cast<uint32_t>(region.start_coordinates[1]);
220
221 for (uint32_t row = 0; row < crop_h; ++row) {
222 std::memcpy(
223 dst + static_cast<size_t>(row * crop_stride),
224 src + (static_cast<size_t>(y0 + row) * stride) + static_cast<size_t>(x0 * channels),
225 crop_stride * sizeof(float));
226 }
227
229 const auto& contour = analysis.frame.contours[m_index];
230 const float origin_x = nx;
231 const float origin_y = ny;
232 const float scale_x = nw / static_cast<float>(crop_w);
233 const float scale_y = nh / static_cast<float>(crop_h);
235 std::span<float>(cropped),
236 crop_w, crop_h, channels,
237 contour,
238 origin_x, origin_y, scale_x, scale_y);
239 }
240
241 output_type out;
242 if constexpr (std::is_same_v<OutputType, std::vector<Kakshya::DataVariant>>) {
243 out.data = std::vector<Kakshya::DataVariant> { std::move(cropped) };
244 } else {
245 out.data = OperationHelper::reconstruct_from_double<OutputType>({}, {});
246 }
247
248 out.dimensions = { Kakshya::DataDimension::spatial_2d(crop_w, crop_h) };
249 out.modality = (channels == 1)
252 out.metadata = input.metadata;
253 out.metadata["crop_w"] = crop_w;
254 out.metadata["crop_h"] = crop_h;
255 out.metadata["vision_extractor_mode"] = static_cast<int>(m_mode);
256 out.metadata["vision_extractor_index"] = m_index;
257 return out;
258 }
259
260private:
261 struct CropPC {
263 uint32_t out_w, out_h;
264 };
265
267 uint32_t m_index { 0 };
268};
269
270// ============================================================================
271// Aliases
272// ============================================================================
273
274/// Default: container in, DataVariant pixels out.
276 std::shared_ptr<Kakshya::SignalSourceContainer>,
277 std::vector<Kakshya::DataVariant>>;
278
279/// DataVariant pixels in, DataVariant pixels out.
281 std::vector<Kakshya::DataVariant>,
282 std::vector<Kakshya::DataVariant>>;
283
284} // namespace MayaFlux::Yantra
Core::GlobalInputConfig input
Definition Config.cpp:38
Contour extraction from binary float masks.
uint32_t h
Definition InkPress.cpp:28
size_t b
Modern, digital-first universal extractor framework for Maya Flux.
std::shared_ptr< GpuExecutionContext< InputType, OutputType > > m_gpu_backend
virtual output_type apply_operation_internal(const input_type &input, const ExecutionContext &context)
Internal execution method - ComputeMatrix can access this.
void set_output_dimensions(uint32_t w, uint32_t h)
Override the output storage image dimensions for the next dispatch.
GpuExecutionContext specialisation for image compute shaders.
Template-flexible extractor base with instance-defined I/O types.
std::string get_extractor_name() const override
Get extractor-specific name (derived classes override this)
void set_mode(VisionExtractionMode mode)
VisionExtractor(VisionExtractionMode mode=VisionExtractionMode::BBOX, uint32_t index=0)
Construct with extraction mode and target index.
output_type apply_operation_internal(const input_type &input, const ExecutionContext &context) override
Internal execution method - ComputeMatrix can access this.
ExtractionType get_extraction_type() const override
Gets the extraction type category for this extractor.
std::vector< std::string > get_available_methods() const override
Get available extraction methods for this extractor.
std::array< float, 4 > compute_normalised_rect(const VisionAnalysis &analysis) const
Compute the normalised crop rectangle for a given VisionAnalysis.
output_type extract_implementation(const input_type &input) override
Pure virtual extraction implementation - derived classes implement this.
VisionExtractionMode get_mode() const
Extracts a pixel sub-region guided by a VisionAnalysis in input metadata.
@ ComputeMatrix
Compute operations (Yantra - algorithms, matrices, DSP)
@ Yantra
DSP algorithms, computational units, matrix operations, Grammar.
@ IMAGE_COLOR
2D RGB/RGBA image
@ IMAGE_2D
2D image (grayscale or single channel)
Region normalised_rect_to_region(float nx, float ny, float nw, float nh, uint32_t pixel_w, uint32_t pixel_h)
Convert a normalised image rectangle to a pixel-space Region.
void apply_contour_mask(std::span< float > pixels, uint32_t w, uint32_t h, uint32_t channels, const Contour &contour, float origin_x, float origin_y, float scale_x, float scale_y)
Zero all pixels in pixels that fall outside contour.
Definition Contours.cpp:211
ExtractionType
Categories of extraction operations for discovery and organization.
@ REGION_BASED
Extract from spatial/temporal regions.
VisionExtractionMode
Selects the spatial mask used to crop pixels from a container.
@ BBOX
Crop the axis-aligned rectangle of a BoundingBox.
@ CONTOUR_MASKED
Crop the tight bounding rect of a Contour; zero pixels outside polygon.
@ CONTOUR_TIGHT
Crop the tight bounding rect of a Contour; no polygon mask.
static DataDimension spatial_2d(uint64_t width, uint64_t height)
Convenience constructor for a 2D spatial dimension.
Definition NDData.cpp:85
std::vector< uint64_t > end_coordinates
Ending frame index (inclusive)
Definition Region.hpp:78
std::vector< uint64_t > start_coordinates
Starting frame index (inclusive)
Definition Region.hpp:75
Represents a point or span in N-dimensional space.
Definition Region.hpp:73
T data
The actual computation data.
Definition DataIO.hpp:25
std::vector< Kakshya::DataDimension > dimensions
Data dimensional structure.
Definition DataIO.hpp:26
Kakshya::DataModality modality
Data modality (audio, image, spectral, etc.)
Definition DataIO.hpp:27
std::unordered_map< std::string, std::any > metadata
Associated metadata.
Definition DataIO.hpp:28
Input/Output container for computation pipeline data flow with structure preservation.
Definition DataIO.hpp:24
std::vector< Kinesis::Vision::Contour > contours
std::vector< Kinesis::Vision::BoundingBox > boxes
Context information controlling how a compute operation executes.
Analysis result produced by VisionAnalyzer for one frame.