文章目录
- 1 原理
- 2 API
- 3 图像分割
- 4 代码解释
1 原理 KMeans算法概述
- KMeans算法的作者是MacQueen, KMeans的算法是对数据进行分类的算法,采用的硬分类方式,是属于非监督学习的算法;
- 对于给定的样本集,按照样本之间的距离大小,将样本划分为K个簇,让簇内的点尽量紧密的连接在一起,而让簇间的距离尽量的大。
- 1:选择K个点作为初始质心。
- 2:Repeat
- 3: 计算邻近度,将每个点指派到最近的质心,形成K个簇;
- 4: 重新计算每个簇的质心;
- 5: Until 质心不发生变化或者新的中心和之前的中心之间的距离小于某阈值,或迭代次数超过某阈值,认为聚类已经收敛,终止。
compactness, labels, (centers) = kmeans(data, K, bestLabels, criteria, attempts, flags, centers=None)
参数:
- data:输入的样本数据,必须是按行组织样本,每一行为一个样本数据,列表示样本的维度。
- K:最终的簇的数目。
- bestLabels:预设的分类标签或者None。
- criteria:迭代停止的模式选择,这是一个含有三个元素的元组型数。格式为(type, max_iter, epsilon) 其中,type有如下模式:
- cv2.TERM_CRITERIA_EPS :精确度(误差)满足epsilon,则停止。
- cv2.TERM_CRITERIA_MAX_ITER:迭代次数超过max_iter,则停止。
- cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER:两者结合,满足任意一个结束。
- attempts:重复试验kmeans算法次数,将会返回最好的一次结果。
- flags:初始中心选择,可选以下三种:
- cv2.KMEANS_PP_CENTERS:使用kmeans++算法的中心初始化算法,即初始中心的选择使眼色相差最大。
- cv2.KMEANS_RANDOM_CENTERS:每次随机选择初始中心
- compactness:密度,返回每个点到相应重心的距离的平方和。
- labels:结果标记,每个成员被标记为分组的序号,如 0,1,2,3,4…等。
- centers:由聚类的中心的描述信息(可能是坐标,也可能是色彩值)组成的数组。
- 在一张图片中,每一个像素点对应位置坐标和色彩坐标,用k-means算法对图像聚类不是聚类位置信息,而是对其色彩进行聚类。
- kmeans能够实现简单的分割,当然效果不是非常好,需要经过一些后处理调整,才能得到高精度的分割图。
文章图片
import numpy as np
import cv2 as cv
import matplotlib.pyplot as pltdef test_KMeans(image_path) :
image = cv.imread(image_path, cv.IMREAD_COLOR)
image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
pixel_value = https://www.it610.com/article/np.float32(image.reshape((-1, 3)))#终止条件
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 200, 0.1)#起始的中心选择
flags = cv.KMEANS_RANDOM_CENTERS#定义簇的数量
K = 3_, labels, center = cv.kmeans(pixel_value, K, None, criteria, 10, flags)
center = np.uint8(center)#将所有像素转换为质心的颜色
segmented_image = center[labels.flatten()]#重塑回原始图像尺寸
segmented_image = segmented_image.reshape((image.shape))plt.figure(figsize = (8, 4))
plt.subplot(121)
plt.imshow(image)
plt.axis('off')
plt.title(f'$input\_image$')
plt.subplot(122)
plt.imshow(segmented_image)
plt.axis('off')
plt.title(f'$segmented\_image$')
plt.tight_layout()
plt.savefig('segmented_result.png')
plt.show()if __name__ == '__main__':
test_KMeans('images/shenzhen.png')
效果:
文章图片
整体效果还是不错的,但是一些细节的地方处理的不好,比如说湖面有部分被分为了天空,改进策略有有规则地初始化质心等。
4 代码解释 【图像处理|【OpenCv】图像分割——聚类算法】大家有疑惑的地方就是
segmented_image = center[labels.flatten()]
是怎么将所有像素转换为质心的颜色的。我们前面说过,返回值center是色彩的描述信息,当图片为三通道时,center的维度就是(K,Channels),K是簇的个数,Channels是图片的通道数,如当center返回值是[[ 33 71 57], [193 202 214],[ 65 134 173]]时,[ 33 71 57]分别表示第一个簇心的R、G、B通道的像素值。其次labels返回每个成员被标记为分组的序号,如 0,1,2,3,4…等,在过程中是将R、G、B通道的像素信息整合到一起来标记,所以labels的维度只相当于某一通道展平,如图片本来是[2,4,3],那labels是[8,1]。因此labels中每个标记对应center中的每个簇的下标,如0对应center下标为0的簇心信息。则segmented_image = center[labels.flatten()]
也是将一个通道"拓展"成三通道的过程。也等效于于下面的代码: labels = labels.flatten()
segmented_image = np.zeros((len(labels), 3), dtype = np.uint8)
for i in range(len(labels)) :
segmented_image[i] = center[labels[i]]
推荐阅读
- Python|【Opencv实战】这是我见过的最强大“美颜滤镜”,代码美颜傻瓜式一键操作~(附源码)
- 图像算法|非局部均值滤波算法(NL-means)
- 区块链|教程丨三分钟教你制作专属NFT智能合约
- github|github太慢了(两种方式解决这个痛!.)
- 编程语言|宁愿“大小周”、每天只写 200 行代码、月薪 8k-17k 人群再涨!揭晓中国开发者真实现状...
- 算法|复现经典(《统计学习方法》第21章 PageRank算法)
- 神经网络|(翻译)60分钟入门深度学习工具-PyTorch
- 数据结构与算法|【蓝桥杯】国奖学长带你复盘第十三届蓝桥杯模拟赛
- 信息安全|“脚本小子”和真正黑客的区别是什么()