- Visual C++数字图像模式识别典型案例详解
- 冯伟兴 梁洪 王臣业编著
- 1123字
- 2025-03-16 03:50:49
5.4.1 人脸肤色相似度比较
编程实现
[1] 添加继承自ImageDib类的FaceDetect类进行有关人脸检测的算法编程与实现。在文件FaceDetect.h中定义该类如代码5-1所示。
代码5-1 FaceDetect类
class FaceDetect : public ImageDib { public: int m_nBitCountOut; //输出图像每像素位数 unsigned char * m_pImgDataOut; //输出图像位图数据指针 LPRGBQUAD m_lpColorTableOut; //输出图像颜色表 unsigned char * m_pImgDataIn; //输入图像位图数据指针 double** m_pSimArray; //相似度矩阵 double Cb_Mean; double Cr_Mean; double Cov00; double Cov01; double Cov10; double Cov11; private: int m_imgWidthOut; //输出图像的宽,像素为单位 int m_imgHeightOut; //输出图像的高,像素为单位 int m_nColorTableLengthOut; //输出图像颜色表长度 public: void CalSBound(int top,int bottom,int left,int right); FaceDetect(); //不带参数的构造函数 FaceDetect(CSize size, int nBitCount, LPRGBQUAD lpColorTable, unsigned char *pImgData1,unsigned char *pImgData2); //带参数的构造函数 ~FaceDetect(); //析构函数 bool CalBin(); void CalMedFl(double **s,int w,int h,int n); void CalSim(); CSize GetDimensions(); //以像素为单位返回输出图像的宽和高 };
[2] 在视图类里添加消息映射函数Onsimilardegree(),以进行相似度计算。Onsimilardegree ()函数代码如代码5-2所示。
代码5-2 Onsimilardegree()函数
void CDemo1View::Onsimilardegree() { //获取文档类指针 CDemo1Doc *pDoc=GetDocument(); //获取ImgCenterDib类对象m_dib的指针,访问当前DIB数据 ImageDib *pDib=pDoc->GetPDib(); //只处理彩色图像 if(pDib->m_nBitCount!=24){ ::MessageBox(0, "只处理彩色图像", MB_OK,0); return ; } FaceDetect simcalculation(pDib->GetDimensions(),pDib->m_nBitCount, pDib->m_lpColorTable, pDib->m_pImgData,NULL); simcalculation.CalSim(); //建立一个新视图,显示结果 CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd); //发送新建文件的消息,创建一个新的文档-视图 pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW); //获取新建视图指针 CDemo1View* pView=(CDemo1View*)pFrame->MDIGetActive()->GetActiveView(); //获取相关联的新的文档类指针 CDemo1Doc* pDocNew=pView->GetDocument(); //获取新文档中的ImgCenterDib类对象指针 ImageDib *dibNew=pDocNew->GetPDib(); //将变换后的输出图像作为新建文档的DIB进行显示 dibNew->ReplaceDib(simcalculation.GetDimensions(),simcalculation.m_nBitCou ntOut,simca lculation.m_lpColorTableOut, simcalculation.m_pImgDataOut); //设置滚动窗口 pView->OnInitialUpdate(); //文档数据置脏,提示存盘信息 pDocNew->SetModifiedFlag(TRUE); //各视图刷新显示 pDocNew->UpdateAllViews(pView); }
[3] 上述代码中,调用了FaceDetect类中的CalSim()函数,以进行肤色相似度计算,其具体代码如代码5-3所示。
代码5-3 CalSim()函数
void FaceDetect::CalSim() { //若为灰度图像,则返回 if(m_nBitCount==8) return; //释放旧的输出图像数据及颜色表缓冲区 if(m_pImgDataOut!=NULL){ delete []m_pImgDataOut; m_pImgDataOut=NULL; } if(m_lpColorTableOut!=NULL){ delete []m_lpColorTableOut; m_lpColorTableOut=NULL; } //灰值化后,每像素位数为8比特 m_nBitCountOut=8; //颜色表长度 m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut); //申请颜色表缓冲区,生成灰度图像的颜色表 if(m_nColorTableLengthOut!=0){ m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut]; for(int i=0; i<m_nColorTableLengthOut;i++){ m_lpColorTableOut[i].rgbBlue=i; m_lpColorTableOut[i].rgbGreen=i; m_lpColorTableOut[i].rgbRed=i; m_lpColorTableOut[i].rgbReserved=0; } } //输入图像每像素字节数,彩色图像为3字节/像素 int pixelByteIn=3; //输入图像每行像素所占字节数,必须是4的倍数 int lineByteIn=(m_imgWidth*pixelByteIn+3)/4*4; //输出图像的宽高,与输入图像相等 m_imgWidthOut=m_imgWidth; m_imgHeightOut=m_imgHeight; //输出图像每行像素所占字节数,必须是4的倍数 int lineByteOut=(m_imgWidth*m_nBitCountOut/8+3)/4*4; //申请输出图像位图数据缓冲区 m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeight]; //循环变量,图像的坐标 int i,j,k,j1,j2,flag; char c_t1[4]; for(i=0;i<m_imgHeight;i++){ for(j=0;j<m_imgWidth;j++){ *(m_pImgDataOut+i*lineByteOut+j)=255; } } m_pSimArray = new double*[m_imgHeight]; for(i=0;i<m_imgHeight;i++) m_pSimArray[i] = new double[m_imgWidth]; //将RGB色彩空间变换到YCgCr色彩空间,然后计算该点属于皮肤区域的概率 for(i=0;i<m_imgHeight;i++) for (j=0;j<m_imgWidth;j++){ for(k=0;k<3;k++){ c_t1[k]=*(m_pImgDataIn1+i*lineByteIn+j*pixelByteIn+k); } int C_b=(int)c_t1[0]&255; int C_g=(int)c_t1[1]&255; int C_r=(int)c_t1[2]&255; double Cb=(128-37.797*C_r/255-74.203*C_g/255+112*C_b/255); double Cr=(128+112*C_r/255-93.786*C_g/255-18.214*C_b/255); double tt =(Cb-Cb_Mean)*((Cb-Cb_Mean)*Cov11-(Cr-Cr_Mean)*Cov10)+ (Cr-Cr_Mean)*(-(Cb-Cb_Mean)*Cov01+(Cr-Cr_Mean)*Cov00); tt =(-0.5*tt)/(Cov00*Cov11-Cov01*Cov10); m_pSimArray[i][j]=exp(tt); } //调用中值滤波函数 CalMedFl(m_pSimArray,m_imgWidth, m_imgHeight,9); //统计出该幅图像上所有像素点的最大肤色相似度 double max=0.0; for(i=0;i<m_imgHeight;i++) for (j=0;j<m_imgWidth;j++){ if(m_pSimArray[i][j]>max) max=m_pSimArray[i][j]; } //将各个像素的肤色相似度值归一化 for( i=0;i<m_imgHeight;i++) for (j=0;j<m_imgWidth;j++){ m_pSimArray[i][j]= m_pSimArray[i][j]/max; } //将各像素的肤色相似度值变换到[0,255]上,以进行灰度图像的显示 for(i=0;i<m_imgHeight;i++) for(j=0;j<m_imgWidth;j++){ *(m_pImgDataOut+i*lineByteOut+j)=(int)(m_pSimArray[i][j]*255); } }
[4] CalSim()函数调用了FaceDetect类中的CalMedFl()函数,以进行中值滤波,其具体代码如代码5-4所示。
代码5-4 CalMedFl()函数
void FaceDetect::CalMedFl(double **s, int w, int h, int n) { int i,j; double **temp; temp = new double*[h+2*(int)(n/2)]; for(i=0;i<h+2*(int)(n/2);i++) temp[i] = new double[w+2*(int)(n/2)]; for(i=0;i<w+2*(int)(n/2);i++) for(j=0;j<h+2*(int)(n/2);j++) temp[j][i] = 0.0; for(i=0;i<h;i++) for(j=0;j<w;j++) temp[i+(int)(n/2)][j+(int)(n/2)]=s[i][j]; for(i=0;i<h;i++) for(j=0;j<w;j++) { s[i][j]=0.0; for(int r=0;r<n;r++) for(int c=0;c<n;c++) s[i][j]+=temp[i+r][j+c]; s[i][j]/=n*n; } if(temp!=NULL) { for(i=0;i<h+2;i++) if(temp[i]!=NULL) delete temp[i]; delete temp; } }