龙空技术网

使用K-means聚类方法分割图像

Lemon1号 224

前言:

而今大家对“kmeans聚类算法实现图像分割”大体比较着重,朋友们都需要分析一些“kmeans聚类算法实现图像分割”的相关资讯。那么小编同时在网络上网罗了一些关于“kmeans聚类算法实现图像分割””的相关内容,希望小伙伴们能喜欢,兄弟们快快来学习一下吧!

使用C++、opencv中的Kmeans进行图像分割K-means算法的原理

K-means算法是基于距离相似性的聚类算法,通过比较样本之间的相似性,将形式的样本划分到同一个类别中,K-Means算法的基本过程为:

初始化常数 ,随机初始化k个聚类中心。重复计算以下过程,直到聚类中心不再改变:

计算每个样本与每个聚类中心之间的相似度,将样本划分到最相似的类别中;

计算划分到每个类别中的所有样本特征的均值,并将该均值作为每个类新的聚类中心;

输出最终的聚类中心以及每个样本所属的类别。

在K-Means算法中,需要随机初始化k个聚类中心,而K-Means算法对初始聚类中心的选取较为敏感,若选择的聚类中心不好,则得到的聚类结果会非常差,因此,对K-Means算法提出了很多的改进的方法,如K-Means++算法,在K-Means++算法中,希望初始化的k个聚类中心之间的距离尽可能的大,其具体过程为:

在数据集中随机选择一个样本点作为第一个初始化的聚类中心选择出其余的聚类中心:

计算样本中的每一个样本点与已经初始化的聚类中心之间的距离,并选择其中最短的距离

以概率选择距离最大的样本作为新的聚类中心,重复上述过程,直到 个聚类中心都被确定

对k个初始化的聚类中心,利用K-Means算法计算最终的聚类中心。

更多关于 K-Means算法的原理可查看:

opencv中关于Kmeans的API:

double kmeans(InputArray data, int K, InputOutputArray bestLabels, TermCriteria criteria, int attempts, int flags, OutputArray centers=noArray() )

data: 需要自动聚类的数据,一般是一个Mat。浮点型的矩阵,每行为一个样本。

k: 取成几类,比较关键的一个参数。

bestLabels: 返回的类别标记,整型数字。

criteria: 算法结束的标准,获取期望精度的迭代最大次数

attempts: 判断某个样本为某个类的最少聚类次数,比如值为3时,则某个样本聚类3次都为同一个类,则确定下来。

flags: 确定簇心的计算方式。有三个值可选:KMEANS_RANDOM_CENTERS 表示随机初始化簇心。KMEANS_PP_CENTERS 表示用kmeans++算法来初始化簇心,KMEANS_USE_INITIAL_LABELS 表示第一次聚类时用用户给定的值初始化聚类,后面几次的聚类,则自动确定簇心。

centers: 用来初始化簇心的。与前一个flags参数的选择有关。如果选择KMEANS_RANDOM_CENTERS随机初始化簇心,则这个参数可省略。

使用聚类的方法分割图像,即将图像的像素点值(通常用彩色图像,像素点值为一个三元数组(b,g,r))作为聚类的元素,从而将图像中所有的点分为n类,达到分割的效果。这里只是展示代码效果,实际上可以根据需要,将其他颜色参数(如H、S、I、L、a、b等)、颜色参数的组合(NRI、NGI、NBI等)作为分类的数据点传入训练器,这样可能会对复杂的分割有帮助。

代码如下:

