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

◆ downsample_2x() [2/3]

MAYAFLUX_API void MayaFlux::Kinesis::Vision::downsample_2x ( std::span< const float >  src,
std::span< float >  dst,
uint32_t  w,
uint32_t  h,
uint32_t  channels,
uint32_t &  new_w,
uint32_t &  new_h 
)

2x box-filter downsample for multi-channel interleaved data.

Each output pixel is the per-channel average of the corresponding 2x2 block. Output dimensions are floor(w/2) x floor(h/2).

Parameters
srcInterleaved float span, size must be w * h * channels.
dstOutput span, size must be >= floor(w/2) * floor(h/2) * channels.
wInput width in pixels.
hInput height in pixels.
channelsChannels per pixel (1 = existing behaviour, 4 = RGBA).
new_wReceives output width.
new_hReceives output height.

Definition at line 508 of file PixelOps.cpp.

514{
515 if (channels == 1) {
516 downsample_2x(src, dst, w, h, new_w, new_h);
517 return;
518 }
519
520 new_w = w / 2;
521 new_h = h / 2;
522 const uint32_t ch = channels;
523 const uint32_t row_stride = w * ch;
524 const uint32_t out_stride = new_w * ch;
525
526 std::for_each(std::execution::par_unseq,
527 std::views::iota(uint32_t { 0 }, new_h).begin(),
528 std::views::iota(uint32_t { 0 }, new_h).end(),
529 [&](uint32_t oy) {
530 const float* row0 = src.data() + static_cast<size_t>(oy * 2) * row_stride;
531 const float* row1 = src.data() + static_cast<size_t>(oy * 2 + 1) * row_stride;
532 float* drow = dst.data() + static_cast<size_t>(oy) * out_stride;
533
534 uint32_t ox = 0;
535
536#ifdef MAYAFLUX_ARCH_X64
537 if (ch == 4) {
538 const __m256 quarter = _mm256_set1_ps(0.25F);
539 for (; ox + 1 <= new_w; ++ox) {
540 const float* p00 = row0 + ox * 8;
541 const float* p01 = row0 + ox * 8 + 4;
542 const float* p10 = row1 + ox * 8;
543 const float* p11 = row1 + ox * 8 + 4;
544
545 __m128 v00 = _mm_loadu_ps(p00);
546 __m128 v01 = _mm_loadu_ps(p01);
547 __m128 v10 = _mm_loadu_ps(p10);
548 __m128 v11 = _mm_loadu_ps(p11);
549
550 __m128 sum = _mm_add_ps(_mm_add_ps(v00, v01), _mm_add_ps(v10, v11));
551 __m128 res = _mm_mul_ps(sum, _mm_set1_ps(0.25F));
552 _mm_storeu_ps(drow + ox * 4, res);
553 }
554 return;
555 }
556#elif defined(MAYAFLUX_ARCH_ARM64)
557 if (ch == 4) {
558 for (; ox + 1 <= new_w; ++ox) {
559 const float* p00 = row0 + ox * 8;
560 const float* p01 = row0 + ox * 8 + 4;
561 const float* p10 = row1 + ox * 8;
562 const float* p11 = row1 + ox * 8 + 4;
563
564 float32x4_t v00 = vld1q_f32(p00);
565 float32x4_t v01 = vld1q_f32(p01);
566 float32x4_t v10 = vld1q_f32(p10);
567 float32x4_t v11 = vld1q_f32(p11);
568
569 float32x4_t sum = vaddq_f32(vaddq_f32(v00, v01), vaddq_f32(v10, v11));
570 vst1q_f32(drow + ox * 4, vmulq_n_f32(sum, 0.25F));
571 }
572 return;
573 }
574#endif
575
576 for (; ox < new_w; ++ox) {
577 const float* p00 = row0 + ox * 2 * ch;
578 const float* p01 = row0 + (ox * 2 + 1) * ch;
579 const float* p10 = row1 + ox * 2 * ch;
580 const float* p11 = row1 + (ox * 2 + 1) * ch;
581 float* out = drow + ox * ch;
582 for (uint32_t c = 0; c < ch; ++c)
583 out[c] = (p00[c] + p01[c] + p10[c] + p11[c]) * 0.25F;
584 }
585 });
586}
uint32_t h
Definition InkPress.cpp:29
uint32_t * dst
const uint32_t * src
std::vector< float > * out
uint32_t channels
std::vector< double > sum(std::span< const double > data, size_t n_windows, uint32_t hop_size, uint32_t window_size)
Sum per window.
Definition Analysis.cpp:469
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:423

References channels, downsample_2x(), dst, h, out, and src.

+ Here is the call graph for this function: