- Visual C++數字圖像模式識別典型案例詳解
- 馮偉興 梁洪 王臣業編著
- 1123字
- 2018-12-31 19:39:08
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; } }