王若宇



摘 要:為了從一些復雜的場景中提取出人像,用到的開源代碼有很多,其均假設若一個像素的顏色在較長時間內變化不大,則認為它是背景。但是,這些開源代碼在用于一些自拍攝像頭時效果較差,因為當一個人端坐在攝像頭前,他的像素不會發生很大變化。因此,本文提出了另外一種算法,該算法基于如下假設:在背景建模期間前景不會出現,且背景建模結束后,背景的變化始終為建模期間背景變化的子集。這種非動態的算法適用于提取距離攝像頭距離更近的對象。
關鍵詞:前景提取;前景檢測;背景建模
Abstract: In order to extract human images from some complex scenes, many open source codes are used, which assume that if the color of a pixel does not change much in a long time, it is considered as the background. However, these open source codes are not very effective for some self timer cameras, because when a person sits in front of the camera, his pixels will not change greatly. Therefore, this paper proposed another algorithm, which was based on the following assumption: the foreground would not appear during the background modeling, and after the background modeling, the background change was always a subset of the background change during the modeling. This non dynamic algorithm is suitable for extracting objects closer to the camera.
Keywords: foreground extraction;foreground detection;background modeling
1 算法設計
1.1 算法思路
由于是從攝像頭采集的圖像,因此其有BGR三個通道,每個通道的值為[0,255]。為每一個像素的每一個通道創建一個編碼本(CodeBook[1]),編碼本中儲存有若干個碼元(CodeElement),一個碼元中儲存一個區間。在前景檢測階段,若某一像素的三個通道都落在對應編碼本的任一碼元里,則認為它是背景;否則,認為它是前景。據此得到掩模,然后利用形態學開閉操作、輪廓檢測、凸包運算等消除噪聲,優化掩模效果。
創建編碼本和碼元的思路在數據結構介紹中解釋。
1.2 數據結構介紹
1.2.1 碼元(CodeElement)。創建碼元的代碼如下:
1.2.2 編碼本(CodeBook)。創建編碼本的代碼如下:
其中,learnHigh和learnLow表示一個學習閾值。在背景建模階段,對輸入圖像的每一個像素的每一通道,遍歷其編碼本中的碼元,如果該通道的值在某個碼元中,則跳過;如果該通道的值雖然不在某個碼元中,但它在(Min-learnLow)~(Max+learnHigh)中,則表示該碼元應該學習這個像素,因此應擴大碼元的區間使之包含這個像素。若該通道的值不滿足上述兩個條件,則應該為它的編碼本新建一個碼元,并使碼元的Max和Min初始值為該通道的值。
1.2.3 編碼本索引。編碼本索引為codeBooks[]。其本質為Python中的一個列表。它的元素個數為像素數乘以通道數。本來使用三維數組來儲存可能會更為直觀,但列表并不支持。列表的index與圖像的位置和通道的映射關系為:
1.3 核心代碼介紹
1.3.1 創建編碼本。創建編碼本的函數代碼如下:
在開始算法時,所需采集的圖像信息已經確定,因此編碼本數量已經確定。按照設計的順序向編碼本索引中添加所有編碼本,以便之后對其進行操作。
該函數的參數依次為三個通道的學習上限和學習下限。
1.3.2 更新編碼本。更新編碼本的函數代碼如下:
建模的核心代碼用于建模時更新各個編碼本中的碼元。根據輸入的圖像數據,有選擇地新建碼元或者擴大碼元范圍。
該函數的參數為當前像素在當前通道的顏色和索引。
1.3.3 清除不常用的碼元。清除不常用的碼元的函數代碼如下:
將更新時間很久遠的碼元清除,以便減少碼元數量,提高代碼效率。但是,本次算法由于效率較低,建模數量本身就比較小,而且維護碼元更新時間需要大量開銷,因此暫時不用這個函數。
1.3.4 計算掩模。計算掩模的函數代碼如下:
根據輸入的顏色數值及其索引,判斷該數值是否在索引指向的編碼本的某一碼元中,若是,則返回True,否則返回False。
該函數的參數為當前像素在當前通道的顏色和索引。
返回值為表明輸入顏色是否在輸入索引所指向的編碼本中的布爾型值。
1.3.5 主函數循環流程設計
1.3.5.1 建模。設置變量frameNum記錄當前幀數,若幀數小于事先設置的createdFrame變量,則表示該幀用于建模,用如下三層循環對該幀所有像素的三個通道遍歷,均調用updateCodeBook()函數更新其編碼本:
1.3.5.2 顯示。當幀數frameNum大于事先設置的createdFrame變量時,表示該幀用于顯示。使用如下三層循環尋找掩模:
從圖1可以看到,其存在大量噪聲,因此需要用形態學方法對其進行處理。
1.3.5.3 優化處理。優化處理步驟如下。
第一步,進行開閉操作初步去除噪聲,代碼如下。
從圖2可知,仍有部分噪聲,且手邊界被腐蝕。
為了查看目前效果,設置建模幀數為100,并在建模時有意將手出現在建模范圍內,但并不一直出現。將處理后掩模對應原視頻幀輸出,效果如圖3所示。
從圖3可知,雖然效果不錯,但需要的建模時間較長(1 min),且建模時要刻意將手出現在視頻里,調節建模效果。
分析20幀建模結果發現,噪聲周長遠小于識別目標。結合分析100幀建模結果發現,手的邊界被腐蝕了部分,應該據此進行進一步處理。
第二步,消除小輪廓,用凸包運算填充大輪廓。
圖4中兩種風格的圖像都是在同一模型下識別的。由于研究者使用的攝像頭會在畫面較暗時調整相關參數,變為下面的圖像風格,正好可以用于測試編碼本算法對背景有很大影響但規律變化時的效果。在建模時,刻意調整攝像頭相關參數,將上下兩圖的風格都加入模型中。而后在前景檢測階段,無論攝像頭在哪種風格下,都可以準確識別前景。但是,由于凸包運算使得下邊掩模丟失部分細節。若檢測范圍較大,這些細節可以被忽視。
1.4 代碼內參數介紹
video為前景的視頻來源。backGround為背景的視頻來源。smallContour為區分大小輪廓的閾值,周長小于該值為小輪廓,否則為大輪廓。createdFrame為用于建模的幀數。width為由于算法效率太低,只能處理小范圍圖像,用該值規定處理的寬度;height為由于算法效率太低,只能處理小范圍圖像,用該值規定處理的高度,具體是取視頻左上角該大小的圖像,即坐標為[0:height][0:width]的像素。changeNum用于元組擴大范圍時,不但包含傳入的顏色,而且進一步根據該值擴大范圍。基于如下猜測:當顏色color為背景時,[color-changeNum,color+changeNum]都可能為背景。函數creatCodeBook(10, 10, 10, 10, 10, 10)的參數為各個通道的學習閾值。該值越大元組范圍越大,元組數目越少。
2 算法特點總結
使用Python實現一個簡單的編碼本算法。但是,不動態更新編碼本,而是與背景減除的思想結合,在程序開始時建模,期待用戶將盡可能多的背景情況包含在模型中,又不出現前景。這個條件雖然苛刻,但是有其道理:在只根據當前攝像頭輸入運行算法的情況下(即沒有現成的模型,沒有約定的背景或者前景顏色),若一個人端坐在攝像頭前,其衣服上的像素顏色變化范圍將很小,與背景顏色變化規律幾乎是一致的,因此,若建模的時候出現前景,很難將它與背景區別開。
本算法適用于背景規律變化的情況,在建模階段獲取的全部信息都可以在前景檢測階段被成功識別為背景。
此外,對編碼本算法做了些許修改,比如,每像素的每個通道一個編碼本,而不是每像素一個編碼本;學習閾值儲存在編碼本中而不是碼元中等。
本算法未針對前景出現后背景的變化進行計算(如前景的陰影,或前景出現后攝像頭自動調節亮度)。攝像頭自動調節亮度的問題可通過將視頻轉化為YUV通道,然后增大V通道的changeNum和學習閾值來改善。
參考文獻:
[1]Gary Bradski,Adrian Kaehler.Learning Opencv[M].北京:清華大學出版社,2009.