最近工作中接触到了海康视频yuv格式到rgb转换的问题,查找过网上的资料,发现相关资料很多,转换公式也比较多,但盲目拿来用,却会碰到很多问题,等到问 题解决,回头想想,问题出在没有搞清楚转换数据源用的是什么yuv格式,比如我一开始以为是hikvision的视频流解码之后的是yuv420格式,后该咨询了该公司相关技术人员才知道是yv12格式。关于yuv格式的资料,请参见博客http://blog.csdn.net/searchsun/article/details/2443867。于是上网查找公式,找到了starspace的博客 http://www.cnblogs.com/starspace/archive/2008/12/16/1356007.html,用了博客文中的公式,得到了结果,但是出现了新的问题,出来的图像上很多地方出现了亮点,这些亮点是单颜色,即红、绿、蓝。
经过仔细检查原始公式,发现作者在计算r分量的时候有一个系数计算错误,1.596027实际应该是408.58/256 = 1.596016。修改了这个问题,以为问题会解决,但是还是有问题,不明白是怎么回事,后来想到之前网上找到过其它公式,虽然没能解决我的问题,但是注 意到了其中一个细节,即yuv格式转成rgb分量的时候,需要进行溢出判断,因为公式中用到了浮点数的计算,是有可能出现rgb值小于0或者大于255的 情况的,而我们知道rgb只能在0-255范围内,所以必须对这两种情况进行处理。于是我将starspace博客中的公式作了溢出处理,得到下面的公 式:
int iSrc = 0; // (0, width*height)
// YCbCr转换为RGB
for(int i =0 ; i < dest->dwSize; )
{
UCHAR y,u,v;
y = yBuf[iSrc];
u = uBuf[iSrc / 4];
v = vBuf[iSrc / 4];
double temp;
temp = 1.164383*(y- 16) + 0 + 1.596016*(v - 128);
dBuf[i] = (unsigned char)(temp < 0 ? 0 : (temp > 255 ? 255 : temp));
temp = (1.164383*(y- 16) - 0.391762*(u - 128) - 0.812969*(v - 128));
dBuf[i + 1] =
(unsigned char)(temp < 0 ? 0 : (temp > 255 ? 255 : temp));
temp = 1.164383*(y- 16) + 2.017230*(u - 128) + 0;
dBuf[i + 2] =
(unsigned char)(temp < 0 ? 0 : (temp > 255 ? 255 : temp));
i += 3;
++iSrc;
}
再 结合yv12格式的存储是遵循先存y,后存v,再存u,v和u采样数量只有y的四分之一,结合视频分辨率,假设是width × height,那么一帧视频数据中前width×height个字节是y,之后width×height×0.25个字节是v,最后的 width×height×0.25个字节是u,根据这个规则,正确获取yuv分量,并用上述公式,就能得到正确的rgb分量。
上面公式中yBuf,uBuf,vBuf是根据yv12获取:
UCHAR *yBuf = sBuf; // sBuf是yv12格式的buf
UCHAR *vBuf = yBuf + width * height;
UCHAR *uBuf = vBuf + ((width * height) >> 2);