我需要编写一个程序来拍照,将它们转换为YCbCr格式,操作图片然后以RGB格式返回结果。在我编写操作之前,我编写了从RGB到YCbCr的转换并返回并想测试它是否有效。在我测试过的大多数图片上都有效,并返回与原始图片相同的图片。我有2张图片的问题,其中转换似乎改变了一些像素。图片是(较大图片中的裁剪区域):
原文:
结果:
原文:
结果:
我正在从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];
}
其中redChannel
,greenChannel
和blueChannel
以及YChannel
,CbChannel
和CrChannel
属于unsigned char *
类型, height
和width
是图片的维度。为什么这些图片没有返回相同,而所有其他测试图片返回完全正常。
P.S。
我已经使用命令rgb2ycbcr
和ycbcr2rgb
在Matlab中测试了这两张图片,并使用uint8
将它们四舍五入,这给了我很好的结果。
in=imread(pic);
YCbCr = uint8(rgb2ycbcr(in));
out = uint8(ycbcr2rgb(YCbCr));
imshow(out);
答案 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 ;
}
否则,你将会被包围。