進行運動物體檢測就是將動態的前景從靜態的背景中分離出來。將當前畫面與假設是靜態背景進行比較發現有明顯的變化的區域,就能夠認爲該區域出現移動的物體。在實際狀況中因爲光照陰影等因素干擾比較大,經過像素直接進行比較每每很容易形成誤檢。所以有很多算法被開發出來在進行先後景分離的時候對運動和其餘因素形成的變更進行區分。opencv中提供了多種背景減除的算法,其中基於高斯混合模型(GMM)的cv2.BackgroundSubtractorMOG()
和cv2.BackgroundSubtractorMOG2()
已經基於貝葉斯模型的cv2.bgsegm.createBackgroundSubtractorGMG()
最爲經常使用。html
GMM進行先後景分離最先是在2001年的文章An improved adaptive background mixture model for real-time tracking with shadow detection
中提出的。其設計思路爲:python
cv2.BackgroundSubtractorMOG()
的函數就是對次方法的實現。基於2004年提出的Improved adaptive Gausian mixture model for background subtractio
和2006年提出的Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction
算法對上述GMM算法進行改良的就是opencv的cv2.BackgroundSubtractorMOG2()
的函數。主要的提高是對每一個像素都選擇合適數量的高斯分佈而非原來的所有相同的個數。此外,這個函數還容許是否檢測陰影。android
使用方法(以MOG2爲例)算法
import cv2 cam = cv2.VideoCapture(0) fgbg = cv2.createBackgroundSubtractorMOG() while cam.isOpened(): ret, frame = cam.read() if ret: fgmask = fgbg.apply(frame) # 經過腐蝕和膨脹過濾一些噪聲 erode = cv2.erode(fgmask, (21, 21), iterations=1) dilate = cv2.dilate(fgmask, (21, 21), iterations=1) (_, cnts, _) = cv2.findContours(dilate.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in cnts: c_area = cv2.contourArea(c) if c_area < 1600 or c_area > 16000: # 過濾過小或太大的運動物體,這類誤檢機率比較高 continue (x, y, w, h) = cv2.boundingRect(c) cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2) cv2.imshow("origin", frame) if cv2.waitKey(1) == ord('q'): break cv2.destroyAllWindows()
根據2012年的文章Visual Tracking of Human Visitors under Variable-Lighting Conditions for a Responsive Audio Art Installation
, opencv開發了相應的函數cv2.bgsegm.createBackgroundSubtractorGMG()
(好像在3.2中被放到了contrib中,在以前能夠直接用cv2.createBackgroundSubtractorGMG()
進行調用)。這個方法默認使用前120張圖片進行背景的建模,並使用機率前景分割算法找到可能的前景(基於貝葉斯推測)。爲了更好適應不一樣光照變化的影響,新的圖片的權重比舊圖片要高。app
使用方法ide
cam = cv2.VideoCapture(0) kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (8, 8)) fgbg = cv2.bgsegm.createBackgroundSubtractorGMG(initializationFrames=10) while cam.isOpened(): ret, frame = cam.read() if ret: fgmask = fgbg.apply(frame) fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel) # 過濾噪聲 (_, cnts, _) = cv2.findContours(dilate.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in cnts: c_area = cv2.contourArea(c) if c_area < 1600 or c_area > 16000: # 過濾過小或太大的運動物體,這類誤檢機率比較高 continue (x, y, w, h) = cv2.boundingRect(c) cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2) cv2.imshow("origin", frame) if cv2.waitKey(1) == ord('q'): break cv2.destroyAllWindows()