找回密码
 立即注册
查看: 291|回复: 0

opencv图像处理之K-means聚类算法

[复制链接]
发表于 2022-4-15 14:47 | 显示全部楼层 |阅读模式
opencv图像处理之K-means聚类算法

    opencv图像处理之K-means聚类算法
      kmeans算法过程与简单的理解基于Opencv的c++代码



opencv图像处理之K-means聚类算法

kmeans是非常经典的聚类算法,至今也还保留着较强的生命力,图像处理中经常用到kmeans算法或者其改进算法进行图像分割操作,在数据挖掘中kmeans经常用来做数据预处理。opencv中提供了完整的kmeans算法,其函数原型为:
  1. doublekmeans( InputArray data,int K, InputOutputArray bestLabels, TermCriteria criteria,int attempts,int flags, OutputArray centers =noArray());
复制代码
其中data表示用于聚类的数据,是N维的数组类型(Mat型),必须浮点型;
K表示需要聚类的类别数;
bestLabels聚类后的标签数组,Mat型;
criteria迭代收敛准则(MAX_ITER最大迭代次数,EPS最高精度);
attemps表示尝试的次数,防止陷入局部最优;
flags 表示聚类中心的选取方式(KMEANS_RANDOM_CENTERS 随机选取,KMEANS_PP_CENTERS使用Arthur提供的算法,KMEANS_USE_INITIAL_LABELS使用初始标签);
centers 表示聚类后的类别中心。
关于kmeans的理论可以参考:略…
kmeans算法过程与简单的理解

聚类算法有很多种(几十种),K-Means是聚类算法中的最常用的一种,算法最大的特点是简单,好理解,运算速度快,但是只能应用于连续型的数据,并且一定要在聚类前需要手工指定要分成几类。
下面,我们描述一下K-means算法的过程,为了尽量不用数学符号,所以描述的不是很严谨,大概就是这个意思,“物以类聚、人以群分”:
    首先输入k的值,即我们希望将数据集经过聚类得到k个分组。从数据集中随机选择k个数据点作为初始大哥(质心,Centroid)对集合中每一个小弟,计算与每一个大哥的距离(距离的含义后面会讲),离哪个大哥距离近,就跟定哪个大哥。这时每一个大哥手下都聚集了一票小弟,这时候召开人民代表大会,每一群选出新的大哥(其实是通过算法选出新的质心)。如果新大哥和老大哥之间的距离小于某一个设置的阈值(表示重新计算的质心的位置变化不大,趋于稳定,或者说收敛),可以认为我们进行的聚类已经达到期望的结果,算法终止。如果新大哥和老大哥距离变化很大,需要迭代3~5步骤。
基于Opencv的c++代码
  1. #include<opencv2/opencv.hpp>#include<iostream>usingnamespace cv;usingnamespace std;intmain(){
  2.         Mat srcImage =imread("girl1.jpg");if(!srcImage.data){printf("could not load image...\n");return-1;}imshow("girl1.jpg", srcImage);//五个颜色,聚类之后的颜色随机从这里面选择
  3.         Scalar colorTab[]={Scalar(0,0,255),Scalar(0,255,0),Scalar(255,0,0),Scalar(0,255,255),Scalar(255,0,255)};int width = srcImage.cols;//图像的宽int height = srcImage.rows;//图像的高int channels = srcImage.channels();//图像的通道数//初始化一些定义int sampleCount = width*height;//所有的像素int clusterCount =4;//分类数
  4.         Mat points(sampleCount, channels, CV_32F,Scalar(10));//points用来保存所有的数据
  5.         Mat labels;//聚类后的标签
  6.         Mat center(clusterCount,1, points.type());//聚类后的类别的中心//将图像的RGB像素转到到样本数据int index;for(int i =0; i < srcImage.rows; i++){for(int j =0; j < srcImage.cols; j++){
  7.                         index = i*width + j;
  8.                         Vec3b bgr = srcImage.at<Vec3b>(i, j);//将图像中的每个通道的数据分别赋值给points的值
  9.                         points.at<float>(index,0)=static_cast<int>(bgr[0]);
  10.                         points.at<float>(index,1)=static_cast<int>(bgr[1]);
  11.                         points.at<float>(index,2)=static_cast<int>(bgr[2]);}}//运行K-means算法//MAX_ITER也可以称为COUNT最大迭代次数,EPS最高精度,10表示最大的迭代次数,0.1表示结果的精确度
  12.         TermCriteria criteria =TermCriteria(TermCriteria::EPS + TermCriteria::COUNT,10,0.1);kmeans(points, clusterCount, labels, criteria,3, KMEANS_PP_CENTERS, center);//显示图像分割结果
  13.         Mat result = Mat::zeros(srcImage.size(), srcImage.type());//创建一张结果图for(int i =0; i < srcImage.rows; i++){for(int j =0; j < srcImage.cols; j++){
  14.                         index = i*width + j;int label = labels.at<int>(index);//每一个像素属于哪个标签
  15.                         result.at<Vec3b>(i, j)[0]= colorTab[label][0];//对结果图中的每一个通道进行赋值
  16.                         result.at<Vec3b>(i, j)[1]= colorTab[label][1];
  17.                         result.at<Vec3b>(i, j)[2]= colorTab[label][2];}}imshow("Kmeans", result);waitKey(0);return0;}
复制代码
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2025-5-17 09:42 , Processed in 0.133597 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表