使用 K-Means Clustering 无监督机器学习算法在 Python 中使用 OpenCV 分割图像的不同部分。
OpenCV和K-Means聚类实现图像分割:图像分割是将图像分割成多个不同区域(或片段)的过程。目标是将图像的表示方式更改为更简单、更有意义的图像。
Python如何分割图像?这是图像处理中的重要一步,因为现实世界的图像并不总是只包含我们想要分类的一个对象。例如,对于自动驾驶汽车,图像将包含道路、汽车、行人等。因此我们可能需要在这里使用分割来分离对象并单独分析每个对象(即图像分类)以检查它是什么。
相关文章: 如何使用 OpenCV 在 Python 中检测人脸。
在本教程中,我们将看到一种图像分割方法,即K-Means Clustering。
K-Means 聚类是一种无监督机器学习算法,旨在将N 个观测值划分为K 个聚类,其中每个观测值都属于具有最近均值的聚类。集群是指由于某些相似性而聚合在一起的数据点的集合。对于图像分割,这里的簇是不同的图像颜色。
以下视频应该让你熟悉 K-Means 聚类算法:
Python图像分割示例:在我们深入研究代码之前,我们需要安装所需的库:
pip3 install opencv-python numpy matplotlib
让我们导入它们:
import cv2
import numpy as np
import matplotlib.pyplot as plt
我将使用此图像进行演示,请随意使用:
加载图像:
# read the image
image = cv2.imread("image.jpg")
OpenCV和K-Means聚类实现图像分割:在我们做任何事情之前,让我们将图像转换为RGB格式:
# convert to RGB
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
复制我们将使用cv2.kmeans()函数,它将一个2D数组作为输入,并且由于我们的原始图像是3D(宽度、高度和深度3 个 RGB值),我们需要将高度和宽度展平为单个向量像素数(3 个 RGB值):
# reshape the image to a 2D array of pixels and 3 color values (RGB)
pixel_values = image.reshape((-1, 3))
# convert to float
pixel_values = np.float32(pixel_values)
让我们尝试打印生成的像素值的形状:
print(pixel_values.shape)
输出:
(2073600, 3)
Python如何分割图像?正如预期的那样,这是将高分辨率(1920, 1050)图像弄平的结果。如果你观看了解释算法的视频,你会看到他在第 3 分钟左右说,当没有任何集群分配发生变化时,算法就会停止。好吧,我们会在这里作弊,因为这是大量数据点,因此需要大量时间来处理,我们将在超过一定迭代次数(例如100 次)或如果集群移动小于某个 epsilon 值(让我们在这里选择0.2),下面的代码定义了OpenCV 中的停止标准:
# define stopping criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.2)
如果你查看图像,会发现三种主要颜色(绿色代表树木,蓝色代表海洋/湖泊,白色至橙色代表天空)。因此,我们将为这张图片使用三个集群:
# number of clusters (K)
k = 3
_, labels, (centers) = cv2.kmeans(pixel_values, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
标签数组是每个像素的聚类标签,它要么是0,要么是1 ,要么是2(因为k = 3),中心指的是中心点(每个质心的值)。
cv2.KMEANS_RANDOM_CENTERS只是指示OpenCV最初随机分配集群的值。
Python图像分割示例:如果你回顾一下代码,我们没有提到我们将扁平化的图像像素值转换为浮点数,我们这样做是因为cv2.kmeans() 需要这样做,让我们将它们转换回8 位像素值:
# convert back to 8 bit values
centers = np.uint8(centers)
# flatten the labels array
labels = labels.flatten()
现在让我们构建分割图像:
# convert all pixels to the color of the centroids
segmented_image = centers[labels.flatten()]
OpenCV和K-Means聚类实现图像分割:转换回原始图像形状并显示:
# reshape back to the original image dimension
segmented_image = segmented_image.reshape(image.shape)
# show the image
plt.imshow(segmented_image)
plt.show()
这是生成的图像:
Python如何分割图像?太棒了,我们还可以禁用图像中的一些集群。例如,让我们禁用集群编号2并显示原始图像:
# disable only the cluster number 2 (turn the pixel into black)
masked_image = np.copy(image)
# convert to the shape of a vector of pixel values
masked_image = masked_image.reshape((-1, 3))
# color (i.e cluster) to disable
cluster = 2
masked_image[labels == cluster] = [0, 0, 0]
# convert back to original shape
masked_image = masked_image.reshape(image.shape)
# show the image
plt.imshow(masked_image)
plt.show()
这是生成的图像:
哇,原来集群 2 是树,请随意:
- 禁用其他集群,看看哪个是准确分割的。
- 调整参数以获得更好的结果(例如
k
)。 - 使用清晰包含不同颜色的不同对象的其他图像。
请注意,还有其他分割技术,例如霍夫变换、轮廓检测和当前最先进的语义分割。