Hsv2rgb univ intrin (#11637)
authorVadim Pisarevsky <vadim.pisarevsky@gmail.com>
Thu, 31 May 2018 18:59:45 +0000 (21:59 +0300)
committerGitHub <noreply@github.com>
Thu, 31 May 2018 18:59:45 +0000 (21:59 +0300)
* add universal intrinsics for HSV2RGB_b

* rewritten HSV2RGB_b without using extra universal intrinsics

* removed unused variable

* undo changes in v_load_deinterleave

modules/imgproc/src/color_hsv.cpp

index d5a41df..94a36f1 100644 (file)
@@ -213,6 +213,91 @@ struct RGB2HSV_f
 };
 
 
+#if CV_SIMD128
+inline void HSV2RGB_simd(v_float32x4& v_h, v_float32x4& v_s, v_float32x4& v_v, float hscale)
+{
+    v_h = v_h * v_setall_f32(hscale);
+    v_float32x4 v_pre_sector = v_cvt_f32(v_trunc(v_h));
+    v_h = v_h - v_pre_sector;
+    v_float32x4 v_tab0 = v_v;
+    v_float32x4 v_one = v_setall_f32(1.0f);
+    v_float32x4 v_tab1 = v_v * (v_one - v_s);
+    v_float32x4 v_tab2 = v_v * (v_one - (v_s * v_h));
+    v_float32x4 v_tab3 = v_v * (v_one - (v_s * (v_one - v_h)));
+
+    v_float32x4 v_one_sixth = v_setall_f32(1.0f / 6.0f);
+    v_float32x4 v_sector = v_pre_sector * v_one_sixth;
+    v_sector = v_cvt_f32(v_trunc(v_sector));
+    v_float32x4 v_six = v_setall_f32(6.0f);
+    v_sector = v_pre_sector - (v_sector * v_six);
+
+    v_float32x4 v_two = v_setall_f32(2.0f);
+    v_h = v_tab1 & (v_sector < v_two);
+    v_h = v_h | (v_tab3 & (v_sector == v_two));
+    v_float32x4 v_three = v_setall_f32(3.0f);
+    v_h = v_h | (v_tab0 & (v_sector == v_three));
+    v_float32x4 v_four = v_setall_f32(4.0f);
+    v_h = v_h | (v_tab0 & (v_sector == v_four));
+    v_h = v_h | (v_tab2 & (v_sector > v_four));
+
+    v_s = v_tab3 & (v_sector < v_one);
+    v_s = v_s | (v_tab0 & (v_sector == v_one));
+    v_s = v_s | (v_tab0 & (v_sector == v_two));
+    v_s = v_s | (v_tab2 & (v_sector == v_three));
+    v_s = v_s | (v_tab1 & (v_sector > v_three));
+
+    v_v = v_tab0 & (v_sector < v_one);
+    v_v = v_v | (v_tab2 & (v_sector == v_one));
+    v_v = v_v | (v_tab1 & (v_sector == v_two));
+    v_v = v_v | (v_tab1 & (v_sector == v_three));
+    v_v = v_v | (v_tab3 & (v_sector == v_four));
+    v_v = v_v | (v_tab0 & (v_sector > v_four));
+}
+#endif
+
+
+inline void HSV2RGB_native(const float* src, float* dst, const float hscale, const int bidx)
+{
+    float h = src[0], s = src[1], v = src[2];
+    float b, g, r;
+
+    if( s == 0 )
+        b = g = r = v;
+    else
+    {
+        static const int sector_data[][3]=
+            {{1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0}};
+        float tab[4];
+        int sector;
+        h *= hscale;
+        if( h < 0 )
+            do h += 6; while( h < 0 );
+        else if( h >= 6 )
+            do h -= 6; while( h >= 6 );
+        sector = cvFloor(h);
+        h -= sector;
+        if( (unsigned)sector >= 6u )
+        {
+            sector = 0;
+            h = 0.f;
+        }
+
+        tab[0] = v;
+        tab[1] = v*(1.f - s);
+        tab[2] = v*(1.f - s*h);
+        tab[3] = v*(1.f - s*(1.f - h));
+
+        b = tab[sector_data[sector][0]];
+        g = tab[sector_data[sector][1]];
+        r = tab[sector_data[sector][2]];
+    }
+
+    dst[bidx] = b;
+    dst[1] = g;
+    dst[bidx^2] = r;
+}
+
+
 struct HSV2RGB_f
 {
     typedef float channel_type;
@@ -224,152 +309,49 @@ struct HSV2RGB_f
         #endif
     }
 
