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
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值