1、转换公式
先说结论,opencv源码中灰度转换公式如下:
Y = (uchar)CV_DESCALE(b * cb + g * cg + r * cr, 15);
//这里 #define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n))
//其中 cb = 3735, cg = 19235, cr = 9798
2、思路
根据 BT.601,RGB与YUV间的转换常量如下:
static const float B2YF = 0.114f; //Blue to Y
static const float G2YF = 0.587f;//Green to Y
static const float R2YF = 0.299f;//Red to Y
将这三个参数进行放大,得到整数形式的转换常量:
RY15 = 9798, // == R2YF*32768 + 0.5
GY15 = 19235, // == G2YF*32768 + 0.5
BY15 = 3735 // == B2YF*32768 + 0.5
使用放大后的参数进行计算:
y = b * BY15 + g * GY15 + r * RY15
最后再进行放缩,得到范围再0~255的Y值:
gray_shift = 15 // 2<<15 大小为 32768
Y = (((y) + (1 << ((gray_shift )-1))) >> (gray_shift ))
以上一系列放缩转换,本质上是为了避免浮点运算。因为进行了放缩截取,所以opencv转换结果会与我们直接使用公式BT.601进行转换得到的结果有一定差异。