数字图像处理人脸检测课程设计报告.docx
《数字图像处理人脸检测课程设计报告.docx》由会员分享,可在线阅读,更多相关《数字图像处理人脸检测课程设计报告.docx(47页珍藏版)》请在冰豆网上搜索。
![数字图像处理人脸检测课程设计报告.docx](https://file1.bdocx.com/fileroot1/2022-12/30/aaed24dd-3feb-4b59-b47a-3cd422341f9c/aaed24dd-3feb-4b59-b47a-3cd422341f9c1.gif)
数字图像处理人脸检测课程设计报告
《数字图像处理》课程设计
——图像处理系统设计
指导教师:
***
班级:
*****
学号:
*****
姓名:
*****
数字图像处理课程设计报告
一、实验题目:
基于肤色的人脸检测系统
二、实验目的:
1、提高分析问题、解决问题的能力,进一步巩固数字图像处理系统中的基本原理与方法。
2、熟悉掌握一门计算机语言,可以进行数字图像的应用处理的开发设计。
三、实验原理:
人脸检测技术的基本方法有:
基于知识的方法,基于特征的方法,模板匹配的方法和基于肤色检测的方法。
人脸肤色特征被证明是一种十分有效地人脸特征。
大量的色彩空间被标注于肤色,例如RGB、HIS、CMYK、YcbCr等。
最简单的肤色模型就是选择上述某一色彩空间中的一个区域作为肤色区域。
光照补偿:
目前基于肤色的人脸检测算法大多假定待检测图像时在光照均匀情况下获得的,而在实际中光的照明肯定是不均匀的。
故对图片先进行光照补偿处理。
此次设计光照补偿的基本思路是把图片中两度最大的5%的像素点提取处理,然后线性放大,具体来说就是调整图片像素的RGB。
肤色分割和人脸建模:
即将光照补偿后的彩色图像分为肤色和非肤色区域,生成只有黑、白两色的二值图像。
具体设计是:
将图像中的RGB转换到YCC空间,在YCC空间中,通过非线性转换尽量将亮度与色度分离,消除色度对亮度的依赖关系。
最后,应用YCC空间中的色度信息对人脸进行色彩建模。
建模的形式是椭圆公式匹配两个色度分量的距离。
二值图像去噪处理:
经过肤色分割和人脸建模后会得到一些连通区域,包括人脸区域和非人脸区域。
为了正确检测人脸,通过膨胀运算合并一些肤色分割过程中的错误分割点,如研究和嘴等非皮肤区域,通过腐蚀运算消除肤色分割中的作为定为非肤色的非肤色点;并利用开、闭运算去除图像中孤立的小店、毛刺与填充物体内的小空洞、连接邻近物体。
并通过人脸相对图像的像素点个数(经验值)即面积法提取,来去掉非人脸区域,从而大致确定人脸区域。
色度匹配:
色度匹配就是根据已知条件设定颜色的上下限来对目标进行提取,例如此次人
脸检测系统设计对人眼和嘴巴的提取。
YCC空间中的色度操作就是对Cr、Cb分量的操作。
对人眼提取时的Cb、Cr分量设定限制分别为(115,120),(112,116),对嘴巴提取的Cr分量设定为Cr=138或148,Cb分量限制在[115,125]之间。
亮度匹配:
是根据图像像素的亮度值来确定,可以使用YCC空间中的亮度值Y,也可以采用其他方法。
本系统是在RGB色彩空间中直接计算亮度值来进行匹配。
眼睛亮度的匹配值是在[100,125]之间。
区域定位:
主要通过递归,计算连续目标像素点个数是否符合条件限制的面积提取法来确定是否为正确目标,返回坐标值来确定区域位置,再通过像素点的叠加及坐标求平均值来计算目标中心位置。
去离散点:
图像去噪处理后,也是通过递归函数,获取符合条件连续的像素点个数,若没有达到一定限制要求,则视为非目标值,在最终确定区域时,去掉该区域或该点的值。
四、实验步骤
1、图像读取、均衡化并进行光照补偿处理。
2、肤色分割和人脸色彩建模以及去噪处理,确定人脸大致区域。
3、人眼的匹配与定位。
4、嘴巴的定位。
5、根据定位坐标,勾勒出检测的人脸。
五、实验结果
图像读入,光线补偿后效果
皮肤颜色建模:
膨胀:
腐蚀:
去掉人脸假区域:
再次膨胀:
再次腐蚀及确定人脸区域:
Cr匹配:
Cb匹配:
眼睛色度匹配:
眼睛亮度匹配:
眼睛双重匹配:
去掉假眼睛区域:
勾勒人脸区域:
六、实验心得
通过本次课程设计,使我进一步掌握了数字图像处理的基本知识与对图像处理的技能以及实现方法。
此次系统设计用到的最基础的就是对二值图像的去噪处理,即不断调用膨胀、腐蚀的闭运算,另外还有图像的均衡化。
七、主要代码
//图像均衡化
voidCFaceView:
:
OnUnitary()
{
hDIBTemp=gDib.CopyHandle(hDIB);//获取复制图片信息
gDib.Normalization(hDIB);
GlobalUnlock(hDIB);
Invalidate();
}
//均衡化
BOOLDIB:
:
Normalization(HANDLEhDIB)
{
if(!
hDIB)
returnFALSE;
LPBITMAPINFOHEADERlpbi;//pImg
intwidth,height;
LPBYTElpData;//data
WORDwBytesPerLine;
lpbi=(LPBITMAPINFOHEADER)GlobalLock(hDIB);
width=lpbi->biWidth;//得到图片宽和高
height=lpbi->biHeight;
lpData=this->FindDIBBits(hDIB);//得到图片数据区
wBytesPerLine=this->BytePerLine(hDIB);//得到图片每行的象素所占字节个数(step)
inthist[256];
floatpr[256],sk[256];
inti,j;
for(i=0;i<256;i++)
{
hist[i]=0;
pr[i]=0;
sk[i]=0;
}
intr,g,b,count=0;
longlOffset;
for(i=0;ifor(j=0;j{
//得到象素数据的偏移
lOffset=this->PixelOffset(i,j,wBytesPerLine);
//得到rgb值
b=*(lpData+lOffset++);
g=*(lpData+lOffset++);
r=*(lpData+lOffset++);
//计算灰度值
intgray=(r*299+g*587+b*114)/1000;
hist[gray]++;
}
for(i=0;i<256;i++)
count+=hist[i];
for(i=0;i<256;i++)
pr[i]=hist[i]/(float)count;
sk[0]=255*pr[0];
for(i=1;i<256;i++)
sk[i]=sk[i-1]+pr[i]*255;
/*
for(i=0;ifor(j=0;j{
//得到象素数据的偏移
lOffset=this->PixelOffset(i,j,wBytesPerLine);
//得到rgb值
*(lpData+lOffset)=sk[*(lpData+lOffset)];
*(lpData+lOffset+1)=sk[*(lpData+lOffset+1)];
*(lpData+lOffset+2)=sk[*(lpData+lOffset+2)];
}
*/
returnTRUE;
}
//光线补偿
voidCFaceView:
:
OnLightingconpensate()
{
hDIBTemp=gDib.CopyHandle(hDIB);//获取复制图片信息
gDib.LightingCompensate(hDIB);
GlobalUnlock(hDIB);
Invalidate();
}
//光照补偿子函数
BOOLDIB:
:
LightingCompensate(HANDLEhDIB)
{
if(!
hDIB)
returnFALSE;
LPBITMAPINFOHEADERlpbi;//pImg
intwidth,height;
LPBYTElpData;//data
WORDwBytesPerLine;
lpbi=(LPBITMAPINFOHEADER)GlobalLock(hDIB);
width=lpbi->biWidth;//得到图片宽和高
height=lpbi->biHeight;
lpData=this->FindDIBBits(hDIB);//得到图片数据区
wBytesPerLine=this->BytePerLine(hDIB);//得到图片每行的象素所占字节个数(step)
constfloatthresholdco=0.05;//比例系数(只提取亮度最大的5%像素)
constintthresholdnum=100;//象素个数的临界常数
inthistogram[256];//灰度级数组
for(inti=0;i<256;i++)
histogram[i]=0;
//对于过于小的图片的判断
if(width*height*thresholdcoreturnfalse;
intcolorr,colorg,colorb;
longlOffset;
//*****统计整个图片的灰度值
for(i=0;ifor(intj=0;j{
//得到象素数据的偏移
lOffset=this->PixelOffset(i,j,wBytesPerLine);
//得到rgb值
colorb=*(lpData+lOffset++);
colorg=*(lpData+lOffset++);
colorr=*(lpData+lOffset++);
//计算灰度值
intgray=(colorr*299+colorg*587+colorb*114)/1000;
histogram[gray]++;
}
intcalnum=0;
inttotal=width*height;
intnum;//设置提取次数(从0计数),从灰度值255依次向下提取
//下面的循环得到满足系数thresholdco的临界灰度级
for(i=0;i<256;i++)
{
if((float)calnum{
calnum+=histogram[255-i];//统计满足亮度灰度值的个数
num=i;//记录提取次数
}
else
break;
}
intaveragegray=0;
calnum=0;
//得到满足条件的象素总的灰度值
for(i=255;i>=255-num;i--)//255-num表示能提取到的亮度达到5%的灰度值
{
averagegray+=histogram[i]*i;//得总的灰度值
calnum+=histogram[i];//得总的满足条件像素点个数
}
averagegray/=calnum;
floatco=255.0/(float)averagegray;//得到光线补偿的系数
//下面的循环对图象进行光线补偿
for(i=0;ifor(intj=0;j{
lOffset=this->PixelOffset(i,j,wBytesPerLine);
colorb=*(lpData+lOffset);
colorb*=co;
if(colorb>255)
colorb=255;
*(lpData+lOffset)=colorb;
colorb=*(lpData+lOffset+1);
colorb*=co;
if(colorb>255)
colorb=255;
*(lpData+lOffset+1)=colorb;
colorb=*(lpData+lOffset+2);
colorb*=co;
if(colorb>255)
colorb=255;
*(lpData+lOffset+2)=colorb;
}
returnTRUE;
}
//皮肤建模
voidCFaceView:
:
OnSkintone()
{
lpYcc=newBYTE[gwBytesPerLine*gheight];//申请内存,提供新的data值
gDib.RgbtoYcc(hDIB,lpYcc);//RGB到YCC色彩空间的转换
gDib.YccTransform(lpYcc,gwBytesPerLine,gheight,gwidth);//YCC空间的非线性转换,消除色度对亮度的依赖
gDib.faceear(lpYcc,gwBytesPerLine,gheight,gwidth,flag);//YCC空间的建模
LPBYTElpData=(LPBYTE)GlobalLock(hDIB)+sizeof(BITMAPINFOHEADER);
for(inti=0;ifor(intj=0;j{
longlOffset=gDib.PixelOffset(i,j,gwBytesPerLine);
if(flag[i][j]==true)//肤色标记为白色
{
*(lpData+lOffset++)=255;
*(lpData+lOffset++)=255;
*(lpData+lOffset++)=255;
}
else
{
*(lpData+lOffset++)=0;
*(lpData+lOffset++)=0;
*(lpData+lOffset++)=0;
}
}
GlobalUnlock(hDIB);
Invalidate();
}
//RGB到YCC的空间色彩转换
voidDIB:
:
RgbtoYcc(HANDLEhDIB,LPBYTElpYcc)
{
LPBITMAPINFOHEADERlpbi;//pImg
intwidth,height;
WORDwBytesPerLine;//step
LPBYTElpData;//data
lpbi=(LPBITMAPINFOHEADER)GlobalLock(hDIB);
//得到图象的基本信息
width=lpbi->biWidth;
height=lpbi->biHeight;
lpData=FindDIBBits(hDIB);
wBytesPerLine=BytePerLine(hDIB);
longlOffset;
//下面的循环实现从rgb到ycc的转化
for(inti=0;ifor(intj=0;j{
lOffset=PixelOffset(i,j,wBytesPerLine);
//得到rgb数值
intb=*(lpData+lOffset);
intg=*(lpData+lOffset+1);
intr=*(lpData+lOffset+2);
//计算得到y,cr,cb的数值
intY=(257*r+504*g+98*b)/1000+16;
intCr=(439*r-368*g-71*b)/1000+128;
intCb=(-148*r-291*g+439*b)/1000+128;
//保存计算得到的数值
*(lpYcc+lOffset++)=Y;
*(lpYcc+lOffset++)=Cr;
*(lpYcc+lOffset++)=Cb;
}
GlobalUnlock(hDIB);
}
//YCC空间的非线性变换的中间量定义
intDIB:
:
_Cb(intY)
{
intavrCb;
if(YavrCb=108+((Kl-Y)*10)/(Kl-Ymin);
elseif(Y>Kh)//亮度很大的情况
avrCb=108+((Y-Kh)*10)/(Ymax-Kh);
else
avrCb=-1;
returnavrCb;
}
intDIB:
:
_Cr(intY)
{
intavrCr;
if(YavrCr=154-((Kl-Y)*10)/(Kl-Ymin);
elseif(Y>Kh)
avrCr=154-((Y-Kh)*22)/(Ymax-Kh);
else
avrCr=-1;
returnavrCr;
}
intDIB:
:
_WCr(intY)
{
intWCr;
if(YWCr=WLcr+((Y-Ymin)*(Wcr-WLcr))/(Kl-Ymin);
elseif(Y>Kh)
WCr=WHcr+((Ymax-Y)*(Wcr-WHcr))/(Ymax-Kh);
elseWCr=-1;
returnWCr;
}
intDIB:
:
_WCb(intY)
{
intWCb;
if(YWCb=WLcb+((Y-Ymin)*(Wcb-WLcb))/(Kl-Ymin);
elseif(Y>Kh)
WCb=WHcb+((Ymax-Y)*(Wcb-WHcb))/(Ymax-Kh);
elseWCb=-1;
returnWCb;
}
//YCC空间的非线性变换
voidDIB:
:
YccTransform(LPBYTElpYcc,WORDwBytesPerLine,intheight,intwidth)
{
intY;
doubleCr,Cb;
longlOffset;
//下面的循环实现ycc色彩空间的非线性转换
for(inti=0;ifor(intj=0;j{
lOffset=PixelOffset(i,j,wBytesPerLine);
Y=*(lpYcc+lOffset);
Cr=*(lpYcc+lOffset+1);
Cb=*(lpYcc+lOffset+2);
//如果y数值在两个临界值之间,保持不变
if(Y>=Kl&&Y<=Kh)
continue;
//调用非线性转换函数调整Cr,Cb的数值并保存
Cr=(Cr-_Cr(Y))*(Wcr/_WCr(Y))+_Cr(Kh);
Cb=(Cb-_Cb(Y))*(Wcb/_WCb(Y))+_Cb(Kh);
*(lpYcc+lOffset+1)=Cr;
*(lpYcc+lOffset+2)=Cb;
}
}
//调用人脸建模的主函数
voidDIB:
:
faceear(LPBYTElpYcc,WORDwBytesPerLine,intheight,intwidth,boolflag[ImgRange][ImgRange])
{
//初始化标志位
for(inti=0;ifor(intj=0;j{
flag[i][j]=false;
}
longlOffset;
intCr;
intCb;
for(i=0;ifor(intj=0;j{
lOffset=PixelOffset(i,j,wBytesPerLine);
Cr=*(lpYcc+lOffset+1);
Cb=*(lpYcc+lOffset+2);
if(FaceModeling(Cr,Cb))//人脸皮肤颜色建模
{
flag[i][j]=true;//人脸区域标志位
}
}
}
//人脸色彩建模的实现函数
BOOLDIB:
:
FaceModeling(intCr,intCb)
{
constfloatCx=114.38;//Cx的系数常量
constfloatCy=160.02;//Cy的系数常量
constfloattheta=2.53;//角度常量
constfloatecx=1.60;//x轴线和y轴线的两个常量
constfloatecy=2.41;
constfloata=25.39;//长短轴设置
constfloatb=14.03;
constfloatjudge=0.5;//相似度常量
floatx=cos(theta)*(Cb-Cx)+sin(theta)*(Cr-Cy);//计算得到x轴数值
floaty=-sin(theta)*(Cb-Cx)+cos(theta)*(Cr-Cy);//y轴数值
floattemp=pow(x-ecx,2)/pow(a,2)+pow(y-ecy,2)/pow(b,2);//计算离心率
//如果满足要求返回真,否则假
if(fabs(temp-1.0)returnTRUE;
else
returnFALSE;
}
//膨胀
voidCFaceView:
:
OnDilationFirst()
{
gDib.Dilation(hDIB);
gDib.Dilation(hDIB);
Invalidate();
}
//四邻域的膨胀
voidDIB:
:
Dilation(HANDLEhDIB)
{
LPBITMAPINFOHEADERlpb