我有一些问题将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频道时,我将值保持在范围内)
答案 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的权重,前者更为普遍。