diff --git a/docs/2026.html b/docs/2026.html index c07ca3e5ef..8a581bfb8b 100644 --- a/docs/2026.html +++ b/docs/2026.html @@ -62,6 +62,8 @@
Removing
  • Function SimdFillBgra.
  • Function SimdHogDirectionHistograms.
  • C++ wrapper Simd::HogDirectionHistograms.
  • +
  • Function SimdHogExtractFeatures.
  • +
  • C++ wrapper Simd::HogExtractFeatures.
  • Python wrapper

    @@ -93,6 +95,7 @@
    Removing
  • Tests for verifying functionality of function FillBgr.
  • Tests for verifying functionality of function FillBgra.
  • Tests for verifying functionality of function HogDirectionHistograms.
  • +
  • Tests for verifying functionality of function HogExtractFeatures.
  • Documentation

    diff --git a/src/Simd/SimdAvx2.h b/src/Simd/SimdAvx2.h index 923476f3c0..882afb45f3 100644 --- a/src/Simd/SimdAvx2.h +++ b/src/Simd/SimdAvx2.h @@ -267,8 +267,6 @@ namespace Simd void AbsSecondDerivativeHistogram(const uint8_t *src, size_t width, size_t height, size_t stride, size_t step, size_t indent, uint32_t * histogram); - void HogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features); - void HogDeinterleave(const float * src, size_t srcStride, size_t width, size_t height, size_t count, float ** dst, size_t dstStride); void HogFilterSeparable(const float * src, size_t srcStride, size_t width, size_t height, const float * rowFilter, size_t rowSize, const float * colFilter, size_t colSize, float * dst, size_t dstStride, int add); diff --git a/src/Simd/SimdAvx2Hog.cpp b/src/Simd/SimdAvx2Hog.cpp index 5474d0d966..219a6ea937 100644 --- a/src/Simd/SimdAvx2Hog.cpp +++ b/src/Simd/SimdAvx2Hog.cpp @@ -23,307 +23,12 @@ */ #include "Simd/SimdStore.h" #include "Simd/SimdArray.h" -#include "Simd/SimdUnpack.h" namespace Simd { #ifdef SIMD_AVX2_ENABLE namespace Avx2 { - class HogFeatureExtractor - { - static const size_t C = 8; - static const size_t Q = 9; - static const size_t Q2 = 18; - - typedef Array Array32i; - typedef Array Array32f; - - size_t _sx, _sy, _hs; - - __m256i _pos[5]; - __m256 _cos[5], _sin[5]; - __m128 _kx[8], _ky[8]; - __m256i _Q, _Q2; - - Array32i _index; - Array32f _value; - Array32f _buffer; - Array32f _histogram; - Array32f _norm; - - void Init(size_t w, size_t h) - { - _sx = w / C; - _hs = _sx + 2; - _sy = h / C; - for (int i = 0; i < 5; ++i) - { - _cos[i] = _mm256_set1_ps((float)::cos(i*M_PI / Q)); - _sin[i] = _mm256_set1_ps((float)::sin(i*M_PI / Q)); - _pos[i] = _mm256_set1_epi32(i); - } - for (int i = 0; i < C; ++i) - { - float k0 = float((15 - i * 2) / 16.0f); - float k1 = 1.0f - k0; - _kx[i] = _mm_setr_ps(k0, k1, k0, k1); - _ky[i] = _mm_setr_ps(k0, k0, k1, k1); - } - _Q = _mm256_set1_epi32(Q); - _Q2 = _mm256_set1_epi32(Q2); - - _index.Resize(w); - _value.Resize(w); - _buffer.Resize((_sx + 1) * 4 * Q2); - _histogram.Resize((_sx + 2)*(_sy + 2)*Q2); - _norm.Resize((_sx + 2)*(_sy + 2)); - } - - template SIMD_INLINE void GetHistogram(const __m256 & dx, const __m256 & dy, size_t col) - { - __m256 _0 = _mm256_set1_ps(-0.0f); - __m256 adx = _mm256_andnot_ps(_0, dx); - __m256 ady = _mm256_andnot_ps(_0, dy); - __m256 bestDot = _mm256_fmadd_ps(adx, _cos[0], _mm256_mul_ps(ady, _sin[0])); - __m256i bestIndex = _pos[0]; - for (int i = 1; i < 5; ++i) - { - __m256 dot = _mm256_fmadd_ps(adx, _cos[i], _mm256_mul_ps(ady, _sin[i])); - __m256 mask = _mm256_cmp_ps(dot, bestDot, _CMP_GT_OS); - bestDot = _mm256_max_ps(dot, bestDot); - bestIndex = _mm256_blendv_epi8(bestIndex, _pos[i], _mm256_castps_si256(mask)); - } - __m256i maskDx = _mm256_castps_si256(_mm256_cmp_ps(dx, _mm256_setzero_ps(), _CMP_LT_OS)); - bestIndex = _mm256_blendv_epi8(bestIndex, _mm256_sub_epi32(_Q, bestIndex), maskDx); - - __m256i maskDy = _mm256_castps_si256(_mm256_cmp_ps(dy, _mm256_setzero_ps(), _CMP_LT_OS)); - __m256i corr = _mm256_and_si256(_mm256_castps_si256(_mm256_cmp_ps(adx, _mm256_setzero_ps(), _CMP_EQ_OS)), K32_00000001); - bestIndex = _mm256_blendv_epi8(bestIndex, _mm256_sub_epi32(_Q2, _mm256_add_epi32(bestIndex, corr)), maskDy); - - bestIndex = _mm256_andnot_si256(_mm256_cmpeq_epi32(bestIndex, _Q2), bestIndex); - - Store((__m256i*)(_index.data + col), bestIndex); - Store(_value.data + col, Sqrt<0>(_mm256_fmadd_ps(adx, adx, _mm256_mul_ps(ady, ady)))); - } - - template SIMD_INLINE __m256 ConvertDifference(const __m128i & a, const __m128i & b) - { - return _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(Sse41::SubUnpackedU8(a, b))); - } - - template SIMD_INLINE void GetHistogram(const uint8_t * src, size_t stride, size_t col) - { - const uint8_t * s = src + col; - __m128i t = Sse41::Load((__m128i*)(s - stride)); - __m128i l = Sse41::Load((__m128i*)(s - 1)); - __m128i r = Sse41::Load((__m128i*)(s + 1)); - __m128i b = Sse41::Load((__m128i*)(s + stride)); - GetHistogram(ConvertDifference<0>(r, l), ConvertDifference<0>(b, t), col + 0); - GetHistogram(ConvertDifference<1>(r, l), ConvertDifference<1>(b, t), col + 8); - } - - void AddRowToBuffer(const uint8_t * src, size_t stride, size_t row, size_t width, size_t aligned) - { - const uint8_t * s = src + stride * row; - GetHistogram(s, stride, 1); - for (size_t col = HA; col < aligned; col += HA) - GetHistogram(s, stride, col); - GetHistogram(s, stride, width - 1 - HA); - - __m128 ky = _ky[(row + 4) & 7]; - __m128 * buffer = (__m128*)_buffer.data; - for (size_t col = 1, n = C, i = 5; col < width - 1; i = 0, n = Simd::Min(C, width - col - 1)) - { - for (; i < n; ++i, ++col) - { - int index = _index[col]; - __m128 value = _mm_set1_ps(_value[col]); - buffer[index] = _mm_fmadd_ps(_mm_mul_ps(ky, _kx[i]), value, buffer[index]); - } - buffer += Q2; - } - } - - void AddToHistogram(size_t row, size_t width, size_t height) - { - typedef float f18_t[18]; - - float * src = _buffer.data; - f18_t * h0 = (f18_t*)_histogram.data + row * _hs; - f18_t * h1 = h0 + _hs; - - for (size_t cell = 0; cell <= width; ++cell) - { - for (size_t i = 0; i < 16; i += F) - { - const float * s = src + i * 4; - __m256 a0 = Load(s + 0x00, s + 0x10); - __m256 a1 = Load(s + 0x04, s + 0x14); - __m256 a2 = Load(s + 0x08, s + 0x18); - __m256 a3 = Load(s + 0x0C, s + 0x1C); - __m256 b0 = _mm256_unpacklo_ps(a0, a2); - __m256 b1 = _mm256_unpackhi_ps(a0, a2); - __m256 b2 = _mm256_unpacklo_ps(a1, a3); - __m256 b3 = _mm256_unpackhi_ps(a1, a3); - Store(h0[0] + i, _mm256_add_ps(Load(h0[0] + i), _mm256_unpacklo_ps(b0, b2))); - Store(h0[1] + i, _mm256_add_ps(Load(h0[1] + i), _mm256_unpackhi_ps(b0, b2))); - Store(h1[0] + i, _mm256_add_ps(Load(h1[0] + i), _mm256_unpacklo_ps(b1, b3))); - Store(h1[1] + i, _mm256_add_ps(Load(h1[1] + i), _mm256_unpackhi_ps(b1, b3))); - } - __m128 * ps = (__m128*)src; - __m128 s0 = _mm_add_ps(_mm_unpacklo_ps(ps[16], ps[17]), Sse41::Load(h0[0] + 16, h0[1] + 16)); - __m128 s1 = _mm_add_ps(_mm_unpackhi_ps(ps[16], ps[17]), Sse41::Load(h1[0] + 16, h1[1] + 16)); - Sse41::StoreHalf<0>(h0[0] + 16, s0); - Sse41::StoreHalf<1>(h0[1] + 16, s0); - Sse41::StoreHalf<0>(h1[0] + 16, s1); - Sse41::StoreHalf<1>(h1[1] + 16, s1); - h0++; - h1++; - src += 72; - } - _buffer.Clear(); - } - - void EstimateHistogram(const uint8_t * src, size_t stride, size_t width, size_t height) - { - _histogram.Clear(); - - size_t aligned = AlignHi(width - 1, HA) - HA; - - _buffer.Clear(); - for (size_t row = 1; row < 4; ++row) - AddRowToBuffer(src, stride, row, width, aligned); - AddToHistogram(0, _sx, _sy); - for (size_t row = 4, cell = 1; row < height - 4; ++row) - { - AddRowToBuffer(src, stride, row, width, aligned); - if ((row & 7) == 3) - AddToHistogram(cell++, _sx, _sy); - } - for (size_t row = height - 4; row < height - 1; ++row) - AddRowToBuffer(src, stride, row, width, aligned); - AddToHistogram(_sy, _sx, _sy); - } - - SIMD_INLINE float GetNorm(const float * src) - { - __m256 norm = _mm256_add_ps(_mm256_loadu_ps(src), _mm256_loadu_ps(src + Q)); - norm = _mm256_mul_ps(norm, norm); - norm = _mm256_hadd_ps(norm, norm); - norm = _mm256_hadd_ps(norm, norm); - float buf[8]; - _mm256_storeu_ps(buf, norm); - return buf[0] + buf[4] + Simd::Square(src[Q - 1] + src[Q2 - 1]); - } - - void EstimateNorm() - { - _norm.Clear(); - for (size_t y = 0, i = 0; y < _sy; y++) - { - const float * h = _histogram.data + ((y + 1)*_hs + 1)*Q2; - float * n = _norm.data + (y + 1)*_hs + 1; - for (size_t x = 0; x < _sx; x++, i++) - n[x] = GetNorm(h + x * Q2); - } - } - - void ExtractFeatures(float * features) - { - __m128 _02 = _mm_set1_ps(0.2f); - __m128 _05 = _mm_set1_ps(0.5f); - __m128 _02357 = _mm_set1_ps(0.2357f); - __m128 eps = _mm_set1_ps(0.0001f); - for (size_t y = 0; y < _sy; y++) - { - float * ph = _histogram.data + ((y + 1)*_hs + 1)*Q2; - for (size_t x = 0; x < _sx; x++) - { - float * dst = features + (y*_sx + x) * 31; - - float * p0 = _norm.data + y * _hs + x; - float * p1 = p0 + _hs; - float * p2 = p1 + _hs; - - __m128 n = _mm_setr_ps( - p1[1] + p1[2] + p2[1] + p2[2], - p0[1] + p0[2] + p1[1] + p1[2], - p1[0] + p1[1] + p2[0] + p2[1], - p0[0] + p0[1] + p1[0] + p1[1]); - - n = _mm_rsqrt_ps(_mm_add_ps(n, eps)); - - __m128 t = _mm_setzero_ps(); - - float * src = ph + x * Q2; - for (int o = 0; o < 16; o += 4) - { - __m128 s = _mm_loadu_ps(src); - __m128 h0 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<0>(s), n), _02); - __m128 h1 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<1>(s), n), _02); - __m128 h2 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<2>(s), n), _02); - __m128 h3 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<3>(s), n), _02); - t = _mm_add_ps(t, _mm_add_ps(_mm_add_ps(h0, h1), _mm_add_ps(h2, h3))); - _mm_storeu_ps(dst, _mm_mul_ps(_05, _mm_hadd_ps(_mm_hadd_ps(h0, h1), _mm_hadd_ps(h2, h3)))); - dst += 4; - src += 4; - } - { - __m128 h0 = _mm_min_ps(_mm_mul_ps(_mm_set1_ps(*src++), n), _02); - __m128 h1 = _mm_min_ps(_mm_mul_ps(_mm_set1_ps(*src++), n), _02); - t = _mm_add_ps(t, _mm_add_ps(h0, h1)); - __m128 h = _mm_hadd_ps(h0, h1); - _mm_storeu_ps(dst, _mm_mul_ps(_05, _mm_hadd_ps(h, h))); - dst += 2; - } - - src = ph + x * Q2; - for (int o = 0; o < 8; o += 4) - { - __m128 s = _mm_add_ps(_mm_loadu_ps(src), _mm_loadu_ps(src + Q)); - __m128 h0 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<0>(s), n), _02); - __m128 h1 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<1>(s), n), _02); - __m128 h2 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<2>(s), n), _02); - __m128 h3 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<3>(s), n), _02); - _mm_storeu_ps(dst, _mm_mul_ps(_05, _mm_hadd_ps(_mm_hadd_ps(h0, h1), _mm_hadd_ps(h2, h3)))); - dst += 4; - src += 4; - } - { - __m128 s = _mm_set1_ps(src[0] + src[Q]); - __m128 h = _mm_min_ps(_mm_mul_ps(s, n), _02); - h = _mm_dp_ps(_05, h, 0xF1); - _mm_store_ss(dst++, h); - } - _mm_storeu_ps(dst, _mm_mul_ps(t, _02357)); - } - } - } - - public: - - void Run(const uint8_t * src, size_t stride, size_t width, size_t height, float * features) - { - Init(width, height); - - EstimateHistogram(src, stride, width, height); - - EstimateNorm(); - - ExtractFeatures(features); - } - }; - - void HogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features) - { - assert(width % 8 == 0 && height % 8 == 0 && width >= 16 && height >= 16); - assert(width >= HA + 2); - - HogFeatureExtractor extractor; - extractor.Run(src, stride, width, height, features); - } - SIMD_INLINE void HogDeinterleave(const float * src, size_t count, float ** dst, size_t offset, size_t i) { src += i; diff --git a/src/Simd/SimdAvx512bw.h b/src/Simd/SimdAvx512bw.h index 6eb9e57ce0..84d4b60739 100644 --- a/src/Simd/SimdAvx512bw.h +++ b/src/Simd/SimdAvx512bw.h @@ -261,8 +261,6 @@ namespace Simd void Gemm32fNT(size_t M, size_t N, size_t K, const float* alpha, const float* A, size_t lda, const float* B, size_t ldb, const float* beta, float* C, size_t ldc); - void HogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features); - void HogDeinterleave(const float * src, size_t srcStride, size_t width, size_t height, size_t count, float ** dst, size_t dstStride); void HogFilterSeparable(const float * src, size_t srcStride, size_t width, size_t height, const float * rowFilter, size_t rowSize, const float * colFilter, size_t colSize, float * dst, size_t dstStride, int add); diff --git a/src/Simd/SimdAvx512bwHog.cpp b/src/Simd/SimdAvx512bwHog.cpp index 49cdf0d96c..550c666e3f 100644 --- a/src/Simd/SimdAvx512bwHog.cpp +++ b/src/Simd/SimdAvx512bwHog.cpp @@ -23,310 +23,12 @@ */ #include "Simd/SimdStore.h" #include "Simd/SimdArray.h" -#include "Simd/SimdUnpack.h" namespace Simd { #ifdef SIMD_AVX512BW_ENABLE namespace Avx512bw { - template SIMD_INLINE __m512 CovertDifference(const __m256i & a, const __m256i & b) - { - return _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(Avx2::SubUnpackedU8(a, b))); - } - - class HogFeatureExtractor - { - static const size_t C = 8; - static const size_t Q = 9; - static const size_t Q2 = 18; - - typedef Array Array32i; - typedef Array Array32f; - - size_t _sx, _sy, _hs; - - __m512i _pos[5]; - __m512 _cos[5], _sin[5]; - __m128 _kx[8], _ky[8]; - __m512i _Q, _Q2; - - Array32i _index; - Array32f _value; - Array32f _buffer; - Array32f _histogram; - Array32f _norm; - - void Init(size_t w, size_t h) - { - _sx = w / C; - _hs = _sx + 2; - _sy = h / C; - for (int i = 0; i < 5; ++i) - { - _cos[i] = _mm512_set1_ps((float)::cos(i*M_PI / Q)); - _sin[i] = _mm512_set1_ps((float)::sin(i*M_PI / Q)); - _pos[i] = _mm512_set1_epi32(i); - } - for (int i = 0; i < C; ++i) - { - float k0 = float((15 - i * 2) / 16.0f); - float k1 = 1.0f - k0; - _kx[i] = _mm_setr_ps(k0, k1, k0, k1); - _ky[i] = _mm_setr_ps(k0, k0, k1, k1); - } - _Q = _mm512_set1_epi32(Q); - _Q2 = _mm512_set1_epi32(Q2); - - _index.Resize(w); - _value.Resize(w); - _buffer.Resize((_sx + 1) * 4 * Q2); - _histogram.Resize((_sx + 2)*(_sy + 2)*Q2); - _norm.Resize((_sx + 2)*(_sy + 2)); - } - - template SIMD_INLINE void GetHistogram(const __m512 & dx, const __m512 & dy, size_t col) - { - __m512 _0 = _mm512_set1_ps(-0.0f); - __m512 adx = _mm512_andnot_ps(_0, dx); - __m512 ady = _mm512_andnot_ps(_0, dy); - __m512 bestDot = _mm512_fmadd_ps(adx, _cos[0], _mm512_mul_ps(ady, _sin[0])); - __m512i bestIndex = _pos[0]; - for (int i = 1; i < 5; ++i) - { - __m512 dot = _mm512_fmadd_ps(adx, _cos[i], _mm512_mul_ps(ady, _sin[i])); - bestIndex = _mm512_mask_blend_epi32(_mm512_cmp_ps_mask(dot, bestDot, _CMP_GT_OS), bestIndex, _pos[i]); - bestDot = _mm512_max_ps(dot, bestDot); - } - bestIndex = _mm512_mask_sub_epi32(bestIndex, _mm512_cmp_ps_mask(dx, _0, _CMP_LT_OS), _Q, bestIndex); - - __m512i corr = _mm512_maskz_set1_epi32(_mm512_cmp_ps_mask(adx, _mm512_setzero_ps(), _CMP_EQ_OS), 1); - bestIndex = _mm512_mask_sub_epi32(bestIndex, _mm512_cmp_ps_mask(dy, _0, _CMP_LT_OS), _Q2, _mm512_add_epi32(bestIndex, corr)); - - bestIndex = _mm512_mask_set1_epi32(bestIndex, _mm512_cmpeq_epi32_mask(bestIndex, _Q2), 0); - - Store(_index.data + col, bestIndex); - Store(_value.data + col, _mm512_sqrt_ps(_mm512_fmadd_ps(adx, adx, _mm512_mul_ps(ady, ady)))); - } - - template SIMD_INLINE void GetHistogram(const uint8_t * src, size_t stride, size_t col) - { - const uint8_t * s = src + col; - __m256i t = Avx2::LoadPermuted((__m256i*)(s - stride)); - __m256i l = Avx2::LoadPermuted((__m256i*)(s - 1)); - __m256i r = Avx2::LoadPermuted((__m256i*)(s + 1)); - __m256i b = Avx2::LoadPermuted((__m256i*)(s + stride)); - GetHistogram(CovertDifference<0>(r, l), CovertDifference<0>(b, t), col + 0); - GetHistogram(CovertDifference<1>(r, l), CovertDifference<1>(b, t), col + F); - } - - void AddRowToBuffer(const uint8_t * src, size_t stride, size_t row, size_t width, size_t aligned) - { - const uint8_t * s = src + stride * row; - GetHistogram(s, stride, 1); - for (size_t col = HA; col < aligned; col += HA) - GetHistogram(s, stride, col); - GetHistogram(s, stride, width - 1 - HA); - - __m128 ky = _ky[(row + 4) & 7]; - __m128 * buffer = (__m128*)_buffer.data; - for (size_t col = 1, n = C, i = 5; col < width - 1; i = 0, n = Simd::Min(C, width - col - 1)) - { - for (; i < n; ++i, ++col) - { - int index = _index[col]; - __m128 value = _mm_set1_ps(_value[col]); - buffer[index] = _mm_fmadd_ps(_mm_mul_ps(ky, _kx[i]), value, buffer[index]); - } - buffer += Q2; - } - } - - void AddToHistogram(size_t row, size_t width, size_t height) - { - typedef float f18_t[18]; - - float * src = _buffer.data; - f18_t * h0 = (f18_t*)_histogram.data + row * _hs; - f18_t * h1 = h0 + _hs; - - for (size_t cell = 0; cell <= width; ++cell) - { - __m512 a0 = Load(src + 0x00, src + 0x10, src + 0x20, src + 0x30); - __m512 a1 = Load(src + 0x04, src + 0x14, src + 0x24, src + 0x34); - __m512 a2 = Load(src + 0x08, src + 0x18, src + 0x28, src + 0x38); - __m512 a3 = Load(src + 0x0C, src + 0x1C, src + 0x2C, src + 0x3C); - __m512 b0 = _mm512_unpacklo_ps(a0, a2); - __m512 b1 = _mm512_unpackhi_ps(a0, a2); - __m512 b2 = _mm512_unpacklo_ps(a1, a3); - __m512 b3 = _mm512_unpackhi_ps(a1, a3); - Store(h0[0], _mm512_add_ps(Load(h0[0]), _mm512_unpacklo_ps(b0, b2))); - Store(h0[1], _mm512_add_ps(Load(h0[1]), _mm512_unpackhi_ps(b0, b2))); - Store(h1[0], _mm512_add_ps(Load(h1[0]), _mm512_unpacklo_ps(b1, b3))); - Store(h1[1], _mm512_add_ps(Load(h1[1]), _mm512_unpackhi_ps(b1, b3))); -#if defined(_MSC_VER) - for (size_t i = 16; i < 18; ++i) - { - h0[0][i] += src[i * 4 + 0]; - h0[1][i] += src[i * 4 + 1]; - h1[0][i] += src[i * 4 + 2]; - h1[1][i] += src[i * 4 + 3]; - } -#else - __m128 * ps = (__m128*)src; - __m128 s0 = _mm_add_ps(_mm_unpacklo_ps(ps[16], ps[17]), Sse41::Load(h0[0] + 16, h0[1] + 16)); - __m128 s1 = _mm_add_ps(_mm_unpackhi_ps(ps[16], ps[17]), Sse41::Load(h1[0] + 16, h1[1] + 16)); - Sse41::StoreHalf<0>(h0[0] + 16, s0); - Sse41::StoreHalf<1>(h0[1] + 16, s0); - Sse41::StoreHalf<0>(h1[0] + 16, s1); - Sse41::StoreHalf<1>(h1[1] + 16, s1); -#endif - h0++; - h1++; - src += 72; - } - _buffer.Clear(); - } - - void EstimateHistogram(const uint8_t * src, size_t stride, size_t width, size_t height) - { - _histogram.Clear(); - - size_t aligned = AlignHi(width - 1, HA) - HA; - - _buffer.Clear(); - for (size_t row = 1; row < 4; ++row) - AddRowToBuffer(src, stride, row, width, aligned); - AddToHistogram(0, _sx, _sy); - for (size_t row = 4, cell = 1; row < height - 4; ++row) - { - AddRowToBuffer(src, stride, row, width, aligned); - if ((row & 7) == 3) - AddToHistogram(cell++, _sx, _sy); - } - for (size_t row = height - 4; row < height - 1; ++row) - AddRowToBuffer(src, stride, row, width, aligned); - AddToHistogram(_sy, _sx, _sy); - } - - SIMD_INLINE float GetNorm(const float * src) - { - __m256 norm = _mm256_add_ps(_mm256_loadu_ps(src), _mm256_loadu_ps(src + Q)); - norm = _mm256_mul_ps(norm, norm); - norm = _mm256_hadd_ps(norm, norm); - norm = _mm256_hadd_ps(norm, norm); - float buf[8]; - _mm256_storeu_ps(buf, norm); - return buf[0] + buf[4] + Simd::Square(src[Q - 1] + src[Q2 - 1]); - } - - void EstimateNorm() - { - _norm.Clear(); - for (size_t y = 0, i = 0; y < _sy; y++) - { - const float * h = _histogram.data + ((y + 1)*_hs + 1)*Q2; - float * n = _norm.data + (y + 1)*_hs + 1; - for (size_t x = 0; x < _sx; x++, i++) - n[x] = GetNorm(h + x * Q2); - } - } - - void ExtractFeatures(float * features) - { - __m128 _02 = _mm_set1_ps(0.2f); - __m128 _05 = _mm_set1_ps(0.5f); - __m128 _02357 = _mm_set1_ps(0.2357f); - __m128 eps = _mm_set1_ps(0.0001f); - for (size_t y = 0; y < _sy; y++) - { - float * ph = _histogram.data + ((y + 1)*_hs + 1)*Q2; - for (size_t x = 0; x < _sx; x++) - { - float * dst = features + (y*_sx + x) * 31; - - float * p0 = _norm.data + y * _hs + x; - float * p1 = p0 + _hs; - float * p2 = p1 + _hs; - - __m128 n = _mm_setr_ps( - p1[1] + p1[2] + p2[1] + p2[2], - p0[1] + p0[2] + p1[1] + p1[2], - p1[0] + p1[1] + p2[0] + p2[1], - p0[0] + p0[1] + p1[0] + p1[1]); - - n = _mm_rsqrt_ps(_mm_add_ps(n, eps)); - - __m128 t = _mm_setzero_ps(); - - float * src = ph + x * Q2; - for (int o = 0; o < 16; o += 4) - { - __m128 s = _mm_loadu_ps(src); - __m128 h0 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<0>(s), n), _02); - __m128 h1 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<1>(s), n), _02); - __m128 h2 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<2>(s), n), _02); - __m128 h3 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<3>(s), n), _02); - t = _mm_add_ps(t, _mm_add_ps(_mm_add_ps(h0, h1), _mm_add_ps(h2, h3))); - _mm_storeu_ps(dst, _mm_mul_ps(_05, _mm_hadd_ps(_mm_hadd_ps(h0, h1), _mm_hadd_ps(h2, h3)))); - dst += 4; - src += 4; - } - { - __m128 h0 = _mm_min_ps(_mm_mul_ps(_mm_set1_ps(*src++), n), _02); - __m128 h1 = _mm_min_ps(_mm_mul_ps(_mm_set1_ps(*src++), n), _02); - t = _mm_add_ps(t, _mm_add_ps(h0, h1)); - __m128 h = _mm_hadd_ps(h0, h1); - _mm_storeu_ps(dst, _mm_mul_ps(_05, _mm_hadd_ps(h, h))); - dst += 2; - } - - src = ph + x * Q2; - for (int o = 0; o < 8; o += 4) - { - __m128 s = _mm_add_ps(_mm_loadu_ps(src), _mm_loadu_ps(src + Q)); - __m128 h0 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<0>(s), n), _02); - __m128 h1 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<1>(s), n), _02); - __m128 h2 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<2>(s), n), _02); - __m128 h3 = _mm_min_ps(_mm_mul_ps(Sse41::Broadcast<3>(s), n), _02); - _mm_storeu_ps(dst, _mm_mul_ps(_05, _mm_hadd_ps(_mm_hadd_ps(h0, h1), _mm_hadd_ps(h2, h3)))); - dst += 4; - src += 4; - } - { - __m128 s = _mm_set1_ps(src[0] + src[Q]); - __m128 h = _mm_min_ps(_mm_mul_ps(s, n), _02); - h = _mm_dp_ps(_05, h, 0xF1); - _mm_store_ss(dst++, h); - } - _mm_storeu_ps(dst, _mm_mul_ps(t, _02357)); - } - } - } - - public: - - void Run(const uint8_t * src, size_t stride, size_t width, size_t height, float * features) - { - Init(width, height); - - EstimateHistogram(src, stride, width, height); - - EstimateNorm(); - - ExtractFeatures(features); - } - }; - - void HogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features) - { - assert(width % 8 == 0 && height % 8 == 0 && width >= 16 && height >= 16); - assert(width >= HA + 2); - - HogFeatureExtractor extractor; - extractor.Run(src, stride, width, height, features); - } - SIMD_INLINE void HogDeinterleave(const float * src, size_t count, float ** dst, size_t offset, size_t i) { src += i; diff --git a/src/Simd/SimdBase.h b/src/Simd/SimdBase.h index a2a32c1f8c..14effbf55f 100644 --- a/src/Simd/SimdBase.h +++ b/src/Simd/SimdBase.h @@ -309,8 +309,6 @@ namespace Simd void NormalizeHistogram(const uint8_t * src, size_t srcStride, size_t width, size_t height, uint8_t * dst, size_t dstStride); - void HogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features); - void HogDeinterleave(const float * src, size_t srcStride, size_t width, size_t height, size_t count, float ** dst, size_t dstStride); void HogFilterSeparable(const float * src, size_t srcStride, size_t width, size_t height, const float * rowFilter, size_t rowSize, const float * colFilter, size_t colSize, float * dst, size_t dstStride, int add); diff --git a/src/Simd/SimdBaseHog.cpp b/src/Simd/SimdBaseHog.cpp index cd940bd666..f147657a9a 100644 --- a/src/Simd/SimdBaseHog.cpp +++ b/src/Simd/SimdBaseHog.cpp @@ -27,209 +27,6 @@ namespace Simd { namespace Base { - class HogFeatureExtractor - { - static const size_t C = 8; - static const size_t Q = 9; - static const size_t Q2 = 18; - - size_t _sx, _sy, _hs; - - float _cos[5]; - float _sin[5]; - float _k[C]; - - Array32i _index; - Array32f _value; - Array32f _histogram; - Array32f _norm; - - void Init(size_t w, size_t h) - { - _sx = w / C; - _hs = _sx + 2; - _sy = h / C; - for (int i = 0; i < 5; ++i) - { - _cos[i] = (float)::cos(i*M_PI / Q); - _sin[i] = (float)::sin(i*M_PI / Q); - } - for (int i = 0; i < C; ++i) - _k[i] = float((1 + i * 2) / 16.0f); - _index.Resize(w); - _value.Resize(w); - _histogram.Resize((_sx + 2)*(_sy + 2)*Q2); - _norm.Resize((_sx + 2)*(_sy + 2)); - } - - void AddRowToHistogram(size_t row, size_t width, size_t height) - { - size_t iyp = (row - 4) / C; - float vy0 = _k[(row + 4) & 7]; - float vy1 = 1.0f - vy0; - float * h0 = _histogram.data + ((iyp + 1)*_hs + 0)*Q2; - float * h1 = _histogram.data + ((iyp + 2)*_hs + 0)*Q2; - for (size_t col = 1, n = C, i = 5; col < width - 1; i = 0, n = Simd::Min(C, width - col - 1)) - { - for (; i < n; ++i, ++col) - { - float value = _value[col]; - int index = _index[col]; - float vx0 = _k[i]; - float vx1 = 1.0f - vx0; - h0[index] += vx1 * vy1*value; - h1[index] += vx1 * vy0*value; - h0[Q2 + index] += vx0 * vy1*value; - h1[Q2 + index] += vx0 * vy0*value; - } - h0 += Q2; - h1 += Q2; - } - } - - void EstimateHistogram(const uint8_t * src, size_t stride, size_t width, size_t height) - { - _histogram.Clear(); - for (size_t row = 1; row < height - 1; ++row) - { - const uint8_t * src1 = src + stride * row; - const uint8_t * src0 = src1 - stride; - const uint8_t * src2 = src1 + stride; - - for (size_t col = 1; col < width - 1; ++col) - { - float dy = (float)(src2[col] - src0[col]); - float dx = (float)(src1[col + 1] - src1[col - 1]); - float value = (float)::sqrt(dx*dx + dy * dy); - float ady = Simd::Abs(dy); - float adx = Simd::Abs(dx); - - float bestDot = 0; - int index = 0; - for (int direction = 0; direction < 5; direction++) - { - float dot = _cos[direction] * adx + _sin[direction] * ady; - if (dot > bestDot) - { - bestDot = dot; - index = direction; - } - } - if (dx < 0) - index = Q - index; - if (dy < 0 && index != 0) - index = Q2 - index - (dx == 0); - - _value[col] = value; - _index[col] = index; - } - - AddRowToHistogram(row, width, height); - } - } - - void EstimateNorm() - { - _norm.Clear(); - for (size_t y = 0; y < _sy; ++y) - { - const float * ph = _histogram.data + ((y + 1)*_hs + 1)*Q2; - float * pn = _norm.data + (y + 1)*_hs + 1; - for (size_t x = 0; x < _sx; ++x) - { - const float * h = ph + x * Q2; - for (int o = 0; o < Q; ++o) - pn[x] += Simd::Square(h[o] + h[o + Q]); - } - } - } - - void ExtractFeatures(float * features) - { - float eps = 0.0001f; - for (size_t y = 0; y < _sy; y++) - { - for (size_t x = 0; x < _sx; x++) - { - float * dst = features + (y*_sx + x) * 31; - - float *psrc, n1, n2, n3, n4; - - float * p0 = _norm.data + y * _hs + x; - float * p1 = p0 + _hs; - float * p2 = p1 + _hs; - - n1 = 1.0f / sqrt(p1[1] + p1[2] + p2[1] + p2[2] + eps); - n2 = 1.0f / sqrt(p0[1] + p0[2] + p1[1] + p1[2] + eps); - n3 = 1.0f / sqrt(p1[0] + p1[1] + p2[0] + p2[1] + eps); - n4 = 1.0f / sqrt(p0[0] + p0[1] + p1[0] + p1[1] + eps); - - float t1 = 0; - float t2 = 0; - float t3 = 0; - float t4 = 0; - - psrc = _histogram.data + ((y + 1)*_hs + x + 1)*Q2; - for (int o = 0; o < Q2; o++) - { - float h1 = Simd::Min(*psrc * n1, 0.2f); - float h2 = Simd::Min(*psrc * n2, 0.2f); - float h3 = Simd::Min(*psrc * n3, 0.2f); - float h4 = Simd::Min(*psrc * n4, 0.2f); - *dst = 0.5f * (h1 + h2 + h3 + h4); - t1 += h1; - t2 += h2; - t3 += h3; - t4 += h4; - dst++; - psrc++; - } - - psrc = _histogram.data + ((y + 1)*_hs + x + 1)*Q2; - for (int o = 0; o < Q; o++) - { - float sum = *psrc + *(psrc + Q); - float h1 = Simd::Min(sum * n1, 0.2f); - float h2 = Simd::Min(sum * n2, 0.2f); - float h3 = Simd::Min(sum * n3, 0.2f); - float h4 = Simd::Min(sum * n4, 0.2f); - *dst = 0.5f * (h1 + h2 + h3 + h4); - dst++; - psrc++; - } - - *dst = 0.2357f * t1; - dst++; - *dst = 0.2357f * t2; - dst++; - *dst = 0.2357f * t3; - dst++; - *dst = 0.2357f * t4; - } - } - } - - public: - void Run(const uint8_t * src, size_t stride, size_t width, size_t height, float * features) - { - Init(width, height); - - EstimateHistogram(src, stride, width, height); - - EstimateNorm(); - - ExtractFeatures(features); - } - }; - - void HogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features) - { - assert(width % 8 == 0 && height % 8 == 0 && width >= 16 && height >= 16); - - HogFeatureExtractor extractor; - extractor.Run(src, stride, width, height, features); - } - namespace HogSeparableFilter_Detail { template void Set(float & dst, float value); diff --git a/src/Simd/SimdLib.cpp b/src/Simd/SimdLib.cpp index e711eac978..e7178b7049 100644 --- a/src/Simd/SimdLib.cpp +++ b/src/Simd/SimdLib.cpp @@ -3218,37 +3218,6 @@ SIMD_API void SimdNormalizeHistogram(const uint8_t * src, size_t srcStride, size Base::NormalizeHistogram(src, srcStride, width, height, dst, dstStride); } -SIMD_API void SimdHogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features) -{ - SIMD_EMPTY(); -#ifdef SIMD_AVX512BW_ENABLE - if (Avx512bw::Enable && width >= Avx512bw::HA + 2) - Avx512bw::HogExtractFeatures(src, stride, width, height, features); - else -#endif -#ifdef SIMD_AVX2_ENABLE - if (Avx2::Enable && width >= Avx2::HA + 2) - Avx2::HogExtractFeatures(src, stride, width, height, features); - else -#endif -#ifdef SIMD_SSE41_ENABLE - if (Sse41::Enable && width >= Sse41::A + 2) - Sse41::HogExtractFeatures(src, stride, width, height, features); - else -#endif -#ifdef SIMD_SVE2_ENABLE - if (Sve2::Enable && width >= 3) - Sve2::HogExtractFeatures(src, stride, width, height, features); - else -#endif -#ifdef SIMD_NEON_ENABLE - if (Neon::Enable && width >= Neon::A + 2) - Neon::HogExtractFeatures(src, stride, width, height, features); - else -#endif - Base::HogExtractFeatures(src, stride, width, height, features); -} - SIMD_API void SimdHogDeinterleave(const float * src, size_t srcStride, size_t width, size_t height, size_t count, float ** dst, size_t dstStride) { SIMD_EMPTY(); diff --git a/src/Simd/SimdLib.h b/src/Simd/SimdLib.h index b2000a6b44..7a3591d281 100644 --- a/src/Simd/SimdLib.h +++ b/src/Simd/SimdLib.h @@ -4410,33 +4410,6 @@ extern "C" */ SIMD_API void SimdNormalizeHistogram(const uint8_t * src, size_t srcStride, size_t width, size_t height, uint8_t * dst, size_t dstStride); - /*! @ingroup hog - - \fn void SimdHogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features); - - \short Extracts 31 HOG features per 8x8 cell from an 8-bit gray image. - - \deprecated This function will be removed in the nearest future. - - The function builds 18 signed gradient-orientation histograms for 8x8 cells, estimates - normalization factors from neighboring 2x2 blocks, clips normalized values by 0.2, and writes - 31 features per cell: - \verbatim - features[(cellY*(width/8) + cellX)*31 + 0..17] - contrast-sensitive features; - features[(cellY*(width/8) + cellX)*31 + 18..26] - contrast-insensitive features; - features[(cellY*(width/8) + cellX)*31 + 27..30] - texture energy features. - \endverbatim - - \note This function has a C++ wrapper Simd::HogExtractFeatures(const View & src, float * features). - - \param [in] src - a pointer to pixels data of input 8-bit gray image. - \param [in] stride - a row size of the image (in bytes). - \param [in] width - an image width. It must be a multiple of 8. Its minimal value is 16. - \param [in] height - an image height. It must be a multiple of 8. Its minimal value is 16. - \param [out] features - a pointer to buffer with features. Array must have size greater or equal to (width/8)*(height/8)*31. - */ - SIMD_DEPRECATED SIMD_API void SimdHogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features); - /*! @ingroup hog \fn void SimdHogDeinterleave(const float * src, size_t srcStride, size_t width, size_t height, size_t count, float ** dst, size_t dstStride); diff --git a/src/Simd/SimdLib.hpp b/src/Simd/SimdLib.hpp index 806c3ea94d..7733e5f55b 100644 --- a/src/Simd/SimdLib.hpp +++ b/src/Simd/SimdLib.hpp @@ -2482,35 +2482,6 @@ namespace Simd return (uint8_t)bestThreshold; } - /*! @ingroup hog - - \fn void HogExtractFeatures(const View & src, float * features) - - \short Extracts 31 HOG features per 8x8 cell from an 8-bit gray image. - - \deprecated This function will be removed in the nearest future. - - The function builds 18 signed gradient-orientation histograms for 8x8 cells, estimates - normalization factors from neighboring 2x2 blocks, clips normalized values by 0.2, and writes - 31 features per cell: - \verbatim - features[(cellY*(src.width/8) + cellX)*31 + 0..17] - contrast-sensitive features; - features[(cellY*(src.width/8) + cellX)*31 + 18..26] - contrast-insensitive features; - features[(cellY*(src.width/8) + cellX)*31 + 27..30] - texture energy features. - \endverbatim - - \note This function is a C++ wrapper for function ::SimdHogExtractFeatures. - - \param [in] src - an input 8-bit gray image. Its width and height must be a multiple of 8 and greater or equal to 16. - \param [out] features - a pointer to buffer with features. Array must have size greater or equal to (src.width/8)*(src.height/8)*31. - */ - template class A> SIMD_INLINE void HogExtractFeatures(const View & src, float * features) - { - assert(src.format == View::Gray8 && src.width % 8 == 0 && src.height % 8 == 0 && src.width >= 16 && src.height >= 16); - - SimdHogExtractFeatures(src.data, src.stride, src.width, src.height, features); - } - /*! @ingroup other_conversion \fn void Int16ToGray(const View & src, View & dst) diff --git a/src/Simd/SimdNeon.h b/src/Simd/SimdNeon.h index 25764874a5..9517158375 100644 --- a/src/Simd/SimdNeon.h +++ b/src/Simd/SimdNeon.h @@ -275,8 +275,6 @@ namespace Simd void HogDeinterleave(const float * src, size_t srcStride, size_t width, size_t height, size_t count, float ** dst, size_t dstStride); - void HogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features); - void HogFilterSeparable(const float * src, size_t srcStride, size_t width, size_t height, const float * rowFilter, size_t rowSize, const float * colFilter, size_t colSize, float * dst, size_t dstStride, int add); void Int16ToGray(const uint8_t * src, size_t width, size_t height, size_t srcStride, uint8_t * dst, size_t dstStride); diff --git a/src/Simd/SimdNeonHog.cpp b/src/Simd/SimdNeonHog.cpp index 908297f160..d262eb2bed 100644 --- a/src/Simd/SimdNeonHog.cpp +++ b/src/Simd/SimdNeonHog.cpp @@ -24,7 +24,6 @@ #include "Simd/SimdArray.h" #include "Simd/SimdStore.h" #include "Simd/SimdSet.h" -#include "Simd/SimdExtract.h" namespace Simd { @@ -77,288 +76,6 @@ namespace Simd } } - class HogFeatureExtractor - { - static const size_t C = 8; - static const size_t Q = 9; - static const size_t Q2 = 18; - - typedef Array Array32i; - typedef Array Array32f; - - size_t _sx, _sy, _hs; - - int32x4_t _pos[5]; - float32x4_t _cos[5], _sin[5]; - float32x4_t _kx[8], _ky[8]; - int32x4_t _Q, _Q2; - - Array32i _index; - Array32f _value; - Array32f _buffer; - Array32f _histogram; - Array32f _norm; - - void Init(size_t w, size_t h) - { - _sx = w / C; - _hs = _sx + 2; - _sy = h / C; - for (int i = 0; i < 5; ++i) - { - _cos[i] = vdupq_n_f32((float)::cos(i*M_PI / Q)); - _sin[i] = vdupq_n_f32((float)::sin(i*M_PI / Q)); - _pos[i] = vdupq_n_s32(i); - } - for (int i = 0; i < C; ++i) - { - float k0 = float((15 - i * 2) / 16.0f); - float k1 = 1.0f - k0; - _kx[i] = SetF32(k0, k1, k0, k1); - _ky[i] = SetF32(k0, k0, k1, k1); - } - _Q = vdupq_n_s32(Q); - _Q2 = vdupq_n_s32(Q2); - - _index.Resize(w); - _value.Resize(w); - _buffer.Resize((_sx + 1) * 4 * Q2); - _histogram.Resize((_sx + 2)*(_sy + 2)*Q2); - _norm.Resize((_sx + 2)*(_sy + 2)); - } - - template SIMD_INLINE void GetHistogram32(const float32x4_t & dx, const float32x4_t & dy, size_t col) - { - float32x4_t _0 = vdupq_n_f32(0); - float32x4_t bestDot = _0; - int32x4_t bestIndex = vdupq_n_s32(0); - float32x4_t adx = vabsq_f32(dx); - float32x4_t ady = vabsq_f32(dy); - for (int i = 0; i < 5; ++i) - { - float32x4_t dot = vmlaq_f32(vmulq_f32(adx, _cos[i]), ady, _sin[i]); - uint32x4_t mask = vcgtq_f32(dot, bestDot); - bestDot = vmaxq_f32(dot, bestDot); - bestIndex = vbslq_s32(mask, _pos[i], bestIndex); - } - uint32x4_t maskDx = vcltq_f32(dx, _0); - bestIndex = vbslq_s32(maskDx, vsubq_s32(_Q, bestIndex), bestIndex); - - uint32x4_t maskDy = vcltq_f32(dy, _0); - uint32x4_t corr = vandq_u32(vceqq_f32(adx, _0), K32_00000001); - bestIndex = vbslq_s32(maskDy, vsubq_s32(_Q2, vaddq_s32(bestIndex, (int32x4_t)corr)), bestIndex); - - bestIndex = vbslq_s32(vceqq_s32(bestIndex, _Q2), (int32x4_t)K32_00000000, bestIndex); - - Store(_index.data + col, bestIndex); // fixed program crash. - Store(_value.data + col, Sqrt(vmlaq_f32(vmulq_f32(adx, adx), ady, ady))); - } - - template SIMD_INLINE void GetHistogram16(const int16x8_t & dx, const int16x8_t & dy, size_t col) - { - GetHistogram32(Int16ToFloat<0>(dx), Int16ToFloat<0>(dy), col + 0); - GetHistogram32(Int16ToFloat<1>(dx), Int16ToFloat<1>(dy), col + 4); - } - - template SIMD_INLINE void GetHistogram(const uint8_t * src, size_t stride, size_t col) - { - const uint8_t * s = src + col; - uint8x16_t t = Load(s - stride); - uint8x16_t l = Load(s - 1); - uint8x16_t r = Load(s + 1); - uint8x16_t b = Load(s + stride); - GetHistogram16(Sub<0>(r, l), Sub<0>(b, t), col + 0); - GetHistogram16(Sub<1>(r, l), Sub<1>(b, t), col + 8); - } - - void AddRowToBuffer(const uint8_t * src, size_t stride, size_t row, size_t width, size_t aligned) - { - const uint8_t * s = src + stride*row; - GetHistogram(s, stride, 1); - for (size_t col = A; col < aligned; col += A) - GetHistogram(s, stride, col); - GetHistogram(s, stride, width - 1 - A); - - float32x4_t * buffer = (float32x4_t*)_buffer.data; - float32x4_t ky = _ky[(row + 4) & 7]; - for (size_t col = 1, n = C, i = 5; col < width - 1; i = 0, n = Simd::Min(C, width - col - 1)) - { - for (; i < n; ++i, ++col) - { - int index = _index[col]; - float32x4_t value = vdupq_n_f32(_value[col]); - buffer[index] = vmlaq_f32(buffer[index], value, vmulq_f32(ky, _kx[i])); - } - buffer += Q2; - } - } - - void AddToHistogram(size_t row, size_t width, size_t height) - { - typedef float f18_t[18]; - const float * src = _buffer.data; - f18_t * h0 = (f18_t*)_histogram.data + row*_hs; - f18_t * h1 = h0 + _hs; - for (size_t cell = 0; cell <= width; ++cell) - { - for (size_t i = 0; i < 16; i += 4) - { - float32x4x4_t s = Load4(src + 4 * i); - Store(h0[0] + i, vaddq_f32(Load(h0[0] + i), s.val[0])); - Store(h0[1] + i, vaddq_f32(Load(h0[1] + i), s.val[1])); - Store(h1[0] + i, vaddq_f32(Load(h1[0] + i), s.val[2])); - Store(h1[1] + i, vaddq_f32(Load(h1[1] + i), s.val[3])); - } - float32x2x4_t s = LoadHalf4(src + 64); - Store(h0[0] + 16, vadd_f32(LoadHalf(h0[0] + 16), s.val[0])); - Store(h0[1] + 16, vadd_f32(LoadHalf(h0[1] + 16), s.val[1])); - Store(h1[0] + 16, vadd_f32(LoadHalf(h1[0] + 16), s.val[2])); - Store(h1[1] + 16, vadd_f32(LoadHalf(h1[1] + 16), s.val[3])); - h0++; - h1++; - src += 4 * Q2; - } - _buffer.Clear(); - } - - void EstimateHistogram(const uint8_t * src, size_t stride, size_t width, size_t height) - { - _histogram.Clear(); - - size_t aligned = AlignHi(width - 1, A) - A; - - _buffer.Clear(); - for (size_t row = 1; row < 4; ++row) - AddRowToBuffer(src, stride, row, width, aligned); - AddToHistogram(0, _sx, _sy); - for (size_t row = 4, cell = 1; row < height - 4; ++row) - { - AddRowToBuffer(src, stride, row, width, aligned); - if ((row & 7) == 3) - AddToHistogram(cell++, _sx, _sy); - } - for (size_t row = height - 4; row < height - 1; ++row) - AddRowToBuffer(src, stride, row, width, aligned); - AddToHistogram(_sy, _sx, _sy); - } - - SIMD_INLINE float GetNorm(const float * src) - { - float32x4_t norm = vdupq_n_f32(0); - for (size_t i = 0; i < 8; i += 4) - { - float32x4_t sum = vaddq_f32(Load(src + i + 0), Load(src + i + Q)); - norm = vmlaq_f32(norm, sum, sum); - } - return ExtractSum32f(norm) + Simd::Square(src[Q - 1] + src[Q2 - 1]); - } - - void EstimateNorm() - { - _norm.Clear(); - for (size_t y = 0, i = 0; y < _sy; y++) - { - const float * h = _histogram.data + ((y + 1)*_hs + 1)*Q2; - float * n = _norm.data + (y + 1)*_hs + 1; - for (size_t x = 0; x < _sx; x++, i++) - n[x] = GetNorm(h + x*Q2); - } - } - - void ExtractFeatures(float * features) - { - float32x4_t _02 = vdupq_n_f32(0.2f); - float32x4_t _05 = vdupq_n_f32(0.5f); - float32x4_t _02357 = vdupq_n_f32(0.2357f); - float32x4_t eps = vdupq_n_f32(0.0001f); - for (size_t y = 0; y < _sy; y++) - { - float * ph = _histogram.data + ((y + 1)*_hs + 1)*Q2; - for (size_t x = 0; x < _sx; x++) - { - float * dst = features + (y*_sx + x) * 31; - - float * p0 = _norm.data + y*_hs + x; - float * p1 = p0 + _hs; - float * p2 = p1 + _hs; - - float32x4_t n = SetF32( - p1[1] + p1[2] + p2[1] + p2[2], - p0[1] + p0[2] + p1[1] + p1[2], - p1[0] + p1[1] + p2[0] + p2[1], - p0[0] + p0[1] + p1[0] + p1[1]); - - n = ReciprocalSqrt(vaddq_f32(n, eps)); - - float32x4_t t = vdupq_n_f32(0); - - float * src = ph + x*Q2; - for (int o = 0; o < 16; o += 4) - { - float32x4_t s = Load(src); - float32x4_t h0 = vminq_f32(vmulq_f32(Broadcast<0>(s), n), _02); - float32x4_t h1 = vminq_f32(vmulq_f32(Broadcast<1>(s), n), _02); - float32x4_t h2 = vminq_f32(vmulq_f32(Broadcast<2>(s), n), _02); - float32x4_t h3 = vminq_f32(vmulq_f32(Broadcast<3>(s), n), _02); - t = vaddq_f32(t, vaddq_f32(vaddq_f32(h0, h1), vaddq_f32(h2, h3))); - Store(dst, vmulq_f32(_05, Hadd32f(Hadd32f(h0, h1), Hadd32f(h2, h3)))); - dst += 4; - src += 4; - } - { - float32x4_t h0 = vminq_f32(vmulq_f32(vdupq_n_f32(*src++), n), _02); - float32x4_t h1 = vminq_f32(vmulq_f32(vdupq_n_f32(*src++), n), _02); - t = vaddq_f32(t, vaddq_f32(h0, h1)); - float32x4_t h = Hadd32f(h0, h1); - Store(dst, vmulq_f32(_05, Hadd32f(h, h))); - dst += 2; - } - - src = ph + x*Q2; - for (int o = 0; o < 8; o += 4) - { - float32x4_t s = vaddq_f32(Load(src), Load(src + Q)); - float32x4_t h0 = vminq_f32(vmulq_f32(Broadcast<0>(s), n), _02); - float32x4_t h1 = vminq_f32(vmulq_f32(Broadcast<1>(s), n), _02); - float32x4_t h2 = vminq_f32(vmulq_f32(Broadcast<2>(s), n), _02); - float32x4_t h3 = vminq_f32(vmulq_f32(Broadcast<3>(s), n), _02); - Store(dst, vmulq_f32(_05, Hadd32f(Hadd32f(h0, h1), Hadd32f(h2, h3)))); - dst += 4; - src += 4; - } - { - float32x4_t s = vdupq_n_f32(src[0] + src[Q]); - float32x4_t h = vminq_f32(vmulq_f32(s, n), _02); - h = vmulq_f32(_05, h); - *dst++ = ExtractSum32f(h); - } - Store(dst, vmulq_f32(t, _02357)); - } - } - } - - public: - - void Run(const uint8_t * src, size_t stride, size_t width, size_t height, float * features) - { - Init(width, height); - - EstimateHistogram(src, stride, width, height); - - EstimateNorm(); - - ExtractFeatures(features); - } - }; - - void HogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features) - { - assert(width % 8 == 0 && height % 8 == 0 && width >= 16 && height >= 16); - - HogFeatureExtractor extractor; - extractor.Run(src, stride, width, height, features); - } - namespace HogSeparableFilter_Detail { template SIMD_INLINE void Set(float * dst, const float32x4_t & value, const float32x4_t & mask) diff --git a/src/Simd/SimdSse41.h b/src/Simd/SimdSse41.h index b517df495b..7e28838f7f 100644 --- a/src/Simd/SimdSse41.h +++ b/src/Simd/SimdSse41.h @@ -253,8 +253,6 @@ namespace Simd void HogDeinterleave(const float* src, size_t srcStride, size_t width, size_t height, size_t count, float** dst, size_t dstStride); - void HogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features); - void HogFilterSeparable(const float* src, size_t srcStride, size_t width, size_t height, const float* rowFilter, size_t rowSize, const float* colFilter, size_t colSize, float* dst, size_t dstStride, int add); void Int16ToGray(const uint8_t* src, size_t width, size_t height, size_t srcStride, uint8_t* dst, size_t dstStride); diff --git a/src/Simd/SimdSse41Hog.cpp b/src/Simd/SimdSse41Hog.cpp index 8bad710cc3..580a7bb2f6 100644 --- a/src/Simd/SimdSse41Hog.cpp +++ b/src/Simd/SimdSse41Hog.cpp @@ -23,7 +23,6 @@ */ #include "Simd/SimdStore.h" #include "Simd/SimdArray.h" -#include "Simd/SimdUnpack.h" namespace Simd { @@ -80,296 +79,6 @@ namespace Simd } } - class HogFeatureExtractor - { - static const size_t C = 8; - static const size_t Q = 9; - static const size_t Q2 = 18; - - size_t _sx, _sy, _hs; - - __m128i _pos[5]; - __m128 _cos[5], _sin[5]; - __m128 _kx[8], _ky[8]; - __m128i _Q, _Q2; - - Array32i _index; - Array32f _value; - Array32f _buffer; - Array32f _histogram; - Array32f _norm; - - void Init(size_t w, size_t h) - { - _sx = w / C; - _hs = _sx + 2; - _sy = h / C; - for (int i = 0; i < 5; ++i) - { - _cos[i] = _mm_set1_ps((float)::cos(i*M_PI / Q)); - _sin[i] = _mm_set1_ps((float)::sin(i*M_PI / Q)); - _pos[i] = _mm_set1_epi32(i); - } - for (int i = 0; i < C; ++i) - { - float k0 = float((15 - i * 2) / 16.0f); - float k1 = 1.0f - k0; - _kx[i] = _mm_setr_ps(k0, k1, k0, k1); - _ky[i] = _mm_setr_ps(k0, k0, k1, k1); - } - _Q = _mm_set1_epi32(Q); - _Q2 = _mm_set1_epi32(Q2); - - _index.Resize(w); - _value.Resize(w); - _buffer.Resize((_sx + 1) * 4 * Q2); - _histogram.Resize((_sx + 2)*(_sy + 2)*Q2); - _norm.Resize((_sx + 2)*(_sy + 2)); - } - - template SIMD_INLINE void GetHistogram(const __m128 & dx, const __m128 & dy, size_t col) - { - __m128 _0 = _mm_set1_ps(-0.0f); - __m128 adx = _mm_andnot_ps(_0, dx); - __m128 ady = _mm_andnot_ps(_0, dy); - __m128 bestDot = _mm_add_ps(_mm_mul_ps(adx, _cos[0]), _mm_mul_ps(ady, _sin[0])); - __m128i bestIndex = _pos[0]; - for (int i = 1; i < 5; ++i) - { - __m128 dot = _mm_add_ps(_mm_mul_ps(adx, _cos[i]), _mm_mul_ps(ady, _sin[i])); - __m128 mask = _mm_cmpgt_ps(dot, bestDot); - bestDot = _mm_max_ps(dot, bestDot); - bestIndex = _mm_blendv_epi8(bestIndex, _pos[i], _mm_castps_si128(mask)); - } - __m128i maskDx = _mm_castps_si128(_mm_cmplt_ps(dx, _mm_setzero_ps())); - bestIndex = _mm_blendv_epi8(bestIndex, _mm_sub_epi32(_Q, bestIndex), maskDx); - - __m128i maskDy = _mm_castps_si128(_mm_cmplt_ps(dy, _mm_setzero_ps())); - __m128i corr = _mm_and_si128(_mm_castps_si128(_mm_cmpeq_ps(adx, _mm_setzero_ps())), K32_00000001); - bestIndex = _mm_blendv_epi8(bestIndex, _mm_sub_epi32(_Q2, _mm_add_epi32(bestIndex, corr)), maskDy); - - bestIndex = _mm_andnot_si128(_mm_cmpeq_epi32(bestIndex, _Q2), bestIndex); - - Store((__m128i*)(_index.data + col), bestIndex); - Store(_value.data + col, Sqrt<0>(_mm_add_ps(_mm_mul_ps(adx, adx), _mm_mul_ps(ady, ady)))); - } - - template SIMD_INLINE void GetHistogram(const __m128i & dx, const __m128i & dy, size_t col) - { - GetHistogram(_mm_cvtepi32_ps(UnpackI16<0>(dx)), _mm_cvtepi32_ps(UnpackI16<0>(dy)), col + 0); - GetHistogram(_mm_cvtepi32_ps(UnpackI16<1>(dx)), _mm_cvtepi32_ps(UnpackI16<1>(dy)), col + 4); - } - - template SIMD_INLINE void GetHistogram(const uint8_t * src, size_t stride, size_t col) - { - const uint8_t * s = src + col; - __m128i t = Load((__m128i*)(s - stride)); - __m128i l = Load((__m128i*)(s - 1)); - __m128i r = Load((__m128i*)(s + 1)); - __m128i b = Load((__m128i*)(s + stride)); - GetHistogram(SubUnpackedU8<0>(r, l), SubUnpackedU8<0>(b, t), col + 0); - GetHistogram(SubUnpackedU8<1>(r, l), SubUnpackedU8<1>(b, t), col + 8); - } - - void AddRowToBuffer(const uint8_t * src, size_t stride, size_t row, size_t width, size_t aligned) - { - const uint8_t * s = src + stride * row; - GetHistogram(s, stride, 1); - for (size_t col = A; col < aligned; col += A) - GetHistogram(s, stride, col); - GetHistogram(s, stride, width - 1 - A); - - __m128 * buffer = (__m128*)_buffer.data; - __m128 ky = _ky[(row + 4) & 7]; - for (size_t col = 1, n = C, i = 5; col < width - 1; i = 0, n = Simd::Min(C, width - col - 1)) - { - for (; i < n; ++i, ++col) - { - int index = _index[col]; - __m128 value = _mm_set1_ps(_value[col]); - buffer[index] = _mm_add_ps(buffer[index], _mm_mul_ps(value, _mm_mul_ps(ky, _kx[i]))); - } - buffer += Q2; - } - } - - void AddToHistogram(size_t row, size_t width, size_t height) - { - typedef float f18_t[18]; - float * src = _buffer.data; - f18_t * h0 = (f18_t*)_histogram.data + row * _hs; - f18_t * h1 = h0 + _hs; - for (size_t cell = 0; cell <= width; ++cell) - { - __m128 * ps = (__m128*)src; - for (size_t i = 0; i < 16; i += 4) - { - __m128 s00 = _mm_unpacklo_ps(ps[i + 0], ps[i + 2]); - __m128 s01 = _mm_unpacklo_ps(ps[i + 1], ps[i + 3]); - __m128 s10 = _mm_unpackhi_ps(ps[i + 0], ps[i + 2]); - __m128 s11 = _mm_unpackhi_ps(ps[i + 1], ps[i + 3]); - - _mm_storeu_ps(h0[0] + i, _mm_add_ps(_mm_loadu_ps(h0[0] + i), _mm_unpacklo_ps(s00, s01))); - _mm_storeu_ps(h0[1] + i, _mm_add_ps(_mm_loadu_ps(h0[1] + i), _mm_unpackhi_ps(s00, s01))); - _mm_storeu_ps(h1[0] + i, _mm_add_ps(_mm_loadu_ps(h1[0] + i), _mm_unpacklo_ps(s10, s11))); - _mm_storeu_ps(h1[1] + i, _mm_add_ps(_mm_loadu_ps(h1[1] + i), _mm_unpackhi_ps(s10, s11))); - } - __m128 s0 = _mm_add_ps(_mm_unpacklo_ps(ps[16], ps[17]), Load(h0[0] + 16, h0[1] + 16)); - __m128 s1 = _mm_add_ps(_mm_unpackhi_ps(ps[16], ps[17]), Load(h1[0] + 16, h1[1] + 16)); - StoreHalf<0>(h0[0] + 16, s0); - StoreHalf<1>(h0[1] + 16, s0); - StoreHalf<0>(h1[0] + 16, s1); - StoreHalf<1>(h1[1] + 16, s1); - h0++; - h1++; - src += 4 * Q2; - } - _buffer.Clear(); - } - - void EstimateHistogram(const uint8_t * src, size_t stride, size_t width, size_t height) - { - _histogram.Clear(); - - size_t aligned = AlignHi(width - 1, A) - A; - - _buffer.Clear(); - for (size_t row = 1; row < 4; ++row) - AddRowToBuffer(src, stride, row, width, aligned); - AddToHistogram(0, _sx, _sy); - for (size_t row = 4, cell = 1; row < height - 4; ++row) - { - AddRowToBuffer(src, stride, row, width, aligned); - if ((row & 7) == 3) - AddToHistogram(cell++, _sx, _sy); - } - for (size_t row = height - 4; row < height - 1; ++row) - AddRowToBuffer(src, stride, row, width, aligned); - AddToHistogram(_sy, _sx, _sy); - } - - SIMD_INLINE float GetNorm(const float * src) - { - __m128 _norm = _mm_setzero_ps(); - for (size_t i = 0; i < 8; i += 4) - { - __m128 sum = _mm_add_ps(_mm_loadu_ps(src + i + 0), _mm_loadu_ps(src + i + Q)); - _norm = _mm_add_ps(_norm, _mm_mul_ps(sum, sum)); - } - _norm = _mm_hadd_ps(_norm, _norm); - _norm = _mm_hadd_ps(_norm, _norm); - float norm; - _mm_store_ss(&norm, _norm); - return norm + Simd::Square(src[Q - 1] + src[Q2 - 1]); - } - - void EstimateNorm() - { - _norm.Clear(); - for (size_t y = 0, i = 0; y < _sy; y++) - { - const float * h = _histogram.data + ((y + 1)*_hs + 1)*Q2; - float * n = _norm.data + (y + 1)*_hs + 1; - for (size_t x = 0; x < _sx; x++, i++) - n[x] = GetNorm(h + x * Q2); - } - } - - void ExtractFeatures(float * features) - { - __m128 _02 = _mm_set1_ps(0.2f); - __m128 _05 = _mm_set1_ps(0.5f); - __m128 _02357 = _mm_set1_ps(0.2357f); - __m128 eps = _mm_set1_ps(0.0001f); - for (size_t y = 0; y < _sy; y++) - { - float * ph = _histogram.data + ((y + 1)*_hs + 1)*Q2; - for (size_t x = 0; x < _sx; x++) - { - float * dst = features + (y*_sx + x) * 31; - - float * p0 = _norm.data + y * _hs + x; - float * p1 = p0 + _hs; - float * p2 = p1 + _hs; - - __m128 n = _mm_setr_ps( - p1[1] + p1[2] + p2[1] + p2[2], - p0[1] + p0[2] + p1[1] + p1[2], - p1[0] + p1[1] + p2[0] + p2[1], - p0[0] + p0[1] + p1[0] + p1[1]); - - n = _mm_rsqrt_ps(_mm_add_ps(n, eps)); - - __m128 t = _mm_setzero_ps(); - - float * src = ph + x * Q2; - for (int o = 0; o < 16; o += 4) - { - __m128 s = _mm_loadu_ps(src); - __m128 h0 = _mm_min_ps(_mm_mul_ps(Broadcast<0>(s), n), _02); - __m128 h1 = _mm_min_ps(_mm_mul_ps(Broadcast<1>(s), n), _02); - __m128 h2 = _mm_min_ps(_mm_mul_ps(Broadcast<2>(s), n), _02); - __m128 h3 = _mm_min_ps(_mm_mul_ps(Broadcast<3>(s), n), _02); - t = _mm_add_ps(t, _mm_add_ps(_mm_add_ps(h0, h1), _mm_add_ps(h2, h3))); - _mm_storeu_ps(dst, _mm_mul_ps(_05, _mm_hadd_ps(_mm_hadd_ps(h0, h1), _mm_hadd_ps(h2, h3)))); - dst += 4; - src += 4; - } - { - __m128 h0 = _mm_min_ps(_mm_mul_ps(_mm_set1_ps(*src++), n), _02); - __m128 h1 = _mm_min_ps(_mm_mul_ps(_mm_set1_ps(*src++), n), _02); - t = _mm_add_ps(t, _mm_add_ps(h0, h1)); - __m128 h = _mm_hadd_ps(h0, h1); - _mm_storeu_ps(dst, _mm_mul_ps(_05, _mm_hadd_ps(h, h))); - dst += 2; - } - - src = ph + x * Q2; - for (int o = 0; o < 8; o += 4) - { - __m128 s = _mm_add_ps(_mm_loadu_ps(src), _mm_loadu_ps(src + Q)); - __m128 h0 = _mm_min_ps(_mm_mul_ps(Broadcast<0>(s), n), _02); - __m128 h1 = _mm_min_ps(_mm_mul_ps(Broadcast<1>(s), n), _02); - __m128 h2 = _mm_min_ps(_mm_mul_ps(Broadcast<2>(s), n), _02); - __m128 h3 = _mm_min_ps(_mm_mul_ps(Broadcast<3>(s), n), _02); - _mm_storeu_ps(dst, _mm_mul_ps(_05, _mm_hadd_ps(_mm_hadd_ps(h0, h1), _mm_hadd_ps(h2, h3)))); - dst += 4; - src += 4; - } - { - __m128 s = _mm_set1_ps(src[0] + src[Q]); - __m128 h = _mm_min_ps(_mm_mul_ps(s, n), _02); - h = _mm_dp_ps(_05, h, 0xF1); - _mm_store_ss(dst++, h); - } - _mm_storeu_ps(dst, _mm_mul_ps(t, _02357)); - } - } - } - - public: - - void Run(const uint8_t * src, size_t stride, size_t width, size_t height, float * features) - { - Init(width, height); - - EstimateHistogram(src, stride, width, height); - - EstimateNorm(); - - ExtractFeatures(features); - } - }; - - void HogExtractFeatures(const uint8_t * src, size_t stride, size_t width, size_t height, float * features) - { - assert(width % 8 == 0 && height % 8 == 0 && width >= 16 && height >= 16); - assert(width >= A + 2); - - HogFeatureExtractor extractor; - extractor.Run(src, stride, width, height, features); - } - //----------------------------------------------------------------------------------------- namespace HogSeparableFilter_Detail diff --git a/src/Simd/SimdSve2.h b/src/Simd/SimdSve2.h index 76e32384c1..590a9ac1c6 100644 --- a/src/Simd/SimdSve2.h +++ b/src/Simd/SimdSve2.h @@ -200,8 +200,6 @@ namespace Simd void Gemm32fNT(size_t M, size_t N, size_t K, const float* alpha, const float* A, size_t lda, const float* B, size_t ldb, const float* beta, float* C, size_t ldc); - void HogExtractFeatures(const uint8_t* src, size_t stride, size_t width, size_t height, float* features); - void HogDeinterleave(const float* src, size_t srcStride, size_t width, size_t height, size_t count, float** dst, size_t dstStride); void HogFilterSeparable(const float* src, size_t srcStride, size_t width, size_t height, diff --git a/src/Simd/SimdSve2Hog.cpp b/src/Simd/SimdSve2Hog.cpp index 6de6a4b284..31cd59e54c 100644 --- a/src/Simd/SimdSve2Hog.cpp +++ b/src/Simd/SimdSve2Hog.cpp @@ -29,290 +29,6 @@ namespace Simd #ifdef SIMD_SVE2_ENABLE namespace Sve2 { - SIMD_INLINE svbool_t HogTailMask(size_t col, size_t end, const svuint32_t& offsets) - { - const svbool_t mask = svptrue_b32(); - return svcmplt_n_u32(mask, svadd_n_u32_x(mask, offsets, (uint32_t)col), (uint32_t)end); - } - - SIMD_INLINE svint16_t HogDifferenceLo(const svuint8_t& a, const svuint8_t& b) - { - svbool_t mask = svptrue_b16(); - return svsub_s16_x(mask, svreinterpret_s16_u16(svmovlb_u16(a)), svreinterpret_s16_u16(svmovlb_u16(b))); - } - - SIMD_INLINE svint16_t HogDifferenceHi(const svuint8_t& a, const svuint8_t& b) - { - svbool_t mask = svptrue_b16(); - return svsub_s16_x(mask, svreinterpret_s16_u16(svmovlt_u16(a)), svreinterpret_s16_u16(svmovlt_u16(b))); - } - - class HogFeatureExtractor - { - static const size_t C = 8; - static const size_t Q = 9; - static const size_t Q2 = 18; - - typedef Array Array32i; - typedef Array Array32f; - - size_t _sx, _sy, _hs; - - float _cos[5], _sin[5]; - float _kx[C][4], _ky[C][4]; - - Array32i _index; - Array32f _value; - Array32f _buffer; - Array32f _histogram; - Array32f _norm; - - void Init(size_t w, size_t h) - { - _sx = w / C; - _hs = _sx + 2; - _sy = h / C; - for (int i = 0; i < 5; ++i) - { - _cos[i] = (float)::cos(i * M_PI / Q); - _sin[i] = (float)::sin(i * M_PI / Q); - } - for (int i = 0; i < (int)C; ++i) - { - float k0 = float((15 - i * 2) / 16.0f); - float k1 = 1.0f - k0; - _kx[i][0] = k0; - _kx[i][1] = k1; - _kx[i][2] = k0; - _kx[i][3] = k1; - _ky[i][0] = k0; - _ky[i][1] = k0; - _ky[i][2] = k1; - _ky[i][3] = k1; - } - - _index.Resize(w); - _value.Resize(w); - _buffer.Resize((_sx + 1) * 4 * Q2); - _histogram.Resize((_sx + 2) * (_sy + 2) * Q2); - _norm.Resize((_sx + 2) * (_sy + 2)); - } - - SIMD_INLINE void GetHistogram32(const svint32_t& dx, const svint32_t& dy, size_t col, const svuint32_t& offsets, const svbool_t& mask) - { - svfloat32_t _0 = svdup_n_f32(0.0f); - svfloat32_t _dx = svcvt_f32_s32_x(mask, dx); - svfloat32_t _dy = svcvt_f32_s32_x(mask, dy); - svfloat32_t adx = svabs_f32_x(mask, _dx); - svfloat32_t ady = svabs_f32_x(mask, _dy); - svfloat32_t bestDot = _0; - svint32_t bestIndex = svdup_n_s32(0); - for (int i = 0; i < 5; ++i) - { - svfloat32_t dot = svmla_f32_x(mask, svmul_n_f32_x(mask, adx, _cos[i]), ady, svdup_n_f32(_sin[i])); - svbool_t positive = svcmpgt_f32(mask, dot, bestDot); - bestDot = svmax_f32_x(mask, dot, bestDot); - bestIndex = svsel_s32(positive, svdup_n_s32(i), bestIndex); - } - - svbool_t negativeDx = svcmplt_n_f32(mask, _dx, 0.0f); - bestIndex = svsel_s32(negativeDx, svsub_s32_x(mask, svdup_n_s32((int)Q), bestIndex), bestIndex); - - svbool_t negativeDy = svcmplt_n_f32(mask, _dy, 0.0f); - svint32_t correction = svsel_s32(svcmpeq_n_f32(mask, adx, 0.0f), svdup_n_s32(1), svdup_n_s32(0)); - bestIndex = svsel_s32(negativeDy, svsub_s32_x(mask, svdup_n_s32((int)Q2), svadd_s32_x(mask, bestIndex, correction)), bestIndex); - bestIndex = svsel_s32(svcmpeq_n_s32(mask, bestIndex, (int)Q2), svdup_n_s32(0), bestIndex); - - svst1_scatter_u32index_s32(mask, _index.data + col, offsets, bestIndex); - svst1_scatter_u32index_f32(mask, _value.data + col, offsets, svsqrt_f32_x(mask, svmla_f32_x(mask, svmul_f32_x(mask, adx, adx), ady, ady))); - } - - SIMD_INLINE void GetHistogram16(const svint16_t& dx, const svint16_t& dy, size_t col, const svuint32_t& loOffsets, const svuint32_t& hiOffsets, const svbool_t& maskLo, const svbool_t& maskHi) - { - GetHistogram32(svmovlb_s32(dx), svmovlb_s32(dy), col, loOffsets, maskLo); - GetHistogram32(svmovlt_s32(dx), svmovlt_s32(dy), col, hiOffsets, maskHi); - } - - SIMD_INLINE void GetHistogram(const uint8_t* src, size_t stride, size_t col, size_t end) - { - const uint8_t* s = src + col; - svbool_t mask = svwhilelt_b8(col, end); - const svuint32_t offsets0 = svindex_u32(0, 4); - const svuint32_t offsets1 = svindex_u32(2, 4); - const svuint32_t offsets2 = svindex_u32(1, 4); - const svuint32_t offsets3 = svindex_u32(3, 4); - svuint8_t t = svld1_u8(mask, s - stride); - svuint8_t l = svld1_u8(mask, s - 1); - svuint8_t r = svld1_u8(mask, s + 1); - svuint8_t b = svld1_u8(mask, s + stride); - GetHistogram16(HogDifferenceLo(r, l), HogDifferenceLo(b, t), col, offsets0, offsets1, HogTailMask(col, end, offsets0), HogTailMask(col, end, offsets1)); - GetHistogram16(HogDifferenceHi(r, l), HogDifferenceHi(b, t), col, offsets2, offsets3, HogTailMask(col, end, offsets2), HogTailMask(col, end, offsets3)); - } - - void AddRowToBuffer(const uint8_t* src, size_t stride, size_t row, size_t width) - { - const uint8_t* s = src + stride * row; - size_t A = svcntb(), end = width - 1; - for (size_t col = 1; col < end; col += A) - GetHistogram(s, stride, col, end); - - float* buffer = _buffer.data; - svbool_t mask = svwhilelt_b32(size_t(0), size_t(4)); - svfloat32_t ky = svld1_f32(mask, _ky[(row + 4) & 7]); - for (size_t col = 1, n = C, i = 5; col < width - 1; i = 0, n = Simd::Min(C, width - col - 1)) - { - for (; i < n; ++i, ++col) - { - int index = _index[col]; - float* dst = buffer + index * 4; - svfloat32_t weight = svmul_f32_x(mask, ky, svld1_f32(mask, _kx[i])); - svst1_f32(mask, dst, svmla_f32_x(mask, svld1_f32(mask, dst), weight, svdup_n_f32(_value[col]))); - } - buffer += 4 * Q2; - } - } - - void AddToHistogram(size_t row, size_t width, size_t height) - { - const float* src = _buffer.data; - float* h0 = _histogram.data + row * _hs * Q2; - float* h1 = h0 + _hs * Q2; - size_t F = svcntw(); - for (size_t cell = 0; cell <= width; ++cell) - { - for (size_t i = 0; i < Q2; i += F) - { - svbool_t mask = svwhilelt_b32(i, Q2); - svuint32_t offsets = svadd_n_u32_x(mask, svmul_n_u32_x(mask, svindex_u32(0, 1), 4), (uint32_t)(4 * i)); - svfloat32_t s0 = svld1_gather_u32index_f32(mask, src, offsets); - svfloat32_t s1 = svld1_gather_u32index_f32(mask, src + 1, offsets); - svfloat32_t s2 = svld1_gather_u32index_f32(mask, src + 2, offsets); - svfloat32_t s3 = svld1_gather_u32index_f32(mask, src + 3, offsets); - svst1_f32(mask, h0 + i, svadd_f32_x(mask, svld1_f32(mask, h0 + i), s0)); - svst1_f32(mask, h0 + Q2 + i, svadd_f32_x(mask, svld1_f32(mask, h0 + Q2 + i), s1)); - svst1_f32(mask, h1 + i, svadd_f32_x(mask, svld1_f32(mask, h1 + i), s2)); - svst1_f32(mask, h1 + Q2 + i, svadd_f32_x(mask, svld1_f32(mask, h1 + Q2 + i), s3)); - } - h0 += Q2; - h1 += Q2; - src += 4 * Q2; - } - _buffer.Clear(); - } - - void EstimateHistogram(const uint8_t* src, size_t stride, size_t width, size_t height) - { - _histogram.Clear(); - - _buffer.Clear(); - for (size_t row = 1; row < 4; ++row) - AddRowToBuffer(src, stride, row, width); - AddToHistogram(0, _sx, _sy); - for (size_t row = 4, cell = 1; row < height - 4; ++row) - { - AddRowToBuffer(src, stride, row, width); - if ((row & 7) == 3) - AddToHistogram(cell++, _sx, _sy); - } - for (size_t row = height - 4; row < height - 1; ++row) - AddRowToBuffer(src, stride, row, width); - AddToHistogram(_sy, _sx, _sy); - } - - SIMD_INLINE float GetNorm(const float* src) - { - svfloat32_t norm = svdup_n_f32(0.0f); - size_t F = svcntw(); - for (size_t i = 0; i < Q; i += F) - { - svbool_t mask = svwhilelt_b32(i, Q); - svfloat32_t sum = svadd_f32_x(mask, svld1_f32(mask, src + i), svld1_f32(mask, src + i + Q)); - norm = svmla_f32_m(mask, norm, sum, sum); - } - return svaddv_f32(svptrue_b32(), norm); - } - - void EstimateNorm() - { - _norm.Clear(); - for (size_t y = 0; y < _sy; y++) - { - const float* h = _histogram.data + ((y + 1) * _hs + 1) * Q2; - float* n = _norm.data + (y + 1) * _hs + 1; - for (size_t x = 0; x < _sx; x++) - n[x] = GetNorm(h + x * Q2); - } - } - - void ExtractFeatures(float* features) - { - svbool_t mask = svwhilelt_b32(size_t(0), size_t(4)); - svfloat32_t _02 = svdup_n_f32(0.2f); - svfloat32_t _05 = svdup_n_f32(0.5f); - svfloat32_t _02357 = svdup_n_f32(0.2357f); - svfloat32_t _1 = svdup_n_f32(1.0f); - svfloat32_t eps = svdup_n_f32(0.0001f); - float ns[4]; - for (size_t y = 0; y < _sy; y++) - { - const float* ph = _histogram.data + ((y + 1) * _hs + 1) * Q2; - for (size_t x = 0; x < _sx; x++) - { - float* dst = features + (y * _sx + x) * 31; - - float* p0 = _norm.data + y * _hs + x; - float* p1 = p0 + _hs; - float* p2 = p1 + _hs; - - ns[0] = p1[1] + p1[2] + p2[1] + p2[2]; - ns[1] = p0[1] + p0[2] + p1[1] + p1[2]; - ns[2] = p1[0] + p1[1] + p2[0] + p2[1]; - ns[3] = p0[0] + p0[1] + p1[0] + p1[1]; - svfloat32_t n = svdiv_f32_x(mask, _1, svsqrt_f32_x(mask, svadd_f32_x(mask, svld1_f32(mask, ns), eps))); - svfloat32_t t = svdup_n_f32(0.0f); - - const float* src = ph + x * Q2; - for (int o = 0; o < (int)Q2; ++o) - { - svfloat32_t h = svmin_f32_x(mask, svmul_f32_x(mask, svdup_n_f32(src[o]), n), _02); - dst[o] = 0.5f * svaddv_f32(mask, h); - t = svadd_f32_x(mask, t, h); - } - dst += Q2; - - for (int o = 0; o < (int)Q; ++o) - { - svfloat32_t h = svmin_f32_x(mask, svmul_f32_x(mask, svdup_n_f32(src[o] + src[o + Q]), n), _02); - dst[o] = 0.5f * svaddv_f32(mask, h); - } - dst += Q; - - svst1_f32(mask, dst, svmul_f32_x(mask, t, _02357)); - } - } - } - - public: - void Run(const uint8_t* src, size_t stride, size_t width, size_t height, float* features) - { - Init(width, height); - - EstimateHistogram(src, stride, width, height); - - EstimateNorm(); - - ExtractFeatures(features); - } - }; - - void HogExtractFeatures(const uint8_t* src, size_t stride, size_t width, size_t height, float* features) - { - assert(width % 8 == 0 && height % 8 == 0 && width >= 16 && height >= 16); - - HogFeatureExtractor extractor; - extractor.Run(src, stride, width, height, features); - } - SIMD_INLINE void HogDeinterleave(const float* src, const svuint32_t& offsets, const svbool_t& mask, float* dst) { svst1_f32(mask, dst, svld1_gather_u32index_f32(mask, src, offsets)); diff --git a/src/Test/Test.cpp b/src/Test/Test.cpp index 7fd4588843..4e66c78518 100644 --- a/src/Test/Test.cpp +++ b/src/Test/Test.cpp @@ -249,7 +249,6 @@ namespace Test TEST_ADD_GROUP_A0(AbsSecondDerivativeHistogram); TEST_ADD_GROUP_A0(ChangeColors); - TEST_ADD_GROUP_A0(HogExtractFeatures); TEST_ADD_GROUP_A0(HogDeinterleave); TEST_ADD_GROUP_A0(HogFilterSeparable); diff --git a/src/Test/TestHog.cpp b/src/Test/TestHog.cpp index d31fcd574e..5e6e4d0b05 100644 --- a/src/Test/TestHog.cpp +++ b/src/Test/TestHog.cpp @@ -38,96 +38,6 @@ namespace Test { - namespace - { - struct FuncHEF - { - typedef void(*FuncPtr)(const uint8_t * src, size_t stride, size_t width, size_t height, float * features); - - FuncPtr func; - String description; - - FuncHEF(const FuncPtr & f, const String & d) : func(f), description(d) {} - - void Call(const View & src, float * features) const - { - TEST_PERFORMANCE_TEST(description); - func(src.data, src.stride, src.width, src.height, features); - } - }; - } - -#define FUNC_HEF(function) FuncHEF(function, #function) - - bool HogExtractFeaturesAutoTest(int width, int height, const FuncHEF & f1, const FuncHEF & f2) - { - bool result = true; - - width = (int)Simd::AlignHi(std::max(16, width), 8); - height = (int)Simd::AlignHi(std::max(16, height), 8); - - TEST_LOG_SS(Info, "Test " << f1.description << " & " << f2.description << " [" << width << ", " << height << "]."); - - View src(width, height, View::Gray8, NULL, TEST_ALIGN(width)); - FillRandom(src); - - const size_t size = (width / 8)*(height / 8) * 31; - Buffer32f features1(size, 0), features2(size, 0); - - TEST_EXECUTE_AT_LEAST_MIN_TIME(f1.Call(src, features1.data())); - - TEST_EXECUTE_AT_LEAST_MIN_TIME(f2.Call(src, features2.data())); - - result = result && Compare(features1, features2, EPS, true, 64); - - return result; - } - - bool HogExtractFeaturesAutoTest(const FuncHEF & f1, const FuncHEF & f2) - { - bool result = true; - - result = result && HogExtractFeaturesAutoTest(W, H, f1, f2); - result = result && HogExtractFeaturesAutoTest(W + 8, H - 8, f1, f2); - - return result; - } - - bool HogExtractFeaturesAutoTest(const Options & options) - { - bool result = true; - - if (TestBase(options)) - result = result && HogExtractFeaturesAutoTest(FUNC_HEF(Simd::Base::HogExtractFeatures), FUNC_HEF(SimdHogExtractFeatures)); - -#ifdef SIMD_SSE41_ENABLE - if (Simd::Sse41::Enable && TestSse41(options) && W >= Simd::Sse41::A + 2) - result = result && HogExtractFeaturesAutoTest(FUNC_HEF(Simd::Sse41::HogExtractFeatures), FUNC_HEF(SimdHogExtractFeatures)); -#endif - -#ifdef SIMD_AVX2_ENABLE - if (Simd::Avx2::Enable && TestAvx2(options) && W >= Simd::Avx2::HA + 2) - result = result && HogExtractFeaturesAutoTest(FUNC_HEF(Simd::Avx2::HogExtractFeatures), FUNC_HEF(SimdHogExtractFeatures)); -#endif - -#ifdef SIMD_AVX512BW_ENABLE - if (Simd::Avx512bw::Enable && TestAvx512bw(options) && W >= Simd::Avx512bw::HA + 2) - result = result && HogExtractFeaturesAutoTest(FUNC_HEF(Simd::Avx512bw::HogExtractFeatures), FUNC_HEF(SimdHogExtractFeatures)); -#endif - -#ifdef SIMD_SVE2_ENABLE - if (Simd::Sve2::Enable && TestSve2(options) && W >= svcntb() + 2) - result = result && HogExtractFeaturesAutoTest(FUNC_HEF(Simd::Sve2::HogExtractFeatures), FUNC_HEF(SimdHogExtractFeatures)); -#endif - -#ifdef SIMD_NEON_ENABLE - if (Simd::Neon::Enable && TestNeon(options) && W >= Simd::Neon::A + 2) - result = result && HogExtractFeaturesAutoTest(FUNC_HEF(Simd::Neon::HogExtractFeatures), FUNC_HEF(SimdHogExtractFeatures)); -#endif - - return result; - } - namespace { struct FuncHD