使用背景
从广义上说,聚类就是将数据集中在某些方面相似的数据成员放在一起。聚类的的目的也是把数据分类,但是事先是不知道如何去分的,完全是算法自己来判断各条 数据之间的相似性,相似的就放在一起。在图像处理中,可以使用K-means算法对图片进行压缩,使图片具有k个像素点值。
K-means聚类算法流程
- 第一步,确定K值,即将数据集聚集成K个类簇或小组;
- 第二步,从数据集中随机选择K个数据点作为质心(Centroid)或数据中心;
- 第三步,分别计算每个点到每个质心之间的距离,并将每个点划分到离最近质心的小组;
- 第四步,当每个质心都聚集了一些点后,重新定义算法选出新的质心。(对于每个簇,计 算其均值,即得到新的k个质心点);
- 第五步,迭代执行第三步到第四步,直到迭代终止条件满足为止(分类结果不再变化)。
K-means()原型介绍
在OpenCV中,Kmeans()函数原型如下所示:
- retval, bestLabels, centers = kmeans(data, K, bestLabels, criteria, attempts, flags[, centers]);
- data表示聚类数据,最好是np.flloat32类型的N维点集;
- K表示聚类类簇数;
- bestLabels表示输出的整数数组,用于存储每个样本的聚类标签索引;
- criteria表示算法终止条件,即最大迭代次数或所需精度。在某些迭代中,一旦每个簇中心的移动小于criteria.epsilon,算法就会停止;
- attempts表示重复试验kmeans算法的次数,算法返回产生最佳紧凑性的标签;
- flags表示初始中心的选择,两种方法是cv2.KMEANS_PP_CENTERS ;和cv2.KMEANS_RANDOM_CENTERS;
- centers表示集群中心的输出矩阵,每个集群中心为一行数据。
算法实现
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread(r'C:\Users\ZFG\PycharmProjects\Lenet_test\lenna.png', 0)
print (img.shape)
rows, cols = img.shape[:]
data = img.reshape((rows * cols, 1))
data = np.float32(data)
#定义中心
criteria = (cv2.TERM_CRITERIA_EPS +
cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
#设置标签
flags = cv2.KMEANS_RANDOM_CENTERS
#K-Means聚类 聚集成5类
compactness, labels, centers = cv2.kmeans(data, 5, None, criteria, 10, flags)
#生成最终图像
dst = labels.reshape((img.shape[0], img.shape[1]))
#用来正常显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']
#显示图像
titles = [u'原始图像', u'聚类图像']
images = [img, dst]
for i in range(2):
plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
我把lena的灰度图分成了具有五类像素点的值(即k=5),最后展示下效果吧。下图为lena灰度图使用k-menas聚类算法后结果的展示:
- 哈哈吓人吧,自己调试的时候可以根据实际情况调整其k值的大小。最后总结下,虽然k-means算法的实现需要一些程序,但是在opencv中可以调用直接封装好的Kmeans()函数,可以说特别方便了。