無法將rgb轉換為YCbCr,且不丟失。

[英]Unable to convert rgb to YCbCr and back without loss


I need to write a program that will take pictures, transfer them to YCbCr format, manipulate the picture and then return the result back in RGB format. Before I write the manipulation I wrote the transformation from RGB to YCbCr and back and wanted to test that it works. On most pictures I've tested it on it works, and returns back a picture that is identical to the original. I have problems with 2 pictures, where the transformation seems to change some of the pixels. the pictures are (cropped areas from larger pictures):

我需要編寫一個程序來拍照,將它們轉換成YCbCr格式,操作圖片,然后返回RGB格式的結果。在我寫操作之前,我寫了從RGB到YCbCr和back的轉換,並想測試它是否有效。在大多數圖片上,我已經測試過它的工作,並返回一張與原始圖片相同的圖片。我有兩張圖片的問題,其中的變換似乎改變了一些像素。圖片是(從更大的圖片中裁剪出來的):

The original:

原文:

enter image description here

The result:

結果:

enter image description here

The original:

原文:

enter image description here

The result:

結果:

enter image description here

I'm taking the values for the conversion matrices and vectors from this site, and I've tried all the 3 available options, all of them give similar "errors".

我從這個網站取了轉換矩陣和向量的值,我試過了所有的3個選項,它們都給出了類似的“錯誤”。

The code I use:

我使用的代碼:

//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];
}

Where redChannel, greenChannel and blueChannel as well as YChannel, CbChannel and CrChannel are of unsigned char * type, and height and width are the dimensions of the picture. Why doesn't those pictures return the same, while all other tested pictures return perfectly fine.

其中redChannel、greenChannel和blueChannel以及YChannel、CbChannel和CrChannel均為無符號char *類型,且高度和寬度為圖的尺寸。為什么這些照片沒有返回相同的位置,而其他所有的測試圖片都可以完全恢復正常。

p.s.

注。

I've tested both pictures in Matlab using the commands rgb2ycbcr and ycbcr2rgb, and rounding them down with uint8 and it gave me good results.

我在Matlab中使用rgb2ycbcr和ycbcr2rgb的命令測試了這兩張照片,並將它們與uint8進行了對比,結果很好。

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

2 个解决方案

#1


1  

There is no 1-to-1 conversion between YCbCr and RGB. Using the same range of values, there are colors in both color spaces that cannot be represented in the other.

YCbCr和RGB之間沒有1- 1的轉換。使用相同范圍的值,在兩個顏色空間中都有不能表示的顏色。

When you do a conversion in either direction, you need to clamp the values to the range.

當您在任意方向進行轉換時,您需要將值夾到范圍。

For example, an RGB to Y conversion needs to have something like this for every component conversion:

例如,對於每個組件轉換,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 ;      
}

Otherwise, you are going to get wrap around.

否則,你就會被包圍。

#2


1  

I observed that the glitched areas appear to be in areas that are likely either pure black or white.

我觀察到,在那些可能是純黑或純白色的區域,出現了閃光的區域。

Based on this, a guess: rgb2YCbCrVector has type char, for which the value '128' actually overflows to -128.

基於此,猜測:rgb2YCbCrVector具有類型char,其值“128”實際上溢出到-128。

So in the case of r,g,b=0,0,0 you get Y,Cr,Cb=16,-128,-128 instead of 16,128,128. Then when converting back, the formula gives

所以在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

Test program:

測試程序:

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

Output: -256

輸出:-256

So when converting back, redChannel = 0*blah1 - 256*blah2 - 256*blah3

所以當轉換回來時,redChannel = 0*blah1 - 256*blah2 - 256*blah3。

Which is clearly not 0 as you would originally expect.

顯然不像你原來期望的那樣是0。

I would consider storing the conversion vectors as float/double, or at least int. Maybe consider doing the same for the color channels too, though not sure that would make a difference.

我將考慮將轉換向量存儲為float/double,或者至少是int.可能考慮對顏色通道做相同的操作,盡管不確定是否會產生影響。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2014/05/06/7256b69b90a742061968744ff815f37b.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com