目录
如何使用 OpenCV 和 Matplotlib 读取、处理并显示图像。即将为您解答:
读取灰度图像
代码解释
1. 导入库
import cv2
import matplotlib.pyplot as plt
首先,导入了两个重要的库:
cv2
是 OpenCV 库,用于图像处理。matplotlib.pyplot
是 Matplotlib 的子模块,用于绘制图像和图表。
2. 读取彩色图像
image = cv2.imread('001.jpg')
这里使用 cv2.imread
函数读取了一张名为 001.jpg
的图像文件。默认情况下,OpenCV 读取图像时会将其存储为 BGR(蓝-绿-红)格式的图像。
3. 转换为灰度图像
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
接下来,使用 cv2.cvtColor
函数将彩色图像转换为灰度图像。灰度图像仅包含亮度信息,没有颜色信息,每个像素用单一灰度值表示。这种转换在图像处理和分析中非常常见,因为灰度图像更简单、更易于处理。
4. 将 BGR 图像转换为 RGB 格式
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
由于 OpenCV 使用 BGR 顺序存储图像,而 Matplotlib 使用 RGB 顺序显示图像,所以在显示图像之前,需要将图像从 BGR 转换为 RGB。
5. 创建子图并显示图像
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(image_rgb)
plt.title('Original Image')
plt.axis('off')
plt.subplot(1, 2, 2)
plt.imshow(gray_image, cmap='gray')
plt.title('Grayscale Image')
plt.axis('off')
plt.show()
plt.figure(figsize=(10, 5))
:创建一个宽度为 10 英寸、高度为 5 英寸的图像窗口。plt.subplot(1, 2, 1)
和plt.subplot(1, 2, 2)
:创建一个包含两幅子图的窗口。1, 2, 1
表示第一行有两个子图,这是第一个子图;1, 2, 2
表示第二个子图。plt.imshow(image_rgb)
和plt.imshow(gray_image, cmap='gray')
:显示 RGB 图像和灰度图像。cmap='gray'
参数用于指定灰度图像的颜色映射。plt.title
设置每个子图的标题。plt.axis('off')
:隐藏坐标轴,专注于图像本身。plt.show()
:显示图像窗口。
总结:
这段代码展示了如何读取彩色图像,将其转换为灰度图像,然后使用 Matplotlib 显示这两种图像。通过理解这些步骤,学生可以学会如何使用 Python 进行基础的图像处理任务,包括图像的读取、格式转换和显示。
整体代码
import cv2
import matplotlib.pyplot as plt
# 读取彩色图像
image = cv2.imread('001.jpg')
# 转换为灰度图像
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 将 BGR 图像转换为 RGB 格式
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 创建子图进行显示
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(image_rgb)
plt.title('Original Image')
plt.axis('off')
plt.subplot(1, 2, 2)
plt.imshow(gray_image, cmap='gray')
plt.title('Grayscale Image')
plt.axis('off')
plt.show()
效果展示
衍生操作
既然已经读取了灰度图像,我们也不可能只是为了体验一下没有色彩的世界对吧,所以拿到灰度图像之后我们还可以做一些更有意义的事情。
1. 边缘检测
灰度图像通常是边缘检测的第一步,可以使用 Canny
算法进行边缘检测。
代码说明
-
读取彩色图像:
image = cv2.imread('001.jpg')
从文件中读取图像,并存储在
image
变量中。 -
转换为灰度图像:
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
将彩色图像转换为灰度图像,这是边缘检测的常见预处理步骤,因为边缘主要基于亮度变化。
-
进行边缘检测:
edges = cv2.Canny(gray_image, threshold1=100, threshold2=200)
使用 Canny 算法进行边缘检测。
threshold1
和threshold2
是低阈值和高阈值参数,用于控制检测到的边缘的敏感度。 -
图像转换与显示:
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
:将图像从 BGR 转换为 RGB 格式,以便在 Matplotlib 中正确显示颜色。plt.subplot(1, 3, 1)
,plt.subplot(1, 3, 2)
,plt.subplot(1, 3, 3)
:创建包含三个子图的图像窗口。plt.imshow(edges, cmap='gray')
:显示边缘检测结果。
-
展示结果:
plt.show()
显示包含原图像、灰度图像和边缘检测结果的图像窗口。
整体代码
import cv2
import matplotlib.pyplot as plt
# 读取彩色图像
image = cv2.imread('001.jpg')
# 转换为灰度图像
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 使用Canny算法进行边缘检测
edges = cv2.Canny(gray_image, threshold1=100, threshold2=200)
# 将BGR图像转换为RGB格式(用于Matplotlib显示)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 创建子图进行显示
plt.figure(figsize=(15, 5))
plt.subplot(1, 3, 1)
plt.imshow(image_rgb)
plt.title('Original Image')
plt.axis('off')
plt.subplot(1, 3, 2)
plt.imshow(gray_image, cmap='gray')
plt.title('Grayscale Image')
plt.axis('off')
plt.subplot(1, 3, 3)
plt.imshow(edges, cmap='gray')
plt.title('Edge Detection')
plt.axis('off')
plt.show()
效果展示
最右边为边缘检测的结果
应用: 用于检测图像中的物体边界和轮廓,如车道线检测、人脸轮廓识别等。
2. 图像二值化
二值化是一种将灰度图像转换为仅有黑白两色的图像的过程,可以使用阈值方法进行二值化。
代码说明
-
读取彩色图像:
image = cv2.imread('001.jpg')
从文件中读取图像,并存储在
image
变量中。 -
转换为灰度图像:
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
将彩色图像转换为灰度图像,以便进行二值化处理。
-
应用二值化:
_, binary_image = cv2.threshold(gray_image, 127, 255, cv2.THRESH_BINARY)
使用
cv2.threshold
函数进行二值化。参数说明:gray_image
是要处理的灰度图像。127
是二值化的阈值,像素值大于 127 的会被设为 255,像素值小于或等于 127 的会被设为 0。255
是像素值被设为白色的值。cv2.THRESH_BINARY
是指定二值化操作的类型。
-
图像转换与显示:
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
:将图像从 BGR 转换为 RGB 格式,以便在 Matplotlib 中正确显示颜色。plt.subplot(1, 2, 1)
和plt.subplot(1, 2, 2)
:创建包含两个子图的图像窗口,一个显示原图像,一个显示二值化图像。
-
展示结果:
plt.show()
显示包含原图像和二值化图像的图像窗口。
整体代码
import cv2
import matplotlib.pyplot as plt
# 读取彩色图像
image = cv2.imread('001.jpg')
# 转换为灰度图像
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 应用二值化,使用127作为阈值,将大于127的像素值设为255,其余设为0
_, binary_image = cv2.threshold(gray_image, 127, 255, cv2.THRESH_BINARY)
# 将BGR图像转换为RGB格式(用于Matplotlib显示)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 创建子图进行显示
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(image_rgb)
plt.title('Original Image')
plt.axis('off')
plt.subplot(1, 2, 2)
plt.imshow(binary_image, cmap='gray')
plt.title('Binary Image')
plt.axis('off')
plt.show()
效果展示
应用: 二值化图像常用于形状检测、对象分割、OCR(光学字符识别)等领域。
3. 直方图均衡化
通过直方图均衡化可以增强图像的对比度,使得原本对比度较低的图像变得更加清晰。
equalized_image = cv2.equalizeHist(gray_image)
plt.figure(figsize=(10, 5))
plt.imshow(equalized_image, cmap='gray')
plt.title('Histogram Equalization')
plt.axis('off')
plt.show()
应用: 常用于医学影像处理、卫星图像处理等场景,提高细节可见性。
4. 轮廓检测
可以在二值化图像上进行轮廓检测,识别图像中的形状和对象。
代码说明
-
读取彩色图像:
image = cv2.imread('001.jpg')
从文件中读取图像,并存储在
image
变量中。 -
转换为灰度图像:
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
将彩色图像转换为灰度图像,为后续的二值化和轮廓检测做准备。
-
应用二值化:
_, binary_image = cv2.threshold(gray_image, 127, 255, cv2.THRESH_BINARY)
使用
cv2.threshold
进行二值化,将图像转为黑白图像(只有0和255两种值)。 -
检测轮廓:
contours, _ = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
使用
cv2.findContours
检测图像中的轮廓。参数说明:binary_image
是输入的二值化图像。cv2.RETR_EXTERNAL
表示只检测外轮廓。cv2.CHAIN_APPROX_SIMPLE
使用简单的轮廓近似方法来节省内存。
-
绘制轮廓:
contour_image = image.copy() cv2.drawContours(contour_image, contours, -1, (0, 255, 0), 2)
在原图像的副本上绘制检测到的轮廓。
(0, 255, 0)
指定轮廓的颜色为绿色,2
是线条的粗细。 -
图像转换与显示:
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
和contour_image_rgb = cv2.cvtColor(contour_image, cv2.COLOR_BGR2RGB)
:将图像从 BGR 转换为 RGB 格式,以便在 Matplotlib 中正确显示颜色。plt.subplot(1, 3, 1)
、plt.subplot(1, 3, 2)
和plt.subplot(1, 3, 3)
:创建包含三个子图的图像窗口,分别显示原图像、二值化图像和带有轮廓的图像。
-
展示结果:
plt.show()
显示包含原图像、二值化图像和检测到的轮廓图像的窗口。
整体代码
import cv2
import matplotlib.pyplot as plt
# 读取彩色图像
image = cv2.imread('001.jpg')
# 转换为灰度图像
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 应用二值化
_, binary_image = cv2.threshold(gray_image, 127, 255, cv2.THRESH_BINARY)
# 检测轮廓
contours, _ = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 在原图像上绘制轮廓
contour_image = image.copy()
cv2.drawContours(contour_image, contours, -1, (0, 255, 0), 2)
# 将BGR图像转换为RGB格式(用于Matplotlib显示)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
contour_image_rgb = cv2.cvtColor(contour_image, cv2.COLOR_BGR2RGB)
# 创建子图进行显示
plt.figure(figsize=(15, 5))
plt.subplot(1, 3, 1)
plt.imshow(image_rgb)
plt.title('Original Image')
plt.axis('off')
plt.subplot(1, 3, 2)
plt.imshow(binary_image, cmap='gray')
plt.title('Binary Image')
plt.axis('off')
plt.subplot(1, 3, 3)
plt.imshow(contour_image_rgb)
plt.title('Contours Detected')
plt.axis('off')
plt.show()
效果展示
应用: 用于对象检测、形状分析、物体追踪等。
5. 图像分割
可以通过基于阈值、区域增长、边缘检测等方法对图像进行分割,提取感兴趣的区域。
代码说明
-
读取彩色图像
image = cv2.imread('001.jpg') image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
cv2.imread('001.jpg')
读取图像文件,并将其存储在image
变量中。OpenCV 默认以 BGR 格式读取图像。cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
将图像从 BGR 格式转换为 RGB 格式,适用于 Matplotlib 显示。
-
图像数据的形状转换
pixel_values = image_rgb.reshape((-1, 3)) pixel_values = np.float32(pixel_values)
image_rgb.reshape((-1, 3))
将图像重塑为一个二维数组,其中每行包含一个像素的 RGB 颜色值。这样,原始的 (height, width, 3) 形状变为 (height * width, 3)。np.float32(pixel_values)
将像素值转换为浮点型,这是 K-Means 聚类所需的格式。
-
定义 K-Means 聚类参数
k = 4 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2) _, labels, centers = cv2.kmeans(pixel_values, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
k = 4
表示我们要将图像分成 4 个不同的颜色簇。criteria
是 K-Means 算法的终止条件,设定了迭代次数和精度要求。cv2.kmeans
执行 K-Means 聚类算法,并返回labels
和centers
。labels
表示每个像素所属的簇,centers
是每个簇的中心点(代表的颜色)。
-
转换为 8 位整数
centers = np.uint8(centers) labels = labels.flatten()
centers
中的颜色值转换为 8 位整数以便显示。labels.flatten()
将标签展平成一维数组,便于后续操作。
-
将每个像素值转换为其中心值
segmented_image = centers[labels.flatten()]
- 将每个像素的颜色值替换为其所属簇的中心值。这将使图像显示为仅包含 k 个颜色的版本。
-
重塑为原始图像形状
segmented_image = segmented_image.reshape(image_rgb.shape)
- 将图像从 (height * width, 3) 重新塑造为原始的 (height, width, 3) 形状,以便显示。
-
创建遮罩,用于分割图像
labels_reshape = labels.reshape(image_rgb.shape[:2]) mask = labels_reshape == 0
labels_reshape
将标签重塑为与图像的高和宽匹配的二维数组。mask = labels_reshape == 0
创建了一个布尔掩码,选择标签为0
的像素。这将用于分割出这个簇对应的部分。
-
提取对象
segmented_image_2 = np.copy(image_rgb) segmented_image_2[~mask] = 0
segmented_image_2
复制原始图像。segmented_image_2[~mask] = 0
将掩码之外的部分(即未选择的簇)设为黑色,保留选中的对象。
-
显示原图和分割后的图像
plt.figure(figsize=(10, 5)) plt.subplot(1, 3, 1) plt.imshow(image_rgb) plt.title('Original Image') plt.axis('off') plt.subplot(1, 3, 2) plt.imshow(segmented_image) plt.title('Segmented Image (K-Means)') plt.axis('off') plt.subplot(1, 3, 3) plt.imshow(segmented_image_2) plt.title('Object Extraction') plt.axis('off') plt.show()
- 使用 Matplotlib 在同一窗口中显示原始图像、K-Means 分割后的图像,以及根据掩码提取的特定对象。
总结
这个代码主要利用 K-Means 聚类算法对图像进行颜色分割。然后通过选择特定的颜色簇,提取出感兴趣的部分。可以通过修改 mask
的条件来提取不同的颜色区域,进行更复杂的图像分析和处理。
整体代码
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取彩色图像
image = cv2.imread('001.jpg')
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 图像数据的形状
pixel_values = image_rgb.reshape((-1, 3))
pixel_values = np.float32(pixel_values)
# 定义K-Means聚类参数
k = 4 # 聚类的数量
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)
_, labels, centers = cv2.kmeans(pixel_values, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
# 转换为8位整数
centers = np.uint8(centers)
labels = labels.flatten()
# 将每个像素值转换为其中心值
segmented_image = centers[labels.flatten()]
# 重塑为原始图像形状
segmented_image = segmented_image.reshape(image_rgb.shape)
# 创建遮罩,用于分割图像
labels_reshape = labels.reshape(image_rgb.shape[:2])
mask = labels_reshape == 0 # 可选择分割哪个簇
# 提取对象
segmented_image_2 = np.copy(image_rgb)
segmented_image_2[~mask] = 0
# 显示原图和分割后的图像
plt.figure(figsize=(10, 5))
plt.subplot(1, 3, 1)
plt.imshow(image_rgb)
plt.title('Original Image')
plt.axis('off')
plt.subplot(1, 3, 2)
plt.imshow(segmented_image)
plt.title('Segmented Image (K-Means)')
plt.axis('off')
plt.subplot(1, 3, 3)
plt.imshow(segmented_image_2)
plt.title('Object Extraction')
plt.axis('off')
plt.show()
效果展示
在这个代码中,使用了 K-Means 聚类 来对图像进行分割。K-Means 是一种常见的聚类算法,它将图像中的像素聚类成 kkk 个不同的组(簇)。然后我们可以根据这些聚类的结果选择要分割的对象。
分割的是什么?
具体来说,K-Means 将图像中的每个像素根据颜色相似性划分到 kkk 个簇中。在这段代码中,k=4
,这意味着图像中的像素会被分成 4 个不同的组(颜色簇)。每个簇表示图像中颜色相近的一组像素。分割的对象取决于你选择了哪个簇来提取。
在代码中,以下部分决定了你要分割哪个簇:
mask = labels_reshape == 0 # 可选择分割哪个簇
这里 labels_reshape == 0
意味着你选择了标签为 0
的簇,即第一组被聚类出来的像素。这个簇可能代表图像中的一个主要颜色区域。
图像分割的结果
- 原始图像:展示了原始的 RGB 图像。
- 分割后的图像 (Segmented Image):这是 K-Means 聚类后的图像,它会将图像中的颜色减少到 4 种颜色之一(因为
k=4
)。 - 对象提取 (Object Extraction):这个图像展示了从原始图像中提取出来的部分。只有那些被分配到标签
0
的像素保留了原始颜色,其他区域被设为黑色。
所分割的内容
由于 K-Means 是基于颜色的聚类算法,具体分割的内容取决于图像本身及其颜色分布。举例来说:
- 如果图像中有明显的蓝天、绿草和红花,K-Means 可能会将这些部分分成不同的簇。
- 如果你选择
mask = labels_reshape == 0
,那么代码将提取第一个簇中的像素,比如整个蓝天或某个颜色主导的区域。
要点:通过改变 mask = labels_reshape == 0
中的数字(比如 1
, 2
, 3
),你可以选择提取不同的图像部分。这取决于你的目标是什么,比如提取特定颜色的物体或区域。
应用: 在医学影像中分割器官或肿瘤,在遥感图像中分割土地覆盖类型等。
总结
其实他整体的应用还是有很多的,这些也只是一些最基本的应用,大家可以多多开展一下自己的思路,创造更多的好点子。