RGB、YUV和HSV颜色空间模型以及代码
一、概述
颜色通常用三个独立的属性来描述,三个独立变量综合作用,自然就构成一个空间坐标,这就是颜色空间。但被描述的颜色对象本身是客观的,不同颜色空间只是从不同的角度去衡量同一个对象。颜色空间按照基本机构可以分为两大类:基色颜色空间和色、亮分离颜色空间。前者典型的是RGB,后者包括YUV和HSV等等。
二、RGB颜色空间
1、计算机色彩显示器和彩色电视机显示色彩的原理一样,都是采用R、G、B相加混色的原理,通过发射出三种不同强度的电子束,使屏幕内侧覆盖的红、绿、蓝磷光材料发光而产生色彩。这种色彩的表示方法称为RGB色彩空间表示。
2、在RGB颜色空间中,任意色光F都可以用R、G、B三色不同分量的相加混合而成:F=r[R]+r[G]+r[B]。RGB色彩空间还可以用一个三维的立方体来描述。当三基色分量都为0(最弱)时混合为黑色光;当三基色都为k(最大,值由存储空间决定)时混合为白色光。
3、RGB色彩空间根据每个分量在计算机中占用的存储字节数分为如下几种类型:
(1)RGB555
RGB555是一种16位的RGB格式,各分量都用5位表示,剩下的一位不用。
高字节 -> 低字节
XRRRRRGGGGGBBBBB
(2)RGB565
RGB565也是一种16位的RGB格式,但是R占用5位,G占用6位,B占用5位。
(3)RGB24
RGB24是一种24位的RGB格式,各分量占用8位,取值范围为0-255。
(4)RGB32
RGB24是一种32位的RGB格式,各分量占用8位,剩下的8位作Alpha通道或者不用。
4、RGB色彩空间采用物理三基色表示,因而物理意义很清楚,适合彩色显象管工作。然而这一体制并不适应人的视觉特点。因而,产生了其它不同的色彩空间表示法。
三、YUV颜色空间
1、YUV(亦称YCrCb)是被欧洲电视系统所采用的一种颜色编码方法。在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD摄影机进行取像,然后把取得的彩色图像信号经分色、分别放大校正后得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y(即U)、B-Y(即V),最后发送端将亮度和两个色差总共三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V信号分量,那么这样表示的图像就是黑白灰度图像。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。
2、YUV主要用于优化彩色视频信号的传输,使其向后相容老式黑白电视。与RGB视频信号传输相比,它最大的优点在于只需占用极少的频宽(RGB要求三个独立的视频信号同时传输)。其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。“亮度”是透过RGB输入信号来建立的,方法是将RGB信号的特定部分叠加到一起。“色度”则定义了颜色的两个方面─色调与饱和度,分别用Cr和Cb来表示。其中,Cr反映了RGB输入信号红色部分与RGB信号亮度值之间的差异。而Cb反映的是RGB输入信号蓝色部分与RGB信号亮度值之同的差异。
3、YUV和RGB互相转换的公式如下(RGB取值范围均为0-255)︰
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B
R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U
四、HSV颜色空间
1、HSV是一种将RGB色彩空间中的点在倒圆锥体中的表示方法。HSV即色相(Hue)、饱和度(Saturation)、明度(Value),又称HSB(B即Brightness)。色相是色彩的基本属性,就是平常说的颜色的名称,如红色、黄色等。饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。明度(V),取0-max(计算机中HSV取值范围和存储的长度有关)。HSV颜色空间可以用一个圆锥空间模型来描述。圆锥的顶点处,V=0,H和S无定义,代表黑色。圆锥的顶面中心处V=max,S=0,H无定义,代表白色。
2、RGB颜色空间中,三种颜色分量的取值与所生成的颜色之间的联系并不直观。而HSV颜色空间,更类似于人类感觉颜色的方式,封装了关于颜色的信息:“这是什么颜色?深浅如何?明暗如何?”
3、RGB和HSV转换
(1)从RGB到HSV
设max等于r、g和b中的最大者,min为最小者。对应的HSV空间中的(h,s,v)值为:
h在0到360°之间,s在0到100%之间,v在0到max之间。
(2)从HSV到RGB
import numpy as np from skimage import data,img_as_float from PIL import Image import matplotlib.pyplot as plt def _prepare_colorarray(arr): """Check the shape of the array and convert it to floating point representation. """ arr = np.asanyarray(arr) if arr.ndim not in [3, 4] or arr.shape[-1] != 3: msg = ("the input array must be have a shape == (.., ..,[ ..,] 3)), " + "got (" + (", ".join(map(str, arr.shape))) + ")") raise ValueError(msg) return img_as_float(arr) #RGB -- HSV 色相(Hue)、饱和度(Saturation)、明度(Value) def rgb2hsv(rgb): """RGB to HSV color space conversion. Parameters ---------- rgb : array_like The image in RGB format, in a 3-D array of shape ``(.., .., 3)``. Returns ------- out : ndarray The image in HSV format, in a 3-D array of shape ``(.., .., 3)``. Raises ------ ValueError If `rgb` is not a 3-D array of shape ``(.., .., 3)``. Notes ----- Conversion between RGB and HSV color spaces results in some loss of precision, due to integer arithmetic and rounding [1]_. References ---------- .. [1] http://en.wikipedia.org/wiki/HSL_and_HSV Examples -------- >>> from skimage import color >>> from skimage import data >>> img = data.astronaut() >>> img_hsv = color.rgb2hsv(img) """ arr = _prepare_colorarray(rgb) #转化为float类型 out = np.empty_like(arr) #生成与arr相同的0矩阵 # -- V channel out_v = arr.max(-1) # 求每一行的最大值 # -- S channel delta = arr.ptp(-1) # 求每一行的极差 (max - min) # Ignore warning for zero divided by zero old_settings = np.seterr(invalid='ignore') #对浮点类型的处理, 这里有异常进行 忽略 out_s = delta / out_v out_s[delta == 0.] = 0. # -- H channel # red is max idx = (arr[:, :, 0] == out_v) out[idx, 0] = (arr[idx, 1] - arr[idx, 2]) / delta[idx] # green is max idx = (arr[:, :, 1] == out_v) out[idx, 0] = 2. + (arr[idx, 2] - arr[idx, 0]) / delta[idx] # blue is max idx = (arr[:, :, 2] == out_v) out[idx, 0] = 4. + (arr[idx, 0] - arr[idx, 1]) / delta[idx] out_h = (out[:, :, 0] / 6.) % 1. out_h[delta == 0.] = 0. np.seterr(**old_settings) # -- output out[:, :, 0] = out_h out[:, :, 1] = out_s out[:, :, 2] = out_v # remove NaN out[np.isnan(out)] = 0 return out #HSV -- RGB def hsv2rgb(hsv): """HSV to RGB color space conversion. Parameters ---------- hsv : array_like The image in HSV format, in a 3-D array of shape ``(.., .., 3)``. Returns ------- out : ndarray The image in RGB format, in a 3-D array of shape ``(.., .., 3)``. Raises ------ ValueError If `hsv` is not a 3-D array of shape ``(.., .., 3)``. Notes ----- Conversion between RGB and HSV color spaces results in some loss of precision, due to integer arithmetic and rounding [1]_. References ---------- .. [1] http://en.wikipedia.org/wiki/HSL_and_HSV Examples -------- >>> from skimage import data >>> img = data.astronaut() >>> img_hsv = rgb2hsv(img) >>> img_rgb = hsv2rgb(img_hsv) """ arr = _prepare_colorarray(hsv) hi = np.floor(arr[:, :, 0] * 6) f = arr[:, :, 0] * 6 - hi p = arr[:, :, 2] * (1 - arr[:, :, 1]) q = arr[:, :, 2] * (1 - f * arr[:, :, 1]) t = arr[:, :, 2] * (1 - (1 - f) * arr[:, :, 1]) v = arr[:, :, 2] hi = np.dstack([hi, hi, hi]).astype(np.uint8) % 6 out = np.choose(hi, [np.dstack((v, t, p)), np.dstack((q, v, p)), np.dstack((p, v, t)), np.dstack((p, q, v)), np.dstack((t, p, v)), np.dstack((v, p, q))]) return out if __name__ == '__main__': ima = Image.open('./example/image_0401.jpg' ) print(ima.size) img = np.asarray(ima) img_hsv = rgb2hsv(img) #plt.imshow(img_hsv); #plt.show() img = hsv2rgb(img_hsv) plt.imshow(img); plt.show()