目标

  • 学习K值聚类的概念以及工作原理。
  • K均值聚类的OpenCV实现

背景

下面用一个最常用的例子来给大家介绍K 值聚类。

话说有一个公司要生产一批新的T 恤。很明显他们要生产不同大小的T 恤来满足不同客客的要求。所以这个公司搜集了很多人的身高和体重信息,并把这些数据绘制在图上,如下所示:

肯定不能把每个大小的T 恤都生产出来,所以他们把所有的人分为三组,小,中,大,这三组要覆盖所有的人。我们可以使用K 值聚类的方法将所有人分为3 组,这个算法可以找到一个最好的分法并能覆盖所有人。如果不能覆盖全部人的话,公司就只能把这些人分为更多的组,可能是4 个或5 个甚至更多。如下图:

工作原理

这个算法是一个迭代过程,我们会借助图片分步介绍它。考虑下面这组数据,你也可以把它当成T 恤问题来看,我们需要把他们分成两组。

第一步 随机选取两个重心点C1 和C2(有时可以选取数据中的两个点作为起始重心)。
第二步 计算每个点到这两个重心点的距离,如果距离C1 比较近,就标记为0,如果距离C2 比较近,就标记为1。(如果有更多的重心点,可以标记为2、3等)

在我们的例子中我们把属于0 的标记为红色,属于1 的标记为蓝色。我们就会得到下面这幅图。

第三步重新计算所有蓝色点的重心和所有红色点的重心,并以这两个点更新重心点的位置。(图片只是为了演示说明而已,并不代表实际数据),重复步骤2,更新所有的点标记。我们就会得到下面的图:

继续迭代步骤2 和3,直到两个重心点的位置稳定下来。(当然也可以通过设置迭代次数,或者设置重心移动距离的阈值值来终止迭代。此时这些点到它们相应重心的距离之和最小。简单来说C1 到红色点的距离与C2 到蓝色点的距离之和最小。

最终结果如下图所示:

这就是对K 值聚类的一个直观解释。要想知道更多细节和数据,可以去一本关于机器学习的教科书或者参考更多资源中的链接。这只是K 值聚类的基础。现在对这个算法有很多改,比如,如何选取好的初始重心点,怎样加速迭代过程等。

参考资料:Supervised Learning in Machine Learning: Regression and Classification (DeepLearning.AI) | Coursera

OpenCV中的K值聚类

cv2.kmeans()是OpenCV中用于执行k均值聚类的函数。它采用输入数据的特征向量,并将其分成指定数量的簇。

函数的语法如下:

retval, bestLabels, centers = cv2.kmeans(data, K, criteria, attempts, flags, centers)

参数说明:

  • data:输入数据的特征向量,可以是Numpy数组或浮点型矩阵。
  • K:指定要创建的簇的数量。
  • criteria:指定迭代停止的条件,可以是一个元组,包含三个参数:迭代次数、最小误差、最小中心变化。
  • attempts:指定执行算法的次数,每次执行都会选择不同的初始中心。
  • flags:指定使用的计算方法,可以是cv2.KMEANS_RANDOM_CENTERS或cv2.KMEANS_PP_CENTERS。
  • centers:输出参数,包含所有簇的中心点坐标。

返回值说明:

  • retval:返回值表示执行算法的状态,通常为cv2.TERM_CRITERIA_EPS或cv2.TERM_CRITERIA_MAX_ITER之一。
  • bestLabels:每个样本的最佳簇标签。
  • centers:所有簇的中心点坐标。

下面是一个使用cv2.kmeans()函数的简单示例:

import numpy as npimport cv2# 准备数据data = np.random.randint(0, 100, (100, 2)).astype(np.float32)# 设置迭代停止的条件criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)# 执行k均值聚类retval, bestLabels, centers = cv2.kmeans(data, 2, None, 10, cv2.KMEANS_RANDOM_CENTERS)# 打印结果print("retval:", retval)print("bestLabels:", bestLabels)print("centers:", centers)

在上面的示例中,我们首先创建一个包含100个随机二维点的数据集。然后,我们设置了迭代停止的条件,指定要创建2个簇,并使用随机初始中心执行k均值聚类。最后,打印出返回的结果。

请注意,由于k均值聚类是一个迭代算法,结果可能因为初始中心的选择而有所不同。为了获得更好的结果,可以多次执行算法,并选择最佳结果。

颜色量化

颜色量化就是减少图片中颜色数目的一个过程。为什么要减少图片中的颜色呢” />import numpy as npimport cv2img = cv2.imread(‘home.jpg’)Z = img.reshape((-1,3))# convert to np.float32Z = np.float32(Z)# define criteria, number of clusters(K) and apply kmeans()criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)K = 8ret,label,center=cv2.kmeans(Z,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)# Now convert back into uint8, and make original imagecenter = np.uint8(center)res = center[label.flatten()]res2 = res.reshape((img.shape))cv2.imshow(‘res2’,res2)cv2.waitKey(0)cv2.destroyAllWindows()

下面是K=8 的结果: