背景減除(Background Subtraction)是許多基于計算機視覺的任務中的主要預處理步驟瘪阁。如果我們有完整的靜止的背景幀管跺,那么我們可以通過幀差法來計算像素差從而獲取到前景對象伙菜。但是在大多數(shù)情況下贩绕,我們可能沒有這樣的圖像壶愤,所以我們需要從我們擁有的任何圖像中提取背景。當運動物體有陰影時娇哆,由于陰影也在移動,情況會變的變得更加復雜碍讨。為此引入了背景減除算法蒙秒,通過這一方法我們能夠從視頻中分離出運動的物體前景覆获,從而達到目標檢測的目的弄息。 OpenCV已經(jīng)實現(xiàn)了幾種非常容易使用的算法摹量。
環(huán)境
- Python 3.6
- OpenCV 3.2 + contrib
在Python下可以通過直接導入wheel包來安裝opencv+contrib,可以從下面這個網(wǎng)址下載對應的文件:opencv_python?3.2.0+contrib?cp36?cp36m?win_amd64.whl
http://www.lfd.uci.edu/~gohlke/pythonlibs/
KNN
KNN算法,即K-nearest neigbours - based Background/Foreground Segmentation Algorithm。2006年缨称,由Zoran Zivkovic 和Ferdinand van der Heijden在論文"Efficient adaptive density estimation per image pixel for the task of background subtraction."中提出废亭。
bs = cv2.createBackgroundSubtractorKNN(detectShadows=True)
fg_mask = bs.apply(frame)
MOG
MOG算法,即高斯混合模型分離算法具钥,全稱Gaussian Mixture-based Background/Foreground Segmentation Algorithm豆村。2001年,由P.KadewTraKuPong和R.Bowden在論文“An improved adaptive background mixture model for real-time tracking with shadow detection”中提出骂删。它使用一種通過K高斯分布的混合來對每個背景像素進行建模的方法(K = 3?5)掌动。
bs = cv2.bgsegm.createBackgroundSubtractorMOG(history=history)
bs.setHistory(history)
fg_mask = bs.apply(frame)
MOG2
MOG2算法,也是高斯混合模型分離算法宁玫,是MOG的改進算法粗恢。它基于Z.Zivkovic發(fā)布的兩篇論文,即2004年發(fā)布的“Improved adaptive Gausian mixture model for background subtraction”和2006年發(fā)布的“Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction”中提出佛掖。該算法的一個重要特征是 它為每個像素選擇適當數(shù)量的高斯分布,它可以更好地適應不同場景的照明變化等。
bs = cv2.createBackgroundSubtractorMOG2(history=history, detectShadows=True)
bs.setHistory(history)
fg_mask = bs.apply(frame)
GMG
該算法結(jié)合統(tǒng)計背景圖像估計和每像素貝葉斯分割。由 Andrew B. Godbehere, Akihiro Matsukawa, Ken Goldberg在2012年的文章“Visual Tracking of Human Visitors under Variable-Lighting Conditions for a Responsive Audio Art Installation”中提出焊切。該算法使用前幾個(默認為120)幀進行后臺建模。它采用概率前景分割算法,使用貝葉斯推理識別可能的前景對象芽死。
bs = cv2.bgsegm.createBackgroundSubtractorGMG(initializationFrames=history)
fg_mask = bs.apply(frame)
使用KNN根據(jù)前景面積檢測運動物體
代碼:
# coding:utf8
import cv2
def detect_video(video):
camera = cv2.VideoCapture(video)
history = 20 # 訓練幀數(shù)
bs = cv2.createBackgroundSubtractorKNN(detectShadows=True) # 背景減除器落萎,設置陰影檢測
bs.setHistory(history)
frames = 0
while True:
res, frame = camera.read()
if not res:
break
fg_mask = bs.apply(frame) # 獲取 foreground mask
if frames < history:
frames += 1
continue
# 對原始幀進行膨脹去噪
th = cv2.threshold(fg_mask.copy(), 244, 255, cv2.THRESH_BINARY)[1]
th = cv2.erode(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)), iterations=2)
dilated = cv2.dilate(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (8, 3)), iterations=2)
# 獲取所有檢測框
image, contours, hier = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
# 獲取矩形框邊界坐標
x, y, w, h = cv2.boundingRect(c)
# 計算矩形框的面積
area = cv2.contourArea(c)
if 500 < area < 3000:
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow("detection", frame)
cv2.imshow("back", dilated)
if cv2.waitKey(110) & 0xff == 27:
break
camera.release()
if __name__ == '__main__':
video = 'person.avi'
detect_video(video)
效果: