Skip to content

Commit 19e4c77

Browse files
committed
Merge pull request opencv#7546 from savuor:fix2.4/yuv_channel_order
2 parents f2a59b3 + d23190d commit 19e4c77

File tree

2 files changed

+151
-82
lines changed

2 files changed

+151
-82
lines changed

modules/imgproc/src/color.cpp

Lines changed: 81 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,38 @@ static IppStatus sts = ippInit();
102102

103103
namespace cv
104104
{
105+
//constants for conversion from/to RGB and Gray, YUV, YCrCb according to BT.601
106+
const float B2YF = 0.114f;
107+
const float G2YF = 0.587f;
108+
const float R2YF = 0.299f;
109+
//to YCbCr
110+
const float YCBF = 0.564f; // == 1/2/(1-B2YF)
111+
const float YCRF = 0.713f; // == 1/2/(1-R2YF)
112+
const int YCBI = 9241; // == YCBF*16384
113+
const int YCRI = 11682; // == YCRF*16384
114+
//to YUV
115+
const float B2UF = 0.492f;
116+
const float R2VF = 0.877f;
117+
const int B2UI = 8061; // == B2UF*16384
118+
const int R2VI = 14369; // == R2VF*16384
119+
//from YUV
120+
const float U2BF = 2.032f;
121+
const float U2GF = -0.395f;
122+
const float V2GF = -0.581f;
123+
const float V2RF = 1.140f;
124+
const int U2BI = 33292;
125+
const int U2GI = -6472;
126+
const int V2GI = -9519;
127+
const int V2RI = 18678;
128+
//from YCrCb
129+
const float CR2RF = 1.403f;
130+
const float CB2GF = -0.344f;
131+
const float CR2GF = -0.714f;
132+
const float CB2BF = 1.773f;
133+
const int CR2RI = 22987;
134+
const int CB2GI = -5636;
135+
const int CR2GI = -11698;
136+
const int CB2BI = 29049;
105137

106138
// computes cubic spline coefficients for a function: (xi=i, yi=f[i]), i=0..n
107139
template<typename _Tp> static void splineBuild(const _Tp* f, int n, _Tp* tab)
@@ -402,9 +434,9 @@ struct IPPColor2GrayFunctor
402434
{
403435
IPPColor2GrayFunctor(ippiColor2GrayFunc _func) : func(_func)
404436
{
405-
coeffs[0] = 0.114f;
406-
coeffs[1] = 0.587f;
407-
coeffs[2] = 0.299f;
437+
coeffs[0] = B2YF;
438+
coeffs[1] = G2YF;
439+
coeffs[2] = R2YF;
408440
}
409441
bool operator()(const void *src, int srcStep, void *dst, int dstStep, int cols, int rows) const
410442
{
@@ -668,9 +700,9 @@ enum
668700
{
669701
yuv_shift = 14,
670702
xyz_shift = 12,
671-
R2Y = 4899,
672-
G2Y = 9617,
673-
B2Y = 1868,
703+
R2Y = 4899, // B2YF*16384
704+
G2Y = 9617, // G2YF*16384
705+
B2Y = 1868, // B2YF*16384
674706
BLOCK_SIZE = 256
675707
};
676708

@@ -709,7 +741,7 @@ template<typename _Tp> struct RGB2Gray
709741

710742
RGB2Gray(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn)
711743
{
712-
static const float coeffs0[] = { 0.299f, 0.587f, 0.114f };
744+
static const float coeffs0[] = { R2YF, G2YF, B2YF };
713745
memcpy( coeffs, _coeffs ? _coeffs : coeffs0, 3*sizeof(coeffs[0]) );
714746
if(blueIdx == 0)
715747
std::swap(coeffs[0], coeffs[2]);
@@ -787,16 +819,18 @@ template<typename _Tp> struct RGB2YCrCb_f
787819
{
788820
typedef _Tp channel_type;
789821

790-
RGB2YCrCb_f(int _srccn, int _blueIdx, const float* _coeffs) : srccn(_srccn), blueIdx(_blueIdx)
822+
RGB2YCrCb_f(int _srccn, int _blueIdx, bool _isCrCb) : srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
791823
{
792-
static const float coeffs0[] = {0.299f, 0.587f, 0.114f, 0.713f, 0.564f};
793-
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0]));
824+
static const float coeffs_crb[] = { R2YF, G2YF, B2YF, YCRF, YCBF };
825+
static const float coeffs_yuv[] = { R2YF, G2YF, B2YF, R2VF, B2UF };
826+
memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
794827
if(blueIdx==0) std::swap(coeffs[0], coeffs[2]);
795828
}
796829

797830
void operator()(const _Tp* src, _Tp* dst, int n) const
798831
{
799832
int scn = srccn, bidx = blueIdx;
833+
int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
800834
const _Tp delta = ColorChannel<_Tp>::half();
801835
float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
802836
n *= 3;
@@ -805,10 +839,11 @@ template<typename _Tp> struct RGB2YCrCb_f
805839
_Tp Y = saturate_cast<_Tp>(src[0]*C0 + src[1]*C1 + src[2]*C2);
806840
_Tp Cr = saturate_cast<_Tp>((src[bidx^2] - Y)*C3 + delta);
807841
_Tp Cb = saturate_cast<_Tp>((src[bidx] - Y)*C4 + delta);
808-
dst[i] = Y; dst[i+1] = Cr; dst[i+2] = Cb;
842+
dst[i] = Y; dst[i+1+yuvOrder] = Cr; dst[i+2-yuvOrder] = Cb;
809843
}
810844
}
811845
int srccn, blueIdx;
846+
bool isCrCb;
812847
float coeffs[5];
813848
};
814849

