聚类算法实例:K-Means实现图像分割
K-Means聚类
K-means算法是经典的基于划分的聚类方法
基本思想
基于空间中的k个中心点开展数据聚类,在每一次迭代过程中将与之最近的对象分组为同一类别组。通过持续更新各聚类中心的位置并逐步优化其位置坐标值,在达到分类效果最优的状态时停止迭代运算。
最终的k个数据聚类群具有以下显著特征:
各类别内部尽量紧密地聚集在一起,而各类别之间尽量拉开距离以保持清晰区分.该算法的重要特点体现在简明扼要与迅速高效之间,其核心优势在于能够准确预判类别数量的同时合理选择初始中心与距离计算公式.
算法描述
为了实现将样本集划分为k个类别这一目标,在初始化阶段,在数据集D={X₁,X₂,…,Xₘ}中随机选取k个样本点作为聚类中心的初始位置。在第i次迭代过程中,请计算每一个样本点x∈D至当前所有聚类中心的距离,并将其归入具有最小距离的那一类。当经过步骤(2)和(3)重新计算所有聚类中心之后发现其位置变化不超过设定阈值时,则终止迭代过程;否则需要继续执行上述步骤。

局限
K-Means是线性分类器,对于线性不可分数据就会失效,如

K-Means数学依据
样本集:

聚类中心集合:

簇的集合:

为了将样本点划分为明确定义的K个类别(即为一个明确的数量),我们希望每个样本点离其所属簇的聚类中心越近越好。

, 其中

。E越小,簇内相似度越高。
图像分割
该方法即为将一张图片划分为若干互不重叠的区域的过程,并其本质是像素聚类的方式之一,在图像处理领域具有重要价值。
具体可分为以下几类:
-
基于阈值的方法通常根据灰度级或颜色进行分类处理
-
基于边缘检测的方法主要关注图像中的边缘特征
-
基于模型学习的方法则通过建立训练数据集来实现分类任务
-
基于区域技术,如聚类算法
-
基于边缘技术
利用opencv2实现k-means
cv2.kmeans(data, K, bestLabels, criteria, attempts, flags)
参数: data: 分类数据,最好是np.float32的数据,每个特征放一列。
K: 分类数,opencv2的kmeans分类是需要已知分类数的。
bestLabels:预设的分类标签或者None
选择迭代终止的标准:这是一个由三个元素构成的元组类型数值。遵循(type, max_iter, epsilon)的形式;其中type分为以下几种情况:
- cv2.TERM CRITER IA EPS 表示当误差达到epsilon时终止。
- cv2.TERM CRITTER IA MAX_ITER 表示当迭代次数超过max_iter时终止。
- cv2.TERM CRITTER IA EPS+cv2.TERM CRITTER IA MAX_ITER 表示只要满足上述任一条件即可终止
attempts:重复试验kmeans算法次数,将会返回最好的一次结果
flags:参数设置中初始质心选取有两种实现方式:一种是通过伪中心点算法——cv2.KMEANS_PP_CENTERS;另一种是通过随机质心选取算法——cv2.KMEANS_RANDOM_CENTERS。详细说明了不同实现的特点及其适用场景。
返回值: compactness:紧密度,返回每个点到相应重心的距离的平方和
result_labels:结果标记;每个成员将被分配整数值0或1;center_points:一个由聚类中心点构成的集合
对灰度图像进行分割
import cv2
import matplotlib.pyplot as plt
import numpy as np
def seg_kmeans_gray():
#读取图片
img = cv2.imread('pic.jpg', cv2.IMREAD_GRAYSCALE)
# 展平
img_flat = img.reshape((img.shape[0] * img.shape[1], 1))
img_flat = np.float32(img_flat)
# 迭代参数
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TermCriteria_MAX_ITER, 20, 0.5)
flags = cv2.KMEANS_RANDOM_CENTERS
# 进行聚类
compactness, labels, centers = cv2.kmeans(img_flat, 2, None, criteria, 10, flags)
# 显示结果
img_output = labels.reshape((img.shape[0], img.shape[1]))
plt.subplot(121), plt.imshow(img, 'gray'), plt.title('input')
plt.subplot(122), plt.imshow(img_output, 'gray'), plt.title('kmeans')
plt.show()
if __name__ == '__main__':
seg_kmeans_gray()
对彩色图像进行聚类
import cv2
import matplotlib.pyplot as plt
import numpy as np
def seg_kmeans_color():
img = cv2.imread('pic.png', cv2.IMREAD_COLOR)
# 变换图像通道bgr->rgb
b, g, r = cv2.split(img)
img = cv2.merge([r, g, b])
# 3个通道展平
img_flat = img.reshape((img.shape[0] * img.shape[1], 3))
img_flat = np.float32(img_flat)
# 迭代参数
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TermCriteria_MAX_ITER, 20, 0.5)
flags = cv2.KMEANS_RANDOM_CENTERS
# 聚类,这里k=2
compactness, labels, centers = cv2.kmeans(img_flat, 2, None, criteria, 10, flags)
# 显示结果
img_output = labels.reshape((img.shape[0], img.shape[1]))
plt.subplot(121), plt.imshow(img), plt.title('input')
plt.subplot(122), plt.imshow(img_output, 'gray'), plt.title('kmeans')
plt.show()
if __name__ == '__main__':
seg_kmeans_color()
效果图:



- 补:k-means处理文本信息
<>
