学习OpenCV——一次颜色聚类
1.首先区分三个通道,画出每个通道的直方图;
2.平滑直方图,像素值等于前后共七种颜色数量的平均值;
3.取波峰,波谷。(条件:颜色数亮s(i-2)<s(i-1)<s(i)>s(i+1)>s(i+2)或s(i-2)>s(i-1)>s(i)<s(i+1)<s(i+2)))
4.计算算有颜色的组合,并存入一个一维矩阵中;
5.颜色合并(利用map<int,int>);
6.把原图所有颜色与合并后的颜色计算距离,得出距离最近的合并颜色,在另一个原图大小的1通道矩阵中,记录相应位置颜色对应合并颜色的序号;
7.把原图序号相同的颜色加和,求平均值,就是类聚一次后的颜色。
8.把聚类后的颜色存入相应的序号的位置。
即为一次聚类后的结果,效果不很好。是由于聚类次数过少。
利用Kmean2算法,效果会很好。
#include "cv.h" #include"highgui.h" #include<map> #include<vector> #include<iostream> using namespace std; template<typename T>T sqr(T x){return x*x;} CvMat* mat=0; IplImage* image=0; IplImage *histimg=cvCreateImage(cvSize(256,300),IPL_DEPTH_8U,3); IplImage* DrawHist(map<int,int>colornum,int n); map<int,int> Fine(CvMat* mat1u); //CvMat* Merge(CvMat* Fine,int FineNum); int main() { image=cvLoadImage("D:/7.jpg",1); cvNamedWindow("Show",1); cvShowImage("Show",image); IplImage *hist0=0;//cvCreateImage(cvSize(300,300),IPL_DEPTH_8U,1); IplImage *hist1=0;//cvCreateImage(cvSize(300,300),IPL_DEPTH_8U,1); CvMat* r=cvCreateMat(image->height,image->width,CV_8UC1); CvMat* g=cvCreateMat(image->height,image->width,CV_8UC1); CvMat* b=cvCreateMat(image->height,image->width,CV_8UC1); CvMat* rgb=cvCreateMat(image->height,image->width,CV_32FC3); CvMat* result=cvCreateMat(image->height,image->width,CV_32FC3); CvMat* result00=cvCreateMat(image->height,image->width,CV_8UC3); cvConvertScale(image,rgb,1.0/255); cvSplit(image,r,g,b,NULL); map<int,int>fine_r=Fine(r); map<int,int>fine_g=Fine(g); map<int,int>fine_b=Fine(b); int FineNum=fine_r.size()*fine_g.size()*fine_b.size(); cout<<"FineNum: "<<FineNum<<endl; CvMat* Fine=cvCreateMat(1,FineNum,CV_32FC3); //vector<CvScalar>avg;//////////////////////////// int i=0; for(map<int,int>::iterator it0=fine_r.begin();it0!=fine_r.end();it0++){ for(map<int,int>::iterator it1=fine_g.begin();it1!=fine_g.end();it1++){ float* f=(float*)(Fine->data.ptr); for(map<int,int>::iterator it2=fine_b.begin();it2!=fine_b.end();it2++) { f[3*i]=(float)it0->first/255; f[3*i+1]=(float)it1->first/255; f[3*i+2]=(float)it2->first/255; i++; } } } //CvMat* Fine2=0; //Fine2=Merge(Fine,FineNum); vector<pair<int,int>>merge; float* f1=(float*)(Fine->data.ptr); float* f2=(float*)(Fine->data.ptr); for(int m=0;m<FineNum;m++) { for(int n=m+1;n<FineNum;n++) { float d=sqr(f1[3*m]-f2[3*n])+sqr(f1[3*m+1]-f2[3*n+1])+sqr(f1[3*m+2]-f2[3*n+2]); if(d<=0.1){ merge.push_back(make_pair(m,n)); } } } cout<<"merge:"<<merge.size()<<endl; //Fine1中存储把颜色距离平方小于0.05的元素合并后的结果,结果存在第一个元素位置,第二个位置置零 CvMat* Fine1=cvCreateMat(1,FineNum,CV_32FC3); float* F1=(float*)(Fine1->data.ptr); for(vector<pair<int,int>>::iterator iter=merge.begin();iter!=merge.end();iter++) { if(F1[3*(iter->first)]!=0) { F1[3*(iter->first)]=(f1[3*(iter->first)]+f1[3*(iter->second)])/2; F1[3*(iter->first)+1]=(f1[3*(iter->first)+1]+f1[3*(iter->second)+1])/2; F1[3*(iter->first)+2]=(f1[3*(iter->first)+2]+f1[3*(iter->second)+2])/2; F1[3*(iter->second)]=0; F1[3*(iter->second)+1]=0; F1[3*(iter->second)+2]=0; f1[3*(iter->second)]=0; f1[3*(iter->second)+1]=0; f1[3*(iter->second)+2]=0; } else { F1[3*(iter->first)]=f1[3*(iter->first)]; F1[3*(iter->first)+1]=f1[3*(iter->first)+1]; F1[3*(iter->first)+2]=f1[3*(iter->first)+2]; } } //求Fine1中非零元素个数 int no=0; for(int m=0;m<FineNum;m++) { if(F1[m]!=0) no++; } cout<<"Not Zore Num:"<<no<<endl; //Fine2中存储merge后Fine1中的非零元素 CvMat* Fine2=cvCreateMat(1,no*3,CV_32FC1); float* F2=(float*)(Fine2->data.ptr); for(int m=0;m<FineNum;m++) { if(F1[m]!=0) { *F2=F1[m]; F2++; } } cout<<"F2_Width: "<<Fine2->width<<endl; //int no=Fine2->width; CvMat* id =cvCreateMat(image->height,image->width,CV_32SC1); for(int r=0;r<rgb->rows;r++){ int* idx=(int*)(id->data.ptr+r*id->step); float* rgbData=(float*)(rgb->data.ptr+r*rgb->step); for(int c=0;c<rgb->cols;c++,idx++){ float D=200000; int t=0; float* f=(float*)(Fine2->data.ptr); for(int i=0;i<no;i++){ float dist=sqr(rgbData[3*c]-f[3*i])+sqr(rgbData[3*c+1]-f[3*i+1])+sqr(rgbData[3*c+2]-f[3*i+2]); if(dist<D){ D=dist; t=i; } *idx=t; } } } //vector<CvScalar>avg1;////////////////////// CvMat *colorNum= cvCreateMat(1,no, CV_32SC1); cvZero(Fine2); cvZero(colorNum); float* f=(float*)(Fine2->data.ptr); int* num1=(int*)(colorNum->data.ptr); for(int r=0;r<rgb->rows;r++){ int* idx=(int*)(id->data.ptr+r*id->step); float* rgbData=(float*)(rgb->data.ptr+r*rgb->step); for(int c=0;c<rgb->cols;c++){ f[3*idx[c]]+=rgbData[3*c]; f[3*idx[c]+1]+=rgbData[3*c+1]; f[3*idx[c]+2]+=rgbData[3*c+2]; num1[*idx]++; } } for(int i=0;i<no;i++) { f[3*i]/=num1[i]; f[3*i+1]/=num1[i]; f[3*i+2]/=num1[i]; } for(int r=0;r<rgb->rows;r++){ int* idx=(int*)(id->data.ptr+r*id->step); float* resultData=(float*)(result->data.ptr+r*result->step); for(int c=0;c<rgb->cols;c++,idx++) { //CvScalar avg1; resultData[3*c]=f[3*(*idx)]; resultData[3*c+1]=f[3*(*idx)+1]; resultData[3*c+2]=f[3*(*idx)+2]; //cvSet2D(result,r,c,avg1); } } //cvConvertScale(result,result00,255); cvNamedWindow("Result",1); cvShowImage("Result",result); //cvSaveImage("D:/test/out_C-mean量化颜色(峰&谷,直接合并)+(d小于0.1)merge颜色/9.jpg",result00); cvWaitKey(0); } map<int,int> Fine(CvMat* mat1u) { map<int,int>colornum1; IplImage *hist0=0;//cvCreateImage(cvSize(300,300),IPL_DEPTH_8U,1); IplImage *hist1=0;//cvCreateImage(cvSize(300,300),IPL_DEPTH_8U,1); for(int i=0;i<mat1u->rows;i++) { for(int j=0;j<mat1u->cols;j++) { int color=(int)(cvGetReal2D(mat1u,i,j)); ++colornum1[color]; } } int n=colornum1.size(); /* colornum1[0]=0; colornum1[1]=0; colornum1[2]=0; colornum1[n-3]=0; colornum1[n-1]=0; colornum1[n-2]=0; */ cout<<"ColorNum:"<<n<<endl; hist0=DrawHist(colornum1,n); cvNamedWindow("Hist0",1); cvShowImage("Hist0",hist0); //平滑 vector<pair<int, int>> num1; for( map<int,int>::iterator iter=colornum1.begin();iter!=colornum1.end();iter++) { num1.push_back(pair<int,int>(iter->first,iter->second)); } for(vector<pair<int,int>>::size_type i=3;i!=n-4;i++) { int n=(int)((num1[i-3].second+num1[i-2].second+num1[i-1].second+num1[i].second+num1[i+1].second+num1[i+2].second+num1[i+3].second)/7); colornum1[num1[i].first]=n; } hist1=DrawHist(colornum1,n); num1.clear(); for( map<int,int>::iterator iter=colornum1.begin();iter!=colornum1.end();iter++) { num1.push_back(pair<int,int>(iter->first,iter->second)); } map<int,int>merge1; map<int,int>merge2; int j=0; for(vector<pair<int,int>>::size_type i=3;i!=n-4;i++) { if((num1[i-2].second<num1[i-1].second&&num1[i-1].second<num1[i].second && num1[i].second>num1[i+1].second&& num1[i+1].second>num1[i+2].second ||num1[i-2].second>num1[i-1].second&&num1[i-1].second>num1[i].second && num1[i].second<num1[i+1].second&& num1[i+1].second<num1[i+2].second) &&num1[i-1].second!=0&&num1[i-2].second!=0&&num1[i-3].second!=0 &&num1[i+1].second!=0&&num1[i+2].second!=0&&num1[i+3].second!=0) { merge1[i]=num1[i].second; cout<<num1[i].first<<": "<<num1[i].second<<endl; } } //////////////////////////////////////////////////////////////////////////////////// //同一通道上颜色距离小于32的删除 vector<pair<int, int>> num3; for( map<int,int>::iterator iter=merge1.begin();iter!=merge1.end();iter++) { num3.push_back(pair<int,int>(iter->first,iter->second)); } vector<pair<int,int>>::iterator it3,it2; it2=num3.begin(); it3=num3.begin(); ++it3; while(it3!=num3.end()) { if(abs(it2->first-it3->first)<32) { it3=num3.erase(it3); } else { it2=it3; it3++; } } int m3=num3.size(); cout<<"merge color num:"<<m3<<endl; for(vector<pair<int,int>>::size_type i=0;i!=m3;i++) { cout<<num3[i].first<<endl; merge2[num3[i].first]=num3[i].second; } ///////////////////////////////////////////////////////////////////////////////////////////// for( map<int,int>::iterator iter=merge2.begin();iter!=merge2.end();iter++) { int x=iter->first; double y=iter->second; int h=(int)(300-0.1*y); cvCircle(hist1,cvPoint(x,h),1,CV_RGB(255,0,0),-1); } cvNamedWindow("Hist1",1); cvShowImage("Hist1",hist1); cvWaitKey(0); return merge2; } IplImage* DrawHist(map<int,int>colornum,int n) { cvZero(histimg); int bin_w=1; double bin_h=(double)300/3000; for(map<int,int>::iterator it=colornum.begin();it!=colornum.end();it++) { double val =(double) (it->second*bin_h ); CvScalar color = CV_RGB(255,255,0); //(hsv2rgb(i*180.f/hdims); cvLine( histimg, cvPoint(it->first*bin_w,300), cvPoint((it->first)*bin_w,(int)(300-val)),color, 1, 8, 0 ); } return histimg; }
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: [opencv]K-means聚类算法分割图像
- 下一篇: Java如何跳出多层循环