参考文献:基于OpenCV的彩色空间互转 和 图像处理之灰色图转化为RGB图像.
1 色彩空间
1.1 GRAY色彩空间
- GARY色彩空间(灰度图像)通常指8位灰度图,具有256个灰度级,像素值的范围是[0,255]。不同数值表示不同程度的灰色。像素值越低,灰色越深。0表示纯黑色,255表示纯白色。
- GARY色彩空间为单通道,所以通常用二维数组表示一幅灰度图像。
- 其中二值图像:只有0和255两种像素值的灰度图像。
1.2 RGB色彩空间
- 于神经生理学角度出发,即视网膜的三种不同的颜色感受器。能够感受三种不同的颜色:红色、绿色、蓝色,即三基色。
- 自然界中常见的大部分颜色都可以通过将三基色按照一定比例混合得到。而在RGB色彩空间中,存在R(red)、G(green)、B(blue)三个通道。每个色彩通道值的范围都在[0,255]之间,我们用这三个色彩通道的组合表示颜色。下图表示不同RGB对应的颜色:
- 三个通道都是0表示黑色,三个通道都是255表示白色。RGB空间共可以表示256×256×256种颜色。RGB颜色空间基于颜色的加法混色原理,从黑色不断叠加Red,Green,Blue的颜色,最终可以得到白色。
- RGB的空间模型
将R、G、B三个通道作为笛卡尔坐标系中的X、Y、Z轴,就得到了一种对于颜色的空间描述:
而形象化的RGB颜色空间立方体:
其中,需要提前说一句后面会看到的一句话:这个RGB颜色空间立方体在主对角线上的颜色都为灰色。因此只要比例恰当RGB模型也可以从视觉感受器的角度表现为灰色,类似灰度图的视觉感受效果。 - 在应用领域需要注意的事情
首先,不同的Python处理库对彩色图像的通道处理顺序不一致:一般情况下,RGB色彩空间的通道顺序是R→G→B。但是在OpenCV中,通道顺序是B→G→R,而在Matplotlib中是R→G→B。
其次,RGB色彩空间虽然可以识别大部分的颜色,但是不适合科学研究:原因在于RGB(红绿蓝)是依据人眼识别的颜色定义出的空间,可表示大部分颜色。但在科学研究一般不采用RGB颜色空间,因为它的细节难以进行数字化的调整。它将色调,亮度,饱和度三个量放在一起表示,很难分开。
最后,它是最通用的面向硬件的彩色模型。该模型用于彩色监视器和一大类彩色视频摄像。
1.3 HSV色彩空间
- 与RGB色彩空间不同的是,HSV色彩空间是从心理学和视觉的综合角度出发。
- 它提出人眼的色彩知觉的三要素:H:色调(Hue)S:饱和度(Saturation)V:亮度(Value)。
首先,色调(H):色调是色彩的基本属性,就是平常说的颜色的名称,如“赤橙黄绿青蓝紫”等。色调与混合光谱中的主要波长相关,从波长的角度考虑,不同波长的光变现为不同的颜色,实际上体现的是色调的差异。色调的取值区间为[0,360]。色调取不同值,所代表的颜色如下表:
其中,两个角度之间的角度对应两个颜色之间的过渡色。(之所以称之为角度,是因为H的取值范围是0-360。)
其次,饱和度(S):饱和度指色彩的纯度,通俗的说就是颜色的深浅。饱和度越高色彩越纯,饱和度越低则逐渐变灰。饱和度与所加白光的数量成反比。饱和度的取值区间是[0,1]。灰度颜色的饱和度值是0。如果颜色的饱和度很低,那么它计算所得的色调不可靠。在OpenCV内,饱和度要映射到[0,255]范围内。
然后,亮度(V):反应的是人眼感受到的光的明暗程度。如果其中掺入的白色越多,则亮度越高;如果在其中掺入的黑色越多,则亮度越低。亮度的取值区间是[0,1]。当亮度值是0时,图象是纯黑色。在OpenCV内,亮度也要映射到[0,255]范围内。 - RGB色彩空间与HSV色彩空间的另外一点不同:RGB颜色空间中,三种颜色分量的取值与所生成的颜色之间的联系并不直观。而HSV颜色空间,更类似于人类感觉颜色的方式,封装了关于颜色的信息:“这是什么颜色?深浅如何?明暗如何?
- HSV空间模型
HSV颜色空间可以用一个倒圆锥体空间模型来描述。圆锥的顶点处,V=0,H和S无定义,代表黑色。圆锥的底面中心处V=360,S=0,H无定义,代表白色。
这个模型就是按色彩、深浅、明暗来描述的:
- 应用领域:可以用于偏光矫正、去除阴影、图像分割等。
2 颜色空间互转
2.1 可以发生互转的理由
对于一张图片,进行色彩空间转换,只是把它每个像素点的表示形式改变了,不管用RGB的表示形式,还是HSV的表示形式,把像素值按相应色彩空间的规则转换成对应的颜色后,表示的还是这张图片。
2.2 RGB与灰度图互转
**注意:**这里的灰度图在向RGB图像转换时,RGB值均一样,也就是说虽然转换后的图像的通道从灰度图的一层转换为三层,但是从视觉感受上,转换后的图像仍旧为灰色图像。
2.3 RGB与HSV互转
3 Python实现
3.1 将BGR转换为GRAY,再转换回BGR
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import cv2 import numpy as np if __name__ == "__main__": img = cv2.imread('D:/yt/pictures2/dog.jpg', cv2.IMREAD_UNCHANGED) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) bgr = cv2.cvtColor(gray,cv2.COLOR_GRAY2BGR) # 显示图像 cv2.imshow("origin image", img) cv2.imshow("gray image", gray) cv2.imshow("bgr image", bgr) # 保存图像 cv2.imwrite("D:/yt/pictures2/bgr-gray-dog.jpg", gray) cv2.imwrite("D:/yt/pictures2/gray-bgr-dog.jpg", bgr) cv2.waitKey(0) cv2.destroyAllWindows() |
效果
此时会发现一个问题:为什么由RGB转换为灰度图,再转换回RGB时,图像是灰色而不是彩色了?
另外一个问题是如何使得灰度图能够恢复到原来的彩色图像呢?
答案是:逆向处理我们要将RGB表示转换为gGB表示,也就是用灰度分量g取代蓝色分量R,蓝色分量B和绿色分量G不变。我们可以从gGB计算出红色分量R,因为灰度g=pR+qG+tB(其中p=0.2989,q=0.5870,t=0.1140),于是R=(g-qG-t*B)/p。于是我们只要保留B和G两个颜色分量,再加上灰度图g,就可以回复原来的RGB图像。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from __future__ import division import numpy as np import cv2 src = cv2.imread("C:/Users/12914/Pictures/messi.jpg") src_gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY) # RGB在opencv中存储为BGR的顺序,数据结构为一个3D的numpy.array,索引的顺序是行,列,通道: B = src[:,:,0] G = src[:,:,1] R = src[:,:,2] # 灰度g=p*R+q*G+t*B(其中p=0.2989,q=0.5870,t=0.1140),于是B=(g-p*R-q*G)/t。于是我们只要保留R和G两个颜色分量,再加上灰度图g,就可以回复原来的RGB图像。 g = src_gray[:] p = 0.2989; q = 0.5870; t = 0.1140 B_new = (g-p*R-q*G)/t B_new = np.uint8(B_new) src_new = np.zeros((src.shape)).astype("uint8") src_new[:,:,0] = B_new src_new[:,:,1] = G src_new[:,:,2] = R # 显示图像 cv2.imshow("input", src) cv2.imshow("output", src_gray) cv2.imshow("result", src_new) cv2.waitKey(0) cv2.destroyAllWindows() |
效果
认真思考过的学友可能会有看出一件事情:这个回复的过程,不仅仅需要灰度图像的数据,而且还需要原来彩色图像的数据。那么如果我知道了原来彩色图像的数据,那我为什么还要通过转换这种方式得到一张本身就存在的彩色图像呢?所以这样的答案并不适合应用情况,只是用作理解互转过程,换句话说,灰度图可以转换为RGB图像,但是无法恢复到本来的彩色图像。
3.2 将BGR转换为HSV,再转换回BGR
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import cv2 import numpy as np if __name__ == "__main__": img = cv2.imread('D:/yt/pictures2/dog.jpg', cv2.IMREAD_UNCHANGED) hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) bgr = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR) # 显示图像 cv2.imshow("origin image", img) cv2.imshow("hsv image", hsv) cv2.imshow("bgr image", bgr) # 保存图像 cv2.imwrite("D:/yt/pictures2/bgr-hsv-dog.jpg", hsv) cv2.imwrite("D:/yt/pictures2/hsv-bgr-dog.jpg", bgr) cv2.waitKey(0) cv2.destroyAllWindows() |
效果