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).
514{
517 return;
518 }
519
520 new_w = w / 2;
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}
std::vector< float > * out
std::vector< double > sum(std::span< const double > data, size_t n_windows, uint32_t hop_size, uint32_t window_size)
Sum per window.
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.