在Python中正确地将RGB转换成YCbCr

计算机对于颜色的存储有很多种不同的格式,其中最常见的就是RGB了。不过在很多计算机视觉的应用中,我们并不需要颜色信息,这时将颜色转换成YUV就可以在不丢失图片主要信息的前提下节约大量空间。然而,自古以来YUV的标准就相当混乱。最标准的格式应该是YCbCr,具体规范为ITU-R BT.601。不过JPEG的YUV格式更为常见。尤其要命的是,很多库自称是YCbCr,但实际上的实现并不标准,经常和JPEG的YUV混淆,典型的例子就是Python中的Pillow。如果只是使用Pillow库,就算不知道这个问题也不会影响使用。但在Python和MATLAB的软件混合使用的时候就会带来非常多不必要的麻烦。

最近在折腾VDSR,找了半天终于找到一个不需要大改就能跑起来的tensorflow-vdsr。训练集的生成用的MATLAB,出来的就只有Y通道的数据。在实现图片放大程序时发现使用Pillow内置的RGB转YCbCr效果不好,经过查阅资料发现Pillow的YCbCr就是个大坑,而MATLAB中的实现更标准。看起来问题很简单,找一个标准的YCbCr转换就行了。可惜网上找不到多少相关代码,就算有也多少有点问题(至少和MATLAB中的实现不一样)。看来造轮子是无法避免的了。好在MATLAB中相关代码是开源的,移植过来并不麻烦:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# ITU-R BT.601
# https://en.wikipedia.org/wiki/YCbCr
# RGB -> YCbCr
def rgb2ycbcr(rgb):
m = np.array([[ 65.481, 128.553, 24.966],
[-37.797, -74.203, 112],
[ 112, -93.786, -18.214]])
shape = rgb.shape
if len(shape) == 3:
rgb = rgb.reshape((shape[0] * shape[1], 3))
ycbcr = np.dot(rgb, m.transpose() / 255.)
ycbcr[:,0] += 16.
ycbcr[:,1:] += 128.
return ycbcr.reshape(shape)

# ITU-R BT.601
# https://en.wikipedia.org/wiki/YCbCr
# YUV -> RGB
def ycbcr2rgb(ycbcr):
m = np.array([[ 65.481, 128.553, 24.966],
[-37.797, -74.203, 112],
[ 112, -93.786, -18.214]])
shape = ycbcr.shape
if len(shape) == 3:
ycbcr = ycbcr.reshape((shape[0] * shape[1], 3))
rgb = copy.deepcopy(ycbcr)
rgb[:,0] -= 16.
rgb[:,1:] -= 128.
rgb = np.dot(rgb, np.linalg.inv(m.transpose()) * 255.)
return rgb.clip(0, 255).reshape(shape)

文章目录
|