第四章 人臉偵測介紹
4.1 人臉訓練圖庫
人臉訓練圖庫的人臉圖像來自 FERET 圖像資料庫,而非人臉圖像則由其他非 人臉的部份經過剪裁成與人臉圖像相同大小所產生。為了減少人臉位置對判斷所 造成的影響,因此將我們將人臉圖像都裁減成 24*24 像素大小的圖像。圖 4.1 列出經過裁減後的人臉及非人臉圖像。
(a)
(b)
圖 4-1 (a)人臉圖像. (b)非人臉圖像 4.2 矩形特徵
人臉偵測是將偵測圖像根據矩形特徵(Rectangle Feature)計算出來的值來 做是否為人臉的判斷。矩形特徵對於邊緣、線條和簡單的圖形結構相當的靈敏,
所以能夠支持有效的訓練機制。圖 4-2 列出在訓練中所使用的五種不同種類特 徵。
圖 4-2 五種不同種類特徵
43
每一張訓練圖像都是 24*24 像素點,圖 4-2(a)為長和寬的比例最小為二比
A
如果為圖 4-2(e)的特徵時需要三個矩形來代表則數學式會變成如下
j 為特徵的個數,
h
j 是弱分類器,f
j是矩形特徵值,θ
j 是臨界值,x 是 24*24for face example y for non face examples
= ⎨ ⎧ ⎩ −
4. 更新 weights:
⎩ ⎨
= ⎧
+
w if example x is classified incorrectl y
correctly
誤的情況發生,假設有 p 張人臉分類錯誤,這 P 張人臉的 weight 就將會被改變,
用意是希望在下一次分類此圖像時可以被正確的分類,最後能將所有人臉圖像都 正確分類,這就是 weight 更新的意義。
因此 weight 加大的目的在於,如果某一特徵再次分類錯誤此圖像的情形 下,它的錯誤率將會很高,也就不是我們所需要的特徵。而當某一特徵能夠正確 分類錯誤圖像並且它的錯誤率也是最小時,則此特徵就是我們所需要的。所以這 P 張人臉圖像在第二好的特徵之下,如果都能分類正確,那就只需要結合這兩個 特徵便能將所有的人臉圖像正確分類。但如果 P 張裡面還是分類錯誤 x 張的話,
我們就必須一直加大錯誤圖像的 weight,找出第三個或更多個特徵來正確分類 這些人臉圖像,直到所有的人臉圖像都能分類正確為止,則強分類器就由這些所 找到的特徵來組成。
4.5 Cascade 分類器
我們利用以上 adaboost 演算法選出 T 個特徵後,在每個檢測子視窗中都需 要利用這 T 個矩形特徵計算其矩形特徵值,感覺有些浪費時間,因此本節將介紹 Cascade 分類器,這分類器可以幫助我們去減少計算時間。關鍵在於 Cascade 使 用多個 stage 來減少特徵值的計算,當上一級 stage 認定此檢測子視窗為人臉,
它才會丟給下一級 stage 做更嚴格的檢測,因此能夠預先排除大部分的非人臉圖 像,並且偵測出幾乎所有的人臉圖像,而可以調整弱分類器的臨界值使得 hit rate 值達到 100%,也就是所有的人臉圖像都會被正確分類。圖 4-5 就是一個 cascade 的架構圖。
49
圖 4-5 Cascade 架構圖
首先第一個 stage 的分類器由全部的訓練圖像做 adaboost 演算法,接著我 們可以去設定兩個參數
I. hit rate : 正確分類的人臉圖像數目除以人臉圖像的總數
II. false alarm : 錯誤分類的非人臉圖像數目除以非人臉圖像的總數 而要達到以上兩個參數之限制時所需要的特徵數量,就是組成此 stage 的特徵。
一般我們會設定 hit rate 為 100%,假設第一個 stage 由 n 個特徵所組成,則這 n 個特徵能將所有人臉分類正確,不過還是會有非人臉圖像被分類錯誤的情形發 生,因此設定 false alarm 想把錯誤分類降的一個定值,因為我們不要求在第一 個 stage 就能完成所有分類的工作,只要能夠刪除大部分的非人臉圖像就夠 了。之後觸發下一個 stage 分類器再刪除前一個 stage 未能去除的非人臉圖像。
建立這個 stage 一樣透過 adaboost 選出特徵,不過訓練圖像有所不同,人臉圖 像為相同的數量,非人臉圖像則為前一個 stage 未能正確分類的非人臉圖像,這 樣做的目的在於這個 stage 只要專心分類前一 stage 無法正確分類的非人臉圖像 即可,那些已經正確分類的非人臉圖像在前一個 stage 就已經刪除了,這就好像 adaboost 的 weight 更新是要專心分類錯誤的圖像的道理一樣,因此這個 stage 一樣會設定 hit rate 和 false alarm 去選出所需之特徵,而此時會將 false alarm
50
的值設的更低,因此分類的難度也會變高,會使用更多數量的特徵做分類。而如 果能夠在這個 stage 就分類完成所有的圖像,那就只需要兩個 stage 即可,但是 如果還是有錯誤分類發生時,就又會觸發下一個 stage 分類器的形成,直到達成 正確分類所有圖像,所建立完成的 cascade 分類器,就是所需要的分類器。圖 4-6 為 cascade 分類器建立流程圖。
圖 4-6 cascade 分類器流程圖
然而 hit rate 要達到 100%也不是那麼簡單而且還得控制 false alarm 的 值,這是需要適當的調整每一個特徵的臨界值去達到將人臉圖像當作非人臉圖像 的錯誤值為零,雖然較低的臨界值可以提高偵測率達到所要的正確比例,但將伴 隨著較高的將非人臉圖像當作人臉圖像的錯誤發生,因此如何調整平衡兩者之間 關係,是不容易的。
一般來說,一張照片中大部分都是非人臉,人臉通常只佔據圖像的一小部 分,所以訓練圖像中非人臉圖像的數量往往會遠大於人臉圖像,就是依據照片的 特性所設計。cascade 的架構可以在每個 stage 刪除部分的非人臉圖像,而越前 面的 stage 所刪除的會越多,當這些非人臉圖像被刪除後,接下來的 stage 就不 會再對這些非人臉圖像做檢測,因此 Cascade 的架構可以節省很多的計算時間,
因為每經過一個 stage 要計算的特徵就會減少。
51
4-6 臨界值(Threshold)的決定
k
y curleft w
k
y curright
w
是目前找到的臨界值,並且 ferror 重新定義為最小錯誤率。跑完 n 次迴圈之後,
最後找最小錯誤率的臨界值就是最佳的臨界值。圖 4-7 為 OpenCV threshold 決 策的流程圖。
圖 4-7 threshold 決策流程
這種方法是在找出一個能夠使得 curleft 與 curright 越趨近於-1 與+1 的 值,也就是能清楚的分開人臉和非人臉圖像的界線,當然不可能每次都能剛好找 到是-1 和+1 的那個界線,因為兩邊都或多或少會有少數人臉和非人臉的圖像出 現,所以只要找到最靠近-1 和+1 界線的值即可。而判斷 curleft 和 curright 是否趨近於-1 和+1 就是透過 curlerror 和 currerror 來當判斷的標準。
53
第五章 實驗介紹與結果
本章節將分成兩大實驗,第一是如何利用 DirectShow 架構開發出人臉偵測 功能的 Filter,以及當 Filter 開發完成後如何在我們的應用程式中去使用它,
第二是如何利用 DLL 方式去封裝我們的人臉偵測系統,以及封裝好之後如何能夠 在我們 Win CE 平台的裝置中使用這個功能,藉由這兩個實驗讓我們充分了解不 同模組化的形式,他們之間的差異性及特性。以下首先詳細說明如何開發一個 Filter 的流程。
5.1 開發 Filter 流程
開發 Filter 首先要先分析這個 Filter 的功能,以本論文為例是要做一個影 像進來之後,對影像做人臉偵測的演算法計算,接著框出人臉,就這個功能分析 起來,此 Filter 需要一個輸入 Pin 來接收影像資料,也需要一個輸出 Pin 來把 處理完的影像資料送出去,因此可以判斷這個 Filter 是一個 Transform Filter 的取向,所以就可以選定 CTransformFilter 這個 DirectShow 提供的基礎類別來 當我們的父類別,當然 DirectShow 還有提供其他功能取向的父類別,例如 CSource、CBaseRenderer 等等。選定一個父類別來繼承對於 Filter 開發者來說 可以大大降低開發時間,因為這個父類別會把一些通用的函式都寫好,這樣開發 者就省去要開發這些函式的時間,以 CTransformFilter 這個類別為例它就已經 幫我們實現好 CTransformInputPin 和 CTransformOutputPin,所以當我們選擇 CTransformFilter 這個類別當我們的父類別時,其實 Pin 類都已經幫我們實現 好了,我們就可以使用它自帶的 Input Pin 以及 Output Pin 的功能而不用再自 行去開發,因此減少許多開發時間,但是如果開發者對 Pin 有獨特的需求,當然 也可以重寫 CTransformInputPin 和 CTransformOutputPin 來實現獨特的功能。
54
經過以上分析後,我們宣告一個 CFDFilter 繼承 CTransformFilter 的類別,程 式碼實現如圖 5-1 所示
圖 5-1 宣告 Filter 類別
當新建出一個類別來代表我們的 Filter 之後就可以開始一個一個實現這個 Filter 的功能函式。基本 Filter 的開發可以分成兩大部分,一部分是 COM 註冊 架構的實現另一部分是 Filter 架構的實現。首先 COM 註冊架構的實現就是要把 這個 Filter 註冊到系統的註冊表,而這個註冊的用意就是要解決傳統動態連結 的缺點,讓外部使用者不需再透過自己手動去連結檔案,只要給外部使用者一個 GUID,就可以透過這個 GUID 去註冊表中查找到這個 Filter 的資料並自動完成連 結的動作,以下我們將先介紹 COM 註冊架構的實現。
5.1.1 COM 註冊架構實現(Filter 註冊)
在第二章的 2.3 節我們已經有介紹過註冊資訊有四種結構,也有對每個結構 的成員所代表的意義作詳盡的介紹,而在本節我們就是要依據我們 Filter 的需 求去設定每個結構的成員變數,實現的程式碼如圖 5-2 所示
支援媒體
Pin 的說明
55
Filter 說明
類別工廠描述
圖 5-2 註冊程式碼實現
接著我們講解我們所設定的意義,首先從 Filter 說明開始,我們要實現的 Filter 名稱叫做 FaceDetect,而它有一個 CLSID 叫做 CLSID_FaceDetect,沒有 特別要求優先權所以 Merit 設定為 MERIT_DO_NOT_USE,且這個 Filter 有兩支 Pin(Pin 的資訊在 sudpPins 這個結構中),一個是輸入 Pin 名稱為 Input,一個 是輸出 Pin 名稱為 Output,而這兩支 Pin 支援的主要媒體格式(媒體格式在 sudPinTypes 這個結構中)是視訊格式,且這個視訊格式要是 RGB24 的形式,所 以 我 們 分 別 對 Major Type 和 Minor Type 做 MEDIATYPE_Video 以 及 MEDIASUBTYPE_RGB24 的設定。Filter 細節都訂好之後,透過 CFactoryTemplate 結 構 , 我 們 在 類 別 工 廠 創 建 我 們 的 Filter , 包 括 名 字 (FaceDetect) 、 CLSID(CLSID_FaceDetect)、類別創建函式(CFDFilter::CreateInstanc)等。接 著我們透過 DllRegisterServer()以及 DllUnregisterServer()兩個必要函式來 幫我們註冊或反註冊以上的結構到註冊表,而這兩個函式的實現只要簡單的調用 AMovieDllRegisterServer2 這個 API 即可,這個 API 是專門給 DirectShow 的 Filter 註冊使用,它會自動幫我們把以上的結構註冊到註冊表。最後再實現入
接著我們講解我們所設定的意義,首先從 Filter 說明開始,我們要實現的 Filter 名稱叫做 FaceDetect,而它有一個 CLSID 叫做 CLSID_FaceDetect,沒有 特別要求優先權所以 Merit 設定為 MERIT_DO_NOT_USE,且這個 Filter 有兩支 Pin(Pin 的資訊在 sudpPins 這個結構中),一個是輸入 Pin 名稱為 Input,一個 是輸出 Pin 名稱為 Output,而這兩支 Pin 支援的主要媒體格式(媒體格式在 sudPinTypes 這個結構中)是視訊格式,且這個視訊格式要是 RGB24 的形式,所 以 我 們 分 別 對 Major Type 和 Minor Type 做 MEDIATYPE_Video 以 及 MEDIASUBTYPE_RGB24 的設定。Filter 細節都訂好之後,透過 CFactoryTemplate 結 構 , 我 們 在 類 別 工 廠 創 建 我 們 的 Filter , 包 括 名 字 (FaceDetect) 、 CLSID(CLSID_FaceDetect)、類別創建函式(CFDFilter::CreateInstanc)等。接 著我們透過 DllRegisterServer()以及 DllUnregisterServer()兩個必要函式來 幫我們註冊或反註冊以上的結構到註冊表,而這兩個函式的實現只要簡單的調用 AMovieDllRegisterServer2 這個 API 即可,這個 API 是專門給 DirectShow 的 Filter 註冊使用,它會自動幫我們把以上的結構註冊到註冊表。最後再實現入