@@ -817,16 +852,18 @@ template<typename _Tp> struct RGB2YCrCb_i
817852
{
818853
typedef _Tp channel_type;
819854

820-
RGB2YCrCb_i(int _srccn, int _blueIdx, const int* _coeffs)
821-
: srccn(_srccn), blueIdx(_blueIdx)
855+
RGB2YCrCb_i(int _srccn, int _blueIdx, bool _isCrCb)
856+
: srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
822857
{
823-
static const int coeffs0[] = {R2Y, G2Y, B2Y, 11682, 9241};
824-
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0]));
858+
static const int coeffs_crb[] = { R2Y, G2Y, B2Y, YCRI, YCBI };
859+
static const int coeffs_yuv[] = { R2Y, G2Y, B2Y, R2VI, B2UI };
860+
memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
825861
if(blueIdx==0) std::swap(coeffs[0], coeffs[2]);
826862
}
827863
void operator()(const _Tp* src, _Tp* dst, int n) const
828864
{
829865
int scn = srccn, bidx = blueIdx;
866+
int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
830867
int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
831868
int delta = ColorChannel<_Tp>::half()*(1 << yuv_shift);
832869
n *= 3;
@@ -836,11 +873,12 @@ template<typename _Tp> struct RGB2YCrCb_i
836873
int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift);
837874
int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
838875
dst[i] = saturate_cast<_Tp>(Y);
839-
dst[i+1] = saturate_cast<_Tp>(Cr);
840-
dst[i+2] = saturate_cast<_Tp>(Cb);
876+
dst[i+1+yuvOrder] = saturate_cast<_Tp>(Cr);
877+
dst[i+2-yuvOrder] = saturate_cast<_Tp>(Cb);
841878
}
842879
}
843880
int srccn, blueIdx;
881+
bool isCrCb;
844882
int coeffs[5];
845883
};
846884

@@ -849,23 +887,25 @@ template<typename _Tp> struct YCrCb2RGB_f
849887
{
850888
typedef _Tp channel_type;
851889

852-
YCrCb2RGB_f(int _dstcn, int _blueIdx, const float* _coeffs)
853-
: dstcn(_dstcn), blueIdx(_blueIdx)
890+
YCrCb2RGB_f(int _dstcn, int _blueIdx, bool _isCrCb)
891+
: dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
854892
{
855-
static const float coeffs0[] = {1.403f, -0.714f, -0.344f, 1.773f};
856-
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4*sizeof(coeffs[0]));
893+
static const float coeffs_cbr[] = {CR2RF, CR2GF, CB2GF, CB2BF};
894+
static const float coeffs_yuv[] = { V2RF, V2GF, U2GF, U2BF};
895+
memcpy(coeffs, isCrCb ? coeffs_cbr : coeffs_yuv, 4*sizeof(coeffs[0]));
857896
}
858897
void operator()(const _Tp* src, _Tp* dst, int n) const
859898
{
860899
int dcn = dstcn, bidx = blueIdx;
900+
int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
861901
const _Tp delta = ColorChannel<_Tp>::half(), alpha = ColorChannel<_Tp>::max();
862902
float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
863903
n *= 3;
864904
for(int i = 0; i < n; i += 3, dst += dcn)
865905
{
866906
_Tp Y = src[i];
867-
_Tp Cr = src[i+1];
868-
_Tp Cb = src[i+2];
907+
_Tp Cr = src[i+1+yuvOrder];
908+
_Tp Cb = src[i+2-yuvOrder];
869909

870910
_Tp b = saturate_cast<_Tp>(Y + (Cb - delta)*C3);
871911
_Tp g = saturate_cast<_Tp>(Y + (Cb - delta)*C2 + (Cr - delta)*C1);
@@ -877,6 +917,7 @@ template<typename _Tp> struct YCrCb2RGB_f
877917
}
878918
}
879919
int dstcn, blueIdx;
920+
bool isCrCb;
880921
float coeffs[4];
881922
};
882923

@@ -885,24 +926,26 @@ template<typename _Tp> struct YCrCb2RGB_i
885926
{
886927
typedef _Tp channel_type;
887928

888-
YCrCb2RGB_i(int _dstcn, int _blueIdx, const int* _coeffs)
889-
: dstcn(_dstcn), blueIdx(_blueIdx)
929+
YCrCb2RGB_i(int _dstcn, int _blueIdx, bool _isCrCb)
930+
: dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
890931
{
891-
static const int coeffs0[] = {22987, -11698, -5636, 29049};
892-
memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4*sizeof(coeffs[0]));
932+
static const int coeffs_crb[] = { CR2RI, CR2GI, CB2GI, CB2BI};
933+
static const int coeffs_yuv[] = { V2RI, V2GI, U2GI, U2BI };
934+
memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 4*sizeof(coeffs[0]));
893935
}
894936

