Colors 将YCbCr转换为RGB是否可逆?

Colors 将YCbCr转换为RGB是否可逆?,colors,rgb,yuv,Colors,Rgb,Yuv,我在玩一些不同的图像格式,偶然发现了一些奇怪的东西。当从RGB转换到YCbCr,然后再转换回RGB时,结果与我开始时非常相似(像素值的差异几乎总是小于4)。然而,当我从YCbCr转换到RGB,然后再转换回YCbCr时,我通常会得到截然不同的值。有时a值会相差超过40 我不知道这是为什么。我的印象是,可以通过YCbCr表达的颜色是RGB中颜色的一个子集,但看起来这是完全错误的。YCbCr中是否有一些已知的颜色子集可以转换为RGB,然后返回到其原始值 我用于转换的代码(基于): 编辑: 我为这个问题

我在玩一些不同的图像格式,偶然发现了一些奇怪的东西。当从RGB转换到YCbCr,然后再转换回RGB时,结果与我开始时非常相似(像素值的差异几乎总是小于4)。然而,当我从YCbCr转换到RGB,然后再转换回YCbCr时,我通常会得到截然不同的值。有时a值会相差超过40

我不知道这是为什么。我的印象是,可以通过YCbCr表达的颜色是RGB中颜色的一个子集,但看起来这是完全错误的。YCbCr中是否有一些已知的颜色子集可以转换为RGB,然后返回到其原始值

我用于转换的代码(基于):

编辑:

我为这个问题创建了一个基本的3D图形。所有点都是值差小于10的点。它的形状很有趣。X是Cb,Y是Cr,Z是Y


据我所知,您应该能够以最小的精度损失从和转换为两种格式

该网站有另一套转换公式,称为“RGB到全范围YCbCr”和“全范围YCbCr到RGB”,我相信这些是你应该使用的,我认为它应该使你能够无任何问题地前后转换

编辑:

由于这些公式不适用于您,我将分享在android中用于RGB和YUV之间转换的公式:

R = clamp(1 * Y +        0 * (U - 128) + 1.13983 * (V - 128), 0, 255);
G = clamp(1 * Y + -0.39465 * (U - 128) + -0.5806 * (V - 128), 0, 255);
B = clamp(1 * Y + 2.03211 * (U - 128) +       0 * (V - 128), 0, 255);

Y = clamp(0.299    * R + 0.587    * G + 0.114    * B, 0, 255);
U = clamp(-0.14713 * R + -0.28886 * G + 0.436    * B + 128, 0, 255);
V = clamp(0.615    * R + -0.51499 * G + -0.10001 * B + 128, 0, 255);

我刚刚试过,它似乎来回地工作。请注意128的求和和和减法,因为此YUV表示法由无符号字节范围(0..255)组成,RGB也是如此(通常如此),因此如果您的YCbCr确实需要(16..235)和(16..240)范围,您可能需要另一个公式。

正如我在评论中所说,您的第一个问题是,在
yuv2rgb
中的循环内计算时使用的是
y
而不是
c

第二个问题是将RGB值钳制到错误的范围:RGB应为0..255

RGB计算应如下所示:

  r = clamp(1.164*c +           1.596*e, 0, 255)
  g = clamp(1.164*c - 0.392*d - 0.813*e, 0, 255)
  b = clamp(1.164*c + 2.017*d          , 0, 255)

不,根本不是。[以上讨论的都是针对8位的。]在满量程R'G'B'到有限量程YCbCr的情况下,这是显而易见的(只是没有)。例如,您可以在此处进行测试:

全范围R'G'B'值238、77、45通过BT.601矩阵编码为有限YCbCr:学校四舍五入后,您将获得有限范围120、90、201,但如果您将其四舍五入,您将在R'G'B'中获得238、77、44。238,77,44值将变为相同的值。哎呀。游戏结束了

在满量程RGB至满量程YCbCr的情况下。。。YCbCr中的某些值将为负R',G',B'。(例如,在有限范围YCbCr BT.709中,值139、151、24将为RGB-21、182、181,仅转换为全范围YCbCr。)因此,同样,没有双射

下一步,限制范围R'G'B'到限制范围YCbCr。。。同样,没有双射。YCbCr中的黑色实际上是16、128、128,只有这个。所有其他16,x,y都是不允许的[它们在xvYCC中,这是非标准的],而它们在R,G,B中,并且所有235,128,128都是相同的。当然,前面的负R',G',B'也适用


我不知道,由于范围限制为全范围。

您在
yuv2rgb
计算中使用了
y
,而不是
c
。我还没有测试过,所以我不知道这是否是问题的严重程度。谢谢你的建议!遗憾的是,使用其他公式也不起作用。例如,YCbCR值[0,0,0]变为RGB值[0134,0],然后再转换回YCbCR值[78,83,71]。@Ric我编辑了我的回复,并包含了我个人在android中使用过的公式,您可能希望检查它们。感谢您的代码。我在[16,16,16]的YUV值上进行了试验。转换为RGB将得到[0125243],然后再转换回[10119839]。您是对的。首先,我在2.03211元素中有一个输入错误,应该是肯定的。不仅如此,你也说得对,这些值没有转换回相同的值,但根据我的经验,它最终映射到相同的颜色。尝试转换YUV1->RGB1->YUV2->RGB2,然后RGB1和RGB2的值应大致相同。从您的示例(16,16,16)->(0125,0)->(73,92,64)->(0124,0)中可以看出,这是一个很好的打字错误!不幸的是,钳制到这个范围仍然会产生不可逆的结果。[0,0,0]处的YCbCr值转到[0135,0]处的RGB,该RGB给出的最终YCbCr值[84,88,78]@Ric
[0,0,0]
不是有效的YCbCr颜色值。每个的最小值为16。
  r = clamp(1.164*c +           1.596*e, 0, 255)
  g = clamp(1.164*c - 0.392*d - 0.813*e, 0, 255)
  b = clamp(1.164*c + 2.017*d          , 0, 255)