opencv2 kmeans算法 应用

K-Means算法
原理:百度或谷歌之。。。
有一个简单的例子: https://www.youtube.com/watch?v=zHbxbb2ye3E


opencv:
kmeans函数: Finds centers of clusters and groups input samples around the clusters.
     
     
C++函数原型: 
double kmeans(InputArray samples, int clusterCount, InputOutputArray labels, TermCriteria criteria,
int attempts, int flags, OutputArray centers=noArray() )  

Returns

The function returns the compactness of the final clustering. What is compactness? It's a measure of how good the labeling was done. The smaller the better.

When attempts is 1, the value returned is the compactness of the only iteration that happened. Ifattempts is more than 1, the final labeling returned is the one with the least compactness.

 
      
      
Parameters
samples Floating-point matrix of input samples, one row per sample. //输入矩阵
clusterCount Number of clusters to split the set by. //自定义的聚类中心数目
labels Input/output integer array that stores the cluster indices for every sample. //输入或输出的整数数组,用于存储每一个sample的聚类目录(索引)
criteria The algorithm termination criteria, that is, the maximum number of iterations
and/or the desired accuracy. The accuracy is specified as criteria.epsilon. As soon as
each of the cluster centers moves by less than criteria.epsilon on some iteration, the
algorithm stops. //标准,具体见 TermCriteria
attempts Flag to specify the number of times the algorithm is executed using different
initial labelings. The algorithm returns the labels that yield the best compactness (see the
last function parameter).
flags Flag that can take the following values:
KMEANS_RANDOM_CENTERS Select random initial centers in each attempt.
KMEANS_PP_CENTERS Use kmeans++ center initialization by Arthur and Vassilvitskii
[Arthur2007].
KMEANS_USE_INITIAL_LABELS During the first (and possibly the only) attempt,
use the user-supplied labels instead of computing them from the initial centers. For
the second and further attempts, use the random or semi-random centers. Use one of
KMEANS_*_CENTERS flag to specify the exact method.
centers Output matrix of the cluster centers, one row per each cluster center. //输出的聚类中心
示例:
      
      
void getDomainColor(cv::Mat image,int clusterNum) //输入原图,以及设定的聚类数目
{
// cvtColor(image,image,CV_RGB2Lab); //转化成Lab
//cvtColor(image,image,CV_RGB2YUV);
 
//将image复制到samples,3通道的Mat转成一通道的,每一行是颜色的3个值
Mat samples(image.rows * image.cols, 3, CV_32F);
for( int y = 0; y < image.rows; y++ )
for( int x = 0; x < image.cols; x++ )
for( int z = 0; z < 3; z++)
samples.at<float>(y + x*image.rows, z) = image.at<Vec3b>(y,x)[z];
 
Mat labels; //索引
int attempts = 5; //是否合适?
Mat centers; //中心
Mat centerColor(1,clusterNum,image.type()); //存储每一聚类的颜色
Mat percent;
percent=cv::Mat::zeros(1,clusterNum,CV_32F); //每一聚类占的比例
 
double compactness=cv::kmeans(samples, clusterNum, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 0.0001, 10000),
attempts, KMEANS_PP_CENTERS, centers );
cout<<"attempts:"<<attempts<<endl;
cout<<"compactness"<<compactness<<endl;
 
for(int i=0;i<clusterNum;i++)
{
for(int j=0;j<3;j++)
{
 
centerColor.at<Vec3b>(0,i)[j]=centers.at<float>(i,j);
}
}
// cvtColor(centerColor,centerColor,CV_Lab2RGB);
 
Mat new_image( image.size(), image.type() ); //将原图与聚类中心的映射(根据labels)
for( int y = 0; y < image.rows; y++ )
for( int x = 0; x < image.cols; x++ )
{
int cluster_idx = labels.at<int>(y + x*image.rows,0);
percent.at<float>(0,labels.at<int>(y + x*image.rows,0))++; //统计
new_image.at<Vec3b>(y,x)[0] = centers.at<float>(cluster_idx, 0);
new_image.at<Vec3b>(y,x)[1] = centers.at<float>(cluster_idx, 1);
new_image.at<Vec3b>(y,x)[2] = centers.at<float>(cluster_idx, 2);
}
 
percent/=image.total(); //求比例
// cvtColor(new_image,new_image,CV_Lab2RGB);
 
//保存矩阵
cv::FileStorage fs;
fs.open("D:\\a.txt", cv::FileStorage::WRITE);
fs << "centerColor" << centerColor;
fs.release();
 
cv::FileStorage fs1;
fs1.open("D:\\b.txt", cv::FileStorage::WRITE);
fs1 << "center" << centers;
fs1.release();
 
