我使用JPEG转换公式实现了rgb-> ycrcb和ycrcb-> rgb转换
http://www.w3.org/Graphics/JPEG/jfif3.pdf
(同样在:http://en.wikipedia.org/wiki/YCbCr(JPEG转换))。
当检查结果是否正确时(原始 - > YCrCb-> RGB),一些像素相差一,例如201-> 200。
精确误差的平均百分比为0.1%,因此它并不重要。
/// converts RGB pixel to YCrCb using { en.wikipedia.org/wiki/YCbCr: JPEG conversion }
ivect4 rgb2ycrcb(int r, int g, int b)
{
int y = round(0.299*r + 0.587*g + 0.114*b) ;
int cb = round(128.0 - (0.1687*r) - (0.3313*g) + (0.5*b));
int cr = round(128.0 + (0.5*r) - (0.4187*g) - (0.0813*b));
return ivect4(y, cr, cb, 255);
}
/// converts YCrCb pixel to RGB using { en.wikipedia.org/wiki/YCbCr: JPEG conversion }
ivect4 ycrcb2rgb(int y, int cr, int cb)
{
int r = round(1.402*(cr-128) + y);
int g = round(-0.34414*(cb-128)-0.71414*(cr-128) + y);
int b = round(1.772*(cb-128) + y);
return ivect4(r, g, b, 255);
}
我使用圆形公式:
((x)+ 0.5)
使用其他类型的舍入时,例如float(int)或std :: ceil(),结果更糟。
那么,是否有办法做YCrCb< - > RGB转换没有精度损失?
答案 0 :(得分:3)
问题不在于舍入模式。
即使您将浮点常数转换为比率并仅使用整数数学,您仍然会在反转后看到不同的值。
要了解原因,请考虑一个函数,我告诉你我要将数字0到N移动到范围0到N-2。事实是,这种变换只是没有逆。您可以使用浮点计算(f(x) = x*(N-2)/N
)或多或少地精确表示它,但是一些相邻值将映射到整数数学中的相同结果(归类原则!)。这是一个简化和“压缩”范围,但同样的事情发生在你正在使用的任意仿射变换中。
如果你有r,g,b在浮点,并保持这种方式,直到你量化为整数,这将是一个不同的故事 - 但在整数中,你必然总是看到原始和反之间的一些差异。
答案 1 :(得分:1)
是的,据说JPEG XR定义了可逆的颜色转换。如果您想深入调查他们是如何做的,那么代码是开源的。在我链接到的Wiki页面上松散地描述了该方法。
同样this SO post可能会给你一些见解。
答案 2 :(得分:0)
另一个问题是rgb和YCbCR之间没有1到1的映射。有YCbCr值,没有相应的RGB值和RBG值,没有相应的YCbCR值。
答案 3 :(得分:0)
当对两个三元组使用相同数量的位时,在YCbCr空间中只能表示所有RGB值的约60%。这意味着当您使用3 * 8位RGB三元组时,RGB-> YCbCr中发生的损坏最大,将其转换并将其舍入为3 * 8位精度。诀窍是以更高的精度存储YCbCr三元组,直到转发DCT为止。在那里,无论如何都需要扩大数据,所以你可以做到这一点。 16位* 16位 - > MSB16相乘,各种SIMD指令集都很好地支持。
在解码器处它是相反的:逆DCT的结果必须以更高的精度存储,直到进行YCbCr-> RGB转换为止。
这不会使该过程无损失,但对于JPEG,它可能会在质量等级的极端高端购买几分贝的PSNR,即肉眼无法看到差异但可以测量