ycbcr到边缘情况下的rgb颜色转换错误

时间:2018-04-06 19:53:37

标签: python colors rgb

我有一些问题将rgb照片转换为ycbcbr,修改y通道并转换回rgb,通常它工作正常,但对于某些边缘情况,它返回负值或大于255的值,所以当我将其转换回uint8对于matplotlib,它显示出亮点。

RGB到YCbCr

def rgb2ycbcr(data):
    res = np.empty(data.shape)
    res[...,0] = (data[...,0] * 0.299 + data[...,1] * 0.587 + data[...,2] * 0.114)
    res[...,1] = 128 + (data[...,0] * -0.169 + data[...,1] * -0.331 + data[...,2] * 0.5)
    res[...,2] = 128 + (data[...,0] * 0.5 + data[...,1] * -0.419 + data[...,2] * -0.081)
    return res

和YCbCr到RGB:

def ycbcr2rgb(data):
    res = np.empty(data.shape)
    data[...,1] = data[...,1] - 128
    data[...,2] = data[...,2] - 128
    res[...,0] = data[...,0] * 1 + data[...,2] * 1.4
    res[...,1] = data[...,0] * 1 + data[...,1] * -0.343 + data[...,2] * -0.711
    res[...,2] = data[...,0] * 1 + data[...,1] * 1.765
    return res

奇怪的是,当我不接触Y频道时,照片转换为正常(我知道当我修改Y频道时,我将值保持在范围内)

1 个答案:

答案 0 :(得分:4)

由于精度问题,您获得的负值和值超过1,因此您必须舍入/转换为整数:

RGB = np.asarray([[0, 0, 0], [255, 255, 255]])
print(rgb2ycbcr(ycbcr2rgb(RGB)))

[[-0.1423 0.6689 0.1714]
[255.1412 254.3363 254.8299]]

现在一个主要的问题是你使用的舍入太多并且不同意Recommendation ITU-T T.871的常量,相应地将你的代码略微调整为4位小数舍入参考:

RGB = np.asarray([[0, 0, 0], [255, 255, 255]])

def rgb2ycbcr(data):
    res = np.empty(data.shape)
    res[..., 0] = (
        data[..., 0] * 0.299 + data[..., 1] * 0.587 + data[..., 2] * 0.114)
    res[..., 1] = 128 + (
        data[..., 0] * -0.1687 + data[..., 1] * -0.3313 + data[..., 2] * 0.5)
    res[..., 2] = 128 + (
        data[..., 0] * 0.5 + data[..., 1] * -0.4187 + data[..., 2] * -0.0813)
    return res


def ycbcr2rgb(data):
    res = np.empty(data.shape)
    data[..., 1] = data[..., 1] - 128
    data[..., 2] = data[..., 2] - 128
    res[..., 0] = data[..., 0] * 1 + data[..., 2] * 1.402
    res[...,
        1] = data[..., 0] * 1 + data[..., 1] * -0.3441 + data[..., 2] * -0.7141
    res[..., 2] = data[..., 0] * 1 + data[..., 1] * 1.772
    return res

print(rgb2ycbcr(ycbcr2rgb(RGB)))

[[-0.0055 -0.0082 -0.0006]
[255.0054 255.0082 255.0006]]

你仍然需要转换为整数,但应该在更好的位置。 我注意到你正在data修改ycbcr2rgb,你应该在输入定义时复制数组,否则你会有非常令人讨厌的惊喜。

我建议在不Recommendation ITU-T T.871的情况下实施该版本。

我们维护的

Colour有一个非常solid and complete implementation of Y'CbCr,可用于验证您的计算:

RGB = np.asarray([[0, 0, 0], [255, 255, 255]])

print(colour.YCbCr_to_RGB(
    colour.RGB_to_YCbCr(
        RGB,
        K=colour.YCBCR_WEIGHTS['ITU-R BT.601'],
        in_bits=8,
        in_int=True,
        in_legal=False,
        out_bits=8,
        out_int=True,
        out_legal=True),
    K=colour.YCBCR_WEIGHTS['ITU-R BT.601'],
    in_bits=8,
    in_int=True,
    in_legal=True,
    out_bits=8,
    out_int=True,
    out_legal=False))

[[  0   0   0]
[255 255 255]]

我还建议使用BT.709权重代替来自ITU-T T.871 / BT.601的权重,前者更为普遍。