OpenCV中的坐标系与图像通道顺序

1,458 阅读4分钟

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战

OpenCV中的坐标系

为了更好的展示 OpenCV 中的坐标系以及如何访问各个像素,我们首先观察以下低分辨率图像:

低分辨率图片

这个图片的尺寸是 32×41 像素,也就是说,这个图像有 1312 个像素。为了进一步说明,我们可以在每个轴上添加像素计数,如下图所示:

添加像素计数

现在,我们来看看 (x,y)(x, y) 形式的像素索引。请注意,像素索引起始值为零,这意味着左上角位于 (0,0)(0, 0),而不是 (1,1)(1, 1)。下面的图像,索引了 4 个单独的像素,图像的左上角是原点的坐标:

像素索引

单个像素的信息可以从图像中提取,方法与 Python 中引用数组的单个元素相同。

OpenCV中的通道顺序

在 OpenCV 使用中,使用的颜色通道顺序为 BGR 颜色格式而不是 RGB 格式。可以在下图中看到三个通道的顺序:

OpenCV通道顺序

BGR 图像的像素结构如下图所示,作为演示,图示详细说明了如何访问pixel(y=n, x=1):

像素访问

Tips:OpenCV 的最初开发人员选择了 BGR 颜色格式(而不是 RGB 格式),是因为当时 BGR 颜色格式在软件供应商和相机制造商中非常流行,因此选择 BGR 是出于历史原因。

此外,也有其他 Python 包使用的是 RGB 颜色格式(例如,Matplotlib 使用 RGB 颜色格式,Matplotlib 是最流行的 2D Python 绘图库,提供多种绘图方法,可以查看 Python-Matplotlib 可视化获取更多详细信息)。因此,我们需要知道如何将图像从一种格式转换为另一种格式。

当我们掌握了将图像从一种格式转换为另一种格式的方法后,就可以选择使用 OpenCV 进行图像处理,同时利用 Matplotlib 包提供的函数来显示图像,接下来,让我们看看如何处理两个库采用的不同颜色格式。 首先,我们使用 cv2.imread() 函数加载图像:

import cv2
img_OpenCV = cv2.imread('sigonghuiye.jpeg')

图像存储在 img_OpenCV 变量中,因为 cv2.imread() 函数以 BGR 顺序加载图像。然后,我们使用 cv2.split() 函数将加载的图像分成三个通道 (b, g, r) 。这个函数的参数就是我们要分割的图像:

b, g, r = cv2.split(img_OpenCV)

下一步是合并通道(以便根据通道提供的信息构建新图像),但合并时顺序与原图像不同。我们更改 b 和 r 通道的顺序以遵循 RGB 格式,即我们所需要的 Matplotlib 格式:

img_matplotlib = cv2.merge([r, g, b])

此时,我们有两个图像 (img_OpenCV 和 img_matplotlib),接下来,我们将分别使用 OpenCV 和 Matplotlib 绘制她们,以便我们可以对比结果。首先,我们将用 Matplotlib 显示这两个图像。

为了在同一个窗口中使用 Matplotlib 显示两个图像,我们将使用 subplot,它将多个图像放置在同一个窗口中。可以在 subplot 中使用三个参数,例如 subplot(m,n,p),此时,子图处理 m×nm \times n 网格中的图,其中 mm 确定行数,nn 确定列数,而 pp 确定要在网格中放置图的位置。要使用 Matplotlib 显示图像,需要使用 imshow 函数。

在这种情况下,当我们水平显示两个图像时, m=1m = 1n=2n = 2 。我们将对第一个子图 (img_OpenCV) 使用 p=1p = 1,对第二个子图(img_matplotlib) 使用 p=2p = 2

from matplotlib import pyplot as plt
plt.subplot(121)
plt.imshow(img_OpenCV)
plt.subplot(122)
plt.imshow(img_matplotlib)
plt.show()

程序输出如下图所示:

matplotlib绘制结果

可以看出,第一个子图以错误的颜色( BGR 顺序)显示图像,而第二个子图以正确的颜色( RGB 顺序)显示图像。接下来,我们使用 cv2.imshow() 显示两个图像:

cv2.imshow('bgr image', img_OpenCV)
cv2.imshow('rgb image', img_matplotlib)
cv2.waitKey(0)
cv2.destroyAllWindows()

以下屏幕截图显示了执行上述代码获得的结果:

OpenCV绘制结果

正如预期的那样,屏幕截图中,第一张图以正确的色彩显示图像,而第二张图以错误的颜色显示图像。

此外,如果我们想在同一个窗口中显示两个图像,可以构建一个包含这两个图像的拼接图像,将两张图片水平连接起来。为此,我们需要使用 NumPyconcatenate() 方法。该方法的参数是要连接的两个图像和要在哪个轴上进行堆叠,这里,我们令 axis = 1 (水平堆叠它们):

import numpy as np
img_concats = np.concatenate((img_OpenCV, img_matplotlib), axis=1)
cv2.imshow('bgr image and rgb image', img_concats)
cv2.waitKey(0)
cv2.destroyAllWindows()

下图显示了连接后的图像:

拼接后显示

需要考虑的一个因素是 cv2.split() 是一项耗时的操作。如果确实需要划分不同通道,应当首先考虑使用 NumPy 索引。例如,如果想获取图像的一个通道,则可以使用 NumPy 索引获取通道:

B = img_OpenCV[:, :, 0]
G = img_OpenCV[:, :, 1]
R = img_OpenCV[:, :, 2]

另一个需要注意的是,可以使用 NumPy 在一条语句中将图像从 BGR 转换为 RGB:

img_matplotlib = img_OpenCV[:, :, ::-1]

系列链接

OpenCV图像处理基础