k-均值聚类

根据训练数据是否有标签,我们可以将学习划分为监督学习和非监督学习,如:k近邻、支持向量机都是监督学习,提供有标签的数据给算法学习,然后对数据分类,而聚类是无监督学习,事先并不知道分类标签是什么,直接对数据分类,它能够将具有相似属性的对象划分到同一个簇中。聚类方法能够应用于所有对象,簇类的对象越相似,聚类效果越好。

一:K均值聚类的基本思想

K均值聚类是一种将输入数据划分为K个簇的简单聚类算法,该算法不断提取当前分类的中心点,并最终在分类稳定的时候完成聚类,它是一种迭代算法。其步骤如下:

1:随机选取k个点作为分类的中心点。
2:将每个数据点放到距离它最近的中心点所属的类中。
3:重新计算各个分类中的数据点的平均值,将该平均值作为新的分类中心点。
4:重复步骤2和步骤3,直到分类稳定。

注:在步骤1中,可以是随机选取的k个点作为分类的中心点,也可以是随机生成的k个并不存在原始数据中的数据点作为分类中心点。在步骤3中提到的距离最近可以采用不同形式的距离度量方式,当然不同的计算方式会对算法性能产生影响。

二:K均值聚类模块

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

data:输入的待处理数据集合,np.flaot32类型,每个特征放在单独的一列中。
K:要分出的簇的个数,即分类的数目。
bestLabels:表示计算之后各个数据点的最终分类标签(索引),实际调用时,参数bestLabels的值设置为None。
criteria:算法迭代的终止条件。当达到最大循环数目或者指定的精度阈值时,算法停止继续分类迭代计算,该参数由:type、max_iter和eps这3个参数构成。
	type:表示终止的类型,可以是下面3种情况:
		cv2.TERM_CRITERIA_EPS:精度满足eps时,停止迭代。
		cv2.TERM_CRITERIA_MAX_ITER:迭代次数超过阈值max_iter时,停止迭代。
		cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER:上述两个条件中的任意一个满足时,停止迭代。
	max_iter:最大迭代次数
	eps:精确度的阈值。
attempts:在具体实现时,为了获得最佳分类效果,可能需要使用不同的初始分类值进行多次尝试,指定attempts的值,可以让算法使用不同的初始值进行多(attempts)次尝试。
flages:表示选择初始中心点的方法,主要有以下3种:
	cv2.KMEANS_RANDOM_CENTERS:随机选取中心点。
	cv2.KMEANS_PP_CENTERS:基于中心化算法选取中心点。
	cv2.KMEANS_USE_INITIAL_LABELS:使用用户输入的数据作为第一次分类的分类中心点,如果算法需要尝试多次(attempts大于1),后续尝试都是使用随机值或者半随机值作为第一次分类中心点。
	
返回值:
	retval:距离值(也称密度值或者紧密度),返回每个点到相应中心点距离的平方和。
	bestLabels:各个数据点的最终分类标签(索引)。
	centers:每个分类的中心点数据。

三:简单示例

1:在一定范围内随机生成两组数,用cv2.kmeans()对其进行分类:

import cv2
import numpy as np
from matplotlib import pyplot as plt

min=np.random.randint(0,20,(30,2))
max=np.random.randint(40,60,(30,2))

#每个特征必须放在单独的一列`
MI=np.float32(np.vstack((min,max)))

criteria=(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,10,1.0)

ret,label,center=cv2.kmeans(MI,2,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
print("各个点到相应中心点距离的平方和:",ret)
print("各数据点的最终分类标签:",label.flatten())
print("每个分类的中心点:",center)
#各数据分类标签
XM=MI[label.ravel()==0]
DM=MI[label.ravel()==1]

plt.scatter(XM[:,0],XM[:,1],c="g",marker="s")
plt.scatter(DM[:,0],DM[:,1],c="r",marker="o")
plt.scatter(center[0,0],center[0,1],s=200,c="b",marker="o")
plt.scatter(center[1,0],center[1,1],s=200,c="y",marker="s")
plt.xlabel("Height")
plt.ylabel("Width")
plt.show()

>>各个点到相应中心点距离的平方和: 3780.3333538770676
>>各数据点的最终分类标签: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1
							1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
>>每个分类的中心点: [[ 9.333334  9.900001] [49.000004 49.633335]]

在这里插入图片描述

二:对图片进行像素分类

1:在读取图像的时候,需要将通道处理为特征值(如3个通道的RGB图像,需要将图像的通道RGB值处理为一个单独的特征值)。同时为了cv2.kmeans()能够处理,需要将数据类型转换为numpy.float32的形式

import cv2
import numpy as np
from matplotlib import pyplot as plt

img_0=cv2.imread(r"F:\my_project\opencv\img\11.jpg")
#在opencv中,读入的图片为BGR,而plt显示图片时的默认格式为RGB(A),需要进转换,不然会显示错误
img=cv2.cvtColor(img_0,cv2.COLOR_BGR2RGB)
#将每个像素点(BGR的值作为一个单元处理)
data=img.reshape((-1,3))
#转为cv2.keeams能够处理的数据
data=np.float32(data)
criteria=(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,10,1.0)
k=2#通过设置k值,可以将像素分为k类
ret,label,center=cv2.kmeans(data,2,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
#像素需要为整型
center=np.uint8(center)
#使用center内的值替换原像素值
res1=center[label.flatten()]
res2=res1.reshape((img.shape))
#绘图
plt.subplot(221)
plt.imshow(img_0)
plt.title("mistake format show")
plt.subplot(222)
plt.imshow(img)
plt.subplot(223)
plt.imshow(res2)
plt.axis("off")
plt.show()

在这里插入图片描述


版权声明:本文为sc9876543210原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。