OpenCV图像的读写操作
概要
图像由像素组成。 像素可以被认为是非常小的正方形结构,当连接在一起时会生成图像。 它们是任何图像的最小组成部分。
如果您仔细查看前面的图像,您将能够在图像中看到一些正方形。这些被称为像素。 像素没有标准尺寸;它因设备而异。我们经常使用术语“每英寸像素数(PPI)”来定义图像的分辨率。图像的一英寸(或平方英寸)中更多的像素意味着更高的分辨率。
像素位置:图像坐标系
我们知道像素是正方形,是图像的最小组成部分。使用特定像素在图像中的位置进行引用。每个图像都有一个特定的坐标系。OpenCV 中遵循的标准是图像的左上角充当原点(0,0)
。 当我们向右移动时,像素位置的 X
坐标增加,而当我们向下移动时,Y
坐标增加。
图像的三个主要属性:
- 图像尺寸
- 色彩空间
- 图像通道数
图像尺寸
图像的大小由其高度和宽度表示。这些数字表示图像中存在的像素数。因此,尺为 1920×1221
的图像将总共具有 1920×1221 = 2334420
像素。这些数字有时也与图像的分辨率有关。图像中的像素数越多,则意味着图像具有更多的细节,换句话说,我们可以在不损失其细节的情况下进一步放大图像。
我们在这里是如何使用三个词(清晰度,分辨率和细节)来传达相同的感觉,即:图像的质量。与像素数较少的相同图像相比,像素数较高的图像的质量要好得多。
实验中约定 —— 使用图像中的像素数来表示图像的大小。
颜色空间和通道
当人类观察彩色图片时,我们都会在看三种类型的颜色或属性。使用 红色
(red),绿
(green)和 蓝色
(blue) 作为三个属性,从而使其色彩空间成为 RGB
颜色空间,而使用 色
(hue),饱和度
(saturation) 和 明度
(value) 作为三个属性,从而使其色彩空间 HSV
颜色空间。
分离构成图像颜色空间的三个属性:红色,绿色和蓝色。这些属性也称为:通道。因此,RGB 颜色空间具有三个通道:
- 红色通道
- 绿色通道
- 蓝色通道
同样,让 HSV 颜色空间的三个通道:色相,饱和度 和明度:
假设我们要检测图像中存在的边缘。您可以看到 HSV 图像的饱和度通道已经突出了很多边缘。因此,即使我们不进行任何处理并继续使用 HSV 图像的饱和度通道,我们也将有了一个不错的结果。这正是我们需要色彩空间的原因。当我们只想看到图像并欣赏时,RGB 颜色空间比 HSV 颜色空间要好得多。但是,当我们要检测边缘时,HSV 颜色空间要好于 RGB 颜色空间。同样,这不是通用的定律,取决于我们所要处理的图像。
有时,HSV 颜色空间优于 RGB 颜色空间。其背后的原因是 RGB 颜色空间中的红色,绿色和蓝色分量(或通道)之间具有很高的相关性。而HSV 色彩空间使我们能够完全分离图像的明度通道,这有助于我们处理图像。考虑对象检测的情况,要检测图像中存在的对象。将要确保存在光不变性,这意味着无论图像是暗还是亮,都可以检测到物体。由于 HSV 颜色空间使我们能够分隔明度或强度通道,因此最好将它应用到对象检测案例当中。
要注意,我们有各种各样的色彩空间。 RGB 和 HSV 只是其中的两个。
另一个颜色空间:灰度
。当图像只有一个通道时,我们说它处于 灰度模式
。这是因为像素的颜色变成取决于像素值灰色阴影。像素值 0
表示黑色,而像素值 255
表示白色。当我们将 RGB 和 HSV 图像分为三个通道时,剩下的图像每个只有一个通道,这就是为什么将它们转换为灰度并以这种灰色阴影进行着色的原因。
像素值
首先,像素值是什么意思? 像素的值不过是该像素中存在的颜色而已。在此必须注意:每个像素只能具有一种颜色,这就是像素值是固定值的原因。
如果我们谈论的是灰度图像,则像素值的范围可以在 0
到 255
之间,其中 0
代表黑色,255
代表白色。
知道灰度图像只有一个通道,这就是为什么像素值只有一个数字可以确定该像素中存在的颜色阴影的原因。如果我们谈论的是 RGB 图像怎么办?由于 RGB 图像具有三个通道,每个像素将具有三个值:一个值用于红色通道,一个值用于绿色通道,一个值用于蓝色通道。每个通道图像看起来都完全像一个灰度图像。这就是每个通道的像素值在 0 到 255 之间的原因。
OpenCV 概要
OpenCV
,也称为开源计算机视觉库,是最常用的计算机视觉库。它主要是用 C++ 编写的,然而,由于它的 Python 封装器,也经常用在 Python 中。多年来,OpenCV 经过了多次修订,它与其他计算机视觉库的不同之处在于它易于使用且易于操作,它为 QT 和 OpenGL 等库提供支持,最重要的是,它为 Intel 处理器提供了硬件加速。这些强大的功能/优点使 OpenCV 成为理解和实现计算机视觉的各种概念的理想选择。除了OpenCV,我们还将在需要时使用 NumPy
进行一些基本计算,并使用 Matplotlib
进行可视化。
读取图像函数
使用的唯一函数是 cv2.imread
。 此函数采用以下参数:
- 我们要读取/加载的图像的文件名
- 用于指定我们要以哪种模式读取图像的标志
如果我们尝试加载不存在的图像,该函数将返回无(None
)。这可以用来检查图像是否被成功读取。目前,OpenCV 支持 .bmp
,.jpeg
,.jpg
,.png
,.tiff
和 .tif
等格式的图像。详细的列表可以:参考官方文档https://docs.opencv.org/4.2.0/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56。
通常,只有三个标志用于在指定模式下读取图像:
- cv2.IMREAD_UNCHANGED:照原样读取图像。这意味着,如果图像是具有透明背景的 PNG 图像,则它将被读取为 BGRA 图像,其中
A
指定Alpha
通道:负责透明度。 如果不使用此标志,则该图像将作为BGR
图像读取。请注意,BGR
是指图像的蓝色,绿色和红色通道。A
(或Alpha
通道)负责透明度。这就是为什么具有透明背景的图像将被读取为BGRA
而不是BGR
。 同样需要注意的是,默认情况下,OpenCV 使用BGR
模式,这就是我们在这里讨论BGRA
模式而不是RGBA
模式的原因。 - cv2.IMREAD_GRAYSCALE:以灰度格式读取图像,这会将任何彩色图像转换为灰度图像。
- cv2.IMREAD_COLOR:默认标志,它将任何图像读取为彩色图像(
BGR
模式)。
请注意,OpenCV 以 BGR
模式而不是 RGB
模式读取图像。这意味着通道的顺序变为蓝色,绿色和红色。 即使我们将使用其他 OpenCV 函数,也假定图像处于 BGR
模式。
修改图像函数
转换图像的色彩空间将使用 cv2.cvtColor
- 要转换的图像
- 颜色转换标志,如下所示:
cv2.COLOR_{CURRENT_COLOR_SPACE}2{NEW_COLOR_SPACE}
例如,要将 BGR
图像转换为 HSV
图像,将使用 cv2.COLOR_BGR2HSV
。 要将 BGR
图像转换为 灰度
图像,将使用:cv2.COLOR_BGR2GRAY
,依此类推。详细的列表可以:参考官方文档https://docs.opencv.org/4.2.0/d8/d01/group__imgproc__color__conversions.html
拆分和合并渠道。假设您只想修改图像的红色通道,您可以先拆分三个通道(蓝色,绿色和红色),修改红色通道,然后再次合并三个通道。让我们看看如何使用 OpenCV 函数拆分和合并通道:
- 分割通道,可以使用
cv2.split
- 合并通道,可以使用
cv2.merge
函数。 它仅接受一个参数:一个由三个通道(蓝色,绿色和红色)组成的集合,并返回合并的图像。
显示影像函数
我们将使用三个主要函数来进行显示:
- 显示图像,使用
cv2.imshow
函数。它有两个参数。第一个参数是一个字符串,它是我们将在其中显示图像的窗口的名称。第二个参数是我们要显示的图像。 - 保持时间,调用
cv2.imshow
函数后,我们使用cv2.waitKey
函数。此函数指定控件应在窗口上停留多长时间。如果要在用户按下任意键后,才执行下一段代码,则可以提供0
。否则,可以提供一个数字,该数字指定程序在移至下一段代码之前将等待的毫秒数。例如,如果要等待10
毫秒才能执行下一段代码,则可以使用cv2.waitKey(10)
。 - 关闭窗口,如果不调用
cv2.waitKey
函数,则窗口将无法正确显示。但是,运行下一个代码后,该窗口仍将保持打开状态,要关闭所有显示窗口,我们可以使用cv2.destroyAllWindows()
函数。它不带任何参数。建议不再使用显示窗口时将其关闭。
保存图像函数
最后,要保存图像,我们将使用 OpenCV 的 cv2.imwrite
- 一个字符串,指定我们要用于保存图像的文件名
- 我们要保存的图像
实验目标
在本实验中,我们使用上面介绍的 OpenCV 函数,实现图像分离红色
,绿色
和蓝色
通道,并且分别显示,最后将这三个通道保存到磁盘中。
实验内容
加载图像
import cv2 # 导入OpenCV库
import numpy as np
# 读取图像
img = cv2.imread("rose.jpg")
# 通过检查读取图像函数是否返回None,来检查是否已成功读取图像:
if img is None:
print("Image not found")
# 显示读取到的图像
# cv2.imshow("Lion",img)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# 将图像转换为 RGB 模式显示
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# 显示图像
plt.show()
# 显示读取到的图像
# cv2.imshow("Lion",img)
# cv2.waitKey(0)
# cv2.destroyAllWindows() 在juypter内运行可能会导致不兼容使内核崩溃
请注意,每当我们要使用 cv2.imshow
函数显示图像时,都会弹出一个新的显示窗口。该输出在 Jupyter Notebook 中不可见,并将显示在单独的窗口中。
分割通道
# 分割图像通道
blue, green, red = cv2.split(img)
# 单独显示每个通道
# 将图像转换为 RGB 模式显示
# plt.imshow(blue,green,red)
# 显示图像
# plt.show()
# 用numpy.hstzck((a,b,c)) 实现三个通道的图像拼接
compare = np.hstack((blue, green, red))
plt.figure(figsize=(16,8))
plt.imshow(compare)
当然,你也可以分别单独显示每个通道的图片。
保存图像
最后,保存我们获得的三个通道,我们将使用 cv2.imwrite
函数。这将返回 True
。这表明图像已成功写入/保存在磁盘上。此时,您可以在本地目录中找到这几个文件,验证所获得的三个通道是否与此处显示的图像匹配:
# 保存蓝色通道图像为Blue.png文件
cv2.imwrite("Blue.png",blue)
# 保存绿色通道图像为Green.png文件
cv2.imwrite("Green.png",green)
# 保存红色通道图像为Red.png文件
cv2.imwrite("Red.png",red)
结语
在本实验中,我们看到了如何使用 OpenCV 的基本函数,对图像进行读取、修改、显示和保存。