cv::FileStorage fs2;
fs2.open("D:\\c.txt", cv::FileStorage::WRITE);
fs2 << "labels" << labels;
fs2.release();
 
cv::FileStorage fs3;
fs3.open("D:\\d.txt", cv::FileStorage::WRITE);
fs3 << "percent" << percent;
fs3.release();
 
cv::imshow("new_image",new_image);
 
 
 
}
分析centers、centerColor、labels与percent的内容:
因为kmeans是按行作为向量输入的,所以聚类数目为8时,输出的centers是8*3的矩阵,列表示BGR的值,将其转换成1*8的三通道矩阵centerColor,即可得到该图像的主色向量。
labels用于标记输入的sample中,每一行(即每一像素)属于的聚类中心种类
percent表示每一类所占的比例,将颜色与空间分布相结合
attempts取值对聚类的影响:
原图:(720*480)
attempts=1
 
调节对比度:(调节对比度对于聚类无明显影响效果,且光照影响不能去除)
(左图为原图)


Kmeans后的用途:
1.主色,用于图像检索,详见文献《基于主色选择的CBIR检索》(万方或知网里有);
          
          
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
 
int main()
{
cv::Mat src = cv::imread("D:\\t.jpg");
if(src.empty()){
std::cerr<<"can't read the image"<<std::endl;
return -1;
}
 
//step 1 : map the src to the samples
cv::Mat samples(src.total(), 3, CV_32F);
float* samples_ptr = samples.ptr<float>(0);
for( int row = 0; row != src.rows; ++row){
uchar* src_begin = src.ptr<uchar>(row);
uchar* src_end = src_begin + src.cols * src.channels();
//auto samples_ptr = samples.ptr<float>(row * src.cols);
while(src_begin != src_end){
samples_ptr[0] = src_begin[0];
samples_ptr[1] = src_begin[1];
samples_ptr[2] = src_begin[2];
samples_ptr += 3; src_begin +=3;
}
}
 
//step 2 : apply kmeans to find labels and centers
int clusterCount = 3;
cv::Mat labels;
int attempts = 5;
cv::Mat centers;
cv::kmeans(samples, clusterCount, labels,
cv::TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS,
10, 0.01),
attempts, cv::KMEANS_PP_CENTERS, centers);
 
//step 3 : map the centers to the output
cv::Mat new_image(src.size(), src.type());
for( int row = 0; row != src.rows; ++row){
uchar* new_image_begin = new_image.ptr<uchar>(row);
uchar* new_image_end = new_image_begin + new_image.cols * 3;
int* labels_ptr = labels.ptr<int>(row * src.cols);
 
while(new_image_begin != new_image_end){
int const cluster_idx = *labels_ptr;
float* centers_ptr = centers.ptr<float>(cluster_idx);
new_image_begin[0] = centers_ptr[0];
new_image_begin[1] = centers_ptr[1];
new_image_begin[2] = centers_ptr[2];
new_image_begin += 3; ++labels_ptr;
}
}
 
cv::Mat binary;
cv::Canny(new_image, binary, 30, 90);
 
cv::imshow("original", src);
cv::imshow("binary", binary);
cv::imshow( "clustered image", new_image );
 
cv::waitKey();
 
return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV中的kmeans聚类算法是一种用于将数据集分成K个簇的无监督学习算法。它的主要步骤如下: 首先,通过OpenCV中的随机数生成器RNG,生成一些均匀分布的随机点,这些点的位置对应一副图像中的像素位置。 然后,使用kmeans算法对这些随机点进行分类,并计算出每个类簇的中心点。该算法将数据集中的每个样本点分配到最近的中心点,然后更新中心点的位置,再重复这个过程直到满足终止标准为止。 在OpenCV中,kmeans算法的函数原型如下:kmeans(data, K, bestLabels, criteria, attempts, flags, centers)。其中,data是用于聚类的数据,可以是具有浮点坐标的N维点数组;K是用来分割数据集的簇数;bestLabels是输入/输出整数数组,用于存储每个样本的聚类索引;criteria是算法终止标准,包括最大迭代次数和/或所需精度;attempts是用于指定执行算法的次数的标志;flags指定了算法的具体实现方法,可以选择使用随机的初始中心还是使用Arthur和Vassilvitskii进行的中心初始化,或者使用用户提供的标签来进行计算。 通过使用kmeans算法,我们可以将数据集分成具有相似特征的簇,从而实现数据的聚类分析。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [OpenCV中使用kmeans算法的方法](https://blog.csdn.net/jpc20144055069/article/details/102763754)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值