//constants for conversion from/to RGB and YUV, YCrCb according to BT.601
//to YCbCr
-const float YCBF = 0.564f; // == 1/2/(1-B2YF)
-const float YCRF = 0.713f; // == 1/2/(1-R2YF)
-const int YCBI = 9241; // == YCBF*16384
-const int YCRI = 11682; // == YCRF*16384
+static const float YCBF = 0.564f; // == 1/2/(1-B2YF)
+static const float YCRF = 0.713f; // == 1/2/(1-R2YF)
+static const int YCBI = 9241; // == YCBF*16384
+static const int YCRI = 11682; // == YCRF*16384
//to YUV
-const float B2UF = 0.492f;
-const float R2VF = 0.877f;
-const int B2UI = 8061; // == B2UF*16384
-const int R2VI = 14369; // == R2VF*16384
+static const float B2UF = 0.492f;
+static const float R2VF = 0.877f;
+static const int B2UI = 8061; // == B2UF*16384
+static const int R2VI = 14369; // == R2VF*16384
//from YUV
-const float U2BF = 2.032f;
-const float U2GF = -0.395f;
-const float V2GF = -0.581f;
-const float V2RF = 1.140f;
-const int U2BI = 33292;
-const int U2GI = -6472;
-const int V2GI = -9519;
-const int V2RI = 18678;
+static const float U2BF = 2.032f;
+static const float U2GF = -0.395f;
+static const float V2GF = -0.581f;
+static const float V2RF = 1.140f;
+static const int U2BI = 33292;
+static const int U2GI = -6472;
+static const int V2GI = -9519;
+static const int V2RI = 18678;
//from YCrCb
-const float CB2BF = 1.773f;
-const float CB2GF = -0.344f;
-const float CR2GF = -0.714f;
-const float CR2RF = 1.403f;
-const int CB2BI = 29049;
-const int CB2GI = -5636;
-const int CR2GI = -11698;
-const int CR2RI = 22987;
+static const float CB2BF = 1.773f;
+static const float CB2GF = -0.344f;
+static const float CR2GF = -0.714f;
+static const float CR2RF = 1.403f;
+static const int CB2BI = 29049;
+static const int CB2GI = -5636;
+static const int CR2GI = -11698;
+static const int CR2RI = 22987;
///////////////////////////////////// RGB <-> YCrCb //////////////////////////////////////
{
typedef _Tp channel_type;
- RGB2YCrCb_f(int _srccn, int _blueIdx, bool _isCrCb) : srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
+ RGB2YCrCb_f(int _srccn, int _blueIdx, bool _isCrCb) :
+ srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
{
static const float coeffs_crb[] = { R2YF, G2YF, B2YF, YCRF, YCBF };
static const float coeffs_yuv[] = { R2YF, G2YF, B2YF, R2VF, B2UF };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
- if(blueIdx==0) std::swap(coeffs[0], coeffs[2]);
+ for(int i = 0; i < 5; i++)
+ {
+ coeffs[i] = isCrCb ? coeffs_crb[i] : coeffs_yuv[i];
+ }
+ if(blueIdx == 0)
+ std::swap(coeffs[0], coeffs[2]);
}
void operator()(const _Tp* src, _Tp* dst, int n) const
float coeffs[5];
};
-#if CV_NEON
-
template <>
struct RGB2YCrCb_f<float>
{
{
static const float coeffs_crb[] = { R2YF, G2YF, B2YF, YCRF, YCBF };
static const float coeffs_yuv[] = { R2YF, G2YF, B2YF, R2VF, B2UF };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
- if(blueIdx==0)
+ for(int i = 0; i < 5; i++)
+ {
+ coeffs[i] = isCrCb ? coeffs_crb[i] : coeffs_yuv[i];
+ }
+ if(blueIdx == 0)
std::swap(coeffs[0], coeffs[2]);
-
- v_c0 = vdupq_n_f32(coeffs[0]);
- v_c1 = vdupq_n_f32(coeffs[1]);
- v_c2 = vdupq_n_f32(coeffs[2]);
- v_c3 = vdupq_n_f32(coeffs[3]);
- v_c4 = vdupq_n_f32(coeffs[4]);
- v_delta = vdupq_n_f32(ColorChannel<float>::half());
}
void operator()(const float * src, float * dst, int n) const
{
- int scn = srccn, bidx = blueIdx, i = 0;
+ int scn = srccn, bidx = blueIdx;
int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
const float delta = ColorChannel<float>::half();
float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
- n *= 3;
- if (scn == 3)
- for ( ; i <= n - 12; i += 12, src += 12)
+ int i = 0;
+#if CV_SIMD
+ v_float32 vc0 = vx_setall_f32(C0), vc1 = vx_setall_f32(C1), vc2 = vx_setall_f32(C2);
+ v_float32 vc3 = vx_setall_f32(C3), vc4 = vx_setall_f32(C4);
+ v_float32 vdelta = vx_setall_f32(delta);
+ const int vsize = v_float32::nlanes;
+ for( ; i <= n-vsize;
+ i += vsize, src += vsize*scn, dst += vsize*3)
+ {
+ v_float32 b, g, r, dummy;
+ if(scn == 3)
{
- float32x4x3_t v_src = vld3q_f32(src), v_dst;
- v_dst.val[0] = vmlaq_f32(vmlaq_f32(vmulq_f32(v_src.val[0], v_c0), v_src.val[1], v_c1), v_src.val[2], v_c2);
- v_dst.val[1+yuvOrder] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx^2], v_dst.val[0]), v_c3);
- v_dst.val[2-yuvOrder] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx], v_dst.val[0]), v_c4);
-
- vst3q_f32(dst + i, v_dst);
+ v_load_deinterleave(src, b, g, r);
}
- else
- for ( ; i <= n - 12; i += 12, src += 16)
+ else
{
- float32x4x4_t v_src = vld4q_f32(src);
- float32x4x3_t v_dst;
- v_dst.val[0] = vmlaq_f32(vmlaq_f32(vmulq_f32(v_src.val[0], v_c0), v_src.val[1], v_c1), v_src.val[2], v_c2);
- v_dst.val[1+yuvOrder] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx^2], v_dst.val[0]), v_c3);
- v_dst.val[2-yuvOrder] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx], v_dst.val[0]), v_c4);
-
- vst3q_f32(dst + i, v_dst);
+ v_load_deinterleave(src, b, g, r, dummy);
}
- for ( ; i < n; i += 3, src += scn)
- {
- float Y = src[0]*C0 + src[1]*C1 + src[2]*C2;
- float Cr = (src[bidx^2] - Y)*C3 + delta;
- float Cb = (src[bidx] - Y)*C4 + delta;
- dst[i] = Y; dst[i+1+yuvOrder] = Cr; dst[i+2-yuvOrder] = Cb;
- }
- }
- int srccn, blueIdx;
- bool isCrCb;
- float coeffs[5];
- float32x4_t v_c0, v_c1, v_c2, v_c3, v_c4, v_delta;
-};
+ v_float32 y, cr, cb;
+ y = b*vc0 + g*vc1 + r*vc2;
-#elif CV_SSE2
+ if(bidx)
+ std::swap(r, b);
-template <>
-struct RGB2YCrCb_f<float>
-{
- typedef float channel_type;
+ cr = v_fma(r - y, vc3, vdelta);
+ cb = v_fma(b - y, vc4, vdelta);
- RGB2YCrCb_f(int _srccn, int _blueIdx, bool _isCrCb) :
- srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
- {
- static const float coeffs_crb[] = { R2YF, G2YF, B2YF, YCRF, YCBF };
- static const float coeffs_yuv[] = { R2YF, G2YF, B2YF, R2VF, B2UF };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
- if (blueIdx==0)
- std::swap(coeffs[0], coeffs[2]);
-
- v_c0 = _mm_set1_ps(coeffs[0]);
- v_c1 = _mm_set1_ps(coeffs[1]);
- v_c2 = _mm_set1_ps(coeffs[2]);
- v_c3 = _mm_set1_ps(coeffs[3]);
- v_c4 = _mm_set1_ps(coeffs[4]);
- v_delta = _mm_set1_ps(ColorChannel<float>::half());
-
- haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
- }
-
- void process(__m128 v_r, __m128 v_g, __m128 v_b,
- __m128 & v_y, __m128 & v_cr, __m128 & v_cb) const
- {
- v_y = _mm_mul_ps(v_r, v_c0);
- v_y = _mm_add_ps(v_y, _mm_mul_ps(v_g, v_c1));
- v_y = _mm_add_ps(v_y, _mm_mul_ps(v_b, v_c2));
-
- v_cr = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(blueIdx == 0 ? v_b : v_r, v_y), v_c3), v_delta);
- v_cb = _mm_add_ps(_mm_mul_ps(_mm_sub_ps(blueIdx == 2 ? v_b : v_r, v_y), v_c4), v_delta);
- }
-
- void operator()(const float * src, float * dst, int n) const
- {
- int scn = srccn, bidx = blueIdx, i = 0;
- int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
- const float delta = ColorChannel<float>::half();
- float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
- n *= 3;
-
- if (haveSIMD)
- {
- for ( ; i <= n - 24; i += 24, src += 8 * scn)
+ if(yuvOrder)
{
- __m128 v_r0 = _mm_loadu_ps(src);
- __m128 v_r1 = _mm_loadu_ps(src + 4);
- __m128 v_g0 = _mm_loadu_ps(src + 8);
- __m128 v_g1 = _mm_loadu_ps(src + 12);
- __m128 v_b0 = _mm_loadu_ps(src + 16);
- __m128 v_b1 = _mm_loadu_ps(src + 20);
-
- if (scn == 4)
- {
- __m128 v_a0 = _mm_loadu_ps(src + 24);
- __m128 v_a1 = _mm_loadu_ps(src + 28);
- _mm_deinterleave_ps(v_r0, v_r1, v_g0, v_g1,
- v_b0, v_b1, v_a0, v_a1);
- }
- else
- _mm_deinterleave_ps(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
-
- __m128 v_y0, v_cr0, v_cb0;
- process(v_r0, v_g0, v_b0,
- v_y0, v_cr0, v_cb0);
-
- __m128 v_y1, v_cr1, v_cb1;
- process(v_r1, v_g1, v_b1,
- v_y1, v_cr1, v_cb1);
-
- if(isCrCb)
- _mm_interleave_ps(v_y0, v_y1, v_cr0, v_cr1, v_cb0, v_cb1);
- else //YUV
- {
- _mm_interleave_ps(v_y0, v_y1, v_cb0, v_cb1, v_cr0, v_cr1);
- }
-
- _mm_storeu_ps(dst + i, v_y0);
- _mm_storeu_ps(dst + i + 4, v_y1);
- _mm_storeu_ps(dst + i + 8 + yuvOrder*8, v_cr0);
- _mm_storeu_ps(dst + i + 12 + yuvOrder*8, v_cr1);
- _mm_storeu_ps(dst + i + 16 - yuvOrder*8, v_cb0);
- _mm_storeu_ps(dst + i + 20 - yuvOrder*8, v_cb1);
+ v_store_interleave(dst, y, cb, cr);
+ }
+ else
+ {
+ v_store_interleave(dst, y, cr, cb);
}
}
-
- for ( ; i < n; i += 3, src += scn)
+ vx_cleanup();
+#endif
+ for ( ; i < n; i ++, src += scn, dst += 3)
{
float Y = src[0]*C0 + src[1]*C1 + src[2]*C2;
float Cr = (src[bidx^2] - Y)*C3 + delta;
float Cb = (src[bidx] - Y)*C4 + delta;
- dst[i] = Y; dst[i+1+yuvOrder] = Cr; dst[i+2-yuvOrder] = Cb;
+ dst[0 ] = Y;
+ dst[1+yuvOrder] = Cr;
+ dst[2-yuvOrder] = Cb;
}
}
+
int srccn, blueIdx;
bool isCrCb;
float coeffs[5];
- __m128 v_c0, v_c1, v_c2, v_c3, v_c4, v_delta;
- bool haveSIMD;
};
-#endif
template<typename _Tp> struct RGB2YCrCb_i
{
typedef _Tp channel_type;
+ static const int shift = yuv_shift;
RGB2YCrCb_i(int _srccn, int _blueIdx, bool _isCrCb)
: srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
{
static const int coeffs_crb[] = { R2Y, G2Y, B2Y, YCRI, YCBI };
static const int coeffs_yuv[] = { R2Y, G2Y, B2Y, R2VI, B2UI };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
+
+ for(int i = 0; i < 5; i++)
+ {
+ coeffs[i] = isCrCb ? coeffs_crb[i] : coeffs_yuv[i];
+ }
if(blueIdx==0) std::swap(coeffs[0], coeffs[2]);
}
void operator()(const _Tp* src, _Tp* dst, int n) const
int scn = srccn, bidx = blueIdx;
int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
- int delta = ColorChannel<_Tp>::half()*(1 << yuv_shift);
+ int delta = ColorChannel<_Tp>::half()*(1 << shift);
n *= 3;
for(int i = 0; i < n; i += 3, src += scn)
{
- int Y = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, yuv_shift);
- int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift);
- int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
+ int Y = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, shift);
+ int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, shift);
+ int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, shift);
dst[i] = saturate_cast<_Tp>(Y);
dst[i+1+yuvOrder] = saturate_cast<_Tp>(Cr);
dst[i+2-yuvOrder] = saturate_cast<_Tp>(Cb);
int coeffs[5];
};
-#if CV_NEON
-template <>
-struct RGB2YCrCb_i<uchar>
+template<>
+struct RGB2YCrCb_i<ushort>
{
- typedef uchar channel_type;
+ typedef ushort channel_type;
+ static const int shift = yuv_shift;
+ static const int fix_shift = (int)(sizeof(short)*8 - shift);
RGB2YCrCb_i(int _srccn, int _blueIdx, bool _isCrCb)
: srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
{
static const int coeffs_crb[] = { R2Y, G2Y, B2Y, YCRI, YCBI };
static const int coeffs_yuv[] = { R2Y, G2Y, B2Y, R2VI, B2UI };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
- if (blueIdx==0)
- std::swap(coeffs[0], coeffs[2]);
- v_c0 = vdup_n_s16(coeffs[0]);
- v_c1 = vdup_n_s16(coeffs[1]);
- v_c2 = vdup_n_s16(coeffs[2]);
- v_c3 = vdupq_n_s32(coeffs[3]);
- v_c4 = vdupq_n_s32(coeffs[4]);
- v_delta = vdupq_n_s32(ColorChannel<uchar>::half()*(1 << yuv_shift));
- v_delta2 = vdupq_n_s32(1 << (yuv_shift - 1));
+ for(int i = 0; i < 5; i++)
+ {
+ coeffs[i] = isCrCb ? coeffs_crb[i] : coeffs_yuv[i];
+ }
+ if(blueIdx==0)
+ std::swap(coeffs[0], coeffs[2]);
}
- void operator()(const uchar * src, uchar * dst, int n) const
+ void operator()(const ushort* src, ushort* dst, int n) const
{
- int scn = srccn, bidx = blueIdx, i = 0;
+ int scn = srccn, bidx = blueIdx;
int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
- int delta = ColorChannel<uchar>::half()*(1 << yuv_shift);
- n *= 3;
-
- for ( ; i <= n - 24; i += 24, src += scn * 8)
+ int sdelta = ColorChannel<ushort>::half()*(1 << shift);
+ int i = 0;
+#if CV_SIMD
+ const int vsize = v_uint16::nlanes;
+ const int descale = 1 << (shift-1);
+
+ v_int16 b2y = vx_setall_s16((short)C0);
+ v_int16 g2y = vx_setall_s16((short)C1);
+ v_int16 r2y = vx_setall_s16((short)C2);
+ v_int16 one = vx_setall_s16(1);
+ v_int16 z = vx_setzero_s16();
+
+ v_int16 bg2y, r12y;
+ v_int16 dummy;
+ v_zip(b2y, g2y, bg2y, dummy);
+ v_zip(r2y, one, r12y, dummy);
+
+ v_int16 vdescale = vx_setall_s16(1 << (shift-1));
+ v_int32 vc3 = vx_setall_s32(C3);
+ v_int32 vc4 = vx_setall_s32(C4);
+ v_int32 vdd = vx_setall_s32(sdelta + descale);
+
+ for(; i <= n-vsize;
+ i += vsize, src += vsize*scn, dst += vsize*3)
{
- uint8x8x3_t v_dst;
- int16x8x3_t v_src16;
-
- if (scn == 3)
+ v_uint16 r, g, b, a;
+ if(scn == 3)
{
- uint8x8x3_t v_src = vld3_u8(src);
- v_src16.val[0] = vreinterpretq_s16_u16(vmovl_u8(v_src.val[0]));
- v_src16.val[1] = vreinterpretq_s16_u16(vmovl_u8(v_src.val[1]));
- v_src16.val[2] = vreinterpretq_s16_u16(vmovl_u8(v_src.val[2]));
+ v_load_deinterleave(src, b, g, r);
}
else
{
- uint8x8x4_t v_src = vld4_u8(src);
- v_src16.val[0] = vreinterpretq_s16_u16(vmovl_u8(v_src.val[0]));
- v_src16.val[1] = vreinterpretq_s16_u16(vmovl_u8(v_src.val[1]));
- v_src16.val[2] = vreinterpretq_s16_u16(vmovl_u8(v_src.val[2]));
+ v_load_deinterleave(src, b, g, r, a);
}
- int16x4x3_t v_src0;
- v_src0.val[0] = vget_low_s16(v_src16.val[0]);
- v_src0.val[1] = vget_low_s16(v_src16.val[1]);
- v_src0.val[2] = vget_low_s16(v_src16.val[2]);
-
- int32x4_t v_Y0 = vmlal_s16(vmlal_s16(vmull_s16(v_src0.val[0], v_c0), v_src0.val[1], v_c1), v_src0.val[2], v_c2);
- v_Y0 = vshrq_n_s32(vaddq_s32(v_Y0, v_delta2), yuv_shift);
- int32x4_t v_Cr0 = vmlaq_s32(v_delta, vsubq_s32(vmovl_s16(v_src0.val[bidx^2]), v_Y0), v_c3);
- v_Cr0 = vshrq_n_s32(vaddq_s32(v_Cr0, v_delta2), yuv_shift);
- int32x4_t v_Cb0 = vmlaq_s32(v_delta, vsubq_s32(vmovl_s16(v_src0.val[bidx]), v_Y0), v_c4);
- v_Cb0 = vshrq_n_s32(vaddq_s32(v_Cb0, v_delta2), yuv_shift);
-
- v_src0.val[0] = vget_high_s16(v_src16.val[0]);
- v_src0.val[1] = vget_high_s16(v_src16.val[1]);
- v_src0.val[2] = vget_high_s16(v_src16.val[2]);
-
- int32x4_t v_Y1 = vmlal_s16(vmlal_s16(vmull_s16(v_src0.val[0], v_c0), v_src0.val[1], v_c1), v_src0.val[2], v_c2);
- v_Y1 = vshrq_n_s32(vaddq_s32(v_Y1, v_delta2), yuv_shift);
- int32x4_t v_Cr1 = vmlaq_s32(v_delta, vsubq_s32(vmovl_s16(v_src0.val[bidx^2]), v_Y1), v_c3);
- v_Cr1 = vshrq_n_s32(vaddq_s32(v_Cr1, v_delta2), yuv_shift);
- int32x4_t v_Cb1 = vmlaq_s32(v_delta, vsubq_s32(vmovl_s16(v_src0.val[bidx]), v_Y1), v_c4);
- v_Cb1 = vshrq_n_s32(vaddq_s32(v_Cb1, v_delta2), yuv_shift);
-
- v_dst.val[0] = vqmovun_s16(vcombine_s16(vqmovn_s32(v_Y0), vqmovn_s32(v_Y1)));
- v_dst.val[1+yuvOrder] = vqmovun_s16(vcombine_s16(vqmovn_s32(v_Cr0), vqmovn_s32(v_Cr1)));
- v_dst.val[2-yuvOrder] = vqmovun_s16(vcombine_s16(vqmovn_s32(v_Cb0), vqmovn_s32(v_Cb1)));
-
- vst3_u8(dst + i, v_dst);
- }
+ v_uint16 y, cr, cb;
- for ( ; i < n; i += 3, src += scn)
- {
- int Y = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, yuv_shift);
- int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift);
- int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
- dst[i] = saturate_cast<uchar>(Y);
- dst[i+1+yuvOrder] = saturate_cast<uchar>(Cr);
- dst[i+2-yuvOrder] = saturate_cast<uchar>(Cb);
- }
- }
- int srccn, blueIdx, coeffs[5];
- bool isCrCb;
- int16x4_t v_c0, v_c1, v_c2;
- int32x4_t v_c3, v_c4, v_delta, v_delta2;
-};
+ v_int16 sb = v_reinterpret_as_s16(b);
+ v_int16 sr = v_reinterpret_as_s16(r);
+ v_int16 sg = v_reinterpret_as_s16(g);
-template <>
-struct RGB2YCrCb_i<ushort>
-{
- typedef ushort channel_type;
+ v_int16 bg0, bg1;
+ v_int16 rd0, rd1;
+ v_zip(sb, sg, bg0, bg1);
+ v_zip(sr, vdescale, rd0, rd1);
- RGB2YCrCb_i(int _srccn, int _blueIdx, bool _isCrCb)
- : srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
- {
- static const int coeffs_crb[] = { R2Y, G2Y, B2Y, YCRI, YCBI };
- static const int coeffs_yuv[] = { R2Y, G2Y, B2Y, R2VI, B2UI };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
- if (blueIdx==0)
- std::swap(coeffs[0], coeffs[2]);
+ // fixing 16bit signed multiplication
+ v_int16 mr, mg, mb;
+ mr = (sr < z) & r2y;
+ mg = (sg < z) & g2y;
+ mb = (sb < z) & b2y;
+ v_int16 fixmul = v_add_wrap(mr, v_add_wrap(mg, mb)) << fix_shift;
- v_c0 = vdupq_n_s32(coeffs[0]);
- v_c1 = vdupq_n_s32(coeffs[1]);
- v_c2 = vdupq_n_s32(coeffs[2]);
- v_c3 = vdupq_n_s32(coeffs[3]);
- v_c4 = vdupq_n_s32(coeffs[4]);
- v_delta = vdupq_n_s32(ColorChannel<ushort>::half()*(1 << yuv_shift));
- v_delta2 = vdupq_n_s32(1 << (yuv_shift - 1));
- }
+ v_int32 ssy0 = (v_dotprod(bg0, bg2y) + v_dotprod(rd0, r12y)) >> shift;
+ v_int32 ssy1 = (v_dotprod(bg1, bg2y) + v_dotprod(rd1, r12y)) >> shift;
- void operator()(const ushort * src, ushort * dst, int n) const
- {
- int scn = srccn, bidx = blueIdx, i = 0;
- int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
- int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
- int delta = ColorChannel<ushort>::half()*(1 << yuv_shift);
- n *= 3;
+ y = v_reinterpret_as_u16(v_add_wrap(v_pack(ssy0, ssy1), fixmul));
- for ( ; i <= n - 24; i += 24, src += scn * 8)
- {
- uint16x8x3_t v_src, v_dst;
- int32x4x3_t v_src0;
+ if(bidx)
+ swap(r, b);
- if (scn == 3)
- v_src = vld3q_u16(src);
- else
- {
- uint16x8x4_t v_src_ = vld4q_u16(src);
- v_src.val[0] = v_src_.val[0];
- v_src.val[1] = v_src_.val[1];
- v_src.val[2] = v_src_.val[2];
- }
+ // (r-Y) and (b-Y) don't fit into int16 or uint16 range
+ v_uint32 r0, r1, b0, b1;
+ v_expand(r, r0, r1);
+ v_expand(b, b0, b1);
- v_src0.val[0] = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(v_src.val[0])));
- v_src0.val[1] = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(v_src.val[1])));
- v_src0.val[2] = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(v_src.val[2])));
-
- int32x4_t v_Y0 = vmlaq_s32(vmlaq_s32(vmulq_s32(v_src0.val[0], v_c0), v_src0.val[1], v_c1), v_src0.val[2], v_c2);
- v_Y0 = vshrq_n_s32(vaddq_s32(v_Y0, v_delta2), yuv_shift);
- int32x4_t v_Cr0 = vmlaq_s32(v_delta, vsubq_s32(v_src0.val[bidx^2], v_Y0), v_c3);
- v_Cr0 = vshrq_n_s32(vaddq_s32(v_Cr0, v_delta2), yuv_shift);
- int32x4_t v_Cb0 = vmlaq_s32(v_delta, vsubq_s32(v_src0.val[bidx], v_Y0), v_c4);
- v_Cb0 = vshrq_n_s32(vaddq_s32(v_Cb0, v_delta2), yuv_shift);
-
- v_src0.val[0] = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(v_src.val[0])));
- v_src0.val[1] = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(v_src.val[1])));
- v_src0.val[2] = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(v_src.val[2])));
-
- int32x4_t v_Y1 = vmlaq_s32(vmlaq_s32(vmulq_s32(v_src0.val[0], v_c0), v_src0.val[1], v_c1), v_src0.val[2], v_c2);
- v_Y1 = vshrq_n_s32(vaddq_s32(v_Y1, v_delta2), yuv_shift);
- int32x4_t v_Cr1 = vmlaq_s32(v_delta, vsubq_s32(v_src0.val[bidx^2], v_Y1), v_c3);
- v_Cr1 = vshrq_n_s32(vaddq_s32(v_Cr1, v_delta2), yuv_shift);
- int32x4_t v_Cb1 = vmlaq_s32(v_delta, vsubq_s32(v_src0.val[bidx], v_Y1), v_c4);
- v_Cb1 = vshrq_n_s32(vaddq_s32(v_Cb1, v_delta2), yuv_shift);
-
- v_dst.val[0] = vcombine_u16(vqmovun_s32(v_Y0), vqmovun_s32(v_Y1));
- v_dst.val[1+yuvOrder] = vcombine_u16(vqmovun_s32(v_Cr0), vqmovun_s32(v_Cr1));
- v_dst.val[2-yuvOrder] = vcombine_u16(vqmovun_s32(v_Cb0), vqmovun_s32(v_Cb1));
-
- vst3q_u16(dst + i, v_dst);
- }
+ v_uint32 uy0, uy1;
+ v_expand(y, uy0, uy1);
- for ( ; i <= n - 12; i += 12, src += scn * 4)
- {
- uint16x4x3_t v_dst;
- int32x4x3_t v_src0;
+ v_int32 sr0 = v_reinterpret_as_s32(r0);
+ v_int32 sr1 = v_reinterpret_as_s32(r1);
+ v_int32 sb0 = v_reinterpret_as_s32(b0);
+ v_int32 sb1 = v_reinterpret_as_s32(b1);
+ v_int32 sy0 = v_reinterpret_as_s32(uy0);
+ v_int32 sy1 = v_reinterpret_as_s32(uy1);
+
+ sr0 = sr0 - sy0; sr1 = sr1 - sy1;
+ sb0 = sb0 - sy0; sb1 = sb1 - sy1;
- if (scn == 3)
+ v_int32 scr0, scr1, scb0, scb1;
+
+ scr0 = (sr0*vc3 + vdd) >> shift;
+ scr1 = (sr1*vc3 + vdd) >> shift;
+ scb0 = (sb0*vc4 + vdd) >> shift;
+ scb1 = (sb1*vc4 + vdd) >> shift;
+
+ // saturate and pack
+ cr = v_pack_u(scr0, scr1);
+ cb = v_pack_u(scb0, scb1);
+
+ if(yuvOrder)
{
- uint16x4x3_t v_src = vld3_u16(src);
- v_src0.val[0] = vreinterpretq_s32_u32(vmovl_u16(v_src.val[0]));
- v_src0.val[1] = vreinterpretq_s32_u32(vmovl_u16(v_src.val[1]));
- v_src0.val[2] = vreinterpretq_s32_u32(vmovl_u16(v_src.val[2]));
+ v_store_interleave(dst, y, cb, cr);
}
else
{
- uint16x4x4_t v_src = vld4_u16(src);
- v_src0.val[0] = vreinterpretq_s32_u32(vmovl_u16(v_src.val[0]));
- v_src0.val[1] = vreinterpretq_s32_u32(vmovl_u16(v_src.val[1]));
- v_src0.val[2] = vreinterpretq_s32_u32(vmovl_u16(v_src.val[2]));
+ v_store_interleave(dst, y, cr, cb);
}
-
- int32x4_t v_Y = vmlaq_s32(vmlaq_s32(vmulq_s32(v_src0.val[0], v_c0), v_src0.val[1], v_c1), v_src0.val[2], v_c2);
- v_Y = vshrq_n_s32(vaddq_s32(v_Y, v_delta2), yuv_shift);
- int32x4_t v_Cr = vmlaq_s32(v_delta, vsubq_s32(v_src0.val[bidx^2], v_Y), v_c3);
- v_Cr = vshrq_n_s32(vaddq_s32(v_Cr, v_delta2), yuv_shift);
- int32x4_t v_Cb = vmlaq_s32(v_delta, vsubq_s32(v_src0.val[bidx], v_Y), v_c4);
- v_Cb = vshrq_n_s32(vaddq_s32(v_Cb, v_delta2), yuv_shift);
-
- v_dst.val[0] = vqmovun_s32(v_Y);
- v_dst.val[1+yuvOrder] = vqmovun_s32(v_Cr);
- v_dst.val[2-yuvOrder] = vqmovun_s32(v_Cb);
-
- vst3_u16(dst + i, v_dst);
}
-
- for ( ; i < n; i += 3, src += scn)
+ vx_cleanup();
+#endif
+ for( ; i < n; i++, src += scn, dst += 3)
{
- int Y = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, yuv_shift);
- int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift);
- int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
- dst[i] = saturate_cast<ushort>(Y);
- dst[i+1+yuvOrder] = saturate_cast<ushort>(Cr);
- dst[i+2-yuvOrder] = saturate_cast<ushort>(Cb);
+ int Y = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, shift);
+ int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + sdelta, shift);
+ int Cb = CV_DESCALE((src[bidx] - Y)*C4 + sdelta, shift);
+ dst[0] = saturate_cast<ushort>(Y);
+ dst[1+yuvOrder] = saturate_cast<ushort>(Cr);
+ dst[2-yuvOrder] = saturate_cast<ushort>(Cb);
}
}
- int srccn, blueIdx, coeffs[5];
+ int srccn, blueIdx;
bool isCrCb;
- int32x4_t v_c0, v_c1, v_c2, v_c3, v_c4, v_delta, v_delta2;
+ int coeffs[5];
};
-#elif CV_SSE4_1
template <>
struct RGB2YCrCb_i<uchar>
{
typedef uchar channel_type;
+ static const int shift = yuv_shift;
RGB2YCrCb_i(int _srccn, int _blueIdx, bool _isCrCb)
: srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
{
static const int coeffs_crb[] = { R2Y, G2Y, B2Y, YCRI, YCBI };
static const int coeffs_yuv[] = { R2Y, G2Y, B2Y, R2VI, B2UI };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
+ for(int i = 0; i < 5; i++)
+ {
+ coeffs[i] = isCrCb ? coeffs_crb[i] : coeffs_yuv[i];
+ }
if (blueIdx==0)
std::swap(coeffs[0], coeffs[2]);
-
- short delta = 1 << (yuv_shift - 1);
- v_delta_16 = _mm_set1_epi16(delta);
- v_delta_32 = _mm_set1_epi32(delta);
- short delta2 = 1 + ColorChannel<uchar>::half() * 2;
- v_coeff = _mm_set_epi16(delta2, (short)coeffs[4], delta2, (short)coeffs[3], delta2, (short)coeffs[4], delta2, (short)coeffs[3]);
- if(isCrCb)
- v_shuffle2 = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0xf, 0xe, 0xc, 0xb, 0xa, 0x8, 0x7, 0x6, 0x4, 0x3, 0x2, 0x0);
- else //if YUV
- v_shuffle2 = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0xe, 0xf, 0xc, 0xa, 0xb, 0x8, 0x6, 0x7, 0x4, 0x2, 0x3, 0x0);
- haveSIMD = checkHardwareSupport(CV_CPU_SSE4_1);
- }
-
- // 16u x 8
- void process(__m128i* v_rgb, __m128i & v_crgb,
- __m128i* v_rb, uchar * dst) const
- {
- v_rgb[0] = _mm_madd_epi16(v_rgb[0], v_crgb);
- v_rgb[1] = _mm_madd_epi16(v_rgb[1], v_crgb);
- v_rgb[2] = _mm_madd_epi16(v_rgb[2], v_crgb);
- v_rgb[3] = _mm_madd_epi16(v_rgb[3], v_crgb);
- v_rgb[0] = _mm_hadd_epi32(v_rgb[0], v_rgb[1]);
- v_rgb[2] = _mm_hadd_epi32(v_rgb[2], v_rgb[3]);
- v_rgb[0] = _mm_add_epi32(v_rgb[0], v_delta_32);
- v_rgb[2] = _mm_add_epi32(v_rgb[2], v_delta_32);
- v_rgb[0] = _mm_srai_epi32(v_rgb[0], yuv_shift);
- v_rgb[2] = _mm_srai_epi32(v_rgb[2], yuv_shift);
- __m128i v_y = _mm_packs_epi32(v_rgb[0], v_rgb[2]);
-
- v_rb[0] = _mm_cvtepu8_epi16(v_rb[0]);
- v_rb[1] = _mm_cvtepu8_epi16(v_rb[1]);
- v_rb[0] = _mm_sub_epi16(v_rb[0], _mm_unpacklo_epi16(v_y, v_y));
- v_rb[1] = _mm_sub_epi16(v_rb[1], _mm_unpackhi_epi16(v_y, v_y));
- v_rgb[0] = _mm_unpacklo_epi16(v_rb[0], v_delta_16);
- v_rgb[1] = _mm_unpackhi_epi16(v_rb[0], v_delta_16);
- v_rgb[2] = _mm_unpacklo_epi16(v_rb[1], v_delta_16);
- v_rgb[3] = _mm_unpackhi_epi16(v_rb[1], v_delta_16);
- v_rgb[0] = _mm_madd_epi16(v_rgb[0], v_coeff);
- v_rgb[1] = _mm_madd_epi16(v_rgb[1], v_coeff);
- v_rgb[2] = _mm_madd_epi16(v_rgb[2], v_coeff);
- v_rgb[3] = _mm_madd_epi16(v_rgb[3], v_coeff);
- v_rgb[0] = _mm_srai_epi32(v_rgb[0], yuv_shift);
- v_rgb[1] = _mm_srai_epi32(v_rgb[1], yuv_shift);
- v_rgb[2] = _mm_srai_epi32(v_rgb[2], yuv_shift);
- v_rgb[3] = _mm_srai_epi32(v_rgb[3], yuv_shift);
- v_rgb[0] = _mm_packs_epi32(v_rgb[0], v_rgb[1]);
- v_rgb[2] = _mm_packs_epi32(v_rgb[2], v_rgb[3]);
- v_rgb[0] = _mm_packus_epi16(v_rgb[0], v_rgb[2]);
-
- v_rb[0] = _mm_unpacklo_epi16(v_y, v_rgb[0]);
- v_rb[1] = _mm_unpackhi_epi16(v_y, v_rgb[0]);
-
- v_rb[0] = _mm_shuffle_epi8(v_rb[0], v_shuffle2);
- v_rb[1] = _mm_shuffle_epi8(v_rb[1], v_shuffle2);
- v_rb[1] = _mm_alignr_epi8(v_rb[1], _mm_slli_si128(v_rb[0], 4), 12);
-
- _mm_storel_epi64((__m128i *)(dst), v_rb[0]);
- _mm_storeu_si128((__m128i *)(dst + 8), v_rb[1]);
}
void operator()(const uchar * src, uchar * dst, int n) const
int scn = srccn, bidx = blueIdx, i = 0;
int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
- int delta = ColorChannel<uchar>::half()*(1 << yuv_shift);
- n *= 3;
-
- if (haveSIMD)
+ int delta = ColorChannel<uchar>::half()*(1 << shift);
+
+#if CV_SIMD
+ const int vsize = v_uint8::nlanes;
+ const int descaleShift = 1 << (shift-1);
+ v_int16 bg2y;
+ v_int16 r12y;
+ v_int16 dummy;
+ v_zip(vx_setall_s16((short)C0), vx_setall_s16((short)C1), bg2y, dummy);
+ v_zip(vx_setall_s16((short)C2), vx_setall_s16( 1), r12y, dummy);
+
+ // delta + descaleShift == descaleShift*(half*2+1)
+ v_int16 c3h, c4h;
+ const short h21 = (short)(ColorChannel<uchar>::half()*2+1);
+ v_zip(vx_setall_s16((short)C3), vx_setall_s16(h21), c3h, dummy);
+ v_zip(vx_setall_s16((short)C4), vx_setall_s16(h21), c4h, dummy);
+
+ v_int16 vdescale = vx_setall_s16(descaleShift);
+
+ for( ; i <= n-vsize;
+ i += vsize, src += scn*vsize, dst += 3*vsize)
{
- __m128i v_shuffle;
- __m128i v_crgb;
- if (scn == 4)
+ v_uint8 r, g, b, a;
+ if(scn == 3)
{
- if (bidx == 0)
- {
- v_shuffle = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xe, 0x8, 0xa, 0x4, 0x6, 0x0, 0x2);
- }
- else
- {
- v_shuffle = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xc, 0xa, 0x8, 0x6, 0x4, 0x2, 0x0);
- }
- v_crgb = _mm_set_epi16(0, (short)C2, (short)C1, (short)C0, 0, (short)C2, (short)C1, (short)C0);
- for ( ; i <= n - 24; i += 24, src += scn * 8)
- {
- __m128i v_src[2];
- v_src[0] = _mm_loadu_si128((__m128i const *)(src));
- v_src[1] = _mm_loadu_si128((__m128i const *)(src + 16));
+ v_load_deinterleave(src, b, g, r);
+ }
+ else
+ {
+ v_load_deinterleave(src, b, g, r, a);
+ }
- __m128i v_rgb[4];
- v_rgb[0] = _mm_cvtepu8_epi16(v_src[0]);
- v_rgb[1] = _mm_cvtepu8_epi16(_mm_srli_si128(v_src[0], 8));
- v_rgb[2] = _mm_cvtepu8_epi16(v_src[1]);
- v_rgb[3] = _mm_cvtepu8_epi16(_mm_srli_si128(v_src[1], 8));
+ v_uint8 y;
- __m128i v_rb[2];
- v_rb[0] = _mm_shuffle_epi8(v_src[0], v_shuffle);
- v_rb[1] = _mm_shuffle_epi8(v_src[1], v_shuffle);
+ v_uint16 r0, r1, g0, g1, b0, b1;
+ v_expand(r, r0, r1);
+ v_expand(g, g0, g1);
+ v_expand(b, b0, b1);
- process(v_rgb, v_crgb, v_rb, dst + i);
- }
- }
- else
+ v_int16 sr0, sr1, sg0, sg1, sb0, sb1;
+ sr0 = v_reinterpret_as_s16(r0); sr1 = v_reinterpret_as_s16(r1);
+ sg0 = v_reinterpret_as_s16(g0); sg1 = v_reinterpret_as_s16(g1);
+ sb0 = v_reinterpret_as_s16(b0); sb1 = v_reinterpret_as_s16(b1);
+
+ v_uint32 y00, y01, y10, y11;
{
- if (bidx == 0)
- {
- v_shuffle = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0xb, 0x6, 0x8, 0x3, 0x5, 0x0, 0x2);
- }
- else
- {
- v_shuffle = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0x9, 0x8, 0x6, 0x5, 0x3, 0x2, 0x0);
- }
- v_crgb = _mm_set_epi16(0, (short)C2, (short)C1, (short)C0, (short)C2, (short)C1, (short)C0, 0);
- for ( ; i <= n - 24; i += 24, src += scn * 8)
- {
- __m128i v_src[2];
- v_src[0] = _mm_loadu_si128((__m128i const *)(src));
- v_src[1] = _mm_loadl_epi64((__m128i const *)(src + 16));
+ v_int16 bg00, bg01, bg10, bg11;
+ v_int16 rd00, rd01, rd10, rd11;
+ v_zip(sb0, sg0, bg00, bg01);
+ v_zip(sb1, sg1, bg10, bg11);
+ v_zip(sr0, vdescale, rd00, rd01);
+ v_zip(sr1, vdescale, rd10, rd11);
+
+ y00 = v_reinterpret_as_u32(v_dotprod(bg00, bg2y) + v_dotprod(rd00, r12y)) >> shift;
+ y01 = v_reinterpret_as_u32(v_dotprod(bg01, bg2y) + v_dotprod(rd01, r12y)) >> shift;
+ y10 = v_reinterpret_as_u32(v_dotprod(bg10, bg2y) + v_dotprod(rd10, r12y)) >> shift;
+ y11 = v_reinterpret_as_u32(v_dotprod(bg11, bg2y) + v_dotprod(rd11, r12y)) >> shift;
+ }
- __m128i v_rgb[4];
- v_rgb[0] = _mm_cvtepu8_epi16(_mm_slli_si128(v_src[0], 1));
- v_rgb[1] = _mm_cvtepu8_epi16(_mm_srli_si128(v_src[0], 5));
- v_rgb[2] = _mm_cvtepu8_epi16(_mm_alignr_epi8(v_src[1], v_src[0], 11));
- v_rgb[3] = _mm_cvtepu8_epi16(_mm_srli_si128(v_src[1], 1));
+ v_uint16 y0, y1;
+ y0 = v_pack(y00, y01);
+ y1 = v_pack(y10, y11);
- __m128i v_rb[2];
- v_rb[0] = _mm_shuffle_epi8(v_src[0], v_shuffle);
- v_rb[1] = _mm_shuffle_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 12), v_shuffle);
+ y = v_pack(y0, y1);
- process(v_rgb, v_crgb, v_rb, dst + i);
- }
+ v_int16 sy0, sy1;
+ sy0 = v_reinterpret_as_s16(y0);
+ sy1 = v_reinterpret_as_s16(y1);
+
+ // (r-Y) and (b-Y) don't fit into 8 bit, use 16 bits instead
+ sr0 = v_sub_wrap(sr0, sy0);
+ sr1 = v_sub_wrap(sr1, sy1);
+ sb0 = v_sub_wrap(sb0, sy0);
+ sb1 = v_sub_wrap(sb1, sy1);
+
+ if(bidx)
+ {
+ swap(sr0, sb0); swap(sr1, sb1);
}
- }
- for ( ; i < n; i += 3, src += scn)
- {
- int Y = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, yuv_shift);
- int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift);
- int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
- dst[i] = saturate_cast<uchar>(Y);
- dst[i+1+yuvOrder] = saturate_cast<uchar>(Cr);
- dst[i+2-yuvOrder] = saturate_cast<uchar>(Cb);
- }
- }
+ v_uint32 cr00, cr01, cr10, cr11;
+ v_uint32 cb00, cb01, cb10, cb11;
- __m128i v_delta_16, v_delta_32;
- __m128i v_coeff;
- __m128i v_shuffle2;
- int srccn, blueIdx, coeffs[5];
- bool isCrCb;
- bool haveSIMD;
-};
+ // delta + descaleShift == descaleShift*(half*2+1)
+ {
+ v_int16 rd00, rd01, rd10, rd11;
+ v_int16 bd00, bd01, bd10, bd11;
-template <>
-struct RGB2YCrCb_i<ushort>
-{
- typedef ushort channel_type;
+ v_zip(sr0, vdescale, rd00, rd01);
+ v_zip(sr1, vdescale, rd10, rd11);
- RGB2YCrCb_i(int _srccn, int _blueIdx, bool _isCrCb)
- : srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
- {
- static const int coeffs_crb[] = { R2Y, G2Y, B2Y, YCRI, YCBI };
- static const int coeffs_yuv[] = { R2Y, G2Y, B2Y, R2VI, B2UI };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
- if (blueIdx==0)
- std::swap(coeffs[0], coeffs[2]);
+ v_zip(sb0, vdescale, bd00, bd01);
+ v_zip(sb1, vdescale, bd10, bd11);
- v_c0 = _mm_set1_epi32(coeffs[0]);
- v_c1 = _mm_set1_epi32(coeffs[1]);
- v_c2 = _mm_set1_epi32(coeffs[2]);
- v_c3 = _mm_set1_epi32(coeffs[3]);
- v_c4 = _mm_set1_epi32(coeffs[4]);
- v_delta2 = _mm_set1_epi32(1 << (yuv_shift - 1));
- v_delta = _mm_set1_epi32(ColorChannel<ushort>::half()*(1 << yuv_shift));
- v_delta = _mm_add_epi32(v_delta, v_delta2);
- v_zero = _mm_setzero_si128();
-
- haveSIMD = checkHardwareSupport(CV_CPU_SSE4_1);
- }
+ cr00 = v_reinterpret_as_u32(v_dotprod(rd00, c3h));
+ cr01 = v_reinterpret_as_u32(v_dotprod(rd01, c3h));
+ cr10 = v_reinterpret_as_u32(v_dotprod(rd10, c3h));
+ cr11 = v_reinterpret_as_u32(v_dotprod(rd11, c3h));
- // 16u x 8
- void process(__m128i v_r, __m128i v_g, __m128i v_b,
- __m128i & v_y, __m128i & v_cr, __m128i & v_cb) const
- {
- __m128i v_r_p = _mm_unpacklo_epi16(v_r, v_zero);
- __m128i v_g_p = _mm_unpacklo_epi16(v_g, v_zero);
- __m128i v_b_p = _mm_unpacklo_epi16(v_b, v_zero);
-
- __m128i v_y0 = _mm_add_epi32(_mm_mullo_epi32(v_r_p, v_c0),
- _mm_add_epi32(_mm_mullo_epi32(v_g_p, v_c1),
- _mm_mullo_epi32(v_b_p, v_c2)));
- v_y0 = _mm_srli_epi32(_mm_add_epi32(v_delta2, v_y0), yuv_shift);
-
- __m128i v_cr0 = _mm_mullo_epi32(_mm_sub_epi32(blueIdx == 2 ? v_r_p : v_b_p, v_y0), v_c3);
- __m128i v_cb0 = _mm_mullo_epi32(_mm_sub_epi32(blueIdx == 0 ? v_r_p : v_b_p, v_y0), v_c4);
- v_cr0 = _mm_srai_epi32(_mm_add_epi32(v_delta, v_cr0), yuv_shift);
- v_cb0 = _mm_srai_epi32(_mm_add_epi32(v_delta, v_cb0), yuv_shift);
-
- v_r_p = _mm_unpackhi_epi16(v_r, v_zero);
- v_g_p = _mm_unpackhi_epi16(v_g, v_zero);
- v_b_p = _mm_unpackhi_epi16(v_b, v_zero);
-
- __m128i v_y1 = _mm_add_epi32(_mm_mullo_epi32(v_r_p, v_c0),
- _mm_add_epi32(_mm_mullo_epi32(v_g_p, v_c1),
- _mm_mullo_epi32(v_b_p, v_c2)));
- v_y1 = _mm_srli_epi32(_mm_add_epi32(v_delta2, v_y1), yuv_shift);
-
- __m128i v_cr1 = _mm_mullo_epi32(_mm_sub_epi32(blueIdx == 2 ? v_r_p : v_b_p, v_y1), v_c3);
- __m128i v_cb1 = _mm_mullo_epi32(_mm_sub_epi32(blueIdx == 0 ? v_r_p : v_b_p, v_y1), v_c4);
- v_cr1 = _mm_srai_epi32(_mm_add_epi32(v_delta, v_cr1), yuv_shift);
- v_cb1 = _mm_srai_epi32(_mm_add_epi32(v_delta, v_cb1), yuv_shift);
-
- v_y = _mm_packus_epi32(v_y0, v_y1);
- v_cr = _mm_packus_epi32(v_cr0, v_cr1);
- v_cb = _mm_packus_epi32(v_cb0, v_cb1);
- }
+ cb00 = v_reinterpret_as_u32(v_dotprod(bd00, c4h));
+ cb01 = v_reinterpret_as_u32(v_dotprod(bd01, c4h));
+ cb10 = v_reinterpret_as_u32(v_dotprod(bd10, c4h));
+ cb11 = v_reinterpret_as_u32(v_dotprod(bd11, c4h));
+ }
- void operator()(const ushort * src, ushort * dst, int n) const
- {
- int scn = srccn, bidx = blueIdx, i = 0;
- int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
- int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
- int delta = ColorChannel<ushort>::half()*(1 << yuv_shift);
- n *= 3;
+ v_uint8 cr, cb;
- if (haveSIMD)
- {
- for ( ; i <= n - 48; i += 48, src += scn * 16)
- {
- __m128i v_r0 = _mm_loadu_si128((__m128i const *)(src));
- __m128i v_r1 = _mm_loadu_si128((__m128i const *)(src + 8));
- __m128i v_g0 = _mm_loadu_si128((__m128i const *)(src + 16));
- __m128i v_g1 = _mm_loadu_si128((__m128i const *)(src + 24));
- __m128i v_b0 = _mm_loadu_si128((__m128i const *)(src + 32));
- __m128i v_b1 = _mm_loadu_si128((__m128i const *)(src + 40));
-
- if (scn == 4)
- {
- __m128i v_a0 = _mm_loadu_si128((__m128i const *)(src + 48));
- __m128i v_a1 = _mm_loadu_si128((__m128i const *)(src + 56));
+ cr00 = cr00 >> shift;
+ cr01 = cr01 >> shift;
+ cr10 = cr10 >> shift;
+ cr11 = cr11 >> shift;
- _mm_deinterleave_epi16(v_r0, v_r1, v_g0, v_g1,
- v_b0, v_b1, v_a0, v_a1);
- }
- else
- _mm_deinterleave_epi16(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
-
- __m128i v_y0 = v_zero, v_cr0 = v_zero, v_cb0 = v_zero;
- process(v_r0, v_g0, v_b0,
- v_y0, v_cr0, v_cb0);
-
- __m128i v_y1 = v_zero, v_cr1 = v_zero, v_cb1 = v_zero;
- process(v_r1, v_g1, v_b1,
- v_y1, v_cr1, v_cb1);
-
- if(isCrCb)
- _mm_interleave_epi16(v_y0, v_y1, v_cr0, v_cr1, v_cb0, v_cb1);
- else //YUV
- _mm_interleave_epi16(v_y0, v_y1, v_cb0, v_cb1, v_cr0, v_cr1);
-
- _mm_storeu_si128((__m128i *)(dst + i), v_y0);
- _mm_storeu_si128((__m128i *)(dst + i + 8), v_y1);
- _mm_storeu_si128((__m128i *)(dst + i + 16 + yuvOrder*16), v_cr0);
- _mm_storeu_si128((__m128i *)(dst + i + 24 + yuvOrder*16), v_cr1);
- _mm_storeu_si128((__m128i *)(dst + i + 32 - yuvOrder*16), v_cb0);
- _mm_storeu_si128((__m128i *)(dst + i + 40 - yuvOrder*16), v_cb1);
+ cb00 = cb00 >> shift;
+ cb01 = cb01 >> shift;
+ cb10 = cb10 >> shift;
+ cb11 = cb11 >> shift;
+
+ v_uint16 cr0, cr1, cb0, cb1;
+ cr0 = v_pack(cr00, cr01); cr1 = v_pack(cr10, cr11);
+ cb0 = v_pack(cb00, cb01); cb1 = v_pack(cb10, cb11);
+
+ cr = v_pack(cr0, cr1);
+ cb = v_pack(cb0, cb1);
+
+ if(yuvOrder)
+ {
+ v_store_interleave(dst, y, cb, cr);
+ }
+ else
+ {
+ v_store_interleave(dst, y, cr, cb);
}
}
+ vx_cleanup();
+#endif
- for ( ; i < n; i += 3, src += scn)
+ for ( ; i < n; i++, src += scn, dst += 3)
{
- int Y = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, yuv_shift);
- int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift);
- int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
- dst[i] = saturate_cast<ushort>(Y);
- dst[i+1+yuvOrder] = saturate_cast<ushort>(Cr);
- dst[i+2-yuvOrder] = saturate_cast<ushort>(Cb);
+ int Y = CV_DESCALE(src[0]*C0 + src[1]*C1 + src[2]*C2, shift);
+ int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, shift);
+ int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, shift);
+ dst[0] = saturate_cast<uchar>(Y);
+ dst[1+yuvOrder] = saturate_cast<uchar>(Cr);
+ dst[2-yuvOrder] = saturate_cast<uchar>(Cb);
}
}
int srccn, blueIdx, coeffs[5];
bool isCrCb;
- __m128i v_c0, v_c1, v_c2;
- __m128i v_c3, v_c4, v_delta, v_delta2;
- __m128i v_zero;
- bool haveSIMD;
};
-#endif // CV_SSE4_1
template<typename _Tp> struct YCrCb2RGB_f
{
{
static const float coeffs_cbr[] = {CR2RF, CR2GF, CB2GF, CB2BF};
static const float coeffs_yuv[] = { V2RF, V2GF, U2GF, U2BF};
- memcpy(coeffs, isCrCb ? coeffs_cbr : coeffs_yuv, 4*sizeof(coeffs[0]));
+ for(int i = 0; i < 4; i++)
+ {
+ coeffs[i] = isCrCb ? coeffs_cbr[i] : coeffs_yuv[i];
+ }
}
void operator()(const _Tp* src, _Tp* dst, int n) const
{
float coeffs[4];
};
-#if CV_NEON
-template <>
+template<>
struct YCrCb2RGB_f<float>
{
typedef float channel_type;
{
static const float coeffs_cbr[] = {CR2RF, CR2GF, CB2GF, CB2BF};
static const float coeffs_yuv[] = { V2RF, V2GF, U2GF, U2BF};
- memcpy(coeffs, isCrCb ? coeffs_cbr : coeffs_yuv, 4*sizeof(coeffs[0]));
-
- v_c0 = vdupq_n_f32(coeffs[0]);
- v_c1 = vdupq_n_f32(coeffs[1]);
- v_c2 = vdupq_n_f32(coeffs[2]);
- v_c3 = vdupq_n_f32(coeffs[3]);
- v_delta = vdupq_n_f32(ColorChannel<float>::half());
- v_alpha = vdupq_n_f32(ColorChannel<float>::max());
- }
-
- void operator()(const float* src, float* dst, int n) const
- {
- int dcn = dstcn, bidx = blueIdx, i = 0;
- int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
- const float delta = ColorChannel<float>::half(), alpha = ColorChannel<float>::max();
- float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
- n *= 3;
-
- if (dcn == 3)
- for ( ; i <= n - 12; i += 12, dst += 12)
- {
- float32x4x3_t v_src = vld3q_f32(src + i), v_dst;
- float32x4_t v_Y = v_src.val[0], v_Cr = v_src.val[1+yuvOrder], v_Cb = v_src.val[2-yuvOrder];
-
- v_dst.val[bidx] = vmlaq_f32(v_Y, vsubq_f32(v_Cb, v_delta), v_c3);
- v_dst.val[1] = vaddq_f32(vmlaq_f32(vmulq_f32(vsubq_f32(v_Cb, v_delta), v_c2), vsubq_f32(v_Cr, v_delta), v_c1), v_Y);
- v_dst.val[bidx^2] = vmlaq_f32(v_Y, vsubq_f32(v_Cr, v_delta), v_c0);
-
- vst3q_f32(dst, v_dst);
- }
- else
- for ( ; i <= n - 12; i += 12, dst += 16)
- {
- float32x4x3_t v_src = vld3q_f32(src + i);
- float32x4x4_t v_dst;
- float32x4_t v_Y = v_src.val[0], v_Cr = v_src.val[1+yuvOrder], v_Cb = v_src.val[2-yuvOrder];
-
- v_dst.val[bidx] = vmlaq_f32(v_Y, vsubq_f32(v_Cb, v_delta), v_c3);
- v_dst.val[1] = vaddq_f32(vmlaq_f32(vmulq_f32(vsubq_f32(v_Cb, v_delta), v_c2), vsubq_f32(v_Cr, v_delta), v_c1), v_Y);
- v_dst.val[bidx^2] = vmlaq_f32(v_Y, vsubq_f32(v_Cr, v_delta), v_c0);
- v_dst.val[3] = v_alpha;
-
- vst4q_f32(dst, v_dst);
- }
-
- for ( ; i < n; i += 3, dst += dcn)
+ for(int i = 0; i < 4; i++)
{
- float Y = src[i], Cr = src[i+1+yuvOrder], Cb = src[i+2-yuvOrder];
-
- float b = Y + (Cb - delta)*C3;
- float g = Y + (Cb - delta)*C2 + (Cr - delta)*C1;
- float r = Y + (Cr - delta)*C0;
-
- dst[bidx] = b; dst[1] = g; dst[bidx^2] = r;
- if( dcn == 4 )
- dst[3] = alpha;
+ coeffs[i] = isCrCb ? coeffs_cbr[i] : coeffs_yuv[i];
}
}
- int dstcn, blueIdx;
- bool isCrCb;
- float coeffs[4];
- float32x4_t v_c0, v_c1, v_c2, v_c3, v_alpha, v_delta;
-};
-
-#elif CV_SSE2
-
-template <>
-struct YCrCb2RGB_f<float>
-{
- typedef float channel_type;
-
- YCrCb2RGB_f(int _dstcn, int _blueIdx, bool _isCrCb)
- : dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
- {
- static const float coeffs_cbr[] = {CR2RF, CR2GF, CB2GF, CB2BF};
- static const float coeffs_yuv[] = { V2RF, V2GF, U2GF, U2BF};
- memcpy(coeffs, isCrCb ? coeffs_cbr : coeffs_yuv, 4*sizeof(coeffs[0]));
-
- v_c0 = _mm_set1_ps(coeffs[0]);
- v_c1 = _mm_set1_ps(coeffs[1]);
- v_c2 = _mm_set1_ps(coeffs[2]);
- v_c3 = _mm_set1_ps(coeffs[3]);
- v_delta = _mm_set1_ps(ColorChannel<float>::half());
- v_alpha = _mm_set1_ps(ColorChannel<float>::max());
-
- haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
- }
-
- void process(__m128 v_y, __m128 v_cr, __m128 v_cb,
- __m128 & v_r, __m128 & v_g, __m128 & v_b) const
- {
- v_cb = _mm_sub_ps(v_cb, v_delta);
- v_cr = _mm_sub_ps(v_cr, v_delta);
-
- if (!isCrCb)
- std::swap(v_cb, v_cr);
-
- v_b = _mm_mul_ps(v_cb, v_c3);
- v_g = _mm_add_ps(_mm_mul_ps(v_cb, v_c2), _mm_mul_ps(v_cr, v_c1));
- v_r = _mm_mul_ps(v_cr, v_c0);
-
- v_b = _mm_add_ps(v_b, v_y);
- v_g = _mm_add_ps(v_g, v_y);
- v_r = _mm_add_ps(v_r, v_y);
-
- if (blueIdx == 0)
- std::swap(v_b, v_r);
- }
void operator()(const float* src, float* dst, int n) const
{
- int dcn = dstcn, bidx = blueIdx, i = 0;
+ int dcn = dstcn, bidx = blueIdx;
int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
const float delta = ColorChannel<float>::half(), alpha = ColorChannel<float>::max();
float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
- n *= 3;
-
- if (haveSIMD)
- {
- for ( ; i <= n - 24; i += 24, dst += 8 * dcn)
- {
- __m128 v_y0 = _mm_loadu_ps(src + i);
- __m128 v_y1 = _mm_loadu_ps(src + i + 4);
- __m128 v_cr0 = _mm_loadu_ps(src + i + 8);
- __m128 v_cr1 = _mm_loadu_ps(src + i + 12);
- __m128 v_cb0 = _mm_loadu_ps(src + i + 16);
- __m128 v_cb1 = _mm_loadu_ps(src + i + 20);
-
- _mm_deinterleave_ps(v_y0, v_y1, v_cr0, v_cr1, v_cb0, v_cb1);
-
- __m128 v_r0, v_g0, v_b0;
- process(v_y0, v_cr0, v_cb0,
- v_r0, v_g0, v_b0);
- __m128 v_r1, v_g1, v_b1;
- process(v_y1, v_cr1, v_cb1,
- v_r1, v_g1, v_b1);
+ int i = 0;
+#if CV_SIMD
+ v_float32 vc0 = vx_setall_f32(C0), vc1 = vx_setall_f32(C1);
+ v_float32 vc2 = vx_setall_f32(C2), vc3 = vx_setall_f32(C3);
+ v_float32 vdelta = vx_setall_f32(delta);
+ v_float32 valpha = vx_setall_f32(alpha);
+ const int vsize = v_float32::nlanes;
+ for( ; i <= n-vsize;
+ i += vsize, src += vsize*3, dst += vsize*dcn)
+ {
+ v_float32 y, cr, cb;
+ if(yuvOrder)
+ v_load_deinterleave(src, y, cb, cr);
+ else
+ v_load_deinterleave(src, y, cr, cb);
- __m128 v_a0 = v_alpha, v_a1 = v_alpha;
+ v_float32 b, g, r;
- if (dcn == 3)
- _mm_interleave_ps(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
- else
- _mm_interleave_ps(v_r0, v_r1, v_g0, v_g1,
- v_b0, v_b1, v_a0, v_a1);
+ cb -= vdelta; cr -= vdelta;
+ b = v_fma(cb, vc3, y);
+ g = v_fma(cr, vc1, v_fma(cb, vc2, y));
+ r = v_fma(cr, vc0, y);
- _mm_storeu_ps(dst, v_r0);
- _mm_storeu_ps(dst + 4, v_r1);
- _mm_storeu_ps(dst + 8, v_g0);
- _mm_storeu_ps(dst + 12, v_g1);
- _mm_storeu_ps(dst + 16, v_b0);
- _mm_storeu_ps(dst + 20, v_b1);
+ if(bidx)
+ swap(r, b);
- if (dcn == 4)
- {
- _mm_storeu_ps(dst + 24, v_a0);
- _mm_storeu_ps(dst + 28, v_a1);
- }
- }
+ if(dcn == 3)
+ v_store_interleave(dst, b, g, r);
+ else
+ v_store_interleave(dst, b, g, r, valpha);
}
-
- for ( ; i < n; i += 3, dst += dcn)
+ vx_cleanup();
+#endif
+ for(; i < n; i++, src += 3, dst += dcn)
{
- float Y = src[i], Cr = src[i+1+yuvOrder], Cb = src[i+2-yuvOrder];
+ float Y = src[0];
+ float Cr = src[1+yuvOrder];
+ float Cb = src[2-yuvOrder];
float b = Y + (Cb - delta)*C3;
float g = Y + (Cb - delta)*C2 + (Cr - delta)*C1;
int dstcn, blueIdx;
bool isCrCb;
float coeffs[4];
-
- __m128 v_c0, v_c1, v_c2, v_c3, v_alpha, v_delta;
- bool haveSIMD;
};
-#endif
template<typename _Tp> struct YCrCb2RGB_i
{
typedef _Tp channel_type;
+ static const int shift = yuv_shift;
YCrCb2RGB_i(int _dstcn, int _blueIdx, bool _isCrCb)
: dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
{
static const int coeffs_crb[] = { CR2RI, CR2GI, CB2GI, CB2BI};
static const int coeffs_yuv[] = { V2RI, V2GI, U2GI, U2BI };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 4*sizeof(coeffs[0]));
+ for(int i = 0; i < 4; i++)
+ {
+ coeffs[i] = isCrCb ? coeffs_crb[i] : coeffs_yuv[i];
+ }
}
void operator()(const _Tp* src, _Tp* dst, int n) const
_Tp Cr = src[i+1+yuvOrder];
_Tp Cb = src[i+2-yuvOrder];
- int b = Y + CV_DESCALE((Cb - delta)*C3, yuv_shift);
- int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift);
- int r = Y + CV_DESCALE((Cr - delta)*C0, yuv_shift);
+ int b = Y + CV_DESCALE((Cb - delta)*C3, shift);
+ int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, shift);
+ int r = Y + CV_DESCALE((Cr - delta)*C0, shift);
dst[bidx] = saturate_cast<_Tp>(b);
dst[1] = saturate_cast<_Tp>(g);
int coeffs[4];
};
-#if CV_NEON
template <>
struct YCrCb2RGB_i<uchar>
{
typedef uchar channel_type;
+ static const int shift = yuv_shift;
YCrCb2RGB_i(int _dstcn, int _blueIdx, bool _isCrCb)
: dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
{
static const int coeffs_crb[] = { CR2RI, CR2GI, CB2GI, CB2BI};
static const int coeffs_yuv[] = { V2RI, V2GI, U2GI, U2BI };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 4*sizeof(coeffs[0]));
-
- v_c0 = vdupq_n_s32(coeffs[0]);
- v_c1 = vdupq_n_s32(coeffs[1]);
- v_c2 = vdupq_n_s32(coeffs[2]);
- v_c3 = vdupq_n_s32(coeffs[3]);
- v_delta = vdup_n_s16(ColorChannel<uchar>::half());
- v_delta2 = vdupq_n_s32(1 << (yuv_shift - 1));
- v_alpha = vdup_n_u8(ColorChannel<uchar>::max());
+ for(int i = 0; i < 4; i++)
+ {
+ coeffs[i] = isCrCb ? coeffs_crb[i] : coeffs_yuv[i];
+ }
}
void operator()(const uchar* src, uchar* dst, int n) const
int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
const uchar delta = ColorChannel<uchar>::half(), alpha = ColorChannel<uchar>::max();
int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
- n *= 3;
- for ( ; i <= n - 24; i += 24, dst += dcn * 8)
+#if CV_SIMD
+ const int vsize = v_uint8::nlanes;
+ v_uint8 valpha = vx_setall_u8(alpha);
+ v_uint8 vdelta = vx_setall_u8(delta);
+ const int descaleShift = 1 << (shift - 1);
+ v_int32 vdescale = vx_setall_s32(descaleShift);
+
+ v_int16 vc0 = vx_setall_s16((short)C0), vc1 = vx_setall_s16((short)C1), vc2 = vx_setall_s16((short)C2);
+ // if YUV then C3 > 2^15, need to subtract it
+ // to fit in short by short multiplication
+ v_int16 vc3 = vx_setall_s16(yuvOrder ? (short)(C3-(1 << 15)) : (short)C3);
+
+ for( ; i <= n-vsize;
+ i += vsize, src += 3*vsize, dst += dcn*vsize)
{
- uint8x8x3_t v_src = vld3_u8(src + i);
- int16x8x3_t v_src16;
- v_src16.val[0] = vreinterpretq_s16_u16(vmovl_u8(v_src.val[0]));
- v_src16.val[1] = vreinterpretq_s16_u16(vmovl_u8(v_src.val[1]));
- v_src16.val[2] = vreinterpretq_s16_u16(vmovl_u8(v_src.val[2]));
-
- int16x4_t v_Y = vget_low_s16(v_src16.val[0]),
- v_Cr = vget_low_s16(v_src16.val[1+yuvOrder]),
- v_Cb = vget_low_s16(v_src16.val[2-yuvOrder]);
-
- int32x4_t v_b0 = vmulq_s32(v_c3, vsubl_s16(v_Cb, v_delta));
- v_b0 = vaddw_s16(vshrq_n_s32(vaddq_s32(v_b0, v_delta2), yuv_shift), v_Y);
- int32x4_t v_g0 = vmlaq_s32(vmulq_s32(vsubl_s16(v_Cr, v_delta), v_c1), vsubl_s16(v_Cb, v_delta), v_c2);
- v_g0 = vaddw_s16(vshrq_n_s32(vaddq_s32(v_g0, v_delta2), yuv_shift), v_Y);
- int32x4_t v_r0 = vmulq_s32(v_c0, vsubl_s16(v_Cr, v_delta));
- v_r0 = vaddw_s16(vshrq_n_s32(vaddq_s32(v_r0, v_delta2), yuv_shift), v_Y);
-
- v_Y = vget_high_s16(v_src16.val[0]);
- v_Cr = vget_high_s16(v_src16.val[1+yuvOrder]);
- v_Cb = vget_high_s16(v_src16.val[2-yuvOrder]);
-
- int32x4_t v_b1 = vmulq_s32(v_c3, vsubl_s16(v_Cb, v_delta));
- v_b1 = vaddw_s16(vshrq_n_s32(vaddq_s32(v_b1, v_delta2), yuv_shift), v_Y);
- int32x4_t v_g1 = vmlaq_s32(vmulq_s32(vsubl_s16(v_Cr, v_delta), v_c1), vsubl_s16(v_Cb, v_delta), v_c2);
- v_g1 = vaddw_s16(vshrq_n_s32(vaddq_s32(v_g1, v_delta2), yuv_shift), v_Y);
- int32x4_t v_r1 = vmulq_s32(v_c0, vsubl_s16(v_Cr, v_delta));
- v_r1 = vaddw_s16(vshrq_n_s32(vaddq_s32(v_r1, v_delta2), yuv_shift), v_Y);
-
- uint8x8_t v_b = vqmovun_s16(vcombine_s16(vmovn_s32(v_b0), vmovn_s32(v_b1)));
- uint8x8_t v_g = vqmovun_s16(vcombine_s16(vmovn_s32(v_g0), vmovn_s32(v_g1)));
- uint8x8_t v_r = vqmovun_s16(vcombine_s16(vmovn_s32(v_r0), vmovn_s32(v_r1)));
-
- if (dcn == 3)
+ v_uint8 y, cr, cb;
+ if(yuvOrder)
{
- uint8x8x3_t v_dst;
- v_dst.val[bidx] = v_b;
- v_dst.val[1] = v_g;
- v_dst.val[bidx^2] = v_r;
- vst3_u8(dst, v_dst);
+ v_load_deinterleave(src, y, cb, cr);
}
else
{
- uint8x8x4_t v_dst;
- v_dst.val[bidx] = v_b;
- v_dst.val[1] = v_g;
- v_dst.val[bidx^2] = v_r;
- v_dst.val[3] = v_alpha;
- vst4_u8(dst, v_dst);
+ v_load_deinterleave(src, y, cr, cb);
}
- }
-
- for ( ; i < n; i += 3, dst += dcn)
- {
- uchar Y = src[i];
- uchar Cr = src[i+1+yuvOrder];
- uchar Cb = src[i+2-yuvOrder];
-
- int b = Y + CV_DESCALE((Cb - delta)*C3, yuv_shift);
- int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift);
- int r = Y + CV_DESCALE((Cr - delta)*C0, yuv_shift);
-
- dst[bidx] = saturate_cast<uchar>(b);
- dst[1] = saturate_cast<uchar>(g);
- dst[bidx^2] = saturate_cast<uchar>(r);
- if( dcn == 4 )
- dst[3] = alpha;
- }
- }
- int dstcn, blueIdx;
- bool isCrCb;
- int coeffs[4];
- int32x4_t v_c0, v_c1, v_c2, v_c3, v_delta2;
- int16x4_t v_delta;
- uint8x8_t v_alpha;
-};
+ cr = v_sub_wrap(cr, vdelta);
+ cb = v_sub_wrap(cb, vdelta);
-template <>
-struct YCrCb2RGB_i<ushort>
-{
- typedef ushort channel_type;
+ v_int8 scr = v_reinterpret_as_s8(cr);
+ v_int8 scb = v_reinterpret_as_s8(cb);
- YCrCb2RGB_i(int _dstcn, int _blueIdx, bool _isCrCb)
- : dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
- {
- static const int coeffs_crb[] = { CR2RI, CR2GI, CB2GI, CB2BI};
- static const int coeffs_yuv[] = { V2RI, V2GI, U2GI, U2BI };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 4*sizeof(coeffs[0]));
-
- v_c0 = vdupq_n_s32(coeffs[0]);
- v_c1 = vdupq_n_s32(coeffs[1]);
- v_c2 = vdupq_n_s32(coeffs[2]);
- v_c3 = vdupq_n_s32(coeffs[3]);
- v_delta = vdupq_n_s32(ColorChannel<ushort>::half());
- v_delta2 = vdupq_n_s32(1 << (yuv_shift - 1));
- v_alpha = vdupq_n_u16(ColorChannel<ushort>::max());
- v_alpha2 = vget_low_u16(v_alpha);
- }
+ v_int16 scr0, scr1, scb0, scb1;
+ v_expand(scr, scr0, scr1);
+ v_expand(scb, scb0, scb1);
- void operator()(const ushort* src, ushort* dst, int n) const
- {
- int dcn = dstcn, bidx = blueIdx, i = 0;
- int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
- const ushort delta = ColorChannel<ushort>::half(), alpha = ColorChannel<ushort>::max();
- int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
- n *= 3;
+ v_int32 b00, b01, b10, b11;
+ v_int32 g00, g01, g10, g11;
+ v_int32 r00, r01, r10, r11;
- for ( ; i <= n - 24; i += 24, dst += dcn * 8)
- {
- uint16x8x3_t v_src = vld3q_u16(src + i);
-
- int32x4_t v_Y = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(v_src.val[0]))),
- v_Cr = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(v_src.val[1+yuvOrder]))),
- v_Cb = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(v_src.val[2-yuvOrder])));
-
- int32x4_t v_b0 = vmulq_s32(v_c3, vsubq_s32(v_Cb, v_delta));
- v_b0 = vaddq_s32(vshrq_n_s32(vaddq_s32(v_b0, v_delta2), yuv_shift), v_Y);
- int32x4_t v_g0 = vmlaq_s32(vmulq_s32(vsubq_s32(v_Cr, v_delta), v_c1), vsubq_s32(v_Cb, v_delta), v_c2);
- v_g0 = vaddq_s32(vshrq_n_s32(vaddq_s32(v_g0, v_delta2), yuv_shift), v_Y);
- int32x4_t v_r0 = vmulq_s32(v_c0, vsubq_s32(v_Cr, v_delta));
- v_r0 = vaddq_s32(vshrq_n_s32(vaddq_s32(v_r0, v_delta2), yuv_shift), v_Y);
-
- v_Y = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(v_src.val[0]))),
- v_Cr = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(v_src.val[1+yuvOrder]))),
- v_Cb = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(v_src.val[2-yuvOrder])));
-
- int32x4_t v_b1 = vmulq_s32(v_c3, vsubq_s32(v_Cb, v_delta));
- v_b1 = vaddq_s32(vshrq_n_s32(vaddq_s32(v_b1, v_delta2), yuv_shift), v_Y);
- int32x4_t v_g1 = vmlaq_s32(vmulq_s32(vsubq_s32(v_Cr, v_delta), v_c1), vsubq_s32(v_Cb, v_delta), v_c2);
- v_g1 = vaddq_s32(vshrq_n_s32(vaddq_s32(v_g1, v_delta2), yuv_shift), v_Y);
- int32x4_t v_r1 = vmulq_s32(v_c0, vsubq_s32(v_Cr, v_delta));
- v_r1 = vaddq_s32(vshrq_n_s32(vaddq_s32(v_r1, v_delta2), yuv_shift), v_Y);
-
- uint16x8_t v_b = vcombine_u16(vqmovun_s32(v_b0), vqmovun_s32(v_b1));
- uint16x8_t v_g = vcombine_u16(vqmovun_s32(v_g0), vqmovun_s32(v_g1));
- uint16x8_t v_r = vcombine_u16(vqmovun_s32(v_r0), vqmovun_s32(v_r1));
-
- if (dcn == 3)
+ v_mul_expand(scb0, vc3, b00, b01);
+ v_mul_expand(scb1, vc3, b10, b11);
+ if(yuvOrder)
{
- uint16x8x3_t v_dst;
- v_dst.val[bidx] = v_b;
- v_dst.val[1] = v_g;
- v_dst.val[bidx^2] = v_r;
- vst3q_u16(dst, v_dst);
+ // if YUV then C3 > 2^15
+ // so we fix the multiplication
+ v_int32 cb00, cb01, cb10, cb11;
+ v_expand(scb0, cb00, cb01);
+ v_expand(scb1, cb10, cb11);
+ b00 += cb00 << 15; b01 += cb01 << 15;
+ b10 += cb10 << 15; b11 += cb11 << 15;
}
- else
- {
- uint16x8x4_t v_dst;
- v_dst.val[bidx] = v_b;
- v_dst.val[1] = v_g;
- v_dst.val[bidx^2] = v_r;
- v_dst.val[3] = v_alpha;
- vst4q_u16(dst, v_dst);
- }
- }
- for ( ; i <= n - 12; i += 12, dst += dcn * 4)
- {
- uint16x4x3_t v_src = vld3_u16(src + i);
-
- int32x4_t v_Y = vreinterpretq_s32_u32(vmovl_u16(v_src.val[0])),
- v_Cr = vreinterpretq_s32_u32(vmovl_u16(v_src.val[1+yuvOrder])),
- v_Cb = vreinterpretq_s32_u32(vmovl_u16(v_src.val[2-yuvOrder]));
-
- int32x4_t v_b = vmulq_s32(v_c3, vsubq_s32(v_Cb, v_delta));
- v_b = vaddq_s32(vshrq_n_s32(vaddq_s32(v_b, v_delta2), yuv_shift), v_Y);
- int32x4_t v_g = vmlaq_s32(vmulq_s32(vsubq_s32(v_Cr, v_delta), v_c1), vsubq_s32(v_Cb, v_delta), v_c2);
- v_g = vaddq_s32(vshrq_n_s32(vaddq_s32(v_g, v_delta2), yuv_shift), v_Y);
- int32x4_t v_r = vmulq_s32(vsubq_s32(v_Cr, v_delta), v_c0);
- v_r = vaddq_s32(vshrq_n_s32(vaddq_s32(v_r, v_delta2), yuv_shift), v_Y);
-
- uint16x4_t v_bd = vqmovun_s32(v_b);
- uint16x4_t v_gd = vqmovun_s32(v_g);
- uint16x4_t v_rd = vqmovun_s32(v_r);
-
- if (dcn == 3)
+ v_int32 t00, t01, t10, t11;
+ v_mul_expand(scb0, vc2, t00, t01);
+ v_mul_expand(scb1, vc2, t10, t11);
+ v_mul_expand(scr0, vc1, g00, g01);
+ v_mul_expand(scr1, vc1, g10, g11);
+ g00 += t00; g01 += t01;
+ g10 += t10; g11 += t11;
+ v_mul_expand(scr0, vc0, r00, r01);
+ v_mul_expand(scr1, vc0, r10, r11);
+
+ b00 = (b00 + vdescale) >> shift; b01 = (b01 + vdescale) >> shift;
+ b10 = (b10 + vdescale) >> shift; b11 = (b11 + vdescale) >> shift;
+ g00 = (g00 + vdescale) >> shift; g01 = (g01 + vdescale) >> shift;
+ g10 = (g10 + vdescale) >> shift; g11 = (g11 + vdescale) >> shift;
+ r00 = (r00 + vdescale) >> shift; r01 = (r01 + vdescale) >> shift;
+ r10 = (r10 + vdescale) >> shift; r11 = (r11 + vdescale) >> shift;
+
+ v_int16 b0, b1, g0, g1, r0, r1;
+ b0 = v_pack(b00, b01); b1 = v_pack(b10, b11);
+ g0 = v_pack(g00, g01); g1 = v_pack(g10, g11);
+ r0 = v_pack(r00, r01); r1 = v_pack(r10, r11);
+
+ v_uint16 y0, y1;
+ v_expand(y, y0, y1);
+ v_int16 sy0, sy1;
+ sy0 = v_reinterpret_as_s16(y0);
+ sy1 = v_reinterpret_as_s16(y1);
+
+ b0 = v_add_wrap(b0, sy0); b1 = v_add_wrap(b1, sy1);
+ g0 = v_add_wrap(g0, sy0); g1 = v_add_wrap(g1, sy1);
+ r0 = v_add_wrap(r0, sy0); r1 = v_add_wrap(r1, sy1);
+
+ v_uint8 b, g, r;
+ b = v_pack_u(b0, b1);
+ g = v_pack_u(g0, g1);
+ r = v_pack_u(r0, r1);
+
+ if(bidx)
+ swap(r, b);
+
+ if(dcn == 3)
{
- uint16x4x3_t v_dst;
- v_dst.val[bidx] = v_bd;
- v_dst.val[1] = v_gd;
- v_dst.val[bidx^2] = v_rd;
- vst3_u16(dst, v_dst);
+ v_store_interleave(dst, b, g, r);
}
else
{
- uint16x4x4_t v_dst;
- v_dst.val[bidx] = v_bd;
- v_dst.val[1] = v_gd;
- v_dst.val[bidx^2] = v_rd;
- v_dst.val[3] = v_alpha2;
- vst4_u16(dst, v_dst);
+ v_store_interleave(dst, b, g, r, valpha);
}
}
+ vx_cleanup();
+#endif
- for ( ; i < n; i += 3, dst += dcn)
+ for ( ; i < n; i++, src += 3, dst += dcn)
{
- ushort Y = src[i];
- ushort Cr = src[i+1+yuvOrder];
- ushort Cb = src[i+2-yuvOrder];
+ uchar Y = src[0];
+ uchar Cr = src[1+yuvOrder];
+ uchar Cb = src[2-yuvOrder];
- int b = Y + CV_DESCALE((Cb - delta)*C3, yuv_shift);
- int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift);
- int r = Y + CV_DESCALE((Cr - delta)*C0, yuv_shift);
+ int b = Y + CV_DESCALE((Cb - delta)*C3, shift);
+ int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, shift);
+ int r = Y + CV_DESCALE((Cr - delta)*C0, shift);
- dst[bidx] = saturate_cast<ushort>(b);
- dst[1] = saturate_cast<ushort>(g);
- dst[bidx^2] = saturate_cast<ushort>(r);
+ dst[bidx] = saturate_cast<uchar>(b);
+ dst[1] = saturate_cast<uchar>(g);
+ dst[bidx^2] = saturate_cast<uchar>(r);
if( dcn == 4 )
dst[3] = alpha;
}
int dstcn, blueIdx;
bool isCrCb;
int coeffs[4];
-
- int32x4_t v_c0, v_c1, v_c2, v_c3, v_delta2, v_delta;
- uint16x8_t v_alpha;
- uint16x4_t v_alpha2;
};
-#elif CV_SSE2
template <>
-struct YCrCb2RGB_i<uchar>
+struct YCrCb2RGB_i<ushort>
{
- typedef uchar channel_type;
+ typedef ushort channel_type;
+ static const int shift = yuv_shift;
YCrCb2RGB_i(int _dstcn, int _blueIdx, bool _isCrCb)
: dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
{
static const int coeffs_crb[] = { CR2RI, CR2GI, CB2GI, CB2BI};
static const int coeffs_yuv[] = { V2RI, V2GI, U2GI, U2BI };
- memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 4*sizeof(coeffs[0]));
-
- v_c0 = _mm_set1_epi16((short)coeffs[0]);
- v_c1 = _mm_set1_epi16((short)coeffs[1]);
- v_c2 = _mm_set1_epi16((short)coeffs[2]);
- v_c3 = _mm_set1_epi16((short)coeffs[3]);
- v_delta = _mm_set1_epi16(ColorChannel<uchar>::half());
- v_delta2 = _mm_set1_epi32(1 << (yuv_shift - 1));
- v_zero = _mm_setzero_si128();
-
- uchar alpha = ColorChannel<uchar>::max();
- v_alpha = _mm_set1_epi8(*(char *)&alpha);
-
- // when using YUV, one of coefficients is bigger than std::numeric_limits<short>::max(),
- //which is not appropriate for SSE
- useSSE = isCrCb;
- haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
- }
-
-#if CV_SSE4_1
- // 16s x 8
- void process(__m128i* v_src, __m128i* v_shuffle,
- __m128i* v_coeffs) const
- {
- __m128i v_ycrcb[3];
- v_ycrcb[0] = _mm_shuffle_epi8(v_src[0], v_shuffle[0]);
- v_ycrcb[1] = _mm_shuffle_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 8), v_shuffle[0]);
- v_ycrcb[2] = _mm_shuffle_epi8(v_src[1], v_shuffle[0]);
-
- __m128i v_y[3];
- v_y[1] = _mm_shuffle_epi8(v_src[0], v_shuffle[1]);
- v_y[2] = _mm_srli_si128(_mm_shuffle_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 15), v_shuffle[1]), 1);
- v_y[0] = _mm_unpacklo_epi8(v_y[1], v_zero);
- v_y[1] = _mm_unpackhi_epi8(v_y[1], v_zero);
- v_y[2] = _mm_unpacklo_epi8(v_y[2], v_zero);
-
- __m128i v_rgb[6];
- v_rgb[0] = _mm_unpacklo_epi8(v_ycrcb[0], v_zero);
- v_rgb[1] = _mm_unpackhi_epi8(v_ycrcb[0], v_zero);
- v_rgb[2] = _mm_unpacklo_epi8(v_ycrcb[1], v_zero);
- v_rgb[3] = _mm_unpackhi_epi8(v_ycrcb[1], v_zero);
- v_rgb[4] = _mm_unpacklo_epi8(v_ycrcb[2], v_zero);
- v_rgb[5] = _mm_unpackhi_epi8(v_ycrcb[2], v_zero);
-
- v_rgb[0] = _mm_sub_epi16(v_rgb[0], v_delta);
- v_rgb[1] = _mm_sub_epi16(v_rgb[1], v_delta);
- v_rgb[2] = _mm_sub_epi16(v_rgb[2], v_delta);
- v_rgb[3] = _mm_sub_epi16(v_rgb[3], v_delta);
- v_rgb[4] = _mm_sub_epi16(v_rgb[4], v_delta);
- v_rgb[5] = _mm_sub_epi16(v_rgb[5], v_delta);
-
- v_rgb[0] = _mm_madd_epi16(v_rgb[0], v_coeffs[0]);
- v_rgb[1] = _mm_madd_epi16(v_rgb[1], v_coeffs[1]);
- v_rgb[2] = _mm_madd_epi16(v_rgb[2], v_coeffs[2]);
- v_rgb[3] = _mm_madd_epi16(v_rgb[3], v_coeffs[0]);
- v_rgb[4] = _mm_madd_epi16(v_rgb[4], v_coeffs[1]);
- v_rgb[5] = _mm_madd_epi16(v_rgb[5], v_coeffs[2]);
-
- v_rgb[0] = _mm_add_epi32(v_rgb[0], v_delta2);
- v_rgb[1] = _mm_add_epi32(v_rgb[1], v_delta2);
- v_rgb[2] = _mm_add_epi32(v_rgb[2], v_delta2);
- v_rgb[3] = _mm_add_epi32(v_rgb[3], v_delta2);
- v_rgb[4] = _mm_add_epi32(v_rgb[4], v_delta2);
- v_rgb[5] = _mm_add_epi32(v_rgb[5], v_delta2);
-
- v_rgb[0] = _mm_srai_epi32(v_rgb[0], yuv_shift);
- v_rgb[1] = _mm_srai_epi32(v_rgb[1], yuv_shift);
- v_rgb[2] = _mm_srai_epi32(v_rgb[2], yuv_shift);
- v_rgb[3] = _mm_srai_epi32(v_rgb[3], yuv_shift);
- v_rgb[4] = _mm_srai_epi32(v_rgb[4], yuv_shift);
- v_rgb[5] = _mm_srai_epi32(v_rgb[5], yuv_shift);
-
- v_rgb[0] = _mm_packs_epi32(v_rgb[0], v_rgb[1]);
- v_rgb[2] = _mm_packs_epi32(v_rgb[2], v_rgb[3]);
- v_rgb[4] = _mm_packs_epi32(v_rgb[4], v_rgb[5]);
-
- v_rgb[0] = _mm_add_epi16(v_rgb[0], v_y[0]);
- v_rgb[2] = _mm_add_epi16(v_rgb[2], v_y[1]);
- v_rgb[4] = _mm_add_epi16(v_rgb[4], v_y[2]);
-
- v_src[0] = _mm_packus_epi16(v_rgb[0], v_rgb[2]);
- v_src[1] = _mm_packus_epi16(v_rgb[4], v_rgb[4]);
- }
-#endif // CV_SSE4_1
-
- // 16s x 8
- void process(__m128i v_y, __m128i v_cr, __m128i v_cb,
- __m128i & v_r, __m128i & v_g, __m128i & v_b) const
- {
- v_cr = _mm_sub_epi16(v_cr, v_delta);
- v_cb = _mm_sub_epi16(v_cb, v_delta);
-
- __m128i v_y_p = _mm_unpacklo_epi16(v_y, v_zero);
-
- __m128i v_mullo_3 = _mm_mullo_epi16(v_cb, v_c3);
- __m128i v_mullo_2 = _mm_mullo_epi16(v_cb, v_c2);
- __m128i v_mullo_1 = _mm_mullo_epi16(v_cr, v_c1);
- __m128i v_mullo_0 = _mm_mullo_epi16(v_cr, v_c0);
-
- __m128i v_mulhi_3 = _mm_mulhi_epi16(v_cb, v_c3);
- __m128i v_mulhi_2 = _mm_mulhi_epi16(v_cb, v_c2);
- __m128i v_mulhi_1 = _mm_mulhi_epi16(v_cr, v_c1);
- __m128i v_mulhi_0 = _mm_mulhi_epi16(v_cr, v_c0);
-
- __m128i v_b0 = _mm_srai_epi32(_mm_add_epi32(_mm_unpacklo_epi16(v_mullo_3, v_mulhi_3), v_delta2), yuv_shift);
- __m128i v_g0 = _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(_mm_unpacklo_epi16(v_mullo_2, v_mulhi_2),
- _mm_unpacklo_epi16(v_mullo_1, v_mulhi_1)), v_delta2),
- yuv_shift);
- __m128i v_r0 = _mm_srai_epi32(_mm_add_epi32(_mm_unpacklo_epi16(v_mullo_0, v_mulhi_0), v_delta2), yuv_shift);
-
- v_r0 = _mm_add_epi32(v_r0, v_y_p);
- v_g0 = _mm_add_epi32(v_g0, v_y_p);
- v_b0 = _mm_add_epi32(v_b0, v_y_p);
-
- v_y_p = _mm_unpackhi_epi16(v_y, v_zero);
-
- __m128i v_b1 = _mm_srai_epi32(_mm_add_epi32(_mm_unpackhi_epi16(v_mullo_3, v_mulhi_3), v_delta2), yuv_shift);
- __m128i v_g1 = _mm_srai_epi32(_mm_add_epi32(_mm_add_epi32(_mm_unpackhi_epi16(v_mullo_2, v_mulhi_2),
- _mm_unpackhi_epi16(v_mullo_1, v_mulhi_1)), v_delta2),
- yuv_shift);
- __m128i v_r1 = _mm_srai_epi32(_mm_add_epi32(_mm_unpackhi_epi16(v_mullo_0, v_mulhi_0), v_delta2), yuv_shift);
-
- v_r1 = _mm_add_epi32(v_r1, v_y_p);
- v_g1 = _mm_add_epi32(v_g1, v_y_p);
- v_b1 = _mm_add_epi32(v_b1, v_y_p);
-
- v_r = _mm_packs_epi32(v_r0, v_r1);
- v_g = _mm_packs_epi32(v_g0, v_g1);
- v_b = _mm_packs_epi32(v_b0, v_b1);
+ for(int i = 0; i < 4; i++)
+ {
+ coeffs[i] = isCrCb ? coeffs_crb[i] : coeffs_yuv[i];
+ }
}
- void operator()(const uchar* src, uchar* dst, int n) const
+ void operator()(const ushort* src, ushort* dst, int n) const
{
int dcn = dstcn, bidx = blueIdx, i = 0;
int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
- const uchar delta = ColorChannel<uchar>::half(), alpha = ColorChannel<uchar>::max();
+ const ushort delta = ColorChannel<ushort>::half(), alpha = ColorChannel<ushort>::max();
int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
- n *= 3;
-#if CV_SSE4_1
- if (checkHardwareSupport(CV_CPU_SSE4_1) && useSSE)
+#if CV_SIMD
+ const int vsize = v_uint16::nlanes;
+ const int descaleShift = 1 << (shift-1);
+ v_uint16 valpha = vx_setall_u16(alpha);
+ v_uint16 vdelta = vx_setall_u16(delta);
+ v_int16 vc0 = vx_setall_s16((short)C0), vc1 = vx_setall_s16((short)C1), vc2 = vx_setall_s16((short)C2);
+ // if YUV then C3 > 2^15, need to subtract it
+ // to fit in short by short multiplication
+ v_int16 vc3 = vx_setall_s16(yuvOrder ? (short)(C3-(1 << 15)) : (short)C3);
+ v_int32 vdescale = vx_setall_s32(descaleShift);
+ for(; i <= n-vsize;
+ i += vsize, src += vsize*3, dst += vsize*dcn)
{
- __m128i v_shuffle[2];
- v_shuffle[0] = _mm_set_epi8(0x8, 0x7, 0x7, 0x6, 0x6, 0x5, 0x5, 0x4, 0x4, 0x3, 0x3, 0x2, 0x2, 0x1, 0x1, 0x0);
- v_shuffle[1] = _mm_set_epi8(0xf, 0xc, 0xc, 0xc, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0);
- __m128i v_coeffs[3];
- v_coeffs[0] = _mm_set_epi16((short)C0, 0, 0, (short)C3, (short)C2, (short)C1, (short)C0, 0);
- v_coeffs[1] = _mm_set_epi16((short)C2, (short)C1, (short)C0, 0, 0, (short)C3, (short)C2, (short)C1);
- v_coeffs[2] = _mm_set_epi16(0, (short)C3, (short)C2, (short)C1, (short)C0, 0, 0, (short)C3);
-
- if (dcn == 3)
+ v_uint16 y, cr, cb;
+ if(yuvOrder)
{
- if (bidx == 0)
- {
- __m128i v_shuffle_dst = _mm_set_epi8(0xf, 0xc, 0xd, 0xe, 0x9, 0xa, 0xb, 0x6, 0x7, 0x8, 0x3, 0x4, 0x5, 0x0, 0x1, 0x2);
- for ( ; i <= n - 24; i += 24, dst += dcn * 8)
- {
- __m128i v_src[2];
- v_src[0] = _mm_loadu_si128((__m128i const *)(src + i));
- v_src[1] = _mm_loadl_epi64((__m128i const *)(src + i + 16));
-
- process(v_src, v_shuffle, v_coeffs);
-
- __m128i v_dst[2];
- v_dst[0] = _mm_shuffle_epi8(v_src[0], v_shuffle_dst);
- v_dst[1] = _mm_shuffle_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 15), v_shuffle_dst);
-
- _mm_storeu_si128((__m128i *)(dst), _mm_alignr_epi8(v_dst[1], _mm_slli_si128(v_dst[0], 1), 1));
- _mm_storel_epi64((__m128i *)(dst + 16), _mm_srli_si128(v_dst[1], 1));
- }
- }
- else
- {
- for ( ; i <= n - 24; i += 24, dst += dcn * 8)
- {
- __m128i v_src[2];
- v_src[0] = _mm_loadu_si128((__m128i const *)(src + i));
- v_src[1] = _mm_loadl_epi64((__m128i const *)(src + i + 16));
-
- process(v_src, v_shuffle, v_coeffs);
-
- _mm_storeu_si128((__m128i *)(dst), v_src[0]);
- _mm_storel_epi64((__m128i *)(dst + 16), v_src[1]);
- }
- }
+ v_load_deinterleave(src, y, cb, cr);
}
else
{
- if (bidx == 0)
- {
- __m128i v_shuffle_dst = _mm_set_epi8(0x0, 0xa, 0xb, 0xc, 0x0, 0x7, 0x8, 0x9, 0x0, 0x4, 0x5, 0x6, 0x0, 0x1, 0x2, 0x3);
-
- for ( ; i <= n - 24; i += 24, dst += dcn * 8)
- {
- __m128i v_src[2];
- v_src[0] = _mm_loadu_si128((__m128i const *)(src + i));
- v_src[1] = _mm_loadl_epi64((__m128i const *)(src + i + 16));
-
- process(v_src, v_shuffle, v_coeffs);
+ v_load_deinterleave(src, y, cr, cb);
+ }
- _mm_storeu_si128((__m128i *)(dst), _mm_shuffle_epi8(_mm_alignr_epi8(v_src[0], v_alpha, 15), v_shuffle_dst));
- _mm_storeu_si128((__m128i *)(dst + 16), _mm_shuffle_epi8(_mm_alignr_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 12), v_alpha, 15), v_shuffle_dst));
- }
- }
- else
- {
- __m128i v_shuffle_dst = _mm_set_epi8(0x0, 0xc, 0xb, 0xa, 0x0, 0x9, 0x8, 0x7, 0x0, 0x6, 0x5, 0x4, 0x0, 0x3, 0x2, 0x1);
+ v_uint32 uy0, uy1;
+ v_expand(y, uy0, uy1);
+ v_int32 y0 = v_reinterpret_as_s32(uy0);
+ v_int32 y1 = v_reinterpret_as_s32(uy1);
- for ( ; i <= n - 24; i += 24, dst += dcn * 8)
- {
- __m128i v_src[2];
- v_src[0] = _mm_loadu_si128((__m128i const *)(src + i));
- v_src[1] = _mm_loadl_epi64((__m128i const *)(src + i + 16));
+ cr = v_sub_wrap(cr, vdelta);
+ cb = v_sub_wrap(cb, vdelta);
- process(v_src, v_shuffle, v_coeffs);
+ v_int32 b0, b1, g0, g1, r0, r1;
- _mm_storeu_si128((__m128i *)(dst), _mm_shuffle_epi8(_mm_alignr_epi8(v_src[0], v_alpha, 15), v_shuffle_dst));
- _mm_storeu_si128((__m128i *)(dst + 16), _mm_shuffle_epi8(_mm_alignr_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 12), v_alpha, 15), v_shuffle_dst));
- }
- }
+ v_int16 scb = v_reinterpret_as_s16(cb);
+ v_int16 scr = v_reinterpret_as_s16(cr);
+ v_mul_expand(scb, vc3, b0, b1);
+ if(yuvOrder)
+ {
+ // if YUV then C3 > 2^15
+ // so we fix the multiplication
+ v_int32 cb0, cb1;
+ v_expand(scb, cb0, cb1);
+ b0 += cb0 << 15;
+ b1 += cb1 << 15;
}
- }
- else
-#endif // CV_SSE4_1
- if (haveSIMD && useSSE)
- {
- for ( ; i <= n - 96; i += 96, dst += dcn * 32)
+ v_int32 t0, t1;
+ v_mul_expand(scb, vc2, t0, t1);
+ v_mul_expand(scr, vc1, g0, g1);
+ g0 += t0; g1 += t1;
+ v_mul_expand(scr, vc0, r0, r1);
+
+ // shifted term doesn't fit into 16 bits, addition is to be done in 32 bits
+ b0 = ((b0 + vdescale) >> shift) + y0;
+ b1 = ((b1 + vdescale) >> shift) + y1;
+ g0 = ((g0 + vdescale) >> shift) + y0;
+ g1 = ((g1 + vdescale) >> shift) + y1;
+ r0 = ((r0 + vdescale) >> shift) + y0;
+ r1 = ((r1 + vdescale) >> shift) + y1;
+
+ // saturate and pack
+ v_uint16 b, g, r;
+ b = v_pack_u(b0, b1);
+ g = v_pack_u(g0, g1);
+ r = v_pack_u(r0, r1);
+
+ if(bidx)
+ swap(r, b);
+
+ if(dcn == 3)
{
- __m128i v_y0 = _mm_loadu_si128((__m128i const *)(src + i));
- __m128i v_y1 = _mm_loadu_si128((__m128i const *)(src + i + 16));
- __m128i v_cr0 = _mm_loadu_si128((__m128i const *)(src + i + 32));
- __m128i v_cr1 = _mm_loadu_si128((__m128i const *)(src + i + 48));
- __m128i v_cb0 = _mm_loadu_si128((__m128i const *)(src + i + 64));
- __m128i v_cb1 = _mm_loadu_si128((__m128i const *)(src + i + 80));
-
- _mm_deinterleave_epi8(v_y0, v_y1, v_cr0, v_cr1, v_cb0, v_cb1);
-
- __m128i v_r_0 = v_zero, v_g_0 = v_zero, v_b_0 = v_zero;
- process(_mm_unpacklo_epi8(v_y0, v_zero),
- _mm_unpacklo_epi8(v_cr0, v_zero),
- _mm_unpacklo_epi8(v_cb0, v_zero),
- v_r_0, v_g_0, v_b_0);
-
- __m128i v_r_1 = v_zero, v_g_1 = v_zero, v_b_1 = v_zero;
- process(_mm_unpackhi_epi8(v_y0, v_zero),
- _mm_unpackhi_epi8(v_cr0, v_zero),
- _mm_unpackhi_epi8(v_cb0, v_zero),
- v_r_1, v_g_1, v_b_1);
-
- __m128i v_r0 = _mm_packus_epi16(v_r_0, v_r_1);
- __m128i v_g0 = _mm_packus_epi16(v_g_0, v_g_1);
- __m128i v_b0 = _mm_packus_epi16(v_b_0, v_b_1);
-
- process(_mm_unpacklo_epi8(v_y1, v_zero),
- _mm_unpacklo_epi8(v_cr1, v_zero),
- _mm_unpacklo_epi8(v_cb1, v_zero),
- v_r_0, v_g_0, v_b_0);
-
- process(_mm_unpackhi_epi8(v_y1, v_zero),
- _mm_unpackhi_epi8(v_cr1, v_zero),
- _mm_unpackhi_epi8(v_cb1, v_zero),
- v_r_1, v_g_1, v_b_1);
-
- __m128i v_r1 = _mm_packus_epi16(v_r_0, v_r_1);
- __m128i v_g1 = _mm_packus_epi16(v_g_0, v_g_1);
- __m128i v_b1 = _mm_packus_epi16(v_b_0, v_b_1);
-
- if (bidx == 0)
- {
- std::swap(v_r0, v_b0);
- std::swap(v_r1, v_b1);
- }
-
- __m128i v_a0 = v_alpha, v_a1 = v_alpha;
-
- if (dcn == 3)
- _mm_interleave_epi8(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
- else
- _mm_interleave_epi8(v_r0, v_r1, v_g0, v_g1,
- v_b0, v_b1, v_a0, v_a1);
-
- _mm_storeu_si128((__m128i *)(dst), v_r0);
- _mm_storeu_si128((__m128i *)(dst + 16), v_r1);
- _mm_storeu_si128((__m128i *)(dst + 32), v_g0);
- _mm_storeu_si128((__m128i *)(dst + 48), v_g1);
- _mm_storeu_si128((__m128i *)(dst + 64), v_b0);
- _mm_storeu_si128((__m128i *)(dst + 80), v_b1);
-
- if (dcn == 4)
- {
- _mm_storeu_si128((__m128i *)(dst + 96), v_a0);
- _mm_storeu_si128((__m128i *)(dst + 112), v_a1);
- }
+ v_store_interleave(dst, b, g, r);
+ }
+ else
+ {
+ v_store_interleave(dst, b, g, r, valpha);
}
}
+ vx_cleanup();
+#endif
- for ( ; i < n; i += 3, dst += dcn)
+ for ( ; i < n; i++, src += 3, dst += dcn)
{
- uchar Y = src[i];
- uchar Cr = src[i+1+yuvOrder];
- uchar Cb = src[i+2-yuvOrder];
+ ushort Y = src[0];
+ ushort Cr = src[1+yuvOrder];
+ ushort Cb = src[2-yuvOrder];
- int b = Y + CV_DESCALE((Cb - delta)*C3, yuv_shift);
- int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift);
- int r = Y + CV_DESCALE((Cr - delta)*C0, yuv_shift);
+ int b = Y + CV_DESCALE((Cb - delta)*C3, shift);
+ int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, shift);
+ int r = Y + CV_DESCALE((Cr - delta)*C0, shift);
- dst[bidx] = saturate_cast<uchar>(b);
- dst[1] = saturate_cast<uchar>(g);
- dst[bidx^2] = saturate_cast<uchar>(r);
+ dst[bidx] = saturate_cast<ushort>(b);
+ dst[1] = saturate_cast<ushort>(g);
+ dst[bidx^2] = saturate_cast<ushort>(r);
if( dcn == 4 )
dst[3] = alpha;
}
}
int dstcn, blueIdx;
- int coeffs[4];
bool isCrCb;
- bool useSSE, haveSIMD;
-
- __m128i v_c0, v_c1, v_c2, v_c3, v_delta2;
- __m128i v_delta, v_alpha, v_zero;
+ int coeffs[4];
};
-#endif // CV_SSE2
-
///////////////////////////////////// YUV420 -> RGB /////////////////////////////////////
const int ITUR_BT_601_CGV = -385875;
const int ITUR_BT_601_CBV = -74448;
-template<int bIdx, int uIdx>
-struct YUV420sp2RGB888Invoker : ParallelLoopBody
-{
- uchar * dst_data;
- size_t dst_step;
- int width;
- const uchar* my1, *muv;
- size_t stride;
+//R = 1.164(Y - 16) + 1.596(V - 128)
+//G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
+//B = 1.164(Y - 16) + 2.018(U - 128)
- YUV420sp2RGB888Invoker(uchar * _dst_data, size_t _dst_step, int _dst_width, size_t _stride, const uchar* _y1, const uchar* _uv)
- : dst_data(_dst_data), dst_step(_dst_step), width(_dst_width), my1(_y1), muv(_uv), stride(_stride) {}
+//R = (1220542(Y - 16) + 1673527(V - 128) + (1 << 19)) >> 20
+//G = (1220542(Y - 16) - 852492(V - 128) - 409993(U - 128) + (1 << 19)) >> 20
+//B = (1220542(Y - 16) + 2116026(U - 128) + (1 << 19)) >> 20
- void operator()(const Range& range) const CV_OVERRIDE
+template<int bIdx, int dcn, bool is420>
+static inline void cvtYuv42xxp2RGB8(int u, int v, int vy01, int vy11, int vy02, int vy12,
+ uchar* row1, uchar* row2)
+{
+ u = u - 128;
+ v = v - 128;
+
+ int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v;
+ int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u;
+ int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u;
+
+ int y00 = std::max(0, vy01 - 16) * ITUR_BT_601_CY;
+ row1[2-bIdx] = saturate_cast<uchar>((y00 + ruv) >> ITUR_BT_601_SHIFT);
+ row1[1] = saturate_cast<uchar>((y00 + guv) >> ITUR_BT_601_SHIFT);
+ row1[bIdx] = saturate_cast<uchar>((y00 + buv) >> ITUR_BT_601_SHIFT);
+ if(dcn == 4)
+ row1[3] = uchar(0xff);
+
+ int y01 = std::max(0, vy11 - 16) * ITUR_BT_601_CY;
+ row1[dcn+2-bIdx] = saturate_cast<uchar>((y01 + ruv) >> ITUR_BT_601_SHIFT);
+ row1[dcn+1] = saturate_cast<uchar>((y01 + guv) >> ITUR_BT_601_SHIFT);
+ row1[dcn+0+bIdx] = saturate_cast<uchar>((y01 + buv) >> ITUR_BT_601_SHIFT);
+ if(dcn == 4)
+ row1[7] = uchar(0xff);
+
+ if(is420)
{
- int rangeBegin = range.start * 2;
- int rangeEnd = range.end * 2;
-
- //R = 1.164(Y - 16) + 1.596(V - 128)
- //G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
- //B = 1.164(Y - 16) + 2.018(U - 128)
-
- //R = (1220542(Y - 16) + 1673527(V - 128) + (1 << 19)) >> 20
- //G = (1220542(Y - 16) - 852492(V - 128) - 409993(U - 128) + (1 << 19)) >> 20
- //B = (1220542(Y - 16) + 2116026(U - 128) + (1 << 19)) >> 20
-
- const uchar* y1 = my1 + rangeBegin * stride, *uv = muv + rangeBegin * stride / 2;
-
- for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, uv += stride)
- {
- uchar* row1 = dst_data + dst_step * j;
- uchar* row2 = dst_data + dst_step * (j + 1);
- const uchar* y2 = y1 + stride;
-
- for (int i = 0; i < width; i += 2, row1 += 6, row2 += 6)
- {
- int u = int(uv[i + 0 + uIdx]) - 128;
- int v = int(uv[i + 1 - uIdx]) - 128;
-
- int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v;
- int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u;
- int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u;
-
- int y00 = std::max(0, int(y1[i]) - 16) * ITUR_BT_601_CY;
- row1[2-bIdx] = saturate_cast<uchar>((y00 + ruv) >> ITUR_BT_601_SHIFT);
- row1[1] = saturate_cast<uchar>((y00 + guv) >> ITUR_BT_601_SHIFT);
- row1[bIdx] = saturate_cast<uchar>((y00 + buv) >> ITUR_BT_601_SHIFT);
-
- int y01 = std::max(0, int(y1[i + 1]) - 16) * ITUR_BT_601_CY;
- row1[5-bIdx] = saturate_cast<uchar>((y01 + ruv) >> ITUR_BT_601_SHIFT);
- row1[4] = saturate_cast<uchar>((y01 + guv) >> ITUR_BT_601_SHIFT);
- row1[3+bIdx] = saturate_cast<uchar>((y01 + buv) >> ITUR_BT_601_SHIFT);
-
- int y10 = std::max(0, int(y2[i]) - 16) * ITUR_BT_601_CY;
- row2[2-bIdx] = saturate_cast<uchar>((y10 + ruv) >> ITUR_BT_601_SHIFT);
- row2[1] = saturate_cast<uchar>((y10 + guv) >> ITUR_BT_601_SHIFT);
- row2[bIdx] = saturate_cast<uchar>((y10 + buv) >> ITUR_BT_601_SHIFT);
-
- int y11 = std::max(0, int(y2[i + 1]) - 16) * ITUR_BT_601_CY;
- row2[5-bIdx] = saturate_cast<uchar>((y11 + ruv) >> ITUR_BT_601_SHIFT);
- row2[4] = saturate_cast<uchar>((y11 + guv) >> ITUR_BT_601_SHIFT);
- row2[3+bIdx] = saturate_cast<uchar>((y11 + buv) >> ITUR_BT_601_SHIFT);
- }
- }
+ int y10 = std::max(0, vy02 - 16) * ITUR_BT_601_CY;
+ row2[2-bIdx] = saturate_cast<uchar>((y10 + ruv) >> ITUR_BT_601_SHIFT);
+ row2[1] = saturate_cast<uchar>((y10 + guv) >> ITUR_BT_601_SHIFT);
+ row2[bIdx] = saturate_cast<uchar>((y10 + buv) >> ITUR_BT_601_SHIFT);
+ if(dcn == 4)
+ row2[3] = uchar(0xff);
+
+ int y11 = std::max(0, vy12 - 16) * ITUR_BT_601_CY;
+ row2[dcn+2-bIdx] = saturate_cast<uchar>((y11 + ruv) >> ITUR_BT_601_SHIFT);
+ row2[dcn+1] = saturate_cast<uchar>((y11 + guv) >> ITUR_BT_601_SHIFT);
+ row2[dcn+0+bIdx] = saturate_cast<uchar>((y11 + buv) >> ITUR_BT_601_SHIFT);
+ if(dcn == 4)
+ row2[7] = uchar(0xff);
}
-};
+}
-template<int bIdx, int uIdx>
-struct YUV420sp2RGBA8888Invoker : ParallelLoopBody
+template<int bIdx, int uIdx, int dcn>
+struct YUV420sp2RGB8Invoker : ParallelLoopBody
{
uchar * dst_data;
size_t dst_step;
const uchar* my1, *muv;
size_t stride;
- YUV420sp2RGBA8888Invoker(uchar * _dst_data, size_t _dst_step, int _dst_width, size_t _stride, const uchar* _y1, const uchar* _uv)
+ YUV420sp2RGB8Invoker(uchar * _dst_data, size_t _dst_step, int _dst_width, size_t _stride, const uchar* _y1, const uchar* _uv)
: dst_data(_dst_data), dst_step(_dst_step), width(_dst_width), my1(_y1), muv(_uv), stride(_stride) {}
void operator()(const Range& range) const CV_OVERRIDE
{
- int rangeBegin = range.start * 2;
- int rangeEnd = range.end * 2;
-
- //R = 1.164(Y - 16) + 1.596(V - 128)
- //G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
- //B = 1.164(Y - 16) + 2.018(U - 128)
-
- //R = (1220542(Y - 16) + 1673527(V - 128) + (1 << 19)) >> 20
- //G = (1220542(Y - 16) - 852492(V - 128) - 409993(U - 128) + (1 << 19)) >> 20
- //B = (1220542(Y - 16) + 2116026(U - 128) + (1 << 19)) >> 20
+ const int rangeBegin = range.start * 2;
+ const int rangeEnd = range.end * 2;
const uchar* y1 = my1 + rangeBegin * stride, *uv = muv + rangeBegin * stride / 2;
uchar* row2 = dst_data + dst_step * (j + 1);
const uchar* y2 = y1 + stride;
- for (int i = 0; i < width; i += 2, row1 += 8, row2 += 8)
+ for (int i = 0; i < width; i += 2, row1 += dcn*2, row2 += dcn*2)
{
- int u = int(uv[i + 0 + uIdx]) - 128;
- int v = int(uv[i + 1 - uIdx]) - 128;
-
- int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v;
- int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u;
- int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u;
-
- int y00 = std::max(0, int(y1[i]) - 16) * ITUR_BT_601_CY;
- row1[2-bIdx] = saturate_cast<uchar>((y00 + ruv) >> ITUR_BT_601_SHIFT);
- row1[1] = saturate_cast<uchar>((y00 + guv) >> ITUR_BT_601_SHIFT);
- row1[bIdx] = saturate_cast<uchar>((y00 + buv) >> ITUR_BT_601_SHIFT);
- row1[3] = uchar(0xff);
-
- int y01 = std::max(0, int(y1[i + 1]) - 16) * ITUR_BT_601_CY;
- row1[6-bIdx] = saturate_cast<uchar>((y01 + ruv) >> ITUR_BT_601_SHIFT);
- row1[5] = saturate_cast<uchar>((y01 + guv) >> ITUR_BT_601_SHIFT);
- row1[4+bIdx] = saturate_cast<uchar>((y01 + buv) >> ITUR_BT_601_SHIFT);
- row1[7] = uchar(0xff);
-
- int y10 = std::max(0, int(y2[i]) - 16) * ITUR_BT_601_CY;
- row2[2-bIdx] = saturate_cast<uchar>((y10 + ruv) >> ITUR_BT_601_SHIFT);
- row2[1] = saturate_cast<uchar>((y10 + guv) >> ITUR_BT_601_SHIFT);
- row2[bIdx] = saturate_cast<uchar>((y10 + buv) >> ITUR_BT_601_SHIFT);
- row2[3] = uchar(0xff);
-
- int y11 = std::max(0, int(y2[i + 1]) - 16) * ITUR_BT_601_CY;
- row2[6-bIdx] = saturate_cast<uchar>((y11 + ruv) >> ITUR_BT_601_SHIFT);
- row2[5] = saturate_cast<uchar>((y11 + guv) >> ITUR_BT_601_SHIFT);
- row2[4+bIdx] = saturate_cast<uchar>((y11 + buv) >> ITUR_BT_601_SHIFT);
- row2[7] = uchar(0xff);
+ int u = int(uv[i + 0 + uIdx]);
+ int v = int(uv[i + 1 - uIdx]);
+
+ int vy01 = int(y1[i]);
+ int vy11 = int(y1[i + 1]);
+ int vy02 = int(y2[i]);
+ int vy12 = int(y2[i + 1]);
+
+ cvtYuv42xxp2RGB8<bIdx, dcn, true>(u, v, vy01, vy11, vy02, vy12, row1, row2);
}
}
}
};
-template<int bIdx>
-struct YUV420p2RGB888Invoker : ParallelLoopBody
+template<int bIdx, int dcn>
+struct YUV420p2RGB8Invoker : ParallelLoopBody
{
uchar * dst_data;
size_t dst_step;
size_t stride;
int ustepIdx, vstepIdx;
- YUV420p2RGB888Invoker(uchar * _dst_data, size_t _dst_step, int _dst_width, size_t _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx)
+ YUV420p2RGB8Invoker(uchar * _dst_data, size_t _dst_step, int _dst_width, size_t _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx)
: dst_data(_dst_data), dst_step(_dst_step), width(_dst_width), my1(_y1), mu(_u), mv(_v), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {}
void operator()(const Range& range) const CV_OVERRIDE
uchar* row2 = dst_data + dst_step * (j + 1);
const uchar* y2 = y1 + stride;
- for (int i = 0; i < width / 2; i += 1, row1 += 6, row2 += 6)
+ for (int i = 0; i < width / 2; i += 1, row1 += dcn*2, row2 += dcn*2)
{
- int u = int(u1[i]) - 128;
- int v = int(v1[i]) - 128;
-
- int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v;
- int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u;
- int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u;
-
- int y00 = std::max(0, int(y1[2 * i]) - 16) * ITUR_BT_601_CY;
- row1[2-bIdx] = saturate_cast<uchar>((y00 + ruv) >> ITUR_BT_601_SHIFT);
- row1[1] = saturate_cast<uchar>((y00 + guv) >> ITUR_BT_601_SHIFT);
- row1[bIdx] = saturate_cast<uchar>((y00 + buv) >> ITUR_BT_601_SHIFT);
-
- int y01 = std::max(0, int(y1[2 * i + 1]) - 16) * ITUR_BT_601_CY;
- row1[5-bIdx] = saturate_cast<uchar>((y01 + ruv) >> ITUR_BT_601_SHIFT);
- row1[4] = saturate_cast<uchar>((y01 + guv) >> ITUR_BT_601_SHIFT);
- row1[3+bIdx] = saturate_cast<uchar>((y01 + buv) >> ITUR_BT_601_SHIFT);
-
- int y10 = std::max(0, int(y2[2 * i]) - 16) * ITUR_BT_601_CY;
- row2[2-bIdx] = saturate_cast<uchar>((y10 + ruv) >> ITUR_BT_601_SHIFT);
- row2[1] = saturate_cast<uchar>((y10 + guv) >> ITUR_BT_601_SHIFT);
- row2[bIdx] = saturate_cast<uchar>((y10 + buv) >> ITUR_BT_601_SHIFT);
-
- int y11 = std::max(0, int(y2[2 * i + 1]) - 16) * ITUR_BT_601_CY;
- row2[5-bIdx] = saturate_cast<uchar>((y11 + ruv) >> ITUR_BT_601_SHIFT);
- row2[4] = saturate_cast<uchar>((y11 + guv) >> ITUR_BT_601_SHIFT);
- row2[3+bIdx] = saturate_cast<uchar>((y11 + buv) >> ITUR_BT_601_SHIFT);
- }
- }
- }
-};
-
-template<int bIdx>
-struct YUV420p2RGBA8888Invoker : ParallelLoopBody
-{
- uchar * dst_data;
- size_t dst_step;
- int width;
- const uchar* my1, *mu, *mv;
- size_t stride;
- int ustepIdx, vstepIdx;
-
- YUV420p2RGBA8888Invoker(uchar * _dst_data, size_t _dst_step, int _dst_width, size_t _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx)
- : dst_data(_dst_data), dst_step(_dst_step), width(_dst_width), my1(_y1), mu(_u), mv(_v), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {}
-
- void operator()(const Range& range) const CV_OVERRIDE
- {
- int rangeBegin = range.start * 2;
- int rangeEnd = range.end * 2;
-
- int uvsteps[2] = {width/2, static_cast<int>(stride) - width/2};
- int usIdx = ustepIdx, vsIdx = vstepIdx;
-
- const uchar* y1 = my1 + rangeBegin * stride;
- const uchar* u1 = mu + (range.start / 2) * stride;
- const uchar* v1 = mv + (range.start / 2) * stride;
+ int u = int(u1[i]);
+ int v = int(v1[i]);
- if(range.start % 2 == 1)
- {
- u1 += uvsteps[(usIdx++) & 1];
- v1 += uvsteps[(vsIdx++) & 1];
- }
-
- for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += uvsteps[(usIdx++) & 1], v1 += uvsteps[(vsIdx++) & 1])
- {
- uchar* row1 = dst_data + dst_step * j;
- uchar* row2 = dst_data + dst_step * (j + 1);
- const uchar* y2 = y1 + stride;
+ int vy01 = int(y1[2 * i]);
+ int vy11 = int(y1[2 * i + 1]);
+ int vy02 = int(y2[2 * i]);
+ int vy12 = int(y2[2 * i + 1]);
- for (int i = 0; i < width / 2; i += 1, row1 += 8, row2 += 8)
- {
- int u = int(u1[i]) - 128;
- int v = int(v1[i]) - 128;
-
- int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v;
- int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u;
- int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u;
-
- int y00 = std::max(0, int(y1[2 * i]) - 16) * ITUR_BT_601_CY;
- row1[2-bIdx] = saturate_cast<uchar>((y00 + ruv) >> ITUR_BT_601_SHIFT);
- row1[1] = saturate_cast<uchar>((y00 + guv) >> ITUR_BT_601_SHIFT);
- row1[bIdx] = saturate_cast<uchar>((y00 + buv) >> ITUR_BT_601_SHIFT);
- row1[3] = uchar(0xff);
-
- int y01 = std::max(0, int(y1[2 * i + 1]) - 16) * ITUR_BT_601_CY;
- row1[6-bIdx] = saturate_cast<uchar>((y01 + ruv) >> ITUR_BT_601_SHIFT);
- row1[5] = saturate_cast<uchar>((y01 + guv) >> ITUR_BT_601_SHIFT);
- row1[4+bIdx] = saturate_cast<uchar>((y01 + buv) >> ITUR_BT_601_SHIFT);
- row1[7] = uchar(0xff);
-
- int y10 = std::max(0, int(y2[2 * i]) - 16) * ITUR_BT_601_CY;
- row2[2-bIdx] = saturate_cast<uchar>((y10 + ruv) >> ITUR_BT_601_SHIFT);
- row2[1] = saturate_cast<uchar>((y10 + guv) >> ITUR_BT_601_SHIFT);
- row2[bIdx] = saturate_cast<uchar>((y10 + buv) >> ITUR_BT_601_SHIFT);
- row2[3] = uchar(0xff);
-
- int y11 = std::max(0, int(y2[2 * i + 1]) - 16) * ITUR_BT_601_CY;
- row2[6-bIdx] = saturate_cast<uchar>((y11 + ruv) >> ITUR_BT_601_SHIFT);
- row2[5] = saturate_cast<uchar>((y11 + guv) >> ITUR_BT_601_SHIFT);
- row2[4+bIdx] = saturate_cast<uchar>((y11 + buv) >> ITUR_BT_601_SHIFT);
- row2[7] = uchar(0xff);
+ cvtYuv42xxp2RGB8<bIdx, dcn, true>(u, v, vy01, vy11, vy02, vy12, row1, row2);
}
}
}
};
+
#define MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION (320*240)
-template<int bIdx, int uIdx>
+template<int bIdx, int uIdx, int dcn>
inline void cvtYUV420sp2RGB(uchar * dst_data, size_t dst_step, int dst_width, int dst_height, size_t _stride, const uchar* _y1, const uchar* _uv)
{
- YUV420sp2RGB888Invoker<bIdx, uIdx> converter(dst_data, dst_step, dst_width, _stride, _y1, _uv);
- if (dst_width * dst_height >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
- parallel_for_(Range(0, dst_height/2), converter);
- else
- converter(Range(0, dst_height/2));
-}
-
-template<int bIdx, int uIdx>
-inline void cvtYUV420sp2RGBA(uchar * dst_data, size_t dst_step, int dst_width, int dst_height, size_t _stride, const uchar* _y1, const uchar* _uv)
-{
- YUV420sp2RGBA8888Invoker<bIdx, uIdx> converter(dst_data, dst_step, dst_width, _stride, _y1, _uv);
+ YUV420sp2RGB8Invoker<bIdx, uIdx, dcn> converter(dst_data, dst_step, dst_width, _stride, _y1, _uv);
if (dst_width * dst_height >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
parallel_for_(Range(0, dst_height/2), converter);
else
converter(Range(0, dst_height/2));
}
-template<int bIdx>
+template<int bIdx, int dcn>
inline void cvtYUV420p2RGB(uchar * dst_data, size_t dst_step, int dst_width, int dst_height, size_t _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx)
{
- YUV420p2RGB888Invoker<bIdx> converter(dst_data, dst_step, dst_width, _stride, _y1, _u, _v, ustepIdx, vstepIdx);
- if (dst_width * dst_height >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
- parallel_for_(Range(0, dst_height/2), converter);
- else
- converter(Range(0, dst_height/2));
-}
-
-template<int bIdx>
-inline void cvtYUV420p2RGBA(uchar * dst_data, size_t dst_step, int dst_width, int dst_height, size_t _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx)
-{
- YUV420p2RGBA8888Invoker<bIdx> converter(dst_data, dst_step, dst_width, _stride, _y1, _u, _v, ustepIdx, vstepIdx);
+ YUV420p2RGB8Invoker<bIdx, dcn> converter(dst_data, dst_step, dst_width, _stride, _y1, _u, _v, ustepIdx, vstepIdx);
if (dst_width * dst_height >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
parallel_for_(Range(0, dst_height/2), converter);
else
///////////////////////////////////// RGB -> YUV420p /////////////////////////////////////
-struct RGB888toYUV420pInvoker: public ParallelLoopBody
+struct RGB8toYUV420pInvoker: public ParallelLoopBody
{
- RGB888toYUV420pInvoker(const uchar * _src_data, size_t _src_step,
+ RGB8toYUV420pInvoker(const uchar * _src_data, size_t _src_step,
uchar * _y_data, uchar * _uv_data, size_t _dst_step,
int _src_width, int _src_height, int _scn, bool swapBlue_, bool swapUV_, bool interleaved_)
: src_data(_src_data), src_step(_src_step),
}
}
- void convert() const
- {
- if( src_width * src_height >= 320*240 )
- parallel_for_(Range(0, src_height/2), *this);
- else
- operator()(Range(0, src_height/2));
- }
-
-private:
- RGB888toYUV420pInvoker& operator=(const RGB888toYUV420pInvoker&);
-
const uchar * src_data;
size_t src_step;
uchar *y_data, *uv_data;
///////////////////////////////////// YUV422 -> RGB /////////////////////////////////////
-template<int bIdx, int uIdx, int yIdx>
-struct YUV422toRGB888Invoker : ParallelLoopBody
+template<int bIdx, int uIdx, int yIdx, int dcn>
+struct YUV422toRGB8Invoker : ParallelLoopBody
{
uchar * dst_data;
size_t dst_step;
size_t src_step;
int width;
- YUV422toRGB888Invoker(uchar * _dst_data, size_t _dst_step,
- const uchar * _src_data, size_t _src_step,
- int _width)
+ YUV422toRGB8Invoker(uchar * _dst_data, size_t _dst_step,
+ const uchar * _src_data, size_t _src_step,
+ int _width)
: dst_data(_dst_data), dst_step(_dst_step), src_data(_src_data), src_step(_src_step), width(_width) {}
void operator()(const Range& range) const CV_OVERRIDE
{
uchar* row = dst_data + dst_step * j;
- for (int i = 0; i < 2 * width; i += 4, row += 6)
+ for (int i = 0; i < 2 * width; i += 4, row += dcn*2)
{
- int u = int(yuv_src[i + uidx]) - 128;
- int v = int(yuv_src[i + vidx]) - 128;
-
- int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v;
- int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u;
- int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u;
-
- int y00 = std::max(0, int(yuv_src[i + yIdx]) - 16) * ITUR_BT_601_CY;
- row[2-bIdx] = saturate_cast<uchar>((y00 + ruv) >> ITUR_BT_601_SHIFT);
- row[1] = saturate_cast<uchar>((y00 + guv) >> ITUR_BT_601_SHIFT);
- row[bIdx] = saturate_cast<uchar>((y00 + buv) >> ITUR_BT_601_SHIFT);
-
- int y01 = std::max(0, int(yuv_src[i + yIdx + 2]) - 16) * ITUR_BT_601_CY;
- row[5-bIdx] = saturate_cast<uchar>((y01 + ruv) >> ITUR_BT_601_SHIFT);
- row[4] = saturate_cast<uchar>((y01 + guv) >> ITUR_BT_601_SHIFT);
- row[3+bIdx] = saturate_cast<uchar>((y01 + buv) >> ITUR_BT_601_SHIFT);
- }
- }
- }
-};
-
-template<int bIdx, int uIdx, int yIdx>
-struct YUV422toRGBA8888Invoker : ParallelLoopBody
-{
- uchar * dst_data;
- size_t dst_step;
- const uchar * src_data;
- size_t src_step;
- int width;
-
- YUV422toRGBA8888Invoker(uchar * _dst_data, size_t _dst_step,
- const uchar * _src_data, size_t _src_step,
- int _width)
- : dst_data(_dst_data), dst_step(_dst_step), src_data(_src_data), src_step(_src_step), width(_width) {}
-
- void operator()(const Range& range) const CV_OVERRIDE
- {
- int rangeBegin = range.start;
- int rangeEnd = range.end;
-
- const int uidx = 1 - yIdx + uIdx * 2;
- const int vidx = (2 + uidx) % 4;
- const uchar* yuv_src = src_data + rangeBegin * src_step;
+ int u = int(yuv_src[i + uidx]);
+ int v = int(yuv_src[i + vidx]);
- for (int j = rangeBegin; j < rangeEnd; j++, yuv_src += src_step)
- {
- uchar* row = dst_data + dst_step * j;
+ int vy0 = int(yuv_src[i + yIdx]);
+ int vy1 = int(yuv_src[i + yIdx + 2]);
- for (int i = 0; i < 2 * width; i += 4, row += 8)
- {
- int u = int(yuv_src[i + uidx]) - 128;
- int v = int(yuv_src[i + vidx]) - 128;
-
- int ruv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVR * v;
- int guv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CVG * v + ITUR_BT_601_CUG * u;
- int buv = (1 << (ITUR_BT_601_SHIFT - 1)) + ITUR_BT_601_CUB * u;
-
- int y00 = std::max(0, int(yuv_src[i + yIdx]) - 16) * ITUR_BT_601_CY;
- row[2-bIdx] = saturate_cast<uchar>((y00 + ruv) >> ITUR_BT_601_SHIFT);
- row[1] = saturate_cast<uchar>((y00 + guv) >> ITUR_BT_601_SHIFT);
- row[bIdx] = saturate_cast<uchar>((y00 + buv) >> ITUR_BT_601_SHIFT);
- row[3] = uchar(0xff);
-
- int y01 = std::max(0, int(yuv_src[i + yIdx + 2]) - 16) * ITUR_BT_601_CY;
- row[6-bIdx] = saturate_cast<uchar>((y01 + ruv) >> ITUR_BT_601_SHIFT);
- row[5] = saturate_cast<uchar>((y01 + guv) >> ITUR_BT_601_SHIFT);
- row[4+bIdx] = saturate_cast<uchar>((y01 + buv) >> ITUR_BT_601_SHIFT);
- row[7] = uchar(0xff);
+ cvtYuv42xxp2RGB8<bIdx, dcn, false>(u, v, vy0, vy1, 0, 0, row, (uchar*)(0));
}
}
}
#define MIN_SIZE_FOR_PARALLEL_YUV422_CONVERSION (320*240)
-template<int bIdx, int uIdx, int yIdx>
+template<int bIdx, int uIdx, int yIdx, int dcn>
inline void cvtYUV422toRGB(uchar * dst_data, size_t dst_step, const uchar * src_data, size_t src_step,
int width, int height)
{
- YUV422toRGB888Invoker<bIdx, uIdx, yIdx> converter(dst_data, dst_step, src_data, src_step, width);
- if (width * height >= MIN_SIZE_FOR_PARALLEL_YUV422_CONVERSION)
- parallel_for_(Range(0, height), converter);
- else
- converter(Range(0, height));
-}
-
-template<int bIdx, int uIdx, int yIdx>
-inline void cvtYUV422toRGBA(uchar * dst_data, size_t dst_step, const uchar * src_data, size_t src_step,
- int width, int height)
-{
- YUV422toRGBA8888Invoker<bIdx, uIdx, yIdx> converter(dst_data, dst_step, src_data, src_step, width);
+ YUV422toRGB8Invoker<bIdx, uIdx, yIdx, dcn> converter(dst_data, dst_step, src_data, src_step, width);
if (width * height >= MIN_SIZE_FOR_PARALLEL_YUV422_CONVERSION)
parallel_for_(Range(0, height), converter);
else
cvtTwoPlaneYUVtoBGR(src_data, uv, src_step, dst_data, dst_step, dst_width, dst_height, dcn, swapBlue, uIdx);
}
+typedef void (*cvt_2plane_yuv_ptr_t)(uchar * /* dst_data*/,
+ size_t /* dst_step */,
+ int /* dst_width */,
+ int /* dst_height */,
+ size_t /* _stride */,
+ const uchar* /* _y1 */,
+ const uchar* /* _uv */);
+
void cvtTwoPlaneYUVtoBGR(const uchar * y_data, const uchar * uv_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int dst_width, int dst_height,
CV_INSTRUMENT_REGION();
// TODO: add hal replacement method
+
int blueIdx = swapBlue ? 2 : 0;
+
+ cvt_2plane_yuv_ptr_t cvtPtr;
switch(dcn*100 + blueIdx * 10 + uIdx)
{
- case 300: cvtYUV420sp2RGB<0, 0> (dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break;
- case 301: cvtYUV420sp2RGB<0, 1> (dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break;
- case 320: cvtYUV420sp2RGB<2, 0> (dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break;
- case 321: cvtYUV420sp2RGB<2, 1> (dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break;
- case 400: cvtYUV420sp2RGBA<0, 0>(dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break;
- case 401: cvtYUV420sp2RGBA<0, 1>(dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break;
- case 420: cvtYUV420sp2RGBA<2, 0>(dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break;
- case 421: cvtYUV420sp2RGBA<2, 1>(dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data); break;
+ case 300: cvtPtr = cvtYUV420sp2RGB<0, 0, 3>; break;
+ case 301: cvtPtr = cvtYUV420sp2RGB<0, 1, 3>; break;
+ case 320: cvtPtr = cvtYUV420sp2RGB<2, 0, 3>; break;
+ case 321: cvtPtr = cvtYUV420sp2RGB<2, 1, 3>; break;
+ case 400: cvtPtr = cvtYUV420sp2RGB<0, 0, 4>; break;
+ case 401: cvtPtr = cvtYUV420sp2RGB<0, 1, 4>; break;
+ case 420: cvtPtr = cvtYUV420sp2RGB<2, 0, 4>; break;
+ case 421: cvtPtr = cvtYUV420sp2RGB<2, 1, 4>; break;
default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
};
+
+ cvtPtr(dst_data, dst_step, dst_width, dst_height, src_step, y_data, uv_data);
}
+typedef void (*cvt_3plane_yuv_ptr_t)(uchar * /* dst_data */,
+ size_t /* dst_step */,
+ int /* dst_width */,
+ int /* dst_height */,
+ size_t /* _stride */,
+ const uchar* /* _y1 */,
+ const uchar* /* _u */,
+ const uchar* /* _v */,
+ int /* ustepIdx */,
+ int /* vstepIdx */);
+
void cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int dst_width, int dst_height,
if(uIdx == 1) { std::swap(u ,v), std::swap(ustepIdx, vstepIdx); }
int blueIdx = swapBlue ? 2 : 0;
+ cvt_3plane_yuv_ptr_t cvtPtr;
switch(dcn*10 + blueIdx)
{
- case 30: cvtYUV420p2RGB<0>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, u, v, ustepIdx, vstepIdx); break;
- case 32: cvtYUV420p2RGB<2>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, u, v, ustepIdx, vstepIdx); break;
- case 40: cvtYUV420p2RGBA<0>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, u, v, ustepIdx, vstepIdx); break;
- case 42: cvtYUV420p2RGBA<2>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, u, v, ustepIdx, vstepIdx); break;
+ case 30: cvtPtr = cvtYUV420p2RGB<0, 3>; break;
+ case 32: cvtPtr = cvtYUV420p2RGB<2, 3>; break;
+ case 40: cvtPtr = cvtYUV420p2RGB<0, 4>; break;
+ case 42: cvtPtr = cvtYUV420p2RGB<2, 4>; break;
default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
};
+
+ cvtPtr(dst_data, dst_step, dst_width, dst_height, src_step, src_data, u, v, ustepIdx, vstepIdx);
}
void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step,
CALL_HAL(cvtBGRtoThreePlaneYUV, cv_hal_cvtBGRtoThreePlaneYUV, src_data, src_step, dst_data, dst_step, width, height, scn, swapBlue, uIdx);
uchar * uv_data = dst_data + dst_step * height;
- RGB888toYUV420pInvoker(src_data, src_step, dst_data, uv_data, dst_step, width, height, scn, swapBlue, uIdx == 2, false).convert();
+
+ RGB8toYUV420pInvoker cvt(src_data, src_step, dst_data, uv_data, dst_step, width, height,
+ scn, swapBlue, uIdx == 2, false);
+
+ if( width * height >= 320*240 )
+ parallel_for_(Range(0, height/2), cvt);
+ else
+ cvt(Range(0, height/2));
}
void cvtBGRtoTwoPlaneYUV(const uchar * src_data, size_t src_step,
CV_INSTRUMENT_REGION();
// TODO: add hal replacement method
- RGB888toYUV420pInvoker(src_data, src_step, y_data, uv_data, dst_step, width, height, scn, swapBlue, uIdx == 2, true).convert();
+
+ RGB8toYUV420pInvoker cvt(src_data, src_step, y_data, uv_data, dst_step, width, height,
+ scn, swapBlue, uIdx == 2, true);
+
+ if( width * height >= 320*240 )
+ parallel_for_(Range(0, height/2), cvt);
+ else
+ cvt(Range(0, height/2));
}
+typedef void (*cvt_1plane_yuv_ptr_t)(uchar * /* dst_data */,
+ size_t /* dst_step */,
+ const uchar * /* src_data */,
+ size_t /* src_step */,
+ int /* width */,
+ int /* height */);
+
void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int width, int height,
CV_INSTRUMENT_REGION();
CALL_HAL(cvtOnePlaneYUVtoBGR, cv_hal_cvtOnePlaneYUVtoBGR, src_data, src_step, dst_data, dst_step, width, height, dcn, swapBlue, uIdx, ycn);
+
+ cvt_1plane_yuv_ptr_t cvtPtr;
int blueIdx = swapBlue ? 2 : 0;
switch(dcn*1000 + blueIdx*100 + uIdx*10 + ycn)
{
- case 3000: cvtYUV422toRGB<0,0,0>(dst_data, dst_step, src_data, src_step, width, height); break;
- case 3001: cvtYUV422toRGB<0,0,1>(dst_data, dst_step, src_data, src_step, width, height); break;
- case 3010: cvtYUV422toRGB<0,1,0>(dst_data, dst_step, src_data, src_step, width, height); break;
- case 3200: cvtYUV422toRGB<2,0,0>(dst_data, dst_step, src_data, src_step, width, height); break;
- case 3201: cvtYUV422toRGB<2,0,1>(dst_data, dst_step, src_data, src_step, width, height); break;
- case 3210: cvtYUV422toRGB<2,1,0>(dst_data, dst_step, src_data, src_step, width, height); break;
- case 4000: cvtYUV422toRGBA<0,0,0>(dst_data, dst_step, src_data, src_step, width, height); break;
- case 4001: cvtYUV422toRGBA<0,0,1>(dst_data, dst_step, src_data, src_step, width, height); break;
- case 4010: cvtYUV422toRGBA<0,1,0>(dst_data, dst_step, src_data, src_step, width, height); break;
- case 4200: cvtYUV422toRGBA<2,0,0>(dst_data, dst_step, src_data, src_step, width, height); break;
- case 4201: cvtYUV422toRGBA<2,0,1>(dst_data, dst_step, src_data, src_step, width, height); break;
- case 4210: cvtYUV422toRGBA<2,1,0>(dst_data, dst_step, src_data, src_step, width, height); break;
+ case 3000: cvtPtr = cvtYUV422toRGB<0,0,0,3>; break;
+ case 3001: cvtPtr = cvtYUV422toRGB<0,0,1,3>; break;
+ case 3010: cvtPtr = cvtYUV422toRGB<0,1,0,3>; break;
+ case 3200: cvtPtr = cvtYUV422toRGB<2,0,0,3>; break;
+ case 3201: cvtPtr = cvtYUV422toRGB<2,0,1,3>; break;
+ case 3210: cvtPtr = cvtYUV422toRGB<2,1,0,3>; break;
+ case 4000: cvtPtr = cvtYUV422toRGB<0,0,0,4>; break;
+ case 4001: cvtPtr = cvtYUV422toRGB<0,0,1,4>; break;
+ case 4010: cvtPtr = cvtYUV422toRGB<0,1,0,4>; break;
+ case 4200: cvtPtr = cvtYUV422toRGB<2,0,0,4>; break;
+ case 4201: cvtPtr = cvtYUV422toRGB<2,0,1,4>; break;
+ case 4210: cvtPtr = cvtYUV422toRGB<2,1,0,4>; break;
default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
};
+
+ cvtPtr(dst_data, dst_step, src_data, src_step, width, height);
}
} // namespace hal