学习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如何跳出多层循环
