小白学OpenCV系列2-理解图像
上篇文章中,我们学习了如何安装OpenCV,以及一些简单的函数操作,今天这篇文章就一起来看看图像的本质是什么,在计算机里如何表示。
如何表示图像
二值图像
所谓二值图像,就是仅仅包含黑白两种颜色的图像,我们以下面这张图为例,来看看在计算机的世界里是如何看待图像的。
使用下面的代码读取,我们可以看到该图像实际上用了一个256x256的矩阵表示,其中每个单元(也称为像素点)的取值只有0(黑色)和255(白色)两种。
import cv2
import numpy as np # flags=0表示以单通道灰度图形式加载图像
lena = cv2.imread("lena_two.jpg", flags=0)
print(np.shape(lena))
cv2.imshow("lena", lena)
cv2.waitKey()
cv2.destroyAllWindows()
灰度图像
二值图像虽然简单方便,但却不够细腻,缺少细节信息,灰度图像则是在其基础上,用了更多的数值来表示不同的颜色。通常情况下,计算机会将灰度处理为256个灰度级,用数值0-255来表示,也就是说在二值图像所表达的黑白外,增加了254个数值来表示从纯白到纯黑之间不同级别的灰度。
同样使用上述代码,可以看到矩阵大小不变,但是其数值已不再只是0和255了。
彩色图像
相比于二值图像和灰度图像,彩色图像在我们的日常生活中更为常见,它展现了更丰富的细节。那么计算机又如何表示一张彩色图像呢?实际上这里牵扯到一个很重要的概念-颜色空间,不同的颜色空间具有不同的表示方式。
颜色空间就是我们去看待颜色的方式,从生物学角度来看,在视网膜上存在三种不同的颜色感受器,能够感受三种不同的颜色:红色、绿色和蓝色,而自然界中常见的各种色光都可以通过这三种颜色按照一定的比例混合而成。从光学角度来看,可以将颜色解析成主波长、纯度、明度等。从视觉角度来看,可以将颜色解析成色调、饱和度、亮度等。不同的颜色空间适用于不同的场景,在选择的时候需要依据实际需求来决定,颜色空间之间可以按照公式进行转换。
RGB颜色空间是我们经常使用的一种,它存在三个通道,即红色、绿色和蓝色,每个通道的取值范围都在0-255之间,三个通道组合起来就可以表示各种颜色。下表列出了常见RGB值对应的颜色:
RGB值(R,G,B) | 颜色 | 十六进制代码 |
---|---|---|
(0,0,0) | 纯黑色 | #000000 |
(255,255,255) | 纯白色 | #FFFFFF |
(255,0,0) | 红色 | #FF0000 |
(0,255,0) | 绿色 | #00FF00 |
(0,0,255) | 蓝色 | #0000FF |
(255,255,0) | 黄色 | #FFFF00 |
(0,255,255) | 青色 | #00FFFF |
(128,128,128) | 灰色 | #808080 |
事实上,每个通道都可以理解为一个独立的灰度图像,以下图为例,我们来看看其在计算机中是如何存储的:
import cv2
import numpy as np # flags=1表示以BGR三通道格式加载
lena = cv2.imread("lenacolor.png", flags=1)
print(np.shape(lena))
cv2.imshow("lena", lena)
cv2.waitKey()
cv2.destroyAllWindows()
使用上述代码读取后,可以发现它是一个512x512x3的矩阵,前面的两个数字是每个通道的形状,最后的数字代表3个通道,不同的是在OpenCV中,第一个通道是B,第二个通道是G,第三个通道是R,刚好和RGB颜色空间的图像通道相反(第一个通道是R,第二个通道是G,第三个通道是B)。
像素操作
实际上,当图像被读取到计算机里之后,就是一个矩阵罢了,其类型为numpy.array,我们可以通过索引来操作数组值,也可以通过item函数更加高效地访问。下面我们就用该函数实现灰度图像上绘制一个白色矩形框的效果,代码如下所示:
import cv2
import numpy as np # flags=0表示以单通道灰度图加载
lena = cv2.imread("lena.bmp", flags=0)
# 绘制一个白色矩形框
for i in range(10, 100): for j in range(80, 100): print(f"矩阵位置{i},{j}的值从{lena.item(i, j)}更改为255") lena.itemset((i, j), 255) cv2.imshow("lena", lena)
cv2.waitKey()
cv2.destroyAllWindows()
通道操作
之前我们介绍过用RGB颜色空间来表示一张彩色图像,它是由R通道、G通道、B通道三个通道构成的,而在OpenCV中,通道是按照B通道-G通道-R通道的顺序存储的。
通道拆分
在实际应用中,我们可能会需要将三个通道拆分出来,主要有两种方式:索引和库函数。
1、索引拆分
索引拆分的方式很简单,利用下述代码可以将彩色图像分离出三个通道的图像。
import cv2 lena = cv2.imread("lenacolor.png", flags=1) b_lena = lena[:, :, 0]
g_lena = lena[:, :, 1]
r_lena = lena[:, :, 2] print("b通道图像")
cv2.imshow("b_lena", b_lena)
cv2.waitKey() print("g通道图像")
cv2.imshow("g_lena", g_lena)
cv2.waitKey() print("r通道图像")
cv2.imshow("r_lena", r_lena)
cv2.waitKey() cv2.imwrite("b_lena.png", b_lena)
cv2.imwrite("g_lena.png", g_lena)
cv2.imwrite("r_lena.png", r_lena)
cv2.destroyAllWindows()
2、库函数拆分
OpenCV也提供了split函数来拆分图像的通道:
import cv2 lena = cv2.imread("lenacolor.png", flags=1)
b_lena, g_lena, r_lena = cv2.split(lena)
通道合并
既然可以拆分通道,那么也可以将拆分后的各通道进行合并,OpenCV提供了merge函数来实现此功能,借助下述代码可以将上述拆分的各通道合并。
import cv2 b_lena = cv2.imread("b_lena.png", flags=0)
g_lena = cv2.imread("g_lena.png", flags=0)
r_lena = cv2.imread("r_lena.png", flags=0) lena = cv2.merge([b_lena, g_lena, r_lena])
cv2.imshow("lena", lena) cv2.waitKey()
cv2.destroyAllWindows()
可以看到能够完全复原初始的彩色图像,如果我们将b,g,r三个通道颠倒过来,看看又会是怎样的呢?
import cv2 b_lena = cv2.imread("b_lena.png", flags=0)
g_lena = cv2.imread("g_lena.png", flags=0)
r_lena = cv2.imread("r_lena.png", flags=0) lena = cv2.merge([r_lena, g_lena, b_lena])
cv2.imshow("lena", lena) cv2.waitKey()
cv2.destroyAllWindows()
可以看出整张图像的风格从暖色调一下子就变到了冷色调。
获取图像属性
在图像处理过程中,经常需要获取图像的属性,常用的包括:
- shape:如果是彩色图像,则返回包含行数、列数、通道数的数组;如果是二值图像或灰度图像,则仅返回行数和列数。
- size:返回图像的像素数目。
- dtype:返回图像的数据类型。
我们可以通过下述代码来展示其使用方式:
import cv2 lena = cv2.imread("lena.bmp", flags=0)
print(f"灰度图像的属性为:")
print(f"lena.shape={lena.shape}")
print(f"lena.size={lena.size}")
print(f"lena.dtype={lena.dtype}")
lena = cv2.imread("lenacolor.png", flags=1)
print(f"彩色图像的属性为:")
print(f"lena.shape={lena.shape}")
print(f"lena.size={lena.size}")
print(f"lena.dtype={lena.dtype}")
总结
本篇文章主要介绍了几种常见的图像类型:二值图像、灰度图像和彩色图像。二值图像常用0表示黑色,255表示白色;灰度图像则使用了0-255总计256个值来表示不同颜色;彩色图像则有多种表达方式,常见的RGB颜色空间使用了R、G、B三个通道来表示一张彩色空间,每个通道都可以理解为一个独立的灰度图像。另外还介绍了一些常见的图像处理方法,如像素操作(itemset)、通道操作(split、merge)及属性获取(shape、size、dtype)。