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;
- }
- <img src="http://hi.csdn.net/attachment/201203/23/0_1332479095dNOm.gif" alt="">