📄 mainfrm.cpp
字号:
for(i=0;i<255;i++)
{
PixelNum[i]=0;
}
int calNum=0;//连续区域的个数;
for(i=0;i<(lpbi->biHeight);i++)
for(j=0;j<(lpbi->biWidth);j++)
{
Offset=PixelOffset(i,j,wBytesPerLine);
if((*(lpb+Offset)==255)&&(*(lpb+Offset+1)==255)&&(*(lpb+Offset+2)==255))//如果当前点的像素颜色是白色,则递归统计该区域内连续白色像素点的个数;
{
calNum++;
RecursiveCal(lpb,i,j,wBytesPerLine,&(PixelNum[calNum]),calNum);
//如果采集到的人脸面积过大,
//那么,程序在递归的过程中会造成系统stack溢出,
//应如何解决?
}
}
const int AREAPIXEL=1200;//表示人脸的像素个数必须大于AREAPIXEL;
int face_num=calNum;
/*
for(i=0;i<calNum;i++)
{
//如果像素点个数小于一定数目则把这个标志设置为0
if(PixelNum[i]<AREAPIXEL)
{
PixelNum[i]=0;
face_num--;
}
}
*/
int max=0,pnum;
for(i=1;i<=calNum;i++)
{
if(PixelNum[i]>max)
{
max=PixelNum[i];
pnum=i;
}
}
for(i=1;i<=calNum;i++)
{
if(i!=pnum)
{
PixelNum[i]=0;
face_num--;
}
}
if(PixelNum[pnum]<AREAPIXEL)
{
PixelNum[pnum]=0;
face_num--;
}
//下面的循环根据标志数组来最终设定图像的颜色;
for(i=0;i<(lpbi->biHeight);i++)
for(j=0;j<(lpbi->biWidth);j++)
{
Offset=PixelOffset(i,j,wBytesPerLine);
int num=*(lpb+Offset);
// int num2=*(lpb+Offset+1);
// int num3=*(lpb+Offset+2);
//如果当前点不是黑色点;
if(num!=0)
{
//如果当前点标志数组为0,则设置为黑色;
if(PixelNum[num]==0)
{
*(lpb+Offset)=0;
*(lpb+Offset+1)=0;
*(lpb+Offset+2)=0;
}
//否则设置为白色;
else
{
*(lpb+Offset)=255;
*(lpb+Offset+1)=255;
*(lpb+Offset+2)=255;
}
}
}
/*
//---------------------------------------------------
m_iscapture=FALSE;
m_after_skindect=TRUE;
(((CMainFrame*)AfxGetMainWnd())->GetActiveView())->
InvalidateRect(NULL,FALSE);
AfxMessageBox("已去掉非人脸区域!",MB_OK,0);
*/
//--------------------------------------------------
return(face_num);
}
//递归统计该区域连续的白色点像素点个数;
void CMainFrame::RecursiveCal(unsigned char * lpData,int y,int x,DWORD wBytesPerLine,int * pixelNum,int num)
{
LPBITMAPINFOHEADER lpbi;
lpbi=&m_bitmapheader;
long Offset=PixelOffset(y,x,wBytesPerLine);
//如果当前点为白色点;
if((*(lpData+Offset)==255)&&(*(lpData+Offset+1)==255)&&(*(lpData+Offset+2)==255))
{
//把当前点大小设置为序号值;
*(lpData+Offset++)=num;
*(lpData+Offset++)=num;
*(lpData+Offset++)=num;
//像素个数加1
(*pixelNum)++;
int tempx;
int tempy;
//递归当前点下面的点;
tempy=y-1;
tempx=x;
if((y-1)>=0)
RecursiveCal(lpData,tempy,tempx,wBytesPerLine,pixelNum,num);
//递归当前点上面的点;
tempy=y+1;
tempx=x;
if((y+1)<=lpbi->biHeight)
RecursiveCal(lpData,tempy,tempx,wBytesPerLine,pixelNum,num);
//递归当前点左边的点;
tempy=y;
tempx=x-1;
if((x-1)>=0)
RecursiveCal(lpData,tempy,tempx,wBytesPerLine,pixelNum,num);
//递归当前点右边的点;
tempy=y;
tempx=x+1;
if((x+1)<=lpbi->biWidth)
RecursiveCal(lpData,tempy,tempx,wBytesPerLine,pixelNum,num);
}
}
//---------------------------------------------------------
void CMainFrame::OnFace()
{
// TODO: Add your command handler code here
if(m_enable_skindect)
{
// RGB_Copydata();
// rgb_histogram();
RGBToYCrCb();//对得到的视频帧信息进行色彩空间(RGB->YCrCb)的转换,转换后的数据信息存放在m_ycc_buffer[30000]中;
//---------------------------------------------------
m_iscapture=FALSE;
m_after_skindect=TRUE;
(((CMainFrame*)AfxGetMainWnd())->GetActiveView())->
InvalidateRect(NULL,FALSE);
AfxMessageBox("已转换色彩!",MB_OK,0);
//---------------------------------------------------
// ycc_histogram();
// (((CMainFrame*)AfxGetMainWnd())->GetActiveView())->
// InvalidateRect(NULL,FALSE);
Skin_detection();//YCrCb空间肤色检测操作;
// RGB_Copydata();
// RGB_Skin_detection();
dilation();//在视频帧的数据信息中对肤色像素进行膨胀、腐蚀操作;
erosion();
//---------------------------------------------------
m_iscapture=FALSE;
m_after_skindect=TRUE;
(((CMainFrame*)AfxGetMainWnd())->GetActiveView())->
InvalidateRect(NULL,FALSE);
AfxMessageBox("已检测好肤色!",MB_OK,0);
//---------------------------------------------------
int FaceNum=ErasionFalseArea();
//去掉非人脸区域,记录下人脸区域的个数;
/*
//---------------------------------------------------
m_iscapture=FALSE;
m_after_skindect=TRUE;
(((CMainFrame*)AfxGetMainWnd())->GetActiveView())->
InvalidateRect(NULL,FALSE);
AfxMessageBox("已去掉非人脸区域!",MB_OK,0);
//--------------------------------------------------
*/
if(FaceNum==0)
{
AfxMessageBox("采集的视频帧中没有人脸,请重新采集!",MB_OK,0);
}
else
{
AfxMessageBox("可以定位人脸了!",MB_OK,0);
//---------------------------------------------------
m_iscapture=FALSE;
m_after_skindect=TRUE;
(((CMainFrame*)AfxGetMainWnd())->GetActiveView())->
InvalidateRect(NULL,FALSE);
//---------------------------------------------------
// CWnd * p_CWnd=AfxGetMainWnd();
// CMenu * p_CMenu=p_CWnd->GetMenu();
// CMenu * p_Sub_CMenu=p_CMenu->GetSubMenu(5);
// p_Sub_CMenu->EnableMenuItem(ID_FACE, MF_ENABLED);
}
// dilation();//在视频帧的数据信息中对肤色像素进行膨胀、腐蚀操作;
// erosion();
m_enable_skindect=FALSE;
m_enable_facelac=TRUE;
}
else
{
AfxMessageBox("请先采集视频帧!",MB_OK,0);
}
return;
//如果人脸区域的个数为0,则出现"采集的视频帧中没有人脸,请重新采集"的提示框;
//否则,把"人脸定位"菜单项置为可用菜单项,并出现"可定位人脸"的提示框。
}
void CMainFrame::scan()
{
int i,j;
int BlackPixelNum=0;
int flagy=0;
//标记是否出现下边界,0表示没有出现下边界,1表示出现了下边界;
int flagx=0;
//标记是否出现左边界,0表示没有出现左边界,1表示出现了左边界;
long Offset;
unsigned char * lpb;
lpb=m_ycc_buffer;
// lpb=m_rgb_buffer;
LPBITMAPINFOHEADER lpbi;
lpbi=&m_bitmapheader;
//lpbi_ycc是指向"存放'以YCrCb色彩空间表达的数据信息'的信息头信息"的指针;
// lpbi=&m_rgb_bitmapheader;
DWORD wBytesPerLine=BytePerLine(lpbi);
//得到每行像素所占用的字节数;
//从下往上扫描图像
for(i=0;i<lpbi->biHeight;i++)
{
if(flagy==0)
{
for(j=0;j<lpbi->biWidth;j++)
{
Offset=PixelOffset(i,j,wBytesPerLine);
//得到像素点数据在整个数据区中的偏移;
if((*(lpb+Offset)==255)&&(*(lpb+Offset+1)==255)&&(*(lpb+Offset+2)==255))
{
m_y1=i;
//记下人脸的下边界;
flagy=1;
break;
}
}
continue;
}
else
{
for(j=0;j<lpbi->biWidth;j++)
{
Offset=PixelOffset(i,j,wBytesPerLine);
//得到像素点数据在整个数据区中的偏移;
if((*(lpb+Offset)==0)&&(*(lpb+Offset+1)==0)&&(*(lpb+Offset+2)==0))
{
++BlackPixelNum;//记录当前行的黑色像素的个数;
}
}
if(BlackPixelNum==lpbi->biWidth)
{
m_y2=i; //记下人脸的上边界;
break;
}
else
{
BlackPixelNum=0;
continue;//否则扫描下一行;
}
}
}
if(m_y2==-1)
m_y2=lpbi->biHeight-1;
//从左往右扫描图像;
BlackPixelNum=0;
for(i=0;i<lpbi->biWidth;i++)
{
if(flagx==0)
{
for(j=0;j<lpbi->biHeight;j++)
{
Offset=PixelOffset(j,i,wBytesPerLine);
//得到像素点数据在整个数据区中的偏移;
if(*(lpb+Offset)==255)
{
m_x1=i;
//记下人脸的左边界;
flagx=1;
break;
}
}
continue;
}
else
{
for(j=0;j<lpbi->biHeight;j++)
{
Offset=PixelOffset(j,i,wBytesPerLine);
//得到像素点数据在整个数据区中的偏移;
if(*(lpb+Offset)==0)
{
++BlackPixelNum;//记录当前行的黑色像素的个数;
}
}
if(BlackPixelNum==lpbi->biHeight)
{
m_x2=i; //记下人脸的右边界;
break;
}
else
{
BlackPixelNum=0;
continue;//否则扫描下一列;
}
}
}
if(m_x2==-1)
m_x2=lpbi->biWidth-1;
}
void CMainFrame::OnFacelocation()
{
// TODO: Add your command handler code here
//大致定位人脸区域;
int i,j;
// int BlackPixelNum=0;
// int flagy=0;
//标记是否出现下边界,0表示没有出现下边界,1表示出现了下边界;
// int flagx=0;
//标记是否出现左边界,0表示没有出现左边界,1表示出现了左边界;
long Offset;
unsigned char * lpb;
lpb=m_ycc_buffer;
// lpb=m_rgb_buffer;
LPBITMAPINFOHEADER lpbi;
lpbi=&m_bitmapheader;
//lpbi_ycc是指向"存放'以YCrCb色彩空间表达的数据信息'的信息头信息"的指针;
// lpbi=&m_rgb_bitmapheader;
DWORD wBytesPerLine=BytePerLine(lpbi);
//得到每行像素所占用的字节数;
// m_y1=1;
// m_y2=143;
// m_x1=1;
// m_x2=175;
const int AREAPIXEL=1200;//表示人脸的像素个数必须大于AREAPIXEL;
int square=0;
if(m_enable_facelac)
{
while(square<AREAPIXEL)
{
m_x1=-1;
m_x2=-1;
m_y1=-1;
m_y2=-1;
scan();
square=(m_x2-m_x1)*(m_y2-m_y1);
if(square<AREAPIXEL)
{
for(i=m_y1;i<=(m_y2);i++)
for(j=m_x1;j<=(m_x2);j++)
{
Offset=PixelOffset(i,j,wBytesPerLine);
*(lpb+Offset)=0;
*(lpb+Offset+1)=0;
*(lpb+Offset+2)=0;
}
}
}
lpb=((CMainFrame*)AfxGetMainWnd())->m_dibinfo.buffer
+((CMainFrame*)AfxGetMainWnd())->m_dibinfo.VideoFormatSize;
//用矩形定位人脸,矩形边线呈绿色
//画人脸的下边界
i=m_y1;
for(j=m_x1;j<=m_x2;j++)
{
Offset=PixelOffset(i,j,wBytesPerLine);
//得到像素点数据在整个数据区中的偏移;
*(lpb+Offset)=0;
*(lpb+Offset+1)=255;
*(lpb+Offset+2)=0;
}
//画人脸的上边界;
i=m_y2;
for(j=m_x1;j<=m_x2;j++)
{
Offset=PixelOffset(i,j,wBytesPerLine);
//得到像素点数据在整个数据区中的偏移;
*(lpb+Offset)=0;
*(lpb+Offset+1)=255;
*(lpb+Offset+2)=0;
}
//画人脸的左边界;
j=m_x1;
for(i=m_y1;i<=m_y2;i++)
{
Offset=PixelOffset(i,j,wBytesPerLine);
//得到像素点数据在整个数据区中的偏移;
*(lpb+Offset)=0;
*(lpb+Offset+1)=255;
*(lpb+Offset+2)=0;
}
//画人脸的右边界;
j=m_x2;
for(i=m_y1;i<=m_y2;i++)
{
Offset=PixelOffset(i,j,wBytesPerLine);
//得到像素点数据在整个数据区中的偏移;
*(lpb+Offset)=0;
*(lpb+Offset+1)=255;
*(lpb+Offset+2)=0;
}
m_iscapture=TRUE;
m_after_skindect=FALSE;
(((CMainFrame*)AfxGetMainWnd())->GetActiveView())->
InvalidateRect(NULL,FALSE);
}
else
{
AfxMessageBox("请先确定人脸存在再定位!",MB_OK,0);
}
m_enable_facelac=FALSE;
}
void CMainFrame::OnVideofacelac()
{
// TODO: Add your command handler code here
if(videoflag==FALSE)
videoflag=TRUE;
else
videoflag=FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -