在第2篇中提到过,如果是二值图片(黑白图)或者灰度图片,一个像素需要一个8位二进制来表示。而对于彩色图像,一个像素则需要用3个8位二进制来表示。我们认为灰度图只有一个图层,而普通的彩色图像则有三个图层。
对于灰度图来说,像素强调的是白色的程度,当像素值为0时图像表现为黑色,当像素值为255时图像表现为白色。而处于中间的灰色,我们可以理解为“不够白”的颜色。
对于彩色图像,我们通常会用RGB三个颜色表示。它们分别是红、绿、蓝,我们可以通过三种颜色的调配展现出各种颜色。
那在OpenCV中要怎么操作图层呢?我们先打开一张彩色图片,查看它的通道数:
import cv2
# 读取图片
img = cv2.imread("xyql.jpg")
# 查看图片的形状
print(img.shape)
输出结果如下:
(1079, 1080, 3)
其中3就是图片的图层数。我们可以通过索引将三个通道分离出来:
import cv2
# 读取图片
img = cv2.imread('test.jpg')
# 切片提取B通道
b = img[:, :, 0]
# 切片提取G通道
g = img[:, :, 1]
# 切片提取R通道
r = img[:, :, 2]
因为在OpenCV中图片模式默认是BGR,因此我们分离的第0个通道是b,第一个和第二个分别是g和r。我们可以看看三个通道的图像:
上面分别是原始图片和BGR三个通道图片。因为拆分后的图片只有一个通道,所以显示效果都是黑白的。
可以看到原图的娜娜面色红润,所以R通道皮肤部分要比较亮(颜色偏白,像素值较高)。
除了自己索引,我们还可以调用OpenCV的内置方法分离通道,代码如下:
import cv2
# 读取图片
img = cv2.imread('test.jpg')
# 调用OpenCV内置方法进行分离通道
b, g, r = cv2.split(img)
在代码中我们调用了cv2.split()
,如果我们的图片有三个通道我们需要用三个参数接收,如果有四个通道则需要用四个参数接收。
在此之前我们已经接触过几种色彩空间了,比如RGB和GRAY两种。除了RGB和GRAY外,还有XYZ、YCrCb、HSV等。不同的色彩空间删除处理不同的问题,有时候我们会将图片转换成指定的色彩空间以便进行相应的处理。
RGB(我们认为RGB和BGR是同种色彩空间)是一种方便计算机处理的色彩空间,它用三原色组成。但是对人来说RGB这种色彩空间是很难理解的,我们不会说黄色是红色+绿色,也不会说白色是红色+绿色+蓝色(对平常人来说)。
而HSV色彩空间是一种符合人类视觉感知的模型,这种色彩空间会用色调(Hue,也称为色相)、饱和度(Saturation)、亮度(Value)来表示像素。它们的解释分别如下:
摘自《OpenCV轻松入门:面向Python》,作者:李立宗。 ● 色调:色调与混合光谱中的主要光波长相关,例如“赤橙黄绿青蓝紫”分别表示不同的色调。如果从波长的角度考虑,不同波长的光表现为不同的颜色,实际上它们体现的是色调的差异。 ● 饱和度:指相对纯净度,或一种颜色混合白光的数量。纯谱色是全饱和的,像深红色(红加白)和淡紫色(紫加白)这样的彩色是欠饱和的,饱和度与所加白光的数量成反比。 ● 亮度:反映的是人眼感受到的光的明暗程度,该指标与物体的反射度有关。对于色彩来讲,如果在其中掺入的白色越多,则其亮度越高;如果在其中掺入的黑色越多,则其亮度越低。
如果遇到需要调节饱和度的场景时,我们可以选择使用HSV色彩空间。
色彩空间的转换有固定的公式,这些公式都非常简单,我们来简单看其中一个。RGB到YCrCb颜色空间的转换:
其中δ的值计算如下:
当然我们不需要自己计算,在OpenCV中提供了色彩空间转换的函数cv2.cvtColor()
,函数格式如下:
dst = cv2.cvtColor(src, code)
该函数接收两个参数,分别是要转换的图片和转换的模式。最后函数会给我们返回转换后的结果,这里重点关注一下code参数。
code参数我们只需要添加OpenCV中的一些常量即可,这些常量很好理解:
因为图片比较长,这里只列出一部分。命名规则大都为COLOR_XX2YY,也就是函数就是将色彩空间为XX的图片转换为YY色彩空间。其中我们最常用的就是下面几个:
# 将BGR转换成GRAY(灰度图)
cv2.COLOR_BGR2GRAY
# 将BGR转换为RGB
cv2.COLOR_BGR2RGB
# 将BGR转换为HSV
cv2.COLOR_BGR2HSV
# 将BGR转换为BGRA(png图片)
cv2.COLOR_BGR2BGRA
下面我们来实际使用一下,我们先看一段简单的代码:
import cv2
import numpy as np
from PIL import Image
# 读取图片
img = Image.open('nn.jpg')
# 将图片对象转换成ndarray对象
img = np.array(img)
# 显示图片
cv2.imshow('img', img)
cv2.waitKey()
cv2.destroyAllWindows()
下面是原图和上面代码显示的图片:
在代码中我们使用PIL模块读取图片,因为PIL默认是以RGB模式读取,因此当我们直接将它转换为ndarray数组时,OpenCV把R和B通道颠倒了,因此图片颜色异常显示。
PIL模块的安装如下:
pip install pillow
其实我们可以简单分析一下,这次的娜娜依旧面色红润,因为右边的效果图颠倒了R和B通道,因此红色部分显示效果要接近蓝色,而蓝色的衣服效果却接近红色。
想要正常显示我们需要对颜色空间进行一些简单的转换:
import cv2
import numpy as np
from PIL import Image
img = Image.open('nn.jpg')
img = np.array(img)
# 将RGB图片转换成BGR
bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
cv2.imshow('img', bgr)
cv2.waitKey()
cv2.destroyAllWindows()
你们可以自己尝试运行一下,显示效果会和原图一样。其它颜色空间的转换也是一样的,这里就不再一一演示了。