5.4.2 人脸识别与分割

编程实现

[1] 在视图类里添加消息映射函数Onboundary()以实现轮廓提取。Onboundary()函数代码如代码5-5所示。

代码5-5 Onboundary()函数

        void CDemoView::Onboundary()
        {
            CDemoDoc *pDoc=GetDocument();
            ImageDib *pDib=pDoc->GetPDib();
            int i,j,thd;
            CSize size=pDib->GetDimensions();
            int lineByte=(size.cx+3)/4*4;
            long pixel_scales=0;
            for(i=0;i<size.cx;i++){
                for(j=0;j<size.cy;j++){
                    pixel_scales+=*(pDib->m_pImgData+j*lineByte+i);
                }
            }
            thd=pixel_scales/(size.cx*size.cy);
            GrayTrans graytrans(size,pDib->m_nBitCount, pDib->m_lpColorTable, pDib->
                m_pImgData);
            graytrans.Binary(thd);           //调用Binary()对图像进行二值化
            //建立一个新视图,显示分割结果
            CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
            pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
            CDemoView* pView=(CDemoView*)pFrame->MDIGetActive()->GetActiveView();
            CDemoDoc* pDocNew=pView->GetDocument();
            ImageDib *dibNew=pDocNew->GetPDib();
            dibNew->ReplaceDib(graytrans.GetDimensions(),graytrans.m_nBitCountOut,
                graytrans.m_lpColorTableOut, graytrans.m_pImgDataOut);
            pView->OnInitialUpdate();
            pDocNew->SetModifiedFlag(TRUE);
            pDocNew->UpdateAllViews(pView);
        }
        void CDemo1View::Onboundary()
        {
            CDemo1Doc *pDoc=GetDocument();
            ImageDib *pDib=pDoc->GetPDib();
            //只处理灰度图像
            if(pDib->m_nBitCount!=8){
                ::MessageBox(0, "只处理灰度图像", MB_OK,0);
                return ;
            }
            int i,j,thd;
            CSize size=pDib->GetDimensions();
            int lineByte=(size.cx+3)/4*4;
            long pixel_scales=0;
            for(i=0;i<size.cx;i++){
                for(j=0;j<size.cy;j++){
                    pixel_scales+=*(pDib->m_pImgData+j*lineByte+i);
                }
            }
            thd=pixel_scales/(size.cx*size.cy);
            GrayTrans graytrans(size,pDib->m_nBitCount, pDib->m_lpColorTable, pDib->
                m_pImgData);
            //调用Binary()对图像进行二值化
            graytrans.BinaryImage(thd);
            //建立一个新视图,显示分割结果
            CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
            pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
            CDemo1View* pView=(CDemo1View*)pFrame->MDIGetActive()->GetActiveView();
            CDemo1Doc* pDocNew=pView->GetDocument();
            ImageDib *dibNew=pDocNew->GetPDib();
            dibNew->ReplaceDib(graytrans.GetDimensions(),graytrans.m_nBitCountOut,gray
                trans.m_lpColorTableOut, graytrans.m_pImgDataOut);
            pView->OnInitialUpdate();
            pDocNew->SetModifiedFlag(TRUE);
            pDocNew->UpdateAllViews(pView);
        }

[2] 上述代码中调用了GrayTrans类中的BinaryImage ()函数,已进行图像的二值化处理,其具体代码如代码5-6所示。

代码5-6 BinaryImage()函数

        void GrayTrans::BinaryImage(int threshold)
        {
            //对于灰度图像
            if(m_nBitCount==8){
                //释放旧的输出图像数据及颜色表缓冲区
                if(m_pImgDataOut!=NULL){
                    delete []m_pImgDataOut;
                    m_pImgDataOut=NULL;
                }
                if(m_lpColorTableOut!=NULL){
                    delete []m_lpColorTableOut;
                    m_lpColorTableOut=NULL;
                }
                //输出图像的每像素位数、颜色表长度
                m_nBitCountOut=m_nBitCount;
                m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);
                //申请输出图像颜色表缓冲区,并将输入图像颜色表复制至输出图像颜色表中
                m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
                memcpy(m_lpColorTableOut,m_lpColorTable,sizeof(RGBQUAD)*m_
                    nColorTableLengthOut);
                //输出图像的宽高,与输入图像相等
                m_imgWidthOut=m_imgWidth;
                m_imgHeightOut=m_imgHeight;
                //图像每行像素所占字节数,输入图像与输出图像每行像素所占字节数相等
                int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;
                //申请输出图像位图数据缓冲区
                m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];
                //循环变量,图像的坐标
                int i,j;
                //二值化
                for(i=0;i<m_imgHeight;i++){
                    for(j=0;j<m_imgWidth;j++){
                        if(*(m_pImgData+i*lineByte+j)<threshold)
                            *(m_pImgDataOut+i*lineByte+j)=0;
                        else
                            *(m_pImgDataOut+i*lineByte+j)=255;
                    }
                }
            }
            else
            {
                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 m,n;
                //根据灰值化公式为输出图像赋值
                for(m=0;m<m_imgHeight;m++){
                    for(n=0;n<m_imgWidth;n++)
                        *(m_pImgDataOut+m*lineByteOut+n)=0.11**(m_pImgData+m*
    lineByteIn+n*pixelByteIn+0)
                        +0.59**(m_pImgData+m*lineByteIn+n*pixelByteIn+1)
                        +0.30**(m_pImgData+m*lineByteIn+n*pixelByteIn+2)+0.5;
            }
                //输出图像每行像素所占字节数,输入图像与输出图像每行像素所占字节数不等
                int i,j;
                //二值化
                for(i=0;i<m_imgHeight;i++){
                    for(j=0;j<m_imgWidth;j++)
                        if(*(m_pImgDataOut+i*lineByteOut+j)<threshold)
                            *(m_pImgDataOut+i*lineByteOut+j)=0;
                        else
                            *(m_pImgDataOut+i*lineByteOut+j)=255;
                }
            }
        }