如何修复YCrCb转RGB的转换公式?

5

我正在使用来自这个问题的公式:

uint8_t *rgbBuffer = malloc(imageWidth * imageHeight * 3);

// .. iterate over height and width

// from ITU-R BT.601, rounded to integers
rgbOutput[0] = (298 * (y - 16) + 409 * cr - 223) >> 8;
rgbOutput[1] = (298 * (y - 16) + 100 * cb + 208 * cr + 136) >> 8;
rgbOutput[2] = (298 * (y - 16) + 516 * cb - 277) >> 8;

我认为这是基于维基百科文章中的ITU-R_BT.601公式

enter image description here

但我认为这个公式还不太对,因为输出的图像看起来像这样:

I don't actually have green hair

我该如何修复这个公式?


可能是整数溢出/下溢问题吗? - Drew McGowen
你的数组是什么类型? - Fiddling Bits
@FiddlingBits - 字节数组 uint8_t *rgbBuffer = malloc(imageWidth * imageHeight * 3); 我会添加到问题中。 - Robert
+1非常好的问题陈述,引用了其他问题的代码,尤其是展示了问题所在的图片。 - R.. GitHub STOP HELPING ICE
2个回答

4
假设第一个计算的最大值为(y == 255cr == 255):
rgbOutput[0] = (298 * (255 - 16) + 409 * 255 - 223) >> 8;
rgbOutput[0] = (298 * 239 + 104295 - 223) >> 8;
rgbOutput[0] = (71222 + 104295 - 223) >> 8;
rgbOutput[0] = 175294 >> 8; // 175294 == 0x2ACBE
rgbOutput[0] = 684; // 684 == 0x2AC
rgbOutput [0] 可以容纳的最大值为 255。您尝试将 684 分配给它,结果被截断。实际分配给它的值是 1720xAC)。 编辑1 根据您发布的公式,您的第一个计算应如下进行:
rgbOutput[0] = ((298 * y) >> 8) + ((409 * cr) >> 8) - 223;

这将导致(假设ycr的最大值)的值为480,也会导致截断。 编辑2 据说推荐使用以下等式: equation 使用这个方程,你的第一个计算应该是这样的:
rgbOutput[0] = ((255 * (y - 16)) / 219) + ((179 * (cr - 128)) / 112;

这导致一个值,假设ycr的值都取最大值,结果为480(与编辑1中的答案相同),这也会导致截断。 编辑3: 完整解决方案请参见@Robert的答案。
编辑4: 当y == 0cr == 0时,写入y的值也将导致截断,除非进行夹紧处理。

是的 - 你说得对。我已经将它所基于的公式添加到问题中了。还有一些缺失的常数。 - Robert
太好了 - 图像现在看起来好多了!只有一些奇怪的区域,我认为这是截断的结果。你知道最有效的截断值的方法吗?我只需将其存储在“int”中,然后使用if语句检查其大小吗? - Robert
其实没关系,我找到了这个http://codereview.stackexchange.com/q/6502/30438。我自己试试限幅! - Robert
@Robert,你不想截断,因为RGB值应该在0到255之间,对吧? - Fiddling Bits
是的 - 我的意思是夹紧而不是截断。我刚刚修改了公式,现在它运行得非常好。谢谢你的帮助! :) 我会提交我的修改以确保完整性。 - Robert
好的,听起来不错。将大于255的值夹紧到255。祝你好运。 - Fiddling Bits

1

在@Fiddling Bits的帮助下,修正后的代码如下:

uint8_t ClampIntToByte(int n) {
    n = n > 255 ? 255 : n;
    return n < 0 ? 0 : n;
}

rgbOutput[0] = ClampIntToByte(((298 * (y - 16) + 409 * cr) >> 8) - 223);
rgbOutput[1] = ClampIntToByte(((298 * (y - 16) - 100 * cb - 208 * cr) >> 8) + 136);
rgbOutput[2] = ClampIntToByte(((298 * (y - 16) + 516 * cb) >> 8) - 277);

之前问题的答案中漏掉了夹紧部分。很好的发现。 - Fiddling Bits

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接