#include "stdafx.h"#include <string>  #include <iostream>  #include <math.h>  #include <vector>  #include <map>  #include <opencv/cv.h>  #include <opencv/highgui.h> #include <opencv/cxcore.h> #include <opencv2\opencv.hpp>//聚类数目宏定义#define ClusterNum 2  using namespace cv;using namespace std;//K-means聚类Mat clustering(Mat src) {	int row = src.rows;	int col = src.cols;	unsigned long int size = row * col;	//定义聚类图像,用来存储每个位置的类标签	Mat clusters(size, 1, CV_32SC1); 	//将源图转化为数据点	Mat srcPoint(size, 1, CV_32FC3);	Vec3f* srcPoint_p = (Vec3f*)srcPoint.data;	Vec3f* src_p = (Vec3f*)src.data;	unsigned long int i;	for (i = 0; i < size; i++)	{		*srcPoint_p = *src_p;		srcPoint_p++;		src_p++;	}	Mat center(ClusterNum, 1, CV_32FC3);	//用不同的标记度量聚类中心距离和的紧密度	double compactness; 	compactness = kmeans(srcPoint, ClusterNum, clusters,		cvTermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 0.1), ClusterNum,		KMEANS_PP_CENTERS, center);	cout << "center row:" << center.rows << " col:" << center.cols << endl;	for (int y = 0; y < center.rows; y++)	{		Vec3f* imgData = center.ptr<Vec3f>(y);		for (int x = 0; x < center.cols; x++)		{			cout << imgData[x].val[0] << " " << imgData[x].val[1] << " " << imgData[x].val[2] << endl;		}		cout << endl;	}	double minH, maxH;	minMaxLoc(clusters, &minH, &maxH); 	cout << "H-channel min:" << minH << " max:" << maxH << endl;	int* clusters_p = (int*)clusters.data;  	Mat label(src.size(), CV_32SC1);	int* label_p = (int*)label.data;	//将类别分配给Mat标签   	for (i = 0; i < size; i++)	{		*label_p = *clusters_p;		label_p++;		clusters_p++;	}	Mat label_show;	label.convertTo(label_show, CV_8UC1);	normalize(label_show, label_show, 255, 0, CV_MINMAX);	imshow("label", label_show);	map<int, int> count;    	map<int, Vec3f> avg; 	for (int y = 0; y < row; y++)	{		const Vec3f* imgData = src.ptr<Vec3f>(y);		int* idx = label.ptr<int>(y);		for (int x = 0; x < col; x++)		{			avg[idx[x]] += imgData[x];			count[idx[x]] ++;		}	}	//output the average value (clustering center)    	//计算所得的聚类中心与kmean函数中center的第一列一致,    	//以后可以省去后面这些繁复的计算,直接利用center,    	//但是仍然不理解center的除第一列以外的其他列所代表的意思  	for (i = 0; i < ClusterNum; i++)	{		avg[i] /= count[i];		if (avg[i].val[0]>0 && avg[i].val[1]>0 && avg[i].val[2]>0)		{			cout << i << ": " << avg[i].val[0] << " " << avg[i].val[1] << " " << avg[i].val[2] << " count:" << count[i] << endl;		}	}	//显示聚类图像	Mat showImg(src.size(), CV_32FC3);	for (int y = 0; y < row; y++)	{		Vec3f* imgData = showImg.ptr<Vec3f>(y);		int *idx = label.ptr<int>(y);		for (int x = 0; x < col; x++)		{			int id = idx[x];			imgData[x].val[0] = avg[id].val[0];			imgData[x].val[1] = avg[id].val[1];			imgData[x].val[2] = avg[id].val[2];		}	}	normalize(showImg, showImg, 1, 0, CV_MINMAX);//标准化	imshow("show", showImg);	waitKey();	return label;//返回聚类后的标签}int main() {	//读取图像	Mat img = imread("D:\\1.jpg", 1);	if (!img.data)	{		cout << "src image load failed!" << endl;		return -1;	}	imshow("src", img);	//高斯滤波降噪	GaussianBlur(img, img, Size(3, 3), 0);	//转换图片类型	img.convertTo(img, CV_32FC3);	//聚类操作	Mat pixId = clustering(img);}

源图:

标签图(分类后的结果,代码中分为2类):

结果图:

标签: #kmeans聚类算法实现图像分割