原文地址:http://blog.csdn.net/mrharvey/article/details/18085163
最近我一直在研究图像分割,目标提取的算法,由于背景目标的复杂而且噪点很多,所以我一直更换尝试各种算法以达到最好的效果。如果大家有什么经验传递的话,烦请在评论里面留言,感谢。
说回正题吧。为什么要用k-means算法呢?因为我想学习一下机器学习(*^__^*) ,曾经的机器学习我没有好好听课现在后悔了(ㄒoㄒ)//
1 K-means算法
1.1 定义和概述
k-means算法是一种得到最广泛使用的基于划分的聚类算法,把n个对象分为k个簇,以使簇内具有较高的相似度。相似度的计算根据一个簇中对象的平均值来进行。它与处理混合正态分布的最大期望算法很相似,因为他们都试图找到数据中自然聚类的中心。
算法首先随机地选择k个对象,每个对象初始地代表了一个簇的平均值或中心。对剩余的每个对象根据其与各个簇中心的距离,将它赋给最近的簇,然后重新计算每个簇的平均值。这个过程不断重复,直到准则函数收敛。
它假设对象属性来自于空间向量,并且目标是使各个群组内部的均方误差总和最小。假设有k个群组Si, i=1,2,...,k。μi是群组Si内所有元素xj的重心,或叫中心点。
1.2 算法的步骤
1.2.1 文字性的步骤
输入:簇的数目k;包含n个对象的数据集D。
输出:k个簇的集合。
方法:
1) 从D中任意选择k个对象作为初始簇中心;
2) repeat;
3) 根据簇中对象的均值,将每个对象指派到最相似的簇;
4) 更新簇均值,即计算每个簇中对象的均值;
5) 计算准则函数;
6) until准则函数不再发生变化
1.2.2 数学一点的步骤
给定初始的包含k个中心点{ m1,…,mk }的初值。这个过程通常是针对具体的问题有一些启发式的选取方法,或者大多数情况下采用随机选取的办法。因为前面说过 k-means 并不能保证全局最优,而是否能收敛到全局最优解其实和初值的选取有很大的关系,所以有时候我们会多次选取初值跑 k-means ,并取其中最好的一次结果。算法可以分为两个步骤:
分配步骤:
将每个数据点归类到离它最近的那个中心点所代表的 cluster 中。
每一个数据都会被安排到确定的即使它可以指定给两个或多个簇里面。
更新步骤:
计算cluster的均值,并将他作为新中心点。公式如下:
重复迭代上面的两个步骤,直到算法收敛,既分配步骤的分配不会再改变。
1.2.3 简单明了的例子介绍
下面的算法过程示例就借用一下陈皓大牛的博客(http://coolshell.cn/articles/7779.html)介绍:
从上图中,我们可以看到,A, B, C, D, E 是五个在图中点。而灰色的点是我们的种子点,也就是我们用来找点群的点。有两个种子点,所以K=2。
然后,K-Means的算法如下:
- 随机在图中取K(这里K=2)个种子点。
- 然后对图中的所有点求到这K个种子点的距离,假如点Pi离种子点Si最近,那么Pi属于Si点群。(上图中,我们可以看到A,B属于上面的种子点,C,D,E属于下面中部的种子点)
- 接下来,我们要移动种子点到属于他的“点群”的中心。(见图上的第三步)
- 然后重复第2)和第3)步,直到,种子点没有移动(我们可以看到图中的第四步上面的种子点聚合了A,B,C,下面的种子点聚合了D,E)。
2 图像分割
(稍后补上,请原谅)
3 利用K-means进行图像分割算法
3.1Matlab的一个Sample程序
- % this is K-means test program Matlab Sample http://www.mathworks.cn/cn/help/stats/kmeans.html?s_tid=doc_12b
- close all;
- clear all;
- clc;
- % 需要进行分类的数据
- X = [randn(100,2)+ones(100,2);...
- randn(100,2)-ones(100,2)];
- opts = statset('Display','final');
- [idx,ctrs] = kmeans(X,2,...
- 'Distance','city',...
- 'Replicates',5,...
- 'Options',opts);
- plot(X(idx==1,1),X(idx==1,2),'r.','MarkerSize',12)
- hold on
- plot(X(idx==2,1),X(idx==2,2),'b.','MarkerSize',12)
- plot(ctrs(:,1),ctrs(:,2),'kx',...
- 'MarkerSize',12,'LineWidth',2)
- plot(ctrs(:,1),ctrs(:,2),'ko',...
- 'MarkerSize',12,'LineWidth',2)
- legend('Cluster 1','Cluster 2','Centroids',...
- 'Location','NW')
3.2用于图像分割的算法
- close all;
- clear all;
- clc;
- C_Segments=2;
- img_original = imread('1.jpg');%读入图像
- figure,imshow(img_original),title('原始图像'); %显示原图像
- img_gray=rgb2gray(img_original);
- figure,imshow(img_gray),title('原始灰度图像');
- % 获取图像的长宽
- [m,n]=size(img_gray);
- % 灰度阈值计算
- T=graythresh(img_gray);
- img_bw=im2bw(img_gray,T);
- figure,imshow(img_bw),title('原始二值图像');
- % 将图像进行RGB——3通道分解
- A = reshape(img_original(:, :, 1), m*n, 1); % 将RGB分量各转为kmeans使用的数据格式n行,一样一样本
- B = reshape(img_original(:, :, 2), m*n, 1);
- C = reshape(img_original(:, :, 3), m*n, 1);
- dat = [A B C]; % r g b分量组成样本的特征,每个样本有三个属性值,共width*height个样本
- cRGB = kmeans(double(dat), C_Segments,...
- 'Distance','city',...
- 'emptyaction','singleton',...
- 'start','sample'); % 使用聚类算法分为2类
- rRGB = reshape(cRGB, m, n); % 反向转化为图片形式
- figure, imshow(label2rgb(rRGB)),title('RGB通道分割结果'); % 显示分割结果
- % 将图像进行单一通道灰度分解
- GraySeg= reshape(img_gray(:, :), m*n, 1);
- cGray=kmeans(double(GraySeg), 2);
- rGray= reshape(cGray, m, n); % 反向转化为图片形式
- figure, imshow(label2rgb(rGray)),title('灰度通道分割结果'); % 显示分割结果
程序效果:
图1 输入图像
图2 两聚类RGB分割图像
图3 三聚类图像分割结果
存在的问题:
1) 初始种子点的选择,现在不能自动选择,也就是说只能通过人工智能,如果自动选择的话貌似要K-means++(我也不清楚,懂的大牛请评论留言)。
2) 分割效果有点过。需要配合其他分割方法才能达到好的效果。
参考文献
[1]维基百科. K平均算法. http://zh.wikipedia.org/wiki/K%E5%B9%B3%E5%9D%87%E7%AE%97%E6%B3%95,2014-1-9.
[2] 陈皓. K-Means 算法. http://coolshell.cn/articles/7779.html,2014-1-10.
[3] 使用聚类算法(kmeans)分割图像的一个小实验. http://www.aiseminar.cn/bbs/forum.php?mod=viewthread&tid=689,2014-1-10.