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
95void denormalise_to_uint8(std::span<const float> src, std::span<uint8_t> dst)
96{
97 Parallel::transform(Parallel::par_unseq, src.begin(), src.end(), dst.begin(),
98 [](float v) {
99 return static_cast<uint8_t>(std::clamp(v * 255.0F, 0.0F, 255.0F));
100 });
101}
102
103std::vector<uint8_t> denormalise_to_uint8(std::span<const float> src)
104{
105 std::vector<uint8_t> out(src.size());
106 denormalise_to_uint8(src, out);
107 return out;
108}
109
110void set_metadata_value(std::unordered_map<std::string, std::any>& metadata, const std::string& key, std::any value)
111{
112 metadata[key] = std::move(value);
113}
114
115int find_dimension_by_role(const std::vector<DataDimension>& dimensions, DataDimension::Role role)
116{
117 auto it = std::ranges::find_if(dimensions,
118 [role](const DataDimension& dim) { return dim.role == role; });
119
120 return (it != dimensions.end()) ? static_cast<int>(std::distance(dimensions.begin(), it)) : -1;
121}
122
123DataModality detect_data_modality(const std::vector<DataDimension>& dimensions)
124{
125 if (dimensions.empty()) {
127 }
128
129 size_t time_dims = 0, spatial_dims = 0, channel_dims = 0, frequency_dims = 0, custom_dims = 0;
130 size_t total_spatial_elements = 1;
131 size_t total_channels = 0;
132
133 for (const auto& dim : dimensions) {
134 if (dim.grouping) {
135 switch (dim.role) {
146 if (dim.grouping->count == 3)
148 if (dim.grouping->count == 4)
150 break;
151 default:
152 if (dim.grouping->count == 16)
154 break;
155 }
156 }
157 }
158
159 for (const auto& dim : dimensions) {
160 switch (dim.role) {
162 time_dims++;
163 break;
167 spatial_dims++;
168 total_spatial_elements *= dim.size;
169 break;
171 channel_dims++;
172 total_channels += dim.size;
173 break;
175 frequency_dims++;
176 break;
178 default:
179 custom_dims++;
180 break;
181 }
182 }
183
184 if (time_dims == 1 && spatial_dims == 0 && frequency_dims == 0) {
185 if (channel_dims == 0) {
187 } else if (channel_dims == 1) {
188 return (total_channels <= 1) ? DataModality::AUDIO_1D : DataModality::AUDIO_MULTICHANNEL;
189 } else {
191 }
192 }
193
194 if (time_dims >= 1 && frequency_dims >= 1) {
195 if (spatial_dims == 0 && channel_dims <= 1) {
197 }
199 }
200
201 if (spatial_dims >= 2 && time_dims == 0) {
202 if (spatial_dims == 2) {
203 if (channel_dims == 0) {
205 } else if (channel_dims == 1 && total_channels >= 3) {
207 } else {
209 }
210 } else if (spatial_dims == 3) {
212 }
213 }
214
215 if (time_dims >= 1 && spatial_dims >= 2) {
216 if (spatial_dims == 2) {
217 if (channel_dims == 0 || (channel_dims == 1 && total_channels <= 1)) {
219 } else {
221 }
222 }
224 }
225
226 if (spatial_dims == 2 && time_dims == 0 && channel_dims >= 1) {
227 if (total_spatial_elements >= 64 && total_channels >= 1) {
229 }
230 }
231
233}
234
236 const std::vector<DataDimension>& dimensions,
237 const DataVariant& source)
238{
239 const DataModality base = detect_data_modality(dimensions);
240
241 if (base != DataModality::AUDIO_1D && base != DataModality::TENSOR_ND) {
242 return base;
243 }
244
245 return std::visit([&base](const auto& vec) {
246 using V = typename std::decay_t<decltype(vec)>::value_type;
247
248 if constexpr (ComplexData<V>) {
250 } else if constexpr (IntegerData<V>) {
252 } else {
253 return base;
254 }
255 },
256 source);
257}
258
259std::vector<DataDimension> detect_data_dimensions(const DataVariant& data)
260{
262 "{}\n{}\n{}\n{}",
263 "Inferring structure from single DataVariant is not advisable as the method makes naive assumptions that can lead to massive computational errors. "
264 "If the variant is part of a container, region, or segment, please use the appropriate method instead. "
265 "If the variant is part of a vector, please use infer_from_data_variant_vector instead. "
266 "If you are sure you want to proceed, please ignore this warning.");
267
268 return std::visit([](const auto& vec) -> std::vector<DataDimension> {
269 using ValueType = typename std::decay_t<decltype(vec)>::value_type;
270
271 std::vector<DataDimension> dims;
272
273 if constexpr (DecimalData<ValueType>) {
274 dims.emplace_back(DataDimension::time(vec.size()));
275
276 } else if constexpr (ComplexData<ValueType>) {
277 dims.emplace_back(DataDimension::frequency(vec.size()));
278
279 } else if constexpr (IntegerData<ValueType>) {
280 dims.emplace_back(DataDimension::spatial(vec.size(), 'x'));
281 } else if constexpr (GlmData<ValueType>) {
282 constexpr size_t components = glm_component_count<ValueType>();
284
285 if constexpr (GlmVec2Type<ValueType>) {
287 } else if constexpr (GlmVec3Type<ValueType>) {
289 } else if constexpr (GlmVec4Type<ValueType>) {
291 } else if constexpr (GlmMatrixType<ValueType>) {
293 }
294
295 dims.push_back(DataDimension::grouped(
296 "glm_structured_data",
297 static_cast<uint64_t>(vec.size()),
298 static_cast<uint8_t>(components),
299 role));
300 } else {
301 dims.emplace_back(DataDimension::time(vec.size()));
302 }
303
304 return dims;
305 },
306 data);
307}
308
309std::vector<DataDimension> detect_data_dimensions(
310 const std::vector<DataVariant>& variants)
311{
313 "{}\n{}\n{}",
314 "Inferring structure from DataVariant vector is not advisable as the method makes naive assumptions that can lead to massive computational errors. "
315 "If the variants are part of a container, region, or segment, please use the appropriate method instead. "
316 "If you are sure you want to proceed, please ignore this warning.");
317
318 if (variants.empty()) {
319 std::vector<DataDimension> dims;
320 dims.emplace_back("empty_variants", 0, 1, DataDimension::Role::CUSTOM);
321 return dims;
322 }
323
324 std::vector<DataDimension> dimensions;
325 size_t variant_count = variants.size();
326
327 size_t first_variant_size = std::visit([](const auto& vec) -> size_t {
328 return vec.size();
329 },
330 variants[0]);
331
332 bool consistent_glm = std::ranges::all_of(variants, [](const auto& variant) {
333 return std::visit([](const auto& vec) -> bool {
334 using ValueType = typename std::decay_t<decltype(vec)>::value_type;
335 return GlmData<ValueType>;
336 },
337 variant);
338 });
339
340 bool consistent_decimal = std::ranges::all_of(variants, [](const auto& variant) {
341 return std::visit([](const auto& vec) -> bool {
342 using ValueType = typename std::decay_t<decltype(vec)>::value_type;
343 return MayaFlux::DecimalData<ValueType>;
344 },
345 variant);
346 });
347
348 bool consistent_complex = std::ranges::all_of(variants, [](const auto& variant) {
349 return std::visit([](const auto& vec) -> bool {
350 using ValueType = typename std::decay_t<decltype(vec)>::value_type;
351 return MayaFlux::ComplexData<ValueType>;
352 },
353 variant);
354 });
355
356 bool consistent_integer = std::ranges::all_of(variants, [](const auto& variant) {
357 return std::visit([](const auto& vec) -> bool {
358 using ValueType = typename std::decay_t<decltype(vec)>::value_type;
359 return MayaFlux::IntegerData<ValueType>;
360 },
361 variant);
362 });
363
364 if (consistent_glm) {
365 dimensions.emplace_back(DataDimension::channel(variant_count));
366
367 std::visit([&](const auto& first_vec) {
368 using ValueType = typename std::decay_t<decltype(first_vec)>::value_type;
369 constexpr size_t components = glm_component_count<ValueType>();
370
372 if constexpr (GlmVec2Type<ValueType>) {
374 } else if constexpr (GlmVec3Type<ValueType>) {
376 } else if constexpr (GlmVec4Type<ValueType>) {
378 }
379
380 dimensions.emplace_back(DataDimension::grouped(
381 "glm_elements",
382 first_variant_size,
383 static_cast<uint8_t>(components),
384 role));
385 },
386 variants[0]);
387
388 return dimensions;
389 }
390
391 if (variant_count == 1) {
392 if (consistent_decimal) {
393 dimensions.emplace_back(DataDimension::time(first_variant_size, "samples"));
394 } else if (consistent_complex) {
395 dimensions.emplace_back(DataDimension::frequency(first_variant_size, "frequency_data"));
396 } else if (consistent_integer) {
397 dimensions.emplace_back(DataDimension::spatial(first_variant_size, 'x', 1, "data_points"));
398 } else {
399 dimensions.emplace_back("unknown_data", first_variant_size, 1,
401 }
402
403 } else if (variant_count == 2 && (consistent_decimal || consistent_complex || consistent_integer)) {
404 dimensions.emplace_back(DataDimension::channel(2));
405 if (consistent_decimal) {
406 dimensions.emplace_back(DataDimension::time(first_variant_size, "samples"));
407 } else if (consistent_complex) {
408 dimensions.emplace_back(DataDimension::frequency(first_variant_size, "bins"));
409 } else {
410 dimensions.emplace_back(DataDimension::spatial(first_variant_size, 'x', 1, "elements"));
411 }
412
413 } else if (variant_count <= 16 && (consistent_decimal || consistent_complex || consistent_integer)) {
414 dimensions.emplace_back(DataDimension::channel(variant_count));
415 if (consistent_decimal) {
416 dimensions.emplace_back(DataDimension::time(first_variant_size, "samples"));
417 } else if (consistent_complex) {
418 dimensions.emplace_back(DataDimension::frequency(first_variant_size, "bins"));
419 } else {
420 dimensions.emplace_back(DataDimension::spatial(first_variant_size, 'x', 1, "pixels"));
421 }
422
423 } else if (consistent_decimal || consistent_complex || consistent_integer) {
424 if (consistent_decimal) {
425 dimensions.emplace_back(DataDimension::time(variant_count, "time_blocks"));
426 dimensions.emplace_back("block_samples", first_variant_size, 1,
428 } else if (consistent_complex) {
429 dimensions.emplace_back(DataDimension::time(variant_count, "time_windows"));
430 dimensions.emplace_back(DataDimension::frequency(first_variant_size, "frequency_bins"));
431 } else {
432 dimensions.emplace_back(DataDimension::time(variant_count, "frames"));
433 dimensions.emplace_back(DataDimension::spatial(first_variant_size, 'x', 1, "frame_data"));
434 }
435
436 } else {
437 dimensions.emplace_back("mixed_variants", variant_count, 1,
439 dimensions.emplace_back("variant_data", first_variant_size, 1,
441 }
442
443 return dimensions;
444}
445
446}
#define MF_WARN(comp, ctx,...)
Core::GlobalInputConfig input
Definition Config.cpp:38
Eigen::MatrixXd storage
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.
Definition DataUtils.cpp:95
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::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
@ AUDIO_MULTICHANNEL
Multi-channel audio.
@ SPECTRAL_2D
2D spectral data (time + frequency)
@ 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
Role
Semantic role of the dimension.
Definition NDData.hpp:234
@ FREQUENCY
Spectral/frequency axis.
@ TIME
Temporal progression (samples, frames, steps)
@ CUSTOM
User-defined or application-specific.
@ POSITION
Vertex positions (3D space)
@ 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:277
Role role
Semantic hint for common operations.
Definition NDData.hpp:279
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:60
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:100
static DataDimension frequency(uint64_t bins, std::string name="frequency")
Convenience constructor for a frequency dimension.
Definition NDData.cpp:55
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:227