895937
void operator()(const _Tp* src, _Tp* dst, int n) const
896938
{
897939
int dcn = dstcn, bidx = blueIdx;
940+
int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
898941
const _Tp delta = ColorChannel<_Tp>::half(), alpha = ColorChannel<_Tp>::max();
899942
int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
900943
n *= 3;
901944
for(int i = 0; i < n; i += 3, dst += dcn)
902945
{
903946
_Tp Y = src[i];
904-
_Tp Cr = src[i+1];
905-
_Tp Cb = src[i+2];
947+
_Tp Cr = src[i+1+yuvOrder];
948+
_Tp Cb = src[i+2-yuvOrder];
906949

907950
int b = Y + CV_DESCALE((Cb - delta)*C3, yuv_shift);
908951
int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift);
@@ -916,6 +959,7 @@ template<typename _Tp> struct YCrCb2RGB_i
916959
}
917960
}
918961
int dstcn, blueIdx;
962+
bool isCrCb;
919963
int coeffs[4];
920964
};
921965

@@ -3832,10 +3876,7 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
38323876
{
38333877
CV_Assert( scn == 3 || scn == 4 );
38343878
bidx = code == CV_BGR2YCrCb || code == CV_BGR2YUV ? 0 : 2;
3835-
static const float yuv_f[] = { 0.114f, 0.587f, 0.299f, 0.492f, 0.877f };
3836-
static const int yuv_i[] = { B2Y, G2Y, R2Y, 8061, 14369 };
3837-
const float* coeffs_f = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? 0 : yuv_f;
3838-
const int* coeffs_i = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? 0 : yuv_i;
3879+
const bool isCrCb = (code == CV_BGR2YCrCb || code == CV_RGB2YCrCb);
38393880

38403881
_dst.create(sz, CV_MAKETYPE(depth, 3));
38413882
dst = _dst.getMat();
@@ -3846,12 +3887,12 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
38463887
if((code == CV_RGB2YCrCb || code == CV_BGR2YCrCb) && tegra::cvtRGB2YCrCb(src, dst, bidx))
38473888
break;
38483889
#endif
3849-
CvtColorLoop(src, dst, RGB2YCrCb_i<uchar>(scn, bidx, coeffs_i));
3890+
CvtColorLoop(src, dst, RGB2YCrCb_i<uchar>(scn, bidx, isCrCb));
38503891
}
38513892
else if( depth == CV_16U )
3852-
CvtColorLoop(src, dst, RGB2YCrCb_i<ushort>(scn, bidx, coeffs_i));
3893+
CvtColorLoop(src, dst, RGB2YCrCb_i<ushort>(scn, bidx, isCrCb));
38533894
else
3854-
CvtColorLoop(src, dst, RGB2YCrCb_f<float>(scn, bidx, coeffs_f));
3895+
CvtColorLoop(src, dst, RGB2YCrCb_f<float>(scn, bidx, isCrCb));
38553896
}
38563897
break;
38573898

@@ -3861,20 +3902,17 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
38613902
if( dcn <= 0 ) dcn = 3;
38623903
CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) );
38633904
bidx = code == CV_YCrCb2BGR || code == CV_YUV2BGR ? 0 : 2;
3864-
static const float yuv_f[] = { 2.032f, -0.395f, -0.581f, 1.140f };
3865-
static const int yuv_i[] = { 33292, -6472, -9519, 18678 };
3866-
const float* coeffs_f = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? 0 : yuv_f;
3867-
const int* coeffs_i = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? 0 : yuv_i;
3905+
const bool isCrCb = (code == CV_YCrCb2BGR || code == CV_YCrCb2RGB);
38683906

38693907
_dst.create(sz, CV_MAKETYPE(depth, dcn));
38703908
dst = _dst.getMat();
38713909

38723910
if( depth == CV_8U )
3873-
CvtColorLoop(src, dst, YCrCb2RGB_i<uchar>(dcn, bidx, coeffs_i));
3911+
CvtColorLoop(src, dst, YCrCb2RGB_i<uchar>(dcn, bidx, isCrCb));
38743912
else if( depth == CV_16U )
3875-
CvtColorLoop(src, dst, YCrCb2RGB_i<ushort>(dcn, bidx, coeffs_i));
3913+
CvtColorLoop(src, dst, YCrCb2RGB_i<ushort>(dcn, bidx, isCrCb));
38763914
else
3877-
CvtColorLoop(src, dst, YCrCb2RGB_f<float>(dcn, bidx, coeffs_f));
3915+
CvtColorLoop(src, dst, YCrCb2RGB_f<float>(dcn, bidx, isCrCb));
38783916
}
38793917
break;
38803918

0 commit comments

Comments
 (0)