肤色似然图像以及图像二值化的源代码,转自
http://hi.baidu.com/cinvent_new/blog/item/c9cd2039e088ae2497ddd8d1.html
- #include <stdlib.h>
- #include <stdio.h>
- #include <math.h>
- #include <cv.h>
- #include <highgui.h>
- #include<iostream.h>
- IplImage secaipingheng(IplImage* seping);//色彩平衡
- IplImage fusesiran(IplImage* fusi);//肤色似然
- int main(int argc, char *argv[])
- {
- IplImage* img = 0; // 原图
- IplImage* seping = 0;//色彩平衡
- IplImage* ycbcr = 0;//ycbcr
- IplImage* fusi = 0;//肤色似然
- IplImage* fu = 0;//肤色
- img=cvLoadImage("1.jpg",-1);//加载图像
- if(!img)
- {
- cout<<"图片不存在"<<endl;
- return 0;
- }
- cvNamedWindow("原图", 0);
- cvResizeWindow("原图",200,200);
- cvMoveWindow("原图",400,400);
- cvShowImage("原图", img );
- seping=cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U,3);
- ycbcr=cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U,3);
- fusi=cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U,1);
- fu=cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U,3);
- *seping=secaipingheng(img);
- //cvNamedWindow("色彩平衡", CV_WINDOW_AUTOSIZE);
- //cvShowImage("色彩平衡", seping);
- cvSmooth(seping, seping,CV_MEDIAN ,3,0,0,0 );
- cvCvtColor(seping, ycbcr, CV_RGB2YCrCb);// rgb->ycrcb
- *fusi=fusesiran(ycbcr);
- //cvNamedWindow("肤色似然", CV_WINDOW_AUTOSIZE);
- //cvShowImage("肤色似然", fusi);
- int height,width,step,channels;
- uchar *data;
- height = img->height;
- width = img->width;
- step = img->widthStep;
- channels = img->nChannels;
- data = (uchar *)img->imageData;
- int i,j;
- for(i=0;i<height;i++) for(j=0;j<width;j++)
- {
- if(((fusi->imageData + fusi->widthStep*i))[j]==0)
- {
- data[i*step+j*channels+0]=0;
- data[i*step+j*channels+1]=0;
- data[i*step+j*channels+2]=0;
- }
- }
- cvNamedWindow("肤色图", 0);
- cvResizeWindow("肤色图",200,200);
- cvMoveWindow("肤色图",615,400);
- cvShowImage("肤色图", img );
- //cvSaveImage("haha.jpg", img);//
- cvWaitKey(0);
- //cvDestroyWindow( "原图" );//销毁窗口
- //cvReleaseImage( &img ); //释放图像
- //cvDestroyWindow( "肤色图" );//销毁窗口
- //cvReleaseImage( &img ); //释放图像
- //cvDestroyWindow( "色彩平衡" );//销毁窗口
- cvReleaseImage( &seping ); //释放图像
- //cvDestroyWindow( "肤色似然" );//销毁窗口
- cvReleaseImage( &fusi ); //释放图像
- return 1;
- }
- ///色彩平衡//
- IplImage secaipingheng( IplImage* seping)
- {
- IplImage* dst;//色彩平衡
- IplImage* gray;//gray图
- dst=cvCreateImage(cvSize(seping->width,seping->height),IPL_DEPTH_8U,3);
- gray=cvCreateImage(cvSize(seping->width,seping->height),IPL_DEPTH_8U,1);
- int height,width,step,channels;
- uchar *data,*data1;
- height = seping->height;
- width = seping->width;
- step = seping->widthStep;
- channels = seping->nChannels;
- data = (uchar *)seping->imageData;
- data1 = (uchar *)dst->imageData;
- int i,j;
- double R,G,B,Gy,aR,aG,aB;
- cvZero(dst);
- CvMat* MR=cvCreateMat(height,width,CV_64FC1);
- CvMat* MG=cvCreateMat(height,width,CV_64FC1);
- CvMat* MB=cvCreateMat(height,width,CV_64FC1);
- for(i=0;i<height;i++) for(j=0;j<width;j++)
- {
- R=data[i*step+j*channels+0];
- G=data[i*step+j*channels+1];
- B=data[i*step+j*channels+2];
- Gy=((gray->imageData + gray->widthStep*i))[j];
- cvmSet(MR,i,j,R);
- cvmSet(MG,i,j,G);
- cvmSet(MB,i,j,B);
- ((gray->imageData + gray->widthStep*i))[j]=(R+G+B)/3;
- }
- CvScalar argR,argG,argB;
- double argI;
- argR=cvAvg(MR,0);
- argG=cvAvg(MG,0);
- argB=cvAvg(MB,0);
- argI=(argR.val[0]+argG.val[0]+argB.val[0])/3;
- aR=argI/argR.val[0];
- aG=argI/argG.val[0];
- aB=argI/argB.val[0];
- for(i=0;i<height;i++) for(j=0;j<width;j++)
- {
- R=CV_MAT_ELEM(*MR,double,i,j)*aR;
- G=CV_MAT_ELEM(*MG,double,i,j)*aG;
- B=CV_MAT_ELEM(*MB,double,i,j)*aB;
- if(R>255)data1[i*step+j*channels+0]=255;
- else data1[i*step+j*channels+0]=R;
- if(G>255)data1[i*step+j*channels+1]=255;
- else data1[i*step+j*channels+1]=G;
- if(B>255)data1[i*step+j*channels+2]=255;
- else data1[i*step+j*channels+2]=B;
- }
- cvNamedWindow("色彩平衡", CV_WINDOW_AUTOSIZE);
- cvShowImage("色彩平衡", dst);
- //cvWaitKey(0);
- //cvDestroyWindow( "色彩平衡" );//销毁窗口
- //cvReleaseImage( &dst ); //释放图像
- return *dst;
- }
- //肤色似然
- IplImage fusesiran(IplImage* fusi)
- {
- IplImage* dst;//肤色图
- dst=cvCreateImage(cvSize(fusi->width,fusi->height),IPL_DEPTH_8U,1);
- int height,width,step,channels;
- uchar *data;
- height = fusi->height;
- width = fusi->width;
- step = fusi->widthStep;
- channels = fusi->nChannels;
- data = (uchar *)fusi->imageData;
- double c[4]={0.0077 ,-0.0041,-0.0041 ,0.0047};
- CvMat* max=cvCreateMat(height,width,CV_64FC1);//存储肤色概率密度矩阵(数组)
- CvMat* mat=cvCreateMat(2,2,CV_64FC1);//存储协方差矩阵(逆)
- CvMat* a=cvCreateMat(1,2,CV_64FC1);//{cb,cr}
- CvMat* a1=cvCreateMat(2,1,CV_64FC1);//{cb,cr}转至
- CvMat* res=cvCreateMat(1,1,CV_64FC1);
- cvInitMatHeader(mat,2,2,CV_64FC1,c);
- double res1[1]={0};
- cvInitMatHeader(res,1,1,CV_64FC1,res1);
- int i,j;
- double b,r,cb,cr,u;
- //按照上面的公式进行肤色似然度计算
- for(i=0;i<height;i++)
- for(j=0;j<width;j++)
- {
- b=data[i*step+j*channels+1];//cb 分量
- r=data[i*step+j*channels+2];//cr 分量
- cb=b-103.0056;117.4361
- cr=r-140.1309;156.5599
- double p1[2]={cb,cr};
- cvInitMatHeader(a,1,2,CV_64FC1,p1);
- cvMatMulAdd(a,mat,0,a);
- double p2[2]={cb,cr};///
- cvInitMatHeader(a1,2,1,CV_64FC1,p2);
- cvMatMulAdd(a,a1,0,res);
- u=CV_MAT_ELEM(*res,double,0,0);
- u=exp(-0.5*u);
- cvmSet(max,i,j,u);
- }
- double max1=0; //初始化最大值
- double mm=0;
- cvMinMaxLoc(max,NULL,&max1,NULL,NULL);
- //肤色似然度
- for(i=0;i<height;i++) for(j=0;j<width;j++)
- {
- mm=CV_MAT_ELEM(*max,double,i,j)/max1;
- cvmSet(max,i,j,255*mm);
- ((dst->imageData + dst->widthStep*i))[j]=255*mm;
- }
- //cvNamedWindow("肤色6", CV_WINDOW_AUTOSIZE);
- //cvShowImage("肤色6", dst );
- double n[256],p[256];
- for(i=0;i<256;i++)
- {
- n[i]=0;
- p[i]=0;
- }
- int nn;
- for(i=0;i<height;i++) for(j=0;j<width;j++)
- {
- nn=int(CV_MAT_ELEM(*max,double,i,j));
- n[nn]++;
- }
- for(i=0;i<256;i++)
- p[i]=n[i]/(height*width);
- double q,w0,w1,u0,u1,ut,Q[]={0,0,0,0,0,0,0,0,0,0};
- int flag=0;
- for(int m=10;m<=190;m+=20)
- {
- q=0;w0=0;w1=0;u0=0;u1=0;ut=0;
- for(i=0;i<=m;i++) w0+=p[i];
- for(i=m+1;i<=255;i++) w1+=p[i];
- for(i=0;i<=m;i++) u0+=i*p[i]/w0;
- for(i=m+1;i<=255;i++) u1+=i*p[i]/w1;
- for(i=0;i<=255;i++) ut+=i*p[i];
- q=w0*(u0-ut)*(u0-ut)+w1*(u1-ut)*(u1-ut);
- if (q<1)q=0;
- Q[flag]=q;
- flag++;
- }
- double max2=Q[0];
- j=0;
- for(i=1;i<=9;i++)
- if(max2<Q[i])
- {
- max2=Q[i];
- j=i;
- }
- int yuzhi;
- yuzhi=20*j;
- IplImage* dst1;//二值
- dst1=cvCreateImage(cvSize(fusi->width,fusi->height),IPL_DEPTH_8U,1);
- IplImage* dst11;//二值
- dst11=cvCreateImage(cvSize(fusi->width,fusi->height),IPL_DEPTH_8U,1);
- cvZero(dst11);
- cvZero(dst1);
- for(i=0;i<height;i++) for(j=0;j<width;j++)
- {
- nn=int(CV_MAT_ELEM(*max,double,i,j));
- if(nn>yuzhi)((dst1->imageData + dst1->widthStep*i))[j]=255;
- }
- CvMemStorage* storage = cvCreateMemStorage(0);
- CvSeq* contour = 0;
- cvThreshold( dst1, dst1, 128, 255, CV_THRESH_BINARY );
- cvDilate( dst1, dst1, NULL, 1 );
- cvFindContours( dst1, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
- double contour_area = 0;
- for( ; contour != 0; contour = contour->h_next )
- {
- contour_area=100*fabs(cvContourArea( contour, CV_WHOLE_SEQ )); //
- if(contour_area>height*width)//((contour->v_next!=0)&&(contour_area>height*width))//
- cvDrawContours( dst11, contour, CV_RGB(255,255,255), CV_RGB(255,255,255), 0, CV_FILLED, 8 );
- }
- cvNamedWindow("肤色6", 0);
- cvShowImage("肤色6", dst11 );
- //cvWaitKey(0);
- //cvDestroyWindow( "肤色6" );//销毁窗口
- //cvReleaseImage( &dst11 ); //释放图像
- return *dst11;
- }