一、寫(xiě)作背景
基于人臉識(shí)別的考勤系統(tǒng)主要用于對(duì)公司員工的出勤統(tǒng)計(jì),員工簽到時(shí)需要通過(guò)攝像頭采集到員工面部照片,再通過(guò)人臉識(shí)別算法從采集到的照片中取得特征值并與數(shù)據(jù)庫(kù)中預(yù)先存入的員工人臉照片的特征值進(jìn)行分析比較,識(shí)別成功后報(bào)出員工的姓名,則考勤成功。本文主要介紹的是考勤機(jī)后臺(tái)管理程序中的人臉信息錄入部分的設(shè)計(jì),也就是通過(guò)攝像頭進(jìn)行員工面部信息的采集,每個(gè)員工采集若干張照片,需要保存到數(shù)據(jù)庫(kù)中,同時(shí)需要通過(guò)一定的算法保存其對(duì)應(yīng)的特征值。本文就對(duì)一張照片的采集與顯示的關(guān)鍵步驟展開(kāi)闡述,并給出在Visual C + + 6. 0實(shí)現(xiàn)的必要代碼。
二、軟件支持
VFW(Video for Windows) 是Microsoft 1992 年推出的關(guān)于數(shù)字視頻的一個(gè)軟件包,它提供了一系列應(yīng)用程序編程接口,它使應(yīng)用程序?qū)σ曨l的采集和播放變得非常容易實(shí)現(xiàn)。VFW 給程序員提供VBX和AVICap 窗口類(lèi)的高級(jí)編程工具,使程序員能通過(guò)發(fā)送消息來(lái)采集、播放和編輯視頻剪輯。現(xiàn)在的計(jì)算機(jī)用戶(hù)不必專(zhuān)門(mén)安裝VFW,當(dāng)用戶(hù)在安裝Win2dows 時(shí),安裝程序會(huì)自動(dòng)地安裝配置視頻所需的組件,如設(shè)備驅(qū)動(dòng)程序、視頻壓縮程序等。
Visual C + + 6. 0 在支持VFW 方面提供有vfw32. lib、msacm32. lib、winmm. lib 等類(lèi)似的庫(kù),特別是它提供了功能強(qiáng)大、簡(jiǎn)單易行、類(lèi)似于MCIWnd 的窗口類(lèi)AVICap 。AVICap 為應(yīng)用程序提供了一個(gè)簡(jiǎn)單的、基于消息的接口,使之能訪(fǎng)問(wèn)視頻和波形音頻硬件,并能在捕獲視頻流到硬盤(pán)上的過(guò)中進(jìn)行控制。AVICap 支持實(shí)時(shí)的視頻流捕獲和單幀捕獲并提供對(duì)視頻源的控制。它能直接訪(fǎng)問(wèn)視頻緩沖區(qū),不需要生成中間文件,實(shí)時(shí)性很強(qiáng),效率很高。同時(shí),它也可捕獲數(shù)字視頻并保存到文件。在捕獲視頻之前需要?jiǎng)?chuàng)建一個(gè)捕獲窗口,所有的捕獲操作及其設(shè)置都以它為基礎(chǔ)。用AVICap 窗口類(lèi)創(chuàng)建的窗口被稱(chēng)為“捕獲窗口”。捕獲窗口功能強(qiáng)大可以進(jìn)行視頻錄像(將一視頻流和音頻流捕獲到一個(gè)AVI 文件中) 或是畫(huà)面截取。在人臉識(shí)別考勤系統(tǒng)中主要用到畫(huà)面截取功能。下面是截取畫(huà)面時(shí)需要用到的幾個(gè)設(shè)置操作:
?、賱?dòng)態(tài)地同視頻采集設(shè)備連接或斷開(kāi);
②以O(shè)verlay 或Preview 模式對(duì)輸入的視頻流進(jìn)行實(shí)時(shí)顯示;
a. 預(yù)覽(Preview) 模式:該模式把從捕獲硬件傳來(lái)的數(shù)據(jù)送入系統(tǒng)內(nèi)存并且在捕獲窗口中使用GDI函數(shù)來(lái)顯示這些數(shù)據(jù)幀。此種模式要占用一定的系統(tǒng)資源,一般的視頻采集設(shè)備都是通過(guò)這種顯示方式工作的。
b. 疊加(Overlay) 模式:該模式的視頻顯示不經(jīng)過(guò)VGA 卡,而是將其輸出信號(hào)與VGA 的輸出信號(hào)合并,形成組合信號(hào)顯示在計(jì)算機(jī)的監(jiān)視器上。在該模式下所捕捉的視頻數(shù)據(jù)的顯示不需要占用系統(tǒng)資源。
?、墼O(shè)置捕獲速率;
?、茱@示控制視頻源、視頻格式、視頻壓縮的對(duì)話(huà)框;
⑤將捕獲的一個(gè)單幀圖像保存為DIB 格式的文件。
三、實(shí)現(xiàn)原理
采集照片時(shí)捕獲一幀圖像,在臨時(shí)文件夾中保存為DIB 格式的位圖文件,然后通過(guò)文件類(lèi)的讀操作將該位圖文件轉(zhuǎn)化為二進(jìn)制的數(shù)據(jù)同時(shí)獲取數(shù)據(jù)的長(zhǎng)度,再調(diào)用數(shù)據(jù)庫(kù)接口函數(shù)把轉(zhuǎn)化得到的二進(jìn)制數(shù)據(jù)和數(shù)據(jù)的長(zhǎng)度存入數(shù)據(jù)庫(kù),最后刪除臨時(shí)文件夾里的位圖文件;顯示照片時(shí)調(diào)用數(shù)據(jù)庫(kù)訪(fǎng)問(wèn)接口函數(shù)從數(shù)據(jù)庫(kù)取出照片的二進(jìn)制數(shù)據(jù)和數(shù)據(jù)的長(zhǎng)度,再通過(guò)文件類(lèi)的寫(xiě)操作在臨時(shí)文件夾中生成位圖文件用來(lái)顯示,顯示完后刪除該文件。至于把圖片顯示到界面上,只需把臨時(shí)文件夾里的位圖文件通過(guò)繪圖函數(shù)顯示可以了。特征值的算法不在本文討論之列。
四、實(shí)現(xiàn)流程
五、關(guān)鍵程序代碼
(一) 采集照片
1. 在頭文件中定義攝像頭相關(guān)的控制成員變量
HWND m-hWndCap ; PP定義視頻捕捉窗口
CAPDRIVERCAPS m-CapDriverCaps ; PP捕獲驅(qū)動(dòng)器的性能
CAPSTATUS m-CapStatus ; PP捕獲窗口的當(dāng)前狀態(tài)
2. 啟動(dòng)攝像頭
//創(chuàng)建視頻捕捉窗口
m-hWndCap = capCreateCaptureWindow (- T ( ”人臉?shù)浫搿? ,WS-CHILD| WS-VISIBLE , CAMERA-LEFT ,CAMERA- TOP , CAMERA-WIDTH , CAMERAHEIGHT,m-hWnd ,0) ;
/*第一個(gè)參數(shù)指定捕捉窗口的名稱(chēng),第二個(gè)參數(shù)指定捕捉窗口的樣式,第三、四個(gè)參數(shù)指定捕捉窗口的左上角的位置坐標(biāo),第五、六個(gè)參數(shù)指定捕捉窗口的寬度和高度,第七、八個(gè)參數(shù)分別是捕捉窗口的父窗口的句柄和編號(hào)。*/
/*將捕捉窗與默認(rèn)攝像頭連接,如果連接成功則獲得捕獲驅(qū)動(dòng)的性能,放在結(jié)構(gòu)變量m-Cap2 DriverCaps 中*/
if (capDriverConnect (m-hWndCap ,0) )
capDriverGetCaps ( m-hWndCap , &m-CapDriver2Caps ,sizeof (CAPDRIVERCAPS) ) ;
//如果攝像頭支持疊加顯示模式則啟用疊加顯示模式
if (m-CapDriverCaps. fHasOverlay)
capOverlay(m-hWndCap ,TRUE) ;
else
{
capPreviewRate (m-hWndCap ,66) ; //設(shè)置預(yù)覽模式的顯示速率
capPreview(m-hWndCap , TRUE) ; //啟用預(yù)覽模式
}
至此,如果攝像頭正常安裝了驅(qū)動(dòng),就能正常工作了。
3. 采集并預(yù)覽照片
界面上左邊是捕捉窗口,右邊留有和捕捉窗口同樣大小的區(qū)域用于預(yù)覽或顯示捕捉到的照片。
capGrabFrameNoStop (m-hWndCap ) ;//捕捉照片且捕捉窗口畫(huà)面不停止
capFileSaveDIB ( m-hWndCap , ” \ employee.bmp”) ; //保存捕捉到的照片
//獲得照片句柄用于在界面顯示捕捉到的照片
m-hPhotoBmp = (HBITMAP) LoadImage (AfxGetIn2stanceHandle ( ) ,”\ employee. bmp”,IMAGE-BITMAP ,0 ,0 ,LR-CREATEDIBSECTION| LR-LOADFROMFILE) ;
/*第一個(gè)參數(shù)取應(yīng)用程序?qū)嵗浔?第二個(gè)參數(shù)指定照片的路徑及名稱(chēng),第三個(gè)參數(shù)指定照片的類(lèi)型,第四、五個(gè)參數(shù)指定照片的寬和高,為零則使用圖像默認(rèn)大小, 第六個(gè)參數(shù)LR- CREATEDIB2SECTION:當(dāng)圖像類(lèi)型為IMAGE-BITMAP 時(shí),使函數(shù)返回一個(gè)DIB 位圖,而不是一個(gè)兼容的位圖。LRLOADFROMFILE:根據(jù)照片的路徑和名稱(chēng)裝載圖像。*/
Invalidate (FALSE) ; PP重繪窗口顯示照片
為了在界面顯示照片還需添加繪圖函數(shù)On2Paint () :
//在界面添加picture 控件,命名為IDC-STATICPICTURE,并指定圖片控件
CPaintDC dcPicture ( GetDlgItem( IDC-STATIC- PIC2TURE) ) ;
CRect rectPic ; //定義矩形區(qū)域
GetDlgItem( IDC-STATIC- PICTURE) - > GetClien2tRect (&rectPic) ; //指定在圖片控件上
CDC memDC; //建立與顯示設(shè)備兼容的內(nèi)存設(shè)備場(chǎng)境
memDC. CreateCompatibleDC(&dcPicture) ;
memDC. SelectObject (m-hPhotoBmp) ; //將位圖選入內(nèi)存場(chǎng)境
//調(diào)用缺省的窗口過(guò)程來(lái)為沒(méi)有處理的窗口消息提供缺省的處理
CWnd : :DefWindowProc (WM- PAINT , (WPARAM)memDC. m-hDC ,0) ;
dcPicture. BitBlt ( rectPic. left , rectPic. top , rectPic.Width() ,rectPic. Height () ,&memDC ,0 ,0 ,SRCCOPY) ;
/*顯示位圖。前四個(gè)參數(shù)分別指定顯示圖片的左上角頂點(diǎn)的位置坐標(biāo),和圖片的寬高,第五個(gè)參數(shù)表示源設(shè)備場(chǎng)景的地址,第六七兩個(gè)參數(shù)表示顯示圖片的左上角頂點(diǎn)在源設(shè)備環(huán)境的矩形區(qū)域中的坐標(biāo),最后一個(gè)參數(shù)表示將源矩形圖象直接復(fù)制到目標(biāo)矩形上。*/
4. 保存照片到數(shù)據(jù)庫(kù)
先把捕捉到的位圖文件轉(zhuǎn)化成二進(jìn)制數(shù)據(jù),然后通過(guò)接口函數(shù)保存到數(shù)據(jù)庫(kù)中。對(duì)數(shù)據(jù)庫(kù)的操作請(qǐng)參考DAO 或ADO 編程。
CFile bmpFile ; //定義文件類(lèi)變量
if (bmpFile. Open (”\ employee. bmp”,CFile : :mo2deRead) )//讀模式打開(kāi)照片文件
{ LONG nLength = bmpFile. GetLength() ; //獲得照片的文件長(zhǎng)度
unsigned char 3 pData = new unsigned char [ nLength ] ; //申請(qǐng)內(nèi)存空間
//如果申請(qǐng)到空間就讀數(shù)據(jù)到緩沖區(qū),即得到二進(jìn)制數(shù)據(jù)
bmpFile. Read(pData ,nLength) ;//讀照片文件到緩沖區(qū)
bmpFile. Close () ; //關(guān)閉文件
}
Employee. SavePicture ( EmployeeID , &pData ,nLength) ;//對(duì)數(shù)據(jù)庫(kù)訪(fǎng)問(wèn)接口
bmpFile. Remove (”\ employee. bmp”) ; //刪除臨時(shí)文件夾里生成的位圖文件
delete[ ] pData ; //釋放內(nèi)存中申請(qǐng)的緩沖區(qū)
5. 斷開(kāi)攝像頭
capDriverDisconnect (m-hWndCap) ; //斷開(kāi)攝像頭(二) 顯示數(shù)據(jù)庫(kù)中的照片前面已經(jīng)實(shí)現(xiàn)照片的預(yù)覽功能,現(xiàn)在只要從數(shù)據(jù)庫(kù)取出照片數(shù)據(jù),生成位圖文件,取得位圖的句柄顯示問(wèn)題就解決了。
//通過(guò)數(shù)據(jù)庫(kù)接口得到照片的文件長(zhǎng)度(nLength) 和二進(jìn)制照片數(shù)據(jù)的地址pData 。
unsigned char 3 pData = NULL ; //定義字符型指針變量
employee. GetPicture ( &pData , &nLength) ; //取照片數(shù)據(jù)
//如果取到照片數(shù)據(jù)則生成位圖文件
CFile outFile ( ”\ employee. bmp”, CFile : : mode2Create| CFile : :modeWrite) ;
outFile.WriteHuge ( (LPSTR) pData ,nLength) ;
outFile. Close () ;
//取得生成圖片的句柄
六、總結(jié)
Visual C + + 提供的AVICap 窗口類(lèi)為VC 的數(shù)字視頻采集提供了很大的方便,極大增強(qiáng)了VC 多媒體程序開(kāi)發(fā)的能力。本文所描述的照片采集的過(guò)程便是基于此技術(shù),并且已經(jīng)在人臉識(shí)別考勤系統(tǒng)中作為人臉?shù)浫肽K使用,該模塊負(fù)責(zé)在系統(tǒng)最初運(yùn)行時(shí)對(duì)人臉信息采集或是對(duì)已有人臉信息進(jìn)行更新時(shí)使用。經(jīng)過(guò)多次測(cè)試該模塊運(yùn)行穩(wěn)定,可以滿(mǎn)足需求。