-    #if CV_SIMD128
-    inline void process(v_float32x4& v_h, v_float32x4& v_s,
-                        v_float32x4& v_v, v_float32x4& v_scale) const
-    {
-        v_h = v_h * v_scale;
-        v_float32x4 v_pre_sector = v_cvt_f32(v_trunc(v_h));
-        v_h = v_h - v_pre_sector;
-        v_float32x4 v_tab0 = v_v;
-        v_float32x4 v_one = v_setall_f32(1.0f);
-        v_float32x4 v_tab1 = v_v * (v_one - v_s);
-        v_float32x4 v_tab2 = v_v * (v_one - (v_s * v_h));
-        v_float32x4 v_tab3 = v_v * (v_one - (v_s * (v_one - v_h)));
-
-        v_float32x4 v_one_sixth = v_setall_f32(1.0f / 6.0f);
-        v_float32x4 v_sector = v_pre_sector * v_one_sixth;
-        v_sector = v_cvt_f32(v_trunc(v_sector));
-        v_float32x4 v_six = v_setall_f32(6.0f);
-        v_sector = v_pre_sector - (v_sector * v_six);
-
-        v_float32x4 v_two = v_setall_f32(2.0f);
-        v_h = v_tab1 & (v_sector < v_two);
-        v_h = v_h | (v_tab3 & (v_sector == v_two));
-        v_float32x4 v_three = v_setall_f32(3.0f);
-        v_h = v_h | (v_tab0 & (v_sector == v_three));
-        v_float32x4 v_four = v_setall_f32(4.0f);
-        v_h = v_h | (v_tab0 & (v_sector == v_four));
-        v_h = v_h | (v_tab2 & (v_sector > v_four));
-
-        v_s = v_tab3 & (v_sector < v_one);
-        v_s = v_s | (v_tab0 & (v_sector == v_one));
-        v_s = v_s | (v_tab0 & (v_sector == v_two));
-        v_s = v_s | (v_tab2 & (v_sector == v_three));
-        v_s = v_s | (v_tab1 & (v_sector > v_three));
-
-        v_v = v_tab0 & (v_sector < v_one);
-        v_v = v_v | (v_tab2 & (v_sector == v_one));
-        v_v = v_v | (v_tab1 & (v_sector == v_two));
-        v_v = v_v | (v_tab1 & (v_sector == v_three));
-        v_v = v_v | (v_tab3 & (v_sector == v_four));
-        v_v = v_v | (v_tab0 & (v_sector > v_four));
-    }
-    #endif
-
     void operator()(const float* src, float* dst, int n) const
     {
         int i = 0, bidx = blueIdx, dcn = dstcn;
-        float alpha = ColorChannel<float>::max();
         n *= 3;
 
-        #if CV_SIMD128
-        if (hasSIMD)
+        if (dcn == 3)
         {
-            v_float32x4 v_scale = v_setall_f32(hscale);
-            if (dcn == 3)
+            #if CV_SIMD128
+            if (hasSIMD)
             {
-                if (bidx)
-                {
-                    for (; i <= n - 12; i += 12, dst += dcn * 4)
-                    {
-                        v_float32x4 v_h;
-                        v_float32x4 v_s;
-                        v_float32x4 v_v;
-                        v_load_deinterleave(src + i, v_h, v_s, v_v);
-                        process(v_h, v_s, v_v, v_scale);
-                        v_store_interleave(dst, v_v, v_s, v_h);
-                    }
-                } else {
-                    for (; i <= n - 12; i += 12, dst += dcn * 4)
-                    {
-                        v_float32x4 v_h;
-                        v_float32x4 v_s;
-                        v_float32x4 v_v;
-                        v_load_deinterleave(src + i, v_h, v_s, v_v);
-                        process(v_h, v_s, v_v, v_scale);
-                        v_store_interleave(dst, v_h, v_s, v_v);
-                    }
-                }
-            } else { // dcn == 4
-                v_float32x4 v_a = v_setall_f32(alpha);
-                if (bidx)
+                for (; i <= n - 12; i += 12, dst += dcn * 4)
                 {
-                    for (; i <= n - 12; i += 12, dst += dcn * 4)
-                    {
-                        v_float32x4 v_h;
-                        v_float32x4 v_s;
-                        v_float32x4 v_v;
-                        v_load_deinterleave(src + i, v_h, v_s, v_v);
-                        process(v_h, v_s, v_v, v_scale);
-                        v_store_interleave(dst, v_v, v_s, v_h, v_a);
-                    }
-                } else {
-                    for (; i <= n - 12; i += 12, dst += dcn * 4)
-                    {
-                        v_float32x4 v_h;
-                        v_float32x4 v_s;
-                        v_float32x4 v_v;
-                        v_load_deinterleave(src + i, v_h, v_s, v_v);
-                        process(v_h, v_s, v_v, v_scale);
-                        v_store_interleave(dst, v_h, v_s, v_v, v_a);
-                    }
+                    v_float32x4 v_src[3];
+                    v_load_deinterleave(src + i, v_src[0], v_src[1], v_src[2]);
+                    HSV2RGB_simd(v_src[0], v_src[1], v_src[2], hscale);
+                    v_store_interleave(dst, v_src[bidx], v_src[1], v_src[bidx^2]);
                 }
             }
-        }
-        #endif
-
-        for( ; i < n; i += 3, dst += dcn )
-        {
-            float h = src[i], s = src[i+1], v = src[i+2];
-            float b, g, r;
-
-            if( s == 0 )
-                b = g = r = v;
-            else
+            #endif
+            for( ; i < n; i += 3, dst += dcn )
             {
-                static const int sector_data[][3]=
-                    {{1,3,0}, {1,0,2}, {3,0,1}, {0,2,1}, {0,1,3}, {2,1,0}};
-                float tab[4];
-                int sector;
-                h *= hscale;
-                if( h < 0 )
-                    do h += 6; while( h < 0 );
-                else if( h >= 6 )
-                    do h -= 6; while( h >= 6 );
-                sector = cvFloor(h);
-                h -= sector;
-                if( (unsigned)sector >= 6u )
+                HSV2RGB_native(src + i, dst, hscale, bidx);
+            }
+        } else { // dcn == 4
+            float alpha = ColorChannel<float>::max();
+            #if CV_SIMD128
+            if (hasSIMD)
+            {
+                for (; i <= n - 12; i += 12, dst += dcn * 4)
                 {
-                    sector = 0;
-                    h = 0.f;
+                    v_float32x4 v_src[3];
+                    v_load_deinterleave(src + i, v_src[0], v_src[1], v_src[2]);
+                    HSV2RGB_simd(v_src[0], v_src[1], v_src[2], hscale);
+                    v_float32x4 v_a = v_setall_f32(alpha);
+                    v_store_interleave(dst, v_src[bidx], v_src[1], v_src[bidx^2], v_a);
                 }
-
-                tab[0] = v;
-                tab[1] = v*(1.f - s);
-                tab[2] = v*(1.f - s*h);
-                tab[3] = v*(1.f - s*(1.f - h));
-
-                b = tab[sector_data[sector][0]];
-                g = tab[sector_data[sector][1]];
-                r = tab[sector_data[sector][2]];
             }
-
-            dst[bidx] = b;
-            dst[1] = g;
-            dst[bidx^2] = r;
-            if( dcn == 4 )
+            #endif
+            for( ; i < n; i += 3, dst += dcn )
+            {
+                HSV2RGB_native(src + i, dst, hscale, bidx);
                 dst[3] = alpha;
+            }
         }
     }
 
