從本次教程開始,我們進入新的篇章,之前一直在討論OpenCV的特征部分,這次我們來討論OpenCV中的背景分離,又稱背景減法模型。
背景分離(BS)是一種通過使用靜態相機來生成前景掩碼(即包含屬於場景中的移動對象像素的二進制圖像)的常用技術。
顧名思義,BS計算前景掩碼,在當前幀與背景模型之間執行減法運算,其中包含場景的靜態部分,或者更一般而言,考慮到所觀察場景的特征,可以將其視為背景的所有內容。
背景建模包括兩個主要步驟:
1. 背景初始化;
2. 背景更新。
初步,計算背景的初始模型,而在第二步中,更新模型以適應場景中可能的變化。
在本教程中,我們將學習如何使用OpenCV中的BS。
OpenCV中的使用
OpenCV 中已經包含了其中三種比較容易使用的方法,我們逐一來看。
BackgroundSubtractorMOG
這是一個以混合高斯模型為基礎的前景/背景分割算法。它是 P.KadewTraKuPong 和 R.Bowden 在 2001 年提出的。
它使用 K(K=3 或 5)個高斯分布混合對背景像素進行建模。使用這些顏色(在整個視頻中)存在時間的長短作為混合的權重。背景的顏色一般持續的時間最長,而且更加靜止。
一個像素怎么會有分布呢?在 x,y平面上一個像素就是一個像素,沒有分布,但是我們現在講的背景建模是基於時間序列的,因此每一個像素點所在的位置在整個時間序列中就會有很多值,從而構成一個分布
在編寫代碼時,我們需要使用函數:cv2.createBackgroundSubtractorMOG() 創建一個背景對象。這個函數有些可選參數,比如要進行建模場景的時間長度,高斯混合成分的數量,閾值等。將他們全部設置為默認值。然后在整個視頻中我們是需要使用backgroundsubtractor.apply() 就可以得到前景的掩模了
移動的物體會被標記為白色,背景會被標記為黑色的,前景的掩模就是白色的了。
不過目前這個方法已經被棄用了,OpenCV中也沒有了相關函數的API。
BackgroundSubtractorMOG2
這個也是以高斯混合模型為基礎的背景/前景分割算法。它是以 2004 年 和 2006 年 Z.Zivkovic 的兩篇文章為基礎的。這個算法的一個特點是它為每 一個像素選擇一個合適數目的高斯分布。(上一個方法中我們使用是 K 高斯分布)。
這樣就會對由於亮度等發生變化引起的場景變化產生更好的適應。
和前面一樣我們需要創建一個背景對象。但在這里我們我們可以選擇是否檢測陰影。如果 detectShadows = True(默認值),它就會檢測並將影子標記出來,但是這樣做會降低處理速度。影子會被標記為灰色。
BackgroundSubtractorMOG2算法的兩個改進點:
-陰影檢測
-速度快了一倍
我們將使用官方提供的人體跟蹤的視頻:
這個我提供在這兒:
我們來看代碼:
def MOG2(): cap = cv2.VideoCapture("test.avi") fgbg = cv2.createBackgroundSubtractorMOG2() while (1): ret, frame = cap.read() fgmask = fgbg.apply(frame) cv2.imshow('frame', fgmask) k = cv2.waitKey(100) & 0xff if k == 27: break cap.release() cv2.destroyAllWindows()
結果:
可以看到基本的行人與背景分離出來了。
BackgroundSubtractorGMG
此算法結合了靜態背景圖像估計和每個像素的貝葉斯分割。這是 2012 年 Andrew_B.Godbehere,Akihiro_Matsukawa 和 Ken_Goldberg 在文章 中提出的。
它使用前面很少的圖像(默認為前 120 幀)進行背景建模。使用了概率前 景估計算法(使用貝葉斯估計鑒定前景)。這是一種自適應的估計,新觀察到的 對象比舊的對象具有更高的權重,從而對光照變化產生適應。一些形態學操作 如開運算閉運算等被用來除去不需要的噪音。在前幾幀圖像中你會得到一個黑 色窗口。
對結果進行形態學開運算對與去除噪聲很有幫助。
不過同樣的,這個方法目前也是不再用了。
BackgroundSubtractorKNN
KNN作為大名鼎鼎的機器學習算法,其用在背景分離應用中也是得心應手,但是在此不對KNN作過多的解釋,它屬於機器學習的一個算法,比較復雜,我們來看代碼:
def KNN(): cap = cv2.VideoCapture('test.avi') fgbg = cv2.createBackgroundSubtractorKNN() while (1): ret, frame = cap.read() fgmask = fgbg.apply(frame) cv2.imshow('frame', fgmask) k = cv2.waitKey(100) & 0xff if k == 27: break cap.release() cv2.destroyAllWindows()
結果:
實驗結果發現KNN的結果要明顯優於MOG2算法。