无法将rgb转换为YCbCr并返回而不会丢失

时间:2014-05-06 00:01:36

标签: c++ image-processing

我需要编写一个程序来拍照,将它们转换为YCbCr格式,操作图片然后以RGB格式返回结果。在我编写操作之前,我编写了从RGB到YCbCr的转换并返回并想测试它是否有效。在我测试过的大多数图片上都有效,并返回与原始图片相同的图片。我有2张图片的问题,其中转换似乎改变了一些像素。图片是(较大图片中的裁剪区域)

原文:

enter image description here

结果:

enter image description here

原文:

enter image description here

结果:

enter image description here

我正在从this site获取转换矩阵和向量的值,并且我尝试了所有3个可用选项,所有这些选项都给出了类似的“错误”。

我使用的代码:

//transformation matrix from RGB to YCbCr
const double rgb2YCbCrMatrix[3][3] = {
    { 0.257,  0.504,  0.098},
    {-0.148, -0.291,  0.439},
    { 0.439, -0.368, -0.071}
};
//transformation vector from RGB to YcBCr
const char rgb2YCbCrVector[3] = {
    16,
    128,
    128
};
//transformation matrix from YCbCr to RGB
const double TCbCr2rgbMatrix[3][3] = {
    {1.164,  0.000,  1.596},
    {1.164, -0.392, -0.813},
    {1.164,  2.017,  0.000}
};
//transformation vector from RGB to YcBCr
const char YCbCr2rgbVector[3] = {
    -16,
    -128,
    -128};

//calculate the values of the Y, Cb and Cr channels, used the formula for HDTV, as described at http://www.equasys.de/colorconversion.html
for (int i = 0; i < height*width; i++) {
    YChannel[i]  = redChannel[i]*rgb2YCbCrMatrix[0][0]+greenChannel[i]*rgb2YCbCrMatrix[0][1]+blueChannel[i]*rgb2YCbCrMatrix[0][2] + rgb2YCbCrVector[0];
    CbChannel[i] = redChannel[i]*rgb2YCbCrMatrix[1][0]+greenChannel[i]*rgb2YCbCrMatrix[1][1]+blueChannel[i]*rgb2YCbCrMatrix[1][2] + rgb2YCbCrVector[1];
    CrChannel[i] = redChannel[i]*rgb2YCbCrMatrix[2][0]+greenChannel[i]*rgb2YCbCrMatrix[2][1]+blueChannel[i]*rgb2YCbCrMatrix[2][2] + rgb2YCbCrVector[2];
}
//calculate the values of the RGB channels after the transformation, used the formula for HDTV, as described at http://www.equasys.de/colorconversion.html
for (int i = 0; i < height*width; i++) {
    redChannel[i]   = (YChannel[i] + YCbCr2rgbVector[0])*TCbCr2rgbMatrix[0][0]+(CbChannel[i] + YCbCr2rgbVector[1])*TCbCr2rgbMatrix[0][1]+(CrChannel[i] + YCbCr2rgbVector[2])*TCbCr2rgbMatrix[0][2];
    greenChannel[i] = (YChannel[i] + YCbCr2rgbVector[0])*TCbCr2rgbMatrix[1][0]+(CbChannel[i] + YCbCr2rgbVector[1])*TCbCr2rgbMatrix[1][1]+(CrChannel[i] + YCbCr2rgbVector[2])*TCbCr2rgbMatrix[1][2];
    blueChannel[i]  = (YChannel[i] + YCbCr2rgbVector[0])*TCbCr2rgbMatrix[2][0]+(CbChannel[i] + YCbCr2rgbVector[1])*TCbCr2rgbMatrix[2][1]+(CrChannel[i] + YCbCr2rgbVector[2])*TCbCr2rgbMatrix[2][2];
}

其中redChannelgreenChannelblueChannel以及YChannelCbChannelCrChannel属于unsigned char *类型, heightwidth是图片的维度。为什么这些图片没有返回相同,而所有其他测试图片返回完全正常。

P.S。

我已经使用命令rgb2ycbcrycbcr2rgb在Matlab中测试了这两张图片,并使用uint8将它们四舍五入,这给了我很好的结果。

in=imread(pic);
YCbCr = uint8(rgb2ycbcr(in));
out = uint8(ycbcr2rgb(YCbCr));
imshow(out);

2 个答案:

答案 0 :(得分:1)

我观察到,闪烁的区域似乎位于可能是纯黑色或白色的区域。

基于此,猜测:rgb2YCbCrVector的类型为char,其值'128'实际上溢出到-128。

因此,在r,g,b = 0,0,0的情况下,得到Y,Cr,Cb = 16,-128,-128而不是16,128,128。然后在转换回时,公式给出

redChannel = (16-16)*blah + (-128 - 128)*blah2 + (-128 - 128)*blah3

测试程序:

char a = 128;
char b = -128;
printf("%d", a + b);

输出: -256

所以当转换回来时,redChannel = 0 * blah1 - 256 * blah2 - 256 * blah3

这显然不是你原先预期的那样。

我会考虑将转换向量存储为float / double,或者至少为int。也许可以考虑对颜色通道做同样的事情,但不确定这会产生什么影响。

答案 1 :(得分:1)

YCbCr和RGB之间没有1对1的转换。使用相同的值范围,两个颜色空间中的颜色都无法在另一个颜色空间中表示。

当您在任一方向进行转换时,您需要将值限制在范围内。

例如,RGB到Y转换需要为每个组件转换具有类似的内容:

 double RGBtoY (double R, double G, double B)
{
   . . . . 
   if (result < 0.0)
     result = 0.0 ;
   else if (result > 255) // Or whatever maximum value
     result = 255 ;      
}

否则,你将会被包围。