@@ -386,216 +368,111 @@ struct HSV2RGB_b
     typedef uchar channel_type;
 
     HSV2RGB_b(int _dstcn, int _blueIdx, int _hrange)
-    : dstcn(_dstcn), cvt(3, _blueIdx, (float)_hrange)
+    : dstcn(_dstcn), blueIdx(_blueIdx), hscale(6.0f / _hrange)
     {
-        #if CV_NEON
-        v_scale_inv = vdupq_n_f32(1.f/255.f);
-        v_scale = vdupq_n_f32(255.f);
-        v_alpha = vdup_n_u8(ColorChannel<uchar>::max());
-        #elif CV_SSE2
-        v_scale = _mm_set1_ps(255.0f);
-        v_alpha = _mm_set1_ps(ColorChannel<uchar>::max());
-        v_zero = _mm_setzero_si128();
-        haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
+        #if CV_SIMD128
+        hasSIMD = hasSIMD128();
         #endif
     }
 
-    #if CV_SSE2
-    void process(__m128i v_r, __m128i v_g, __m128i v_b,
-                 const __m128& v_coeffs_,
-                 float * buf) const
-    {
-        __m128 v_r0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v_r, v_zero));
-        __m128 v_g0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v_g, v_zero));
-        __m128 v_b0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v_b, v_zero));
-
-        __m128 v_r1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_r, v_zero));
-        __m128 v_g1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_g, v_zero));
-        __m128 v_b1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_b, v_zero));
-
-        __m128 v_coeffs = v_coeffs_;
-
-        v_r0 = _mm_mul_ps(v_r0, v_coeffs);
-        v_g1 = _mm_mul_ps(v_g1, v_coeffs);
-
-        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
-
-        v_r1 = _mm_mul_ps(v_r1, v_coeffs);
-        v_b0 = _mm_mul_ps(v_b0, v_coeffs);
-
-        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
-
-        v_g0 = _mm_mul_ps(v_g0, v_coeffs);
-        v_b1 = _mm_mul_ps(v_b1, v_coeffs);
-
-        _mm_store_ps(buf, v_r0);
-        _mm_store_ps(buf + 4, v_r1);
-        _mm_store_ps(buf + 8, v_g0);
-        _mm_store_ps(buf + 12, v_g1);
-        _mm_store_ps(buf + 16, v_b0);
-        _mm_store_ps(buf + 20, v_b1);
-    }
-    #endif
-
     void operator()(const uchar* src, uchar* dst, int n) const
     {
-        int i, j, dcn = dstcn;
+        int j = 0, dcn = dstcn;
         uchar alpha = ColorChannel<uchar>::max();
-        float CV_DECL_ALIGNED(16) buf[3*BLOCK_SIZE];
-        #if CV_SSE2
-        __m128 v_coeffs = _mm_set_ps(1.f, 1.f/255.f, 1.f/255.f, 1.f);
-        #endif
 
-        for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 )
+        #if CV_SIMD128
+        if (hasSIMD)
         {
-            int dn = std::min(n - i, (int)BLOCK_SIZE);
-            j = 0;
-
-            #if CV_NEON
-            for ( ; j <= (dn - 8) * 3; j += 24)
-            {
-                uint8x8x3_t v_src = vld3_u8(src + j);
-                uint16x8_t v_t0 = vmovl_u8(v_src.val[0]),
-                           v_t1 = vmovl_u8(v_src.val[1]),
-                           v_t2 = vmovl_u8(v_src.val[2]);
-
-                float32x4x3_t v_dst;
-                v_dst.val[0] = vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_t0)));
-                v_dst.val[1] = vmulq_f32(vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_t1))), v_scale_inv);
-                v_dst.val[2] = vmulq_f32(vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_t2))), v_scale_inv);
-                vst3q_f32(buf + j, v_dst);
-
-                v_dst.val[0] = vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_t0)));
-                v_dst.val[1] = vmulq_f32(vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_t1))), v_scale_inv);
-                v_dst.val[2] = vmulq_f32(vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_t2))), v_scale_inv);
-                vst3q_f32(buf + j + 12, v_dst);
-            }
-            #elif CV_SSE2
-            if (haveSIMD)
+            for (j = 0; j <= (n - 16) * 3; j += 48, dst += dcn * 16)
             {
-                for ( ; j <= (dn - 8) * 3; j += 24)
+                v_uint8x16 h_b, s_b, v_b;
+                v_uint16x8 h_w[2], s_w[2], v_w[2];
+                v_uint32x4 h_u[4], s_u[4], v_u[4];
+                v_load_deinterleave(src + j, h_b, s_b, v_b);
+                v_expand(h_b, h_w[0], h_w[1]);
+                v_expand(s_b, s_w[0], s_w[1]);
+                v_expand(v_b, v_w[0], v_w[1]);
+                v_expand(h_w[0], h_u[0], h_u[1]);
+                v_expand(h_w[1], h_u[2], h_u[3]);
+                v_expand(s_w[0], s_u[0], s_u[1]);
+                v_expand(s_w[1], s_u[2], s_u[3]);
+                v_expand(v_w[0], v_u[0], v_u[1]);
+                v_expand(v_w[1], v_u[2], v_u[3]);
+
+                v_int32x4 b_i[4], g_i[4], r_i[4];
+                v_float32x4 v_coeff0 = v_setall_f32(1.0f / 255.0f);
+                v_float32x4 v_coeff1 = v_setall_f32(255.0f);
+
+                for( int k = 0; k < 4; k++ )
                 {
-                    __m128i v_src0 = _mm_loadu_si128((__m128i const *)(src + j));
-                    __m128i v_src1 = _mm_loadl_epi64((__m128i const *)(src + j + 16));
-
-                    process(_mm_unpacklo_epi8(v_src0, v_zero),
-                            _mm_unpackhi_epi8(v_src0, v_zero),
-                            _mm_unpacklo_epi8(v_src1, v_zero),
-                            v_coeffs,
-                            buf + j);
+                    v_float32x4 v_src[3];
+                    v_src[0] = v_cvt_f32(v_reinterpret_as_s32(h_u[k]));
+                    v_src[1] = v_cvt_f32(v_reinterpret_as_s32(s_u[k]));
+                    v_src[2] = v_cvt_f32(v_reinterpret_as_s32(v_u[k]));
+
+                    v_src[1] *= v_coeff0;
+                    v_src[2] *= v_coeff0;
+                    HSV2RGB_simd(v_src[0], v_src[1], v_src[2], hscale);
+
+                    v_src[0] *= v_coeff1;
+                    v_src[1] *= v_coeff1;
+                    v_src[2] *= v_coeff1;
+                    b_i[k] = v_trunc(v_src[0]);
+                    g_i[k] = v_trunc(v_src[1]);
+                    r_i[k] = v_trunc(v_src[2]);
                 }
-            }
-            #endif
 
-            for( ; j < dn*3; j += 3 )
-            {
-                buf[j] = src[j];
-                buf[j+1] = src[j+1]*(1.f/255.f);
-                buf[j+2] = src[j+2]*(1.f/255.f);
-            }
-            cvt(buf, buf, dn);
+                v_uint16x8 r_w[2], g_w[2], b_w[2];
+                v_uint8x16 r_b, g_b, b_b;
 
-            j = 0;
-            #if CV_NEON
-            for ( ; j <= (dn - 8) * 3; j += 24, dst += dcn * 8)
-            {
-                float32x4x3_t v_src0 = vld3q_f32(buf + j), v_src1 = vld3q_f32(buf + j + 12);
-                uint8x8_t v_dst0 = vqmovn_u16(vcombine_u16(vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src0.val[0], v_scale))),
-                                                           vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src1.val[0], v_scale)))));
-                uint8x8_t v_dst1 = vqmovn_u16(vcombine_u16(vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src0.val[1], v_scale))),
-                                                           vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src1.val[1], v_scale)))));
-                uint8x8_t v_dst2 = vqmovn_u16(vcombine_u16(vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src0.val[2], v_scale))),
-                                                           vqmovn_u32(cv_vrndq_u32_f32(vmulq_f32(v_src1.val[2], v_scale)))));
+                r_w[0] = v_pack_u(r_i[0], r_i[1]);
+                r_w[1] = v_pack_u(r_i[2], r_i[3]);
+                r_b = v_pack(r_w[0], r_w[1]);
+                g_w[0] = v_pack_u(g_i[0], g_i[1]);
+                g_w[1] = v_pack_u(g_i[2], g_i[3]);
+                g_b = v_pack(g_w[0], g_w[1]);
+                b_w[0] = v_pack_u(b_i[0], b_i[1]);
+                b_w[1] = v_pack_u(b_i[2], b_i[3]);
+                b_b = v_pack(b_w[0], b_w[1]);
 
-                if (dcn == 4)
+                if( dcn == 3 )
                 {
-                    uint8x8x4_t v_dst;
-                    v_dst.val[0] = v_dst0;
-                    v_dst.val[1] = v_dst1;
-                    v_dst.val[2] = v_dst2;
-                    v_dst.val[3] = v_alpha;
-                    vst4_u8(dst, v_dst);
+                    if( blueIdx == 0 )
+                        v_store_interleave(dst, b_b, g_b, r_b);
+                    else
+                        v_store_interleave(dst, r_b, g_b, b_b);
                 }
                 else
                 {
-                    uint8x8x3_t v_dst;
-                    v_dst.val[0] = v_dst0;
-                    v_dst.val[1] = v_dst1;
-                    v_dst.val[2] = v_dst2;
-                    vst3_u8(dst, v_dst);
+                    v_uint8x16 alpha_b = v_setall_u8(alpha);
+                    if( blueIdx == 0 )
+                        v_store_interleave(dst, b_b, g_b, r_b, alpha_b);
+                    else
+                        v_store_interleave(dst, r_b, g_b, b_b, alpha_b);
                 }
             }
-            #elif CV_SSE2
-            if (dcn == 3 && haveSIMD)
-            {
-                for ( ; j <= (dn * 3 - 16); j += 16, dst += 16)
-                {
-                    __m128 v_src0 = _mm_mul_ps(_mm_load_ps(buf + j), v_scale);
-                    __m128 v_src1 = _mm_mul_ps(_mm_load_ps(buf + j + 4), v_scale);
-                    __m128 v_src2 = _mm_mul_ps(_mm_load_ps(buf + j + 8), v_scale);
-                    __m128 v_src3 = _mm_mul_ps(_mm_load_ps(buf + j + 12), v_scale);
-
-                    __m128i v_dst0 = _mm_packs_epi32(_mm_cvtps_epi32(v_src0),
-                                                     _mm_cvtps_epi32(v_src1));
-                    __m128i v_dst1 = _mm_packs_epi32(_mm_cvtps_epi32(v_src2),
-                                                     _mm_cvtps_epi32(v_src3));
-
-                    _mm_storeu_si128((__m128i *)dst, _mm_packus_epi16(v_dst0, v_dst1));
-                }
-
-                int jr = j % 3;
-                if (jr)
-                    dst -= jr, j -= jr;
-            }
-            else if (dcn == 4 && haveSIMD)
-            {
-                for ( ; j <= (dn * 3 - 12); j += 12, dst += 16)
-                {
-                    __m128 v_buf0 = _mm_mul_ps(_mm_load_ps(buf + j), v_scale);
-                    __m128 v_buf1 = _mm_mul_ps(_mm_load_ps(buf + j + 4), v_scale);
-                    __m128 v_buf2 = _mm_mul_ps(_mm_load_ps(buf + j + 8), v_scale);
-
-                    __m128 v_ba0 = _mm_unpackhi_ps(v_buf0, v_alpha);
-                    __m128 v_ba1 = _mm_unpacklo_ps(v_buf2, v_alpha);
-
-                    __m128i v_src0 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf0, v_ba0, 0x44));
-                    __m128i v_src1 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba0, v_buf1, 0x4e)), 0x78);
-                    __m128i v_src2 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf1, v_ba1, 0x4e));
-                    __m128i v_src3 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba1, v_buf2, 0xee)), 0x78);
-
-                    __m128i v_dst0 = _mm_packs_epi32(v_src0, v_src1);
-                    __m128i v_dst1 = _mm_packs_epi32(v_src2, v_src3);
-
-                    _mm_storeu_si128((__m128i *)dst, _mm_packus_epi16(v_dst0, v_dst1));
-                }
-
-                int jr = j % 3;
-                if (jr)
-                    dst -= jr, j -= jr;
-            }
-            #endif
-
-            for( ; j < dn*3; j += 3, dst += dcn )
-            {
-                dst[0] = saturate_cast<uchar>(buf[j]*255.f);
-                dst[1] = saturate_cast<uchar>(buf[j+1]*255.f);
-                dst[2] = saturate_cast<uchar>(buf[j+2]*255.f);
-                if( dcn == 4 )
-                    dst[3] = alpha;
-            }
+        }
+        #endif
+        for( ; j < n * 3; j += 3, dst += dcn )
+        {
+            float buf[6];
+            buf[0] = src[j];
+            buf[1] = src[j+1] * (1.0f / 255.0f);
+            buf[2] = src[j+2] * (1.0f / 255.0f);
+            HSV2RGB_native(buf, buf + 3, hscale, blueIdx);
+            dst[0] = saturate_cast<uchar>(buf[3] * 255.0f);
+            dst[1] = saturate_cast<uchar>(buf[4] * 255.0f);
+            dst[2] = saturate_cast<uchar>(buf[5] * 255.0f);
+            if( dcn == 4 )
+                dst[3] = alpha;
         }
     }
 
     int dstcn;
-    HSV2RGB_f cvt;
-    #if CV_NEON
-    float32x4_t v_scale, v_scale_inv;
-    uint8x8_t v_alpha;
-    #elif CV_SSE2
-    __m128 v_scale;
-    __m128 v_alpha;
-    __m128i v_zero;
-    bool haveSIMD;
+    int blueIdx;
+    float hscale;
+    #if CV_SIMD128
+    bool hasSIMD;
     #endif
 };