MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
DataUtils.cpp
Go to the documentation of this file.
1#include "DataUtils.hpp"
2
4
5namespace MayaFlux::Kakshya {
6
7uint64_t calculate_total_elements(const std::vector<DataDimension>& dimensions)
8{
9 if (dimensions.empty())
10 return 0;
11
12 return std::transform_reduce(dimensions.begin(), dimensions.end(),
13 uint64_t(1), std::multiplies<>(),
14 [](const DataDimension& dim) { return dim.size; });
15}
16
17uint64_t calculate_frame_size(const std::vector<DataDimension>& dimensions)
18{
19 if (dimensions.empty())
20 return 0;
21
22 return std::transform_reduce(
23 dimensions.begin() + 1, dimensions.end(),
24 uint64_t(1), std::multiplies<>(),
25 [](const DataDimension& dim) constexpr { return dim.size; });
26}
27
28std::type_index get_variant_element_type(const DataVariant& data)
29{
30 return std::visit([](const auto& vec) -> std::type_index {
31 return typeid(typename std::decay_t<decltype(vec)>::value_type);
32 },
33 data);
34}
35
37{
38 std::visit([&](const auto& input_vec, auto& output_vec) {
39 using InputType = typename std::decay_t<decltype(input_vec)>::value_type;
40 using OutputType = typename std::decay_t<decltype(output_vec)>::value_type;
41
42 if constexpr (ProcessableData<InputType> && ProcessableData<OutputType>) {
43 std::vector<OutputType> temp_storage;
44 auto input_span = extract_from_variant<OutputType>(input, temp_storage);
45
46 output_vec.resize(input_span.size());
47 std::copy(input_span.begin(), input_span.end(), output_vec.begin());
48 } else {
49 error<std::invalid_argument>(
52 std::source_location::current(),
53 "Unsupported type conversion from {} to {}",
54 typeid(InputType).name(),
55 typeid(OutputType).name());
56 }
57 },
58 input, output);
59}
60
61std::span<const float> as_normalised_float(
62 const DataVariant& variant, std::vector<float>& storage)
63{
64 return std::visit([&storage](const auto& vec) -> std::span<const float> {
65 using T = typename std::decay_t<decltype(vec)>::value_type;
66
67 if constexpr (std::is_same_v<T, float>) {
68 return { vec.data(), vec.size() };
69
70 } else if constexpr (std::is_same_v<T, uint8_t>) {
71 storage.resize(vec.size());
72 constexpr float k = 1.0F / 255.0F;
73
74 std::transform(Parallel::par_unseq,
75 vec.begin(), vec.end(), storage.begin(),
76 [](uint8_t v) { return static_cast<float>(v) * k; });
77 return { storage.data(), storage.size() };
78
79 } else if constexpr (std::is_same_v<T, uint16_t>) {
80 storage.resize(vec.size());
81 constexpr float k = 1.0F / 65535.0F;
82
83 std::transform(Parallel::par_unseq,
84 vec.begin(), vec.end(), storage.begin(),
85 [](uint16_t v) { return static_cast<float>(v) * k; });
86 return { storage.data(), storage.size() };
87
88 } else {
89 return {};
90 }
91 },
92 variant);
93}
94
95std::pair<const uint8_t*, size_t> variant_bytes(const DataVariant& v)
96{
97 return std::visit(
98 [](const auto& vec) -> std::pair<const uint8_t*, size_t> {
99 using T = typename std::decay_t<decltype(vec)>::value_type;
100 if constexpr (std::is_same_v<T, uint8_t>
101 || std::is_same_v<T, uint16_t>
102 || std::is_same_v<T, float>) {
103 return {
104 reinterpret_cast<const uint8_t*>(vec.data()),
105 vec.size() * sizeof(T)
106 };
107 } else {
108 return { nullptr, 0 };
109 }
110 },
111 v);
112}
113
114std::pair<uint8_t*, size_t> variant_bytes_mutable(DataVariant& v)
115{
116 return std::visit(
117 [](auto& vec) -> std::pair<uint8_t*, size_t> {
118 using T = typename std::decay_t<decltype(vec)>::value_type;
119 if constexpr (std::is_same_v<T, uint8_t>
120 || std::is_same_v<T, uint16_t>
121 || std::is_same_v<T, float>) {
122 return {
123 reinterpret_cast<uint8_t*>(vec.data()),
124 vec.size() * sizeof(T)
125 };
126 } else {
127 return { nullptr, 0 };
128 }
129 },
130 v);
131}
132
133void denormalise_to_uint8(std::span<const float> src, std::span<uint8_t> dst)
134{
135 Parallel::transform(Parallel::par_unseq, src.begin(), src.end(), dst.begin(),
136 [](float v) {
137 return static_cast<uint8_t>(std::clamp(v * 255.0F, 0.0F, 255.0F));
138 });
139}
140
141std::vector<uint8_t> denormalise_to_uint8(std::span<const float> src)
142{
143 std::vector<uint8_t> out(src.size());
144 denormalise_to_uint8(src, out);
145 return out;
146}
147
148void set_metadata_value(std::unordered_map<std::string, std::any>& metadata, const std::string& key, std::any value)
149{
150 metadata[key] = std::move(value);
151}
152
153int find_dimension_by_role(const std::vector<DataDimension>& dimensions, DataDimension::Role role)
154{
155 auto it = std::ranges::find_if(dimensions,
156 [role](const DataDimension& dim) { return dim.role == role; });
157
158 return (it != dimensions.end()) ? static_cast<int>(std::distance(dimensions.begin(), it)) : -1;
159}
160
161DataModality detect_data_modality(const std::vector<DataDimension>& dimensions)
162{
163 if (dimensions.empty()) {
165 }
166
167 size_t time_dims = 0, spatial_dims = 0, channel_dims = 0, frequency_dims = 0, depth_dims = 0, custom_dims = 0;
168 size_t total_spatial_elements = 1;
169 size_t total_channels = 0;
170
171 for (const auto& dim : dimensions) {
172 if (dim.grouping) {
173 switch (dim.role) {
184 if (dim.grouping->count == 3)
186 if (dim.grouping->count == 4)
188 break;
189 default:
190 if (dim.grouping->count == 16)
192 break;
193 }
194 }
195 }
196
197 for (const auto& dim : dimensions) {
198 switch (dim.role) {
200 time_dims++;
201 break;
205 spatial_dims++;
206 total_spatial_elements *= dim.size;
207 break;
209 channel_dims++;
210 total_channels += dim.size;
211 break;
213 frequency_dims++;
214 break;
216 depth_dims++;
217 break;
219 default:
220 custom_dims++;
221 break;
222 }
223 }
224
225 if (time_dims == 1 && spatial_dims == 0 && frequency_dims == 0) {
226 if (channel_dims == 0) {
228 }
229 if (channel_dims == 1) {
230 return (total_channels <= 1) ? DataModality::AUDIO_1D : DataModality::AUDIO_MULTICHANNEL;
231 }
233 }
234
235 if (time_dims >= 1 && frequency_dims >= 1) {
236 if (spatial_dims == 0 && channel_dims <= 1) {
238 }
240 }
241
242 if (spatial_dims >= 2 && time_dims == 0) {
243 if (spatial_dims == 2) {
244 if (channel_dims == 0) {
246 }
247 if (channel_dims == 1 && total_channels >= 3) {
249 }
251 }
252
253 if (spatial_dims == 3) {
255 }
256 }
257
258 if (depth_dims == 1 && spatial_dims == 2) {
259 return time_dims >= 1
262 }
263
264 if (time_dims >= 1 && spatial_dims >= 2) {
265 if (spatial_dims == 2) {
266 if (channel_dims == 0 || (channel_dims == 1 && total_channels <= 1)) {
268 }
269
271 }
273 }
274
275 if (spatial_dims == 2 && time_dims == 0 && channel_dims >= 1) {
276 if (total_spatial_elements >= 64 && total_channels >= 1) {
278 }
279 }
280
282}
283
285 const std::vector<DataDimension>& dimensions,
286 const DataVariant& source)
287{
288 const DataModality base = detect_data_modality(dimensions);
289
290 if (base != DataModality::AUDIO_1D && base != DataModality::TENSOR_ND) {
291 return base;
292 }
293
294 return std::visit([&base](const auto& vec) {
295 using V = typename std::decay_t<decltype(vec)>::value_type;
296
297 if constexpr (ComplexData<V>) {
299 } else if constexpr (IntegerData<V>) {
301 } else {
302 return base;
303 }
304 },
305 source);
306}
307
308std::vector<DataDimension> detect_data_dimensions(const DataVariant& data)
309{
311 "{}\n{}\n{}\n{}",
312 "Inferring structure from single DataVariant is not advisable as the method makes naive assumptions that can lead to massive computational errors. "
313 "If the variant is part of a container, region, or segment, please use the appropriate method instead. "
314 "If the variant is part of a vector, please use infer_from_data_variant_vector instead. "
315 "If you are sure you want to proceed, please ignore this warning.");
316
317 return std::visit([](const auto& vec) -> std::vector<DataDimension> {
318 using ValueType = typename std::decay_t<decltype(vec)>::value_type;
319
320 std::vector<DataDimension> dims;
321
322 if constexpr (DecimalData<ValueType>) {
323 dims.emplace_back(DataDimension::time(vec.size()));
324
325 } else if constexpr (ComplexData<ValueType>) {
326 dims.emplace_back(DataDimension::frequency(vec.size()));
327
328 } else if constexpr (IntegerData<ValueType>) {
329 dims.emplace_back(DataDimension::spatial(vec.size(), 'x'));
330 } else if constexpr (GlmData<ValueType>) {
331 constexpr size_t components = glm_component_count<ValueType>();
333
334 if constexpr (GlmVec2Type<ValueType>) {
336 } else if constexpr (GlmVec3Type<ValueType>) {
338 } else if constexpr (GlmVec4Type<ValueType>) {
340 } else if constexpr (GlmMatrixType<ValueType>) {
342 }
343
344 dims.push_back(DataDimension::grouped(
345 "glm_structured_data",
346 static_cast<uint64_t>(vec.size()),
347 static_cast<uint8_t>(components),
348 role));
349 } else {
350 dims.emplace_back(DataDimension::time(vec.size()));
351 }
352
353 return dims;
354 },
355 data);
356}
357
358std::vector<DataDimension> detect_data_dimensions(
359 const std::vector<DataVariant>& variants)
360{
362 "{}\n{}\n{}",
363 "Inferring structure from DataVariant vector is not advisable as the method makes naive assumptions that can lead to massive computational errors. "
364 "If the variants are part of a container, region, or segment, please use the appropriate method instead. "
365 "If you are sure you want to proceed, please ignore this warning.");
366
367 if (variants.empty()) {
368 std::vector<DataDimension> dims;
369 dims.emplace_back("empty_variants", 0, 1, DataDimension::Role::CUSTOM);
370 return dims;
371 }
372
373 std::vector<DataDimension> dimensions;
374 size_t variant_count = variants.size();
375
376 size_t first_variant_size = std::visit([](const auto& vec) -> size_t {
377 return vec.size();
378 },
379 variants[0]);
380
381 bool consistent_glm = std::ranges::all_of(variants, [](const auto& variant) {
382 return std::visit([](const auto& vec) -> bool {
383 using ValueType = typename std::decay_t<decltype(vec)>::value_type;
384 return GlmData<ValueType>;
385 },
386 variant);
387 });
388
389 bool consistent_decimal = std::ranges::all_of(variants, [](const auto& variant) {
390 return std::visit([](const auto& vec) -> bool {
391 using ValueType = typename std::decay_t<decltype(vec)>::value_type;
392 return MayaFlux::DecimalData<ValueType>;
393 },
394 variant);
395 });
396
397 bool consistent_complex = std::ranges::all_of(variants, [](const auto& variant) {
398 return std::visit([](const auto& vec) -> bool {
399 using ValueType = typename std::decay_t<decltype(vec)>::value_type;
400 return MayaFlux::ComplexData<ValueType>;
401 },
402 variant);
403 });
404
405 bool consistent_integer = std::ranges::all_of(variants, [](const auto& variant) {
406 return std::visit([](const auto& vec) -> bool {
407 using ValueType = typename std::decay_t<decltype(vec)>::value_type;
408 return MayaFlux::IntegerData<ValueType>;
409 },
410 variant);
411 });
412
413 if (consistent_glm) {
414 dimensions.emplace_back(DataDimension::channel(variant_count));
415
416 std::visit([&](const auto& first_vec) {
417 using ValueType = typename std::decay_t<decltype(first_vec)>::value_type;
418 constexpr size_t components = glm_component_count<ValueType>();
419
421 if constexpr (GlmVec2Type<ValueType>) {
423 } else if constexpr (GlmVec3Type<ValueType>) {
425 } else if constexpr (GlmVec4Type<ValueType>) {
427 }
428
429 dimensions.emplace_back(DataDimension::grouped(
430 "glm_elements",
431 first_variant_size,
432 static_cast<uint8_t>(components),
433 role));
434 },
435 variants[0]);
436
437 return dimensions;
438 }
439
440 if (variant_count == 1) {
441 if (consistent_decimal) {
442 dimensions.emplace_back(DataDimension::time(first_variant_size, "samples"));
443 } else if (consistent_complex) {
444 dimensions.emplace_back(DataDimension::frequency(first_variant_size, "frequency_data"));
445 } else if (consistent_integer) {
446 dimensions.emplace_back(DataDimension::spatial(first_variant_size, 'x', 1, "data_points"));
447 } else {
448 dimensions.emplace_back("unknown_data", first_variant_size, 1,
450 }
451
452 } else if (variant_count == 2 && (consistent_decimal || consistent_complex || consistent_integer)) {
453 dimensions.emplace_back(DataDimension::channel(2));
454 if (consistent_decimal) {
455 dimensions.emplace_back(DataDimension::time(first_variant_size, "samples"));
456 } else if (consistent_complex) {
457 dimensions.emplace_back(DataDimension::frequency(first_variant_size, "bins"));
458 } else {
459 dimensions.emplace_back(DataDimension::spatial(first_variant_size, 'x', 1, "elements"));
460 }
461
462 } else if (variant_count <= 16 && (consistent_decimal || consistent_complex || consistent_integer)) {
463 dimensions.emplace_back(DataDimension::channel(variant_count));
464 if (consistent_decimal) {
465 dimensions.emplace_back(DataDimension::time(first_variant_size, "samples"));
466 } else if (consistent_complex) {
467 dimensions.emplace_back(DataDimension::frequency(first_variant_size, "bins"));
468 } else {
469 dimensions.emplace_back(DataDimension::spatial(first_variant_size, 'x', 1, "pixels"));
470 }
471
472 } else if (consistent_decimal || consistent_complex || consistent_integer) {
473 if (consistent_decimal) {
474 dimensions.emplace_back(DataDimension::time(variant_count, "time_blocks"));
475 dimensions.emplace_back("block_samples", first_variant_size, 1,
477 } else if (consistent_complex) {
478 dimensions.emplace_back(DataDimension::time(variant_count, "time_windows"));
479 dimensions.emplace_back(DataDimension::frequency(first_variant_size, "frequency_bins"));
480 } else {
481 dimensions.emplace_back(DataDimension::time(variant_count, "frames"));
482 dimensions.emplace_back(DataDimension::spatial(first_variant_size, 'x', 1, "frame_data"));
483 }
484
485 } else {
486 dimensions.emplace_back("mixed_variants", variant_count, 1,
488 dimensions.emplace_back("variant_data", first_variant_size, 1,
490 }
491
492 return dimensions;
493}
494
495}
#define MF_WARN(comp, ctx,...)
Core::GlobalInputConfig input
Definition Config.cpp:38
std::string name
Definition VKDevice.cpp:143
float value
std::shared_ptr< Core::VKImage > output
float k
@ Runtime
General runtime operations (default fallback)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
void denormalise_to_uint8(std::span< const float > src, std::span< uint8_t > dst)
Convert a normalised float span back to uint8_t pixels.
std::vector< DataDimension > detect_data_dimensions(const DataVariant &data)
Detect data dimensions from a DataVariant.
std::span< const float > as_normalised_float(const DataVariant &variant, std::vector< float > &storage)
Extract a DataVariant holding pixel data as a normalised float span.
Definition DataUtils.cpp:61
uint64_t calculate_frame_size(const std::vector< DataDimension > &dimensions)
Calculate the frame size (number of elements per frame) for a set of dimensions.
Definition DataUtils.cpp:17
std::pair< const uint8_t *, size_t > variant_bytes(const DataVariant &v)
Get a pointer to the raw bytes of a DataVariant and its size.
Definition DataUtils.cpp:95
std::variant< std::vector< double >, std::vector< float >, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< std::complex< float > >, std::vector< std::complex< double > >, std::vector< glm::vec2 >, std::vector< glm::vec3 >, std::vector< glm::vec4 >, std::vector< glm::mat4 > > DataVariant
Multi-type data storage for different precision needs.
Definition NDData.hpp:102
DataModality
Data modality types for cross-modal analysis.
Definition NDData.hpp:164
@ DEPTH_MAP
[height, width, components] - range/disparity image
@ AUDIO_MULTICHANNEL
Multi-channel audio.
@ SPECTRAL_2D
2D spectral data (time + frequency)
@ VIDEO_DEPTH
[frames, height, width, components] - streaming range data
@ UNKNOWN
Unknown or undefined modality.
@ VOLUMETRIC_3D
3D volumetric data
@ VIDEO_GRAYSCALE
3D video (time + 2D grayscale)
@ VIDEO_COLOR
4D video (time + 2D + color)
@ TENSOR_ND
N-dimensional tensor.
@ IMAGE_COLOR
2D RGB/RGBA image
@ IMAGE_2D
2D image (grayscale or single channel)
int find_dimension_by_role(const std::vector< DataDimension > &dimensions, DataDimension::Role role)
Find the index of a dimension by its semantic role.
void set_metadata_value(std::unordered_map< std::string, std::any > &metadata, const std::string &key, std::any value)
Set a value in a metadata map (key-value).
DataModality detect_data_modality(const std::vector< DataDimension > &dimensions)
Detects data modality from dimension information.
std::type_index get_variant_element_type(const DataVariant &data)
Return the native element type of a DataVariant as a type_index.
Definition DataUtils.cpp:28
void safe_copy_data_variant(const DataVariant &input, DataVariant &output)
Safely copy data from a DataVariant to another DataVariant, handling type conversion.
Definition DataUtils.cpp:36
uint64_t calculate_total_elements(const std::vector< DataDimension > &dimensions)
Calculate the total number of elements in an N-dimensional container.
Definition DataUtils.cpp:7
std::pair< uint8_t *, size_t > variant_bytes_mutable(DataVariant &v)
Get a mutable pointer to the raw bytes of a DataVariant and its size.
Role
Semantic role of the dimension.
Definition NDData.hpp:236
@ FREQUENCY
Spectral/frequency axis.
@ TIME
Temporal progression (samples, frames, steps)
@ CUSTOM
User-defined or application-specific.
@ POSITION
Vertex positions (3D space)
@ DEPTH
Distance from the observation point (depth, disparity, range)
@ CHANNEL
Parallel streams (audio channels, color channels)
@ SPATIAL_X
Spatial X axis (images, tensors)
uint64_t size
Number of elements in this dimension.
Definition NDData.hpp:298
Role role
Semantic hint for common operations.
Definition NDData.hpp:300
static DataDimension spatial(uint64_t size, char axis, uint64_t stride=1, std::string name="spatial")
Convenience constructor for a spatial dimension.
Definition NDData.cpp:65
static DataDimension grouped(std::string name, uint64_t element_count, uint8_t components_per_element, Role role=Role::CUSTOM)
Create dimension with component grouping.
Definition NDData.cpp:105
static DataDimension frequency(uint64_t bins, std::string name="frequency")
Convenience constructor for a frequency dimension.
Definition NDData.cpp:60
static DataDimension time(uint64_t samples, std::string name="time")
Convenience constructor for a temporal (time) dimension.
Definition NDData.cpp:45
static DataDimension channel(uint64_t count, uint64_t stride=1)
Convenience constructor for a channel dimension.
Definition NDData.cpp:50
Minimal dimension descriptor focusing on structure only.
Definition NDData.hpp:229