OpenCV  4.10.0
开源计算机视觉
正在加载...
正在搜索...
无匹配项
OpenCV 中的 K 均值聚类

目标

  • 了解如何在 OpenCV 中使用 cv.kmeans() 函数进行数据聚类

了解参数

输入参数

  1. samples:应为 np.float32 数据类型,且每个特征应放在单一列中。
  2. nclusters(K):最后所需的簇数
  3. criteria:这是迭代终止条件。当满足此条件时,算法迭代停止。实际上,它应该是 3 个参数的元组。它们是 `( type, max_iter, epsilon )`
    1. 终止条件类型。它有 3 个标志如下
      • cv.TERM_CRITERIA_EPS - 如果达到指定的精度 epsilon,则停止算法迭代。
      • cv.TERM_CRITERIA_MAX_ITER - 在指定次数的迭代后停止算法,max_iter
      • cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER - 在满足上述任何条件时停止迭代。
    2. max_iter - 指定最大迭代次数的整数。
    3. epsilon - 要求的精度
  4. attempts:标志,用于指定使用不同初始标记执行算法的次数。该算法返回产生最佳紧密度的标签。该紧密度作为输出返回。
  5. flags:此标志用于指定如何获取初始中心。通常为此目的使用两个标志:cv.KMEANS_PP_CENTERScv.KMEANS_RANDOM_CENTERS

输出参数

  1. compactness:它是到其相应中心的每个点的平方距离之和。
  2. labels:这是标签数组(与前一篇文章中的“code”相同),其中每个元素标记为“0”、“1”......
  3. centers:这是簇中心的数组。

现在,我们将通过三个示例了解如何应用 K 均值算法。

1. 仅具有一个特征的数据

考虑一下,你有一组仅具有一个特征的数据,即一维数据。例如,我们可以解决 T 恤问题,其中仅使用人的身高来确定 T 恤的尺码。

因此,我们首先创建数据并在 Matplotlib 中绘制它

import numpy as np
import cv2 as cv
matplotlib 导入 pyplot plt
x = np.random.randint(25,100,25)
y = np.random.randint(175,255,25)
z = np.hstack((x,y))
z = z.reshape((50,1))
z = np.float32(z)
plt.hist(z,256,[0,256]),plt.show()

因此,我们有“z”,即数字为 50,并且值介于 0 到 255 之间的数组。我已将“z”重新塑造成一列向量。当出现多个特征时,它将更方便。然后,我进行 np.float32 类型的制作数据。

我们将获取以下图像

图像

现在,我们应用 KMeans 函数。在该步骤之前,我们需要指定标准。我的标准是,一旦运行算法 10 次迭代,或者达到准确度 epsilon = 1.0,就停止算法并返回答案。

# 定义标准 = ( 类型、max_iter = 10、epsilon = 1.0 )
标准 = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0)
# 设置标志(仅为避免代码中的换行)
标志 = cv.KMEANS_RANDOM_CENTERS
# 应用 KMeans
紧密度、标签、中心 = cv.kmeans(z,2,,标准,10,标志)
double kmeans(InputArray data, int K, InputOutputArray bestLabels, TermCriteria criteria, int attempts, int flags, OutputArray centers=noArray())
找出聚类的中心,并在该中心周围对输入样本进行分组。

这向我们提供了紧密度、标签和中心。在这种情况下,我获得的中心为 60 和 207。标签的大小将与测试数据相同,其中每个数据将标记为“0”、“1”、“2”等,具体取决于其质心。现在,我们根据标签将数据拆分为不同的聚类。

A = z[标签==0]
B = z[标签==1]

现在,我们以红色绘制 A,以蓝色绘制 B,并以黄色绘制其质心。

# 现在以红色绘制“A”,以蓝色绘制“B”,以黄色绘制“中心”
plt.hist(A,256,[0,256],color = 'r')
plt.hist(B,256,[0,256],color = 'b')
plt.hist(中心,32,[0,256],color = 'y')
plt.show()

以下为我们获得的输出

图像

2. 具有多个特征的数据

在上一个示例中,我们只针对 t 恤问题采用身高。在这里,我们将采用身高和体重,即两个特征。

请记住,在以前的情况下,我们将我们的数据变为单列向量。每个特征按列排列,而每一行都对应一个输入测试样本。

例如,在此情况下,我们设置了一个大小为 50x2 的测试数据,即 50 人的身高和体重。第一列对应于所有 50 人的身高,第二列对应于他们的体重。第一行包含两个元素,其中第一个元素是第一位的身高,第二个元素是他的体重。类似地,其余的行对应于其他人的身高和体重。查看下图

图像

现在我直接转到代码

import numpy as np
import cv2 as cv
matplotlib 导入 pyplot plt
X = np.random.randint(25,50,(25,2))
Y = np.random.randint(60,85,(25,2))
Z = np.vstack((X,Y))
# 转换为 np.float32
Z = np.float32(Z)
# 定义准则并应用 kmeans()
标准 = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0)
ret,label,center=cv.kmeans(Z,2,None,criteria,10,cv.KMEANS_RANDOM_CENTERS)
# 现在分离数据,请注意 flatten()
A = Z[label.ravel()==0]
B = Z[label.ravel()==1]
# 绘制数据
plt.scatter(A[:,0],A[:,1])
plt.scatter(B[:,0],B[:,1],c = 'r')
plt.scatter(center[:,0],center[:,1],s = 80,c = 'y', marker = 's')
plt.xlabel('Height'),plt.ylabel('Weight')
plt.show()

以下是我们获得的输出

图像

3. 颜色量化

颜色量化是减少图像中颜色数量的过程。这样做的一个原因是为了减少内存。有时,某些设备可能有限制,只能产生有限数量的颜色。在这些情况下,也会执行颜色量化。这里我们使用 k 均值聚类进行颜色量化。

这里无需解释任何新内容。有 3 个特征,例如 R、G、B。因此,我们需要将图像重新调整为 Mx3 大小的数组(M 是图像中的像素数量)。在聚类后,我们将质心值(它也是 R、G、B)应用于所有像素,从而使生成的图像具有指定数量的颜色。我们还需要将其重新调整回原始图像的形状。以下是代码

import numpy as np
import cv2 as cv
img = cv.imread('home.jpg')
Z = img.reshape((-1,3))
# 转换为 np.float32
Z = np.float32(Z)
# 定义准则、聚类数 (K) 并应用 kmeans()
标准 = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 8
ret,label,center=cv.kmeans(Z,K,None,criteria,10,cv.KMEANS_RANDOM_CENTERS)
# 现在转换回 uint8,并制作原始图像
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((img.shape))
cv.imshow('res2',res2)
void imshow(const String &winname, InputArray mat)
在指定窗口中显示图像。
int waitKey(int delay=0)
等待按下的键。
void destroyAllWindows()
销毁所有 HighGUI 窗口。
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR)
从文件中加载图像。

请参阅 K=8 以下的结果

图像

其他资源

练习