使用JPEG转换公式实现了rgb->ycrcb和ycrcb->rgb转换。
http://www.w3.org/Graphics/JPEG/jfif3.pdf
(相同的at: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)
当使用其他类型的四舍五入,例如浮动(Int)或std::ceil()时,结果会更糟糕。
那么,是否存在这样一种方法来进行YCrCb <-> RGB转换而不损失精度?
发布于 2015-05-06 16:04:21
问题不在于舍入模式。
即使您将浮点常数转换为比率,并且只使用整数数学,在逆运算之后仍然会看到不同的值。
要知道为什么,考虑一个函数,我告诉你,我要把数字从0到N转换到0到N2。事实是,这个变换是没有逆的。您可以使用浮点计算(f(x) = x*(N-2)/N)或多或少精确地表示它,但是一些相邻的值将映射到整数数学中的相同结果(pigeonhole原理!)。这是一个简化和“压缩”范围,但同样的事情发生在任意仿射变换,如您正在使用的。
如果你把r,g,b放在浮点上,并且一直这样,直到你把它量化成整数,那就不一样了--但是在整数中,你总能看到原始和逆之间的一些区别。
发布于 2015-05-07 15:22:18
当对两个三胞胎使用相同数量的位时,只有大约60%的RGB值可以在YCbCr空间中表示。这意味着最大的伤害发生在RGB->YCbCr当你采取一个3*8位的RGB三重奏,转换和循环它回到3*8位的精度。诀窍是以更高的精度存储YCbCr三重奏,直到是时候进行正向离散余弦变换。在那里,数据无论如何都需要放大,所以您可以做例如16位* 16位-> MSB16乘法,这是由各种SIMD指令集很好地支持的。
在解码器上,情况正好相反:反DCT的结果必须以更高的精度存储,直到完成YCbCr->RGB转换为止。
这并不能使过程无损,但对于JPEG,它可以购买几个dB的PSNR在极端高端的质量尺度,即差别不能用肉眼看到,但可以测量。
发布于 2015-06-04 14:55:05
是的,据说JPEG XR定义了一种可逆的颜色转换。如果您想深入了解他们是如何做到的,那么代码是开源的。该方法在我链接到的Wiki页面上进行了松散的描述。
此外,这是如此的帖子可能会给你一些见解。
https://stackoverflow.com/questions/30081784
复制相似问题