MayaFlux 0.5.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 528 of file PixelOps.cpp.

534{
535 if (channels == 1) {
536 downsample_2x(src, dst, w, h, new_w, new_h);
537 return;
538 }
539
540 new_w = w / 2;
541 new_h = h / 2;
542 const uint32_t ch = channels;
543 const uint32_t row_stride = w * ch;
544 const uint32_t out_stride = new_w * ch;
545
546 P::for_each(P::par_unseq,
547 std::views::iota(uint32_t { 0 }, new_h).begin(),
548 std::views::iota(uint32_t { 0 }, new_h).end(),
549 [&](uint32_t oy) {
550 const float* row0 = src.data() + static_cast<size_t>(oy * 2) * row_stride;
551 const float* row1 = src.data() + static_cast<size_t>(oy * 2 + 1) * row_stride;
552 float* drow = dst.data() + static_cast<size_t>(oy) * out_stride;
553
554 uint32_t ox = 0;
555
556#ifdef MAYAFLUX_ARCH_X64
557 if (ch == 4) {
558 const __m256 quarter = _mm256_set1_ps(0.25F);
559 for (; ox + 1 <= new_w; ++ox) {
560 const float* p00 = row0 + ox * 8;
561 const float* p01 = row0 + ox * 8 + 4;
562 const float* p10 = row1 + ox * 8;
563 const float* p11 = row1 + ox * 8 + 4;
564
565 __m128 v00 = _mm_loadu_ps(p00);
566 __m128 v01 = _mm_loadu_ps(p01);
567 __m128 v10 = _mm_loadu_ps(p10);
568 __m128 v11 = _mm_loadu_ps(p11);
569
570 __m128 sum = _mm_add_ps(_mm_add_ps(v00, v01), _mm_add_ps(v10, v11));
571 __m128 res = _mm_mul_ps(sum, _mm_set1_ps(0.25F));
572 _mm_storeu_ps(drow + ox * 4, res);
573 }
574 return;
575 }
576#elif defined(MAYAFLUX_ARCH_ARM64)
577 if (ch == 4) {
578 for (; ox + 1 <= new_w; ++ox) {
579 const float* p00 = row0 + ox * 8;
580 const float* p01 = row0 + ox * 8 + 4;
581 const float* p10 = row1 + ox * 8;
582 const float* p11 = row1 + ox * 8 + 4;
583
584 float32x4_t v00 = vld1q_f32(p00);
585 float32x4_t v01 = vld1q_f32(p01);
586 float32x4_t v10 = vld1q_f32(p10);
587 float32x4_t v11 = vld1q_f32(p11);
588
589 float32x4_t sum = vaddq_f32(vaddq_f32(v00, v01), vaddq_f32(v10, v11));
590 vst1q_f32(drow + ox * 4, vmulq_n_f32(sum, 0.25F));
591 }
592 return;
593 }
594#endif
595
596 for (; ox < new_w; ++ox) {
597 const float* p00 = row0 + ox * 2 * ch;
598 const float* p01 = row0 + (ox * 2 + 1) * ch;
599 const float* p10 = row1 + ox * 2 * ch;
600 const float* p11 = row1 + (ox * 2 + 1) * ch;
601 float* out = drow + ox * ch;
602 for (uint32_t c = 0; c < ch; ++c)
603 out[c] = (p00[c] + p01[c] + p10[c] + p11[c]) * 0.25F;
604 }
605 });
606}
uint32_t h
Definition InkPress.cpp:28
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:443

References downsample_2x(), and h.

+ Here is the call graph for this function: