18void rgba_to_gray(std::span<const float> rgba, std::span<float> dst, uint32_t w, uint32_t
h)
20 const size_t n =
static_cast<size_t>(w) *
h;
22 P::for_each(P::par_unseq,
23 std::views::iota(uint32_t { 0 },
h).begin(),
24 std::views::iota(uint32_t { 0 },
h).end(),
26 const float* src_row = rgba.data() +
static_cast<size_t>(row) * w * 4;
27 float* dst_row = dst.data() +
static_cast<size_t>(row) * w;
29#ifdef MAYAFLUX_ARCH_X64
31 for (; px + 8 <= w; px += 8) {
32 __m128 a0 = _mm_loadu_ps(src_row + px * 4);
33 __m128 a1 = _mm_loadu_ps(src_row + px * 4 + 4);
34 __m128 a2 = _mm_loadu_ps(src_row + px * 4 + 8);
35 __m128 a3 = _mm_loadu_ps(src_row + px * 4 + 12);
36 _MM_TRANSPOSE4_PS(a0, a1, a2, a3);
37 __m128
lo = _mm_fmadd_ps(a0, _mm_set1_ps(0.299F),
38 _mm_fmadd_ps(a1, _mm_set1_ps(0.587F),
39 _mm_mul_ps(a2, _mm_set1_ps(0.114F))));
41 __m128 b0 = _mm_loadu_ps(src_row + px * 4 + 16);
42 __m128 b1 = _mm_loadu_ps(src_row + px * 4 + 20);
43 __m128 b2 = _mm_loadu_ps(src_row + px * 4 + 24);
44 __m128 b3 = _mm_loadu_ps(src_row + px * 4 + 28);
45 _MM_TRANSPOSE4_PS(b0, b1, b2, b3);
46 __m128
hi = _mm_fmadd_ps(b0, _mm_set1_ps(0.299F),
47 _mm_fmadd_ps(b1, _mm_set1_ps(0.587F),
48 _mm_mul_ps(b2, _mm_set1_ps(0.114F))));
50 _mm256_storeu_ps(dst_row + px, _mm256_set_m128(
hi,
lo));
52 for (; px < w; ++px) {
53 const size_t p = px * 4;
54 dst_row[px] = src_row[p] * 0.299F
55 + src_row[p + 1] * 0.587F
56 + src_row[p + 2] * 0.114F;
59#elif defined(MAYAFLUX_ARCH_ARM64)
60 const float32x4_t k_r = vdupq_n_f32(0.299F);
61 const float32x4_t k_g = vdupq_n_f32(0.587F);
62 const float32x4_t k_b = vdupq_n_f32(0.114F);
64 for (; px + 4 <= w; px += 4) {
65 float32x4x4_t p = vld4q_f32(src_row + px * 4);
66 vst1q_f32(dst_row + px,
67 vmlaq_f32(vmlaq_f32(vmulq_f32(p.val[0], k_r), p.val[1], k_g), p.val[2], k_b));
69 for (; px < w; ++px) {
70 const size_t p = px * 4;
71 dst_row[px] = src_row[p] * 0.299F
72 + src_row[p + 1] * 0.587F
73 + src_row[p + 2] * 0.114F;
77 for (uint32_t px = 0; px < w; ++px) {
78 const size_t p = px * 4;
79 dst_row[px] = src_row[p] * 0.299F
80 + src_row[p + 1] * 0.587F
81 + src_row[p + 2] * 0.114F;
138void gray_to_rgba(std::span<const float> gray, std::span<float> dst, uint32_t w, uint32_t
h)
140 const size_t n =
static_cast<size_t>(w) *
h;
142 P::for_each(P::par_unseq,
143 std::views::iota(uint32_t { 0 },
h).begin(),
144 std::views::iota(uint32_t { 0 },
h).end(),
146 const float* src_row = gray.data() +
static_cast<size_t>(row) * w;
147 float* dst_row = dst.data() +
static_cast<size_t>(row) * w * 4;
149#ifdef MAYAFLUX_ARCH_X64
152 const __m256 alpha_mask = _mm256_set_ps(1.0F, 0.0F, 0.0F, 0.0F,
153 1.0F, 0.0F, 0.0F, 0.0F);
155 for (; px + 2 <= w; px += 2) {
156 const float g0 = src_row[px];
157 const float g1 = src_row[px + 1];
159 __m256 v = _mm256_set_ps(1.0F, g1, g1, g1, 1.0F, g0, g0, g0);
160 _mm256_storeu_ps(dst_row + px * 4, v);
162 for (; px < w; ++px) {
163 const float v = src_row[px];
164 dst_row[px * 4] = dst_row[px * 4 + 1] = dst_row[px * 4 + 2] = v;
165 dst_row[px * 4 + 3] = 1.0F;
168#elif defined(MAYAFLUX_ARCH_ARM64)
169 const float32x4_t alpha = vdupq_n_f32(1.0F);
171 for (; px + 4 <= w; px += 4) {
172 float32x4_t g = vld1q_f32(src_row + px);
173 float32x4_t
lo = vzip1q_f32(g, g);
174 float32x4_t
hi = vzip2q_f32(g, g);
175 float32x4x2_t p01 = vzipq_f32(
lo, vdupq_lane_f32(vget_low_f32(alpha), 0));
182 vst4q_f32(dst_row + px * 4, rgba);
187 for (; px < w; ++px) {
188 const float v = src_row[px];
190 dst_row[px * 4 + 1] = v;
191 dst_row[px * 4 + 2] = v;
192 dst_row[px * 4 + 3] = 1.0F;
196 for (uint32_t px = 0; px < w; ++px) {
197 const float v = src_row[px];
199 dst_row[px * 4 + 1] = v;
200 dst_row[px * 4 + 2] = v;
201 dst_row[px * 4 + 3] = 1.0F;
216 const size_t n = gray.size();
217 const float* src = gray.data();
218 float* out = dst.data();
220#ifdef MAYAFLUX_ARCH_X64
221 const __m256 thresh = _mm256_set1_ps(
value);
222 const __m256 one = _mm256_set1_ps(1.0F);
224 for (; i + 8 <= n; i += 8) {
225 __m256 v = _mm256_loadu_ps(src + i);
226 __m256 mask = _mm256_cmp_ps(v, thresh, _CMP_GE_OS);
227 _mm256_storeu_ps(out + i, _mm256_and_ps(mask, one));
230 out[i] = src[i] >=
value ? 1.0F : 0.0F;
232#elif defined(MAYAFLUX_ARCH_ARM64)
233 const float32x4_t thresh = vdupq_n_f32(
value);
234 const float32x4_t one = vdupq_n_f32(1.0F);
236 for (; i + 4 <= n; i += 4) {
237 float32x4_t v = vld1q_f32(src + i);
238 uint32x4_t mask = vcgeq_f32(v, thresh);
240 vreinterpretq_f32_u32(vandq_u32(mask, vreinterpretq_u32_f32(one))));
243 out[i] = src[i] >=
value ? 1.0F : 0.0F;
246 P::transform(P::par_unseq, gray.begin(), gray.end(), dst.begin(),
247 [
value](
float v) { return v >= value ? 1.0F : 0.0F; });
259 std::span<const float> gray, std::span<float> dst,
260 uint32_t w, uint32_t
h,
263 const size_t n =
static_cast<size_t>(w) *
h;
264 const auto half =
static_cast<int32_t
>(
block_size / 2);
266 P::for_each(P::par_unseq,
267 std::views::iota(
size_t { 0 }, n).begin(),
268 std::views::iota(
size_t { 0 }, n).end(),
270 const auto px =
static_cast<int32_t
>(idx % w);
271 const auto py =
static_cast<int32_t
>(idx / w);
276 for (int32_t dy = -half; dy <= half; ++dy) {
277 const int32_t ny = std::clamp(py + dy, 0,
static_cast<int32_t
>(
h) - 1);
278 for (int32_t dx = -half; dx <= half; ++dx) {
279 const int32_t nx = std::clamp(px + dx, 0,
static_cast<int32_t
>(w) - 1);
280 sum += gray[
static_cast<size_t>(ny) * w + nx];
285 const float mean = sum /
static_cast<float>(
count);
286 dst[idx] = gray[idx] >= (
mean -
offset) ? 1.0F : 0.0F;
301 constexpr int32_t bins = 256;
302 std::array<float, bins> hist {};
305 hist[
static_cast<int32_t
>(std::clamp(v, 0.0F, 1.0F) * (bins - 1))]++;
307 const auto total =
static_cast<float>(gray.size());
311 float sum_all = 0.0F;
312 for (int32_t i = 0; i < bins; ++i)
313 sum_all +=
static_cast<float>(i) * hist[i];
317 float best_var = 0.0F;
320 for (int32_t t = 0; t < bins; ++t) {
325 const float w_fg = 1.0F - w_bg;
329 sum_bg +=
static_cast<float>(t) * hist[t];
331 const float mean_bg = sum_bg / w_bg;
332 const float mean_fg = (sum_all - sum_bg) / w_fg;
333 const float diff = mean_fg - mean_bg;
334 const float var = w_bg * w_fg * diff * diff;
336 if (var > best_var) {
342 const float t_norm =
static_cast<float>(best_t) /
static_cast<float>(bins - 1);
358 const Eigen::Index en =
static_cast<Eigen::Index
>(data.size());
359 auto m = Eigen::Map<Eigen::ArrayXf>(data.data(), en);
360 const float mn = m.minCoeff();
361 const float mx = m.maxCoeff();
362 const float range = mx - mn;
366 const float inv = 1.0F / range;
367 float* out = data.data();
368 const size_t n = data.size();
370#ifdef MAYAFLUX_ARCH_X64
371 const __m256 v_mn = _mm256_set1_ps(mn);
372 const __m256 v_inv = _mm256_set1_ps(inv);
374 for (; i + 8 <= n; i += 8) {
375 __m256 v = _mm256_loadu_ps(out + i);
376 _mm256_storeu_ps(out + i, _mm256_mul_ps(_mm256_sub_ps(v, v_mn), v_inv));
379 out[i] = (out[i] - mn) * inv;
381#elif defined(MAYAFLUX_ARCH_ARM64)
382 const float32x4_t v_mn = vdupq_n_f32(mn);
383 const float32x4_t v_inv = vdupq_n_f32(inv);
385 for (; i + 4 <= n; i += 4) {
386 float32x4_t v = vld1q_f32(out + i);
387 vst1q_f32(out + i, vmulq_f32(vsubq_f32(v, v_mn), v_inv));
390 out[i] = (out[i] - mn) * inv;
393 P::transform(P::par_unseq, data.begin(), data.end(), data.begin(),
394 [mn, inv](
float v) { return (v - mn) * inv; });
403 const float inv = 1.0F / (
hi -
lo);
404 float* out = data.data();
405 const size_t n = data.size();
407#ifdef MAYAFLUX_ARCH_X64
408 const __m256 v_lo = _mm256_set1_ps(
lo);
409 const __m256 v_inv = _mm256_set1_ps(inv);
410 const __m256 v_zero = _mm256_setzero_ps();
411 const __m256 v_one = _mm256_set1_ps(1.0F);
413 for (; i + 8 <= n; i += 8) {
414 __m256 v = _mm256_loadu_ps(out + i);
415 v = _mm256_mul_ps(_mm256_sub_ps(v, v_lo), v_inv);
416 v = _mm256_min_ps(_mm256_max_ps(v, v_zero), v_one);
417 _mm256_storeu_ps(out + i, v);
420 out[i] = std::clamp((out[i] -
lo) * inv, 0.0F, 1.0F);
422#elif defined(MAYAFLUX_ARCH_ARM64)
423 const float32x4_t v_lo = vdupq_n_f32(
lo);
424 const float32x4_t v_inv = vdupq_n_f32(inv);
425 const float32x4_t v_zero = vdupq_n_f32(0.0F);
426 const float32x4_t v_one = vdupq_n_f32(1.0F);
428 for (; i + 4 <= n; i += 4) {
429 float32x4_t v = vld1q_f32(out + i);
430 v = vmulq_f32(vsubq_f32(v, v_lo), v_inv);
431 v = vminq_f32(vmaxq_f32(v, v_zero), v_one);
432 vst1q_f32(out + i, v);
435 out[i] = std::clamp((out[i] -
lo) * inv, 0.0F, 1.0F);
438 P::transform(P::par_unseq, data.begin(), data.end(), data.begin(),
439 [
lo, inv](
float v) { return std::clamp((v - lo) * inv, 0.0F, 1.0F); });
444 std::span<const float> src,
445 std::span<float> dst,
446 uint32_t w, uint32_t
h,
447 uint32_t& new_w, uint32_t& new_h)
452 P::for_each(P::par_unseq,
453 std::views::iota(uint32_t { 0 }, new_h).begin(),
454 std::views::iota(uint32_t { 0 }, new_h).end(),
456 const float* row0 = src.data() +
static_cast<size_t>(oy * 2) * w;
457 const float* row1 = src.data() +
static_cast<size_t>(oy * 2 + 1) * w;
458 float* drow = dst.data() +
static_cast<size_t>(oy) * new_w;
460#ifdef MAYAFLUX_ARCH_X64
461 const __m256 quarter = _mm256_set1_ps(0.25F);
463 for (; ox + 8 <= new_w; ox += 8) {
465 __m256 r0a = _mm256_loadu_ps(row0 + ox * 2);
466 __m256 r0b = _mm256_loadu_ps(row0 + ox * 2 + 8);
467 __m256 r1a = _mm256_loadu_ps(row1 + ox * 2);
468 __m256 r1b = _mm256_loadu_ps(row1 + ox * 2 + 8);
471 __m256 sum0 = _mm256_hadd_ps(r0a, r0b);
472 __m256 sum1 = _mm256_hadd_ps(r1a, r1b);
473 __m256 sum = _mm256_add_ps(sum0, sum1);
475 __m256d perm_d = _mm256_permute4x64_pd(_mm256_castps_pd(sum), _MM_SHUFFLE(3, 1, 2, 0));
476 __m256 result = _mm256_mul_ps(_mm256_castpd_ps(perm_d), quarter);
477 _mm256_storeu_ps(drow + ox, result);
479 for (; ox < new_w; ++ox) {
480 drow[ox] = (row0[ox * 2] + row0[ox * 2 + 1]
481 + row1[ox * 2] + row1[ox * 2 + 1])
485#elif defined(MAYAFLUX_ARCH_ARM64)
486 const float32x4_t quarter = vdupq_n_f32(0.25F);
488 for (; ox + 4 <= new_w; ox += 4) {
491 float32x4x2_t r0 = vld2q_f32(row0 + ox * 2);
492 float32x4x2_t r1 = vld2q_f32(row1 + ox * 2);
495 float32x4_t sum = vaddq_f32(
496 vaddq_f32(r0.val[0], r0.val[1]),
497 vaddq_f32(r1.val[0], r1.val[1]));
498 vst1q_f32(drow + ox, vmulq_f32(sum, quarter));
500 for (; ox < new_w; ++ox) {
501 drow[ox] = (row0[ox * 2] + row0[ox * 2 + 1]
502 + row1[ox * 2] + row1[ox * 2 + 1])
507 for (uint32_t ox = 0; ox < new_w; ++ox) {
508 drow[ox] = (row0[ox * 2] + row0[ox * 2 + 1]
509 + row1[ox * 2] + row1[ox * 2 + 1])
529 std::span<const float> src,
530 std::span<float> dst,
531 uint32_t w, uint32_t
h,
533 uint32_t& new_w, uint32_t& new_h)
542 const uint32_t ch = channels;
543 const uint32_t row_stride = w * ch;
544 const uint32_t out_stride = new_w * ch;
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(),
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;
556#ifdef MAYAFLUX_ARCH_X64
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;
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);
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);
576#elif defined(MAYAFLUX_ARCH_ARM64)
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;
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);
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));
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;