您的位置:首页 > 其它

皮肤检测及对检测到皮肤单独校色 (基于自动白平衡)

2015-08-24 18:36 369 查看
原理见前几篇博客,修改修改可以做美颜的程序直接贴代码:

/*对照片中的皮肤单独进行较色,然后塞进原始图片作为输出*/
/*包含皮肤的检测、皮肤的校正两步*/
/*单张照片测试效果不错,但对于一百多张照片,结果还是有偏差,这种单独校正然后再用于贴图的方法 行不通*/
/*时间:2015.8.24*/
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/face.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;
double baidianave(Mat frame,int n)
{
int a[256];
for (int i=0;i<256;i++)
{
a[i]=0;
}
double sum=0;
double ave;
for (int i=0;i<n;i++)
{
int d=frame.at<double>(0,i);
a[d]++;
}
int n0=255;
for (int k=255;k>0;k--)
{
sum+=a[k];
if (sum>frame.rows*frame.cols/25)
{
break;
}
n0--;
}
sum=0;
for (int i=n0;i<256;i++)
{
sum+=a[i]*i;
}
ave=sum/(frame.rows*frame.cols/25);
return ave;
}
double baidianave(Mat frame)
{
int a[256];
//cvZero(a);
for (int i=0;i<256;i++)
{
a[i]=0;
}
double sum=0;
double ave;
for (int i=0;i<frame.rows;i++)
{
for (int j=0;j<frame.cols;j++)
{
int d=(int)frame.at<uchar>(i,j);
a[d]++;
}
}

int n0=255;
for (int k=255;k>0;k--)
{
sum+=a[k];
if (sum>frame.rows*frame.cols/25)
{
break;
}
n0--;
}
sum=0;
for (int i=n0;i<256;i++)
{
sum+=a[i]*i;
}
ave=sum/(frame.rows*frame.cols/25);
return ave;

}

Mat input_image;
Mat output_mask;
Mat output_image;
Mat mask;

int main(int argc,char *argv[])
{
if (2 != argc)
{
cout << "Please enter the image list!" <<endl;
return -1;
}
vector<string> file_names;
FILE *file_list = fopen(argv[1],"r");
char buf[255];
memset(&buf,0,sizeof(buf));

while(fgets(buf,255,file_list))
{
if(buf[strlen(buf)-1] == '\n')
buf[strlen(buf)-1] = '\0';
file_names.push_back(string(buf));

}

fclose(file_list);
int count = file_names.size();

Mat skinCrCbHist = Mat::zeros(Size(256, 256), CV_8UC1);
ellipse(skinCrCbHist, Point(113, 155.6), Size(25,12), -20, 0.0, 360.0, Scalar(255, 255, 255), -1);

Mat element = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1) );
for(int i=0; i<count; i++)
{
string img_nm = file_names[i];
string img_mask = "mask" + img_nm;
int pos = img_nm.rfind('.');
string img_fmt = img_nm.substr(pos+1);
if("jpg" != img_fmt)
{
cout << "Unknown format: " << img_fmt << endl;
continue;
}
input_image=imread(img_nm,1);
if(input_image.empty())
return 0;

Mat ycrcb_image;
output_mask = Mat::zeros(input_image.size(), CV_8UC1);
cvtColor(input_image, ycrcb_image, CV_BGR2YCrCb);
CvScalar s;
s.val[0]=0;
s.val[1]=0;
s.val[2]=255;
for(int i = 0; i < input_image.rows; i++)
{
uchar* p = (uchar*)output_mask.ptr<uchar>(i);
Vec3b* ycrcb = (Vec3b*)ycrcb_image.ptr<Vec3b>(i);
for(int j = 0; j < input_image.cols; j++)
{
if(skinCrCbHist.at<uchar>(ycrcb[j][1], ycrcb[j][2]) > 0)
{
// input_image.at<Vec3b>(i,j)[2]=255;
p[j] = 255;
}
}
}
// imwrite("test.jpg",input_image);
morphologyEx(output_mask,output_mask,MORPH_CLOSE,element);
vector< vector<Point> > contours;
vector< vector<Point> > filterContours;
vector< Vec4i > hierarchy;
contours.clear();
hierarchy.clear();
filterContours.clear();

findContours(output_mask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
for (size_t i = 0; i < contours.size(); i++)
{
if (fabs(contourArea(Mat(contours[i]))) > 2000&&fabs(arcLength(Mat(contours[i]),true))>500)
filterContours.push_back(contours[i]);
}
output_mask.setTo(0);
drawContours(output_mask, filterContours, -1, Scalar(255,0,0), CV_FILLED);
input_image.copyTo(output_image, output_mask);
Mat tempimage=Mat::zeros(input_image.size(), CV_8UC3);
threshold(output_mask,output_mask,20, 255, THRESH_BINARY);
cvtColor(output_mask,output_mask,CV_GRAY2BGR);

Mat frame=Mat::zeros(input_image.size(), CV_8UC3);
output_image.copyTo(frame);
// imshow("frame",frame);
// waitKey(0);
//cout<<frame.rows<<" "<<frame.cols<<endl;
// cvShowImage("处理前图像",frame);
int heightyiban=frame.rows;
int widthyiban=frame.cols;
double Ysum=0;//Y的总和
double Cbsum[4]={0,0,0.0};//图像分成四部分,每部分Cb的总和
double Crsum[4]={0,0,0,0};//图像分成四部分,每部分Cr的总和
double Mb[4],Db[4];//图像分成四部分,每部分Cb的均值和均方差
double Mr[4],Dr[3];//Cr的均值和均方差
Mat imageYCrCb = Mat::zeros(frame.size(), CV_8UC3);
Mat imageCb = Mat::zeros(frame.size(), CV_8UC1);
Mat imageCr = Mat::zeros(frame.size(), CV_8UC1);
Mat imageY = Mat::zeros(frame.size(), CV_8UC1);
// imageYCrCb = cvCreateImage(cvGetSize(frame),8,3);
// imageCb = cvCreateImage(cvGetSize(frame),8,1);
// imageCr = cvCreateImage(cvGetSize(frame),8,1);
// imageY = cvCreateImage(cvGetSize(frame),8,1);
cvtColor(frame,imageYCrCb,CV_BGR2YCrCb);

std::vector<cv::Mat>ybr(imageYCrCb.channels());
split(imageYCrCb,ybr);
// namedWindow("test",0);
// imshow("test",ybr[2]);
// waitKey(0);
//分成三个通道,,,
// imageY,imageCr,imageCb

Mat imageb=Mat::zeros(frame.size(), CV_8UC1);
Mat imagec=Mat::zeros(frame.size(), CV_8UC1);
ybr[1].copyTo(imageb);
ybr[2].copyTo(imagec);
Mat savg,sfangcha;//全局scalar 变量用来放平均值和方差
meanStdDev(ybr[2],savg,sfangcha);
// cvAvgSdv(imageb,&savg,&sfangcha,NULL);
// cout<<savg.at<double>(0)<<endl;
// cout<<sfangcha.at<double>(0)<<endl;
Mb[0]=savg.at<double>(0);
cout<<"Mb: "<<Mb[0]<<endl;
Db[0]=sfangcha.at<double>(0);//求出第一部分cb的均值和均方差
cout<<"Db: "<<Db[0]<<endl;
// cvAvgSdv(imagec,&savg,&sfangcha,NULL);
meanStdDev(ybr[1],savg,sfangcha);
Mr[0]=savg.at<double>(0);
cout<<"Mr: "<<Mr[0]<<endl;
Dr[0]=sfangcha.at<double>(0);;//求出第一部分cr的均值和均方差
cout<<"Dr: "<<Dr[0]<<endl;
double b[4],c[4];
for (int i=0;i<1;i++)
{
if (Mb[i]<0)//计算mb+db*sign(mb)
{
b[i]=Mb[i]+Db[i]*(-1);
}
else
b[i]=Mb[i]+Db[i];
}
for (int i=0;i<4;i++)
{
if (Mr[i]<0)//计算1.5*mr+dr*sign(mb);
{
c[i]=1.5*Mr[i]+Dr[i]*(-1);
}
else
c[i]=1.5*Mr[i]+Dr[i];
}

double Ymax=baidianave(ybr[0]);
//下面是对第一部分进行白点的选择
Mat Bbaidian=Mat::zeros(1,6000000,CV_64FC1);
Mat Gbaidian=Mat::zeros(1,6000000,CV_64FC1);
Mat Rbaidian=Mat::zeros(1,6000000,CV_64FC1);

//CvScalar s1;
int n1=0;
cout<<"b[0]: "<<b[0]<<" c[0]: "<<c[0]<<endl;
for (int i=0;i<heightyiban;i++)
{
for (int j=0;j<widthyiban;j++)
{
// input_image.at<Vec3b>(i,j)[2]=255
if (((ybr[2].at<uchar>(i,j)-b[0])<(1.5*Db[0]))&&((ybr[1].at<uchar>(i,j)-c[0])<(1.5*Dr[0])))
{

double d1=frame.at<Vec3b>(i,j)[0];
Bbaidian.at<double>(0,n1)=d1;

double d2=frame.at<Vec3b>(i,j)[1];
Gbaidian.at<double>(0,n1)=d2;

double d3=frame.at<Vec3b>(i,j)[2];
Rbaidian.at<double>(0,n1)=d3;
n1++;
}
}
}

// cout<<"n1: "<<n1<<endl;
double Bave1=baidianave(Bbaidian,n1);
double Gave1=baidianave(Gbaidian,n1);
double Rave1=baidianave(Rbaidian,n1);
cout<<"Bave1: "<<Bave1<<" Gave1: "<<Gave1<<" Rave1: "<<Rave1<<" Ymax: "<<Ymax<<endl;
Ymax=Ymax;
double Bgain1=Ymax/(Bave1);
double Ggain1=Ymax/(Gave1);
double Rgain1=Ymax/(Rave1);

// CvScalar s1;
// cout<<Bgain1<<" "<<Ggain1<<" "<<Rgain1<<endl;
// int count_out=0;
for (int i=0;i<heightyiban;i++)
{
for (int j=0;j<widthyiban;j++)
{
int tb=Bgain1*frame.at<Vec3b>(i,j)[0];
int tg=Ggain1*frame.at<Vec3b>(i,j)[1];
int tr=Rgain1*frame.at<Vec3b>(i,j)[2];
if (tb>255)
{
tb=255;
// count_out++;
}
if (tg>255)
{
tg=255;
// count_out++;
}
if (tr>255)
{
tr=255;
// count_out++;
}
frame.at<Vec3b>(i,j)[0]=tb;
frame.at<Vec3b>(i,j)[1]=tg;
frame.at<Vec3b>(i,j)[2]=tr;
}
}
// cout<<count_out<<endl;
imwrite("frame.jpg",frame);
// cout<<"Finish!"<<endl;
imwrite("img_nm1.jpg",input_image);
for(int i = 0; i < input_image.rows; i++)
{
uchar* p = (uchar*)output_mask.ptr<uchar>(i);
uchar* p2 = (uchar*)input_image.ptr<uchar>(i);
uchar* p3 = (uchar*)frame.ptr<uchar>(i);
for(int j = 0; j < 3*input_image.cols; )
{
if(p[j] != 0)
{
// cout<<"p: "<<i<<" "<<j<<" "<<float(p[j])<<endl;
// input_image.at<Vec3b>(i,j)[2]=255;
p2[j]=0;
p2[j] = p3[j++];
// cout<<"B: "<<int (p2[j-1])<<" ";
p2[j]=0;
p2[j] = p3[j++];
// cout<<"G: "<<int (p2[j-1])<<" ";
p2[j]=0;
p2[j] = p3[j++];
// cout<<"R: "<<int (p2[j-1])<<endl;;
// cout<<"p2: "<<i<<" "<<j<<" "<<float(p2[j])<<endl;
}
else
j++;
}
}
// Mat tempimage=Mat::zeros(input_image.size(), CV_8UC3);
// cvtColor(output_mask,tempimage,CV_GRAY2BGR);
// imwrite("output_mask.jpg",output_mask);
// imwrite("tempimage.jpg",tempimage);
imwrite(img_nm,input_image);
imwrite(img_mask,output_image);
// imwrite(img_mask,output_mask);
// namedWindow("input image",0);
// // namedWindow("output mask",0);
// namedWindow("output image",0);
// imshow("input image", input_image);
// imshow("output image", output_image);
cout<<"Finish!"<<endl;
// output_image.setTo(0);
// waitKey(0);

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  校色 皮肤检测