#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
//该程序利用OpenCV中的K均值聚类函数Kmeans2对图像进行颜色聚类,达到分割的目的。
//编写此函数的目的是:Kmeans2函数的用法有些难掌握,参考资料少,尤其是对图像进行操作的例子少,我找了很久也找不到,
//找到的例子也运行不了,今天终于自己搞定了,想给大家分享一下,供大家参考,节省大家利用Kmeans2进行图像方面开发的时间
//,少走一些弯路。
//本例子对印章图像sample.bmp进行颜色聚类
//运行此程序一定要配置好OpenCv环境啊!!!
// KMeans2
// 按照给定的类别数目对样本集合进行聚类
//
// void cvKMeans2( const CvArr* samples, int cluster_count,
// CvArr* labels, CvTermCriteria termcrit );
// samples
// 输入样本的浮点矩阵,每个样本一行。
// cluster_count
// 所给定的聚类数目
// labels
// 输出整数向量:每个样本对应的类别标识
// termcrit
// 指定聚类的最大迭代次数和/或精度(两次迭代引起的聚类中心的移动距离)
// 函数 cvKMeans2 执行 k-means 算法 搜索 cluster_count 个类别的中心并对样本进行分类,输出 labels(i) 为样本 i 的类别标识。
void main()
{
IplImage* img=cvLoadImage("sample.bmp");//加载图像,图像放在Debug文件夹里,这里是相对路径
cvNamedWindow( "原始图像", 1 ); //创建窗口
cvShowImage( "原始图像", img ); //显示图像
cvWaitKey(0); //等待按键
int i,j;
CvMat *samples=cvCreateMat((img->width)*(img->height),1,CV_32FC3);//创建样本矩阵,CV_32FC3代表32位浮点3通道(彩色图像)
CvMat *clusters=cvCreateMat((img->width)*(img->height),1,CV_32SC1);//创建类别标记矩阵,CV_32SF1代表32位整型1通道
int k=0;
for (i=0;i<img->width;i++)
{
for (j=0;j<img->height;j++)
{
CvScalar s;
//获取图像各个像素点的三通道值(RGB)
s.val[0]=(float)cvGet2D(img,j,i).val[0];
s.val[1]=(float)cvGet2D(img,j,i).val[1];
s.val[2]=(float)cvGet2D(img,j,i).val[2];
cvSet2D(samples,k++,0,s);//将像素点三通道的值按顺序排入样本矩阵
}
}
int nCuster=2;//聚类类别数,自己修改。
cvKMeans2(samples,nCuster,clusters,cvTermCriteria(CV_TERMCRIT_ITER,100,1.0));//开始聚类,迭代100次,终止误差1.0
IplImage *bin=cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U,1);//创建用于显示的图像,二值图像
k=0;
int val=0;
float step=255/(nCuster-1);
for (i=0;i<img->width;i++)
{
for (j=0;j<img->height;j++)
{
val=(int)clusters->data.i[k++];
CvScalar s;
s.val[0]=255-val*step;//这个是将不同类别取不同的像素值,
cvSet2D(bin,j,i,s); //将每个像素点赋值
}
}
cvNamedWindow( "聚类图像", 1 ); //创建窗口
cvShowImage( "聚类图像", bin ); //显示图像
cvWaitKey(0); //等待按键
cvDestroyWindow( "原始图像" );//销毁窗口
cvReleaseImage( &img ); //释放图像
cvDestroyWindow( "聚类图像" );//销毁窗口
cvReleaseImage( &bin ); //释放图像
}
- 1
- 2
- 3
- 4
- 5
- 6
前往页