Python使用背景差分器實現(xiàn)運動物體檢測
前言
目前,許多運動檢測技術(shù)都是基于簡單的背景差分概念的,即假設(shè)攝像頭(視頻)的曝光和場景中的光照條件是穩(wěn)定的,當攝像頭捕捉到新的幀時,我們可以從參考圖像中減去該幀,并取這個差的絕對值,以獲得幀中每個像素位置的運動測量值。如果幀的任何區(qū)域與參考圖像有很大的不同,我們就認為給定區(qū)域中是一個運動物體。
本文主要簡單介紹基本背景差分器,詳細介紹MOG背景差分器,KNN背景差分器。
一、基本背景差分器
首先,基本背景差分器可以很好地實現(xiàn)運動物體的檢測,代碼實現(xiàn)參考此鏈接
其特點是:此腳本不會動態(tài)更新背景圖像,即當一個運動的物體靜止后,此腳本仍然會標記此物體,除非此物體消失在窗口中,甚至當攝像頭運動或者光線變化時,此腳本會直接標記整個窗口直到程序結(jié)束。
如果我們希望腳本能夠動態(tài)的更新背景模型,即當運動物體靜止后,靜止物體會被納入背景,標記會逐漸消失,這時,我們就可以采用更靈活、更智能的背景差分器(如MOG背景差分器、KNN背景差分器)。
二、MOG背景差分器
OpenCV提供了一個名為 cv2.BackgroundSubtractor 的類,它有實現(xiàn)各種背景差分算法的子類。
對于MOG背景差分器,OpenCV有兩種實現(xiàn),分別命名為:cv2.BackgroundSubtractorMOG 和 cv2.BackgroundSubtractorMOG2,后者是最新改進的實現(xiàn),增加了對陰影檢測的支持,我們將使用它。
流程
1.導入OpenCV,初始化MOG背景差分器,定義erode(腐蝕)、dilate(膨脹)運算的核大小
import cv2 bg_subtractor = cv2.createBackgroundSubtractorMOG2(detectShadows=True) erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
初始化函數(shù)中接收一個參數(shù)detectShadows,將其設(shè)置為True,就會標記出陰影區(qū)域,而不會標記為前景的一部分。
使用腐蝕與膨脹的形態(tài)學操作是為了抑制一些細微的振動頻率。
2.捕捉攝像頭幀,并使用MOG差分器獲得背景掩膜
cap = cv2.VideoCapture(0)
success, frame = cap.read()
while success:
fg_mask = bg_subtractor.apply(frame)
當我們把每一幀傳遞給背景差分器的 apply 方法時,差分器就會更新它的內(nèi)部背景模型,然后返回一個掩膜。
其中,前景部分的掩膜是白色(255),陰影部分的掩膜是灰色(127),背景部分的掩膜是黑色(0)
3.然后對掩膜應(yīng)用閾值來獲得純黑白圖像,并通過形態(tài)學運算對閾值化圖像進行平滑處理。
_, thresh = cv2.threshold(fg_mask, 244, 255, cv2.THRESH_BINARY)
cv2.erode(thresh, erode_kernel, thresh, iterations=2)
cv2.dilate(thresh, dilate_kernel, thresh, iterations=2)
(本示例中,我們開啟了陰影檢測,但我們?nèi)匀幌氚殃幱罢J為是背景,所以對掩膜應(yīng)用一個接近白色(244)的閾值)
4.現(xiàn)在,如果我們直接查看閾值化后的圖像,會發(fā)現(xiàn)運動物體呈現(xiàn)白色斑點,我們想找到白色斑點的輪廓,并在其周圍繪制輪廓。其中,我們將應(yīng)用一個基于輪廓面積的閾值,如果輪廓太小,就認為它不是真正的運動物體(或者不使用此閾值),檢測輪廓與繪制邊框的代碼:
contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) > 1000:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 255, 0), 2)
5.顯示掩膜圖像/閾值化圖像/檢測結(jié)果圖像,繼續(xù)讀取幀,直到按下ESC退出。
cv2.imshow('mog', fg_mask)
cv2.imshow('thresh', thresh)
cv2.imshow('detection', frame)
k = cv2.waitKey(30)
if k == 27: # Escape
break
success, frame = cap.read()
代碼編寫
import cv2
OPENCV_MAJOR_VERSION = int(cv2.__version__.split('.')[0])
bg_subtractor = cv2.createBackgroundSubtractorMOG2(detectShadows=True)
erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
cap = cv2.VideoCapture(0)
success, frame = cap.read()
while success:
fg_mask = bg_subtractor.apply(frame)
_, thresh = cv2.threshold(fg_mask, 244, 255, cv2.THRESH_BINARY)
cv2.erode(thresh, erode_kernel, thresh, iterations=2)
cv2.dilate(thresh, dilate_kernel, thresh, iterations=2)
if OPENCV_MAJOR_VERSION >= 4:
# OpenCV 4 or a later version is being used.
contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
else:
# OpenCV 3 or an earlier version is being used.
# cv2.findContours has an extra return value.
# The extra return value is the thresholded image, which is
# unchanged, so we can ignore it.
_, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if cv2.contourArea(c) > 1000:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 255, 0), 2)
cv2.imshow('mog', fg_mask)
cv2.imshow('thresh', thresh)
cv2.imshow('detection', frame)
k = cv2.waitKey(30)
if k == 27: # Escape
break
success, frame = cap.read()
cap.release()
cv2.destroyAllWindows()
注意:當我們啟用陰影檢測時,我們可以通過一個閾值來移除掩膜上的陰影和反射部分,從而使得檢測能夠準確地框選到實際運動物體(本示例)。如果我們禁用陰影檢測,那么倒影或者反射部分可能都會被框選,從而影響檢測真正運動物體的準確性。
三、KNN背景差分器
通過修改MOG背景差分腳本的很一小部分代碼,即可使用不同的背景差分算法以及不同的形態(tài)學參數(shù)。
1.用cv2.createBackgroundSubtractorKNN替換cv2.createBackgroundSubtractorMOG2,就可以使用基于KNN聚類(而不是MOG聚類)的背景差分器:
bg_subtractor = cv2.createBackgroundSubtractorKNN(detectShadows=True)
(注意:KNN背景差分器仍然支持detectShadows參數(shù)與apply方法)
修改完成之后,就可以使用KNN背景差分器了,可見修改量非常少。
2.當然,此處我們可以使用稍微好點的適應(yīng)于水平細長物體的形態(tài)學核(本例中檢測的是運動的汽車,視頻地址(GitHub,可下載):traffic.flv),并使用此視頻作為輸入
erode_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 5))
dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (17, 11))
cap = cv2.VideoCapture('E:/traffic.flv')
3.最后一個小細節(jié),我們將掩膜窗口標題從“mog”更改為“knn”
cv2.imshow('knn', fg_mask)
到此這篇關(guān)于Python使用背景差分器實現(xiàn)運動物體檢測的文章就介紹到這了,更多相關(guān)Python運動物體檢測內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Tensorflow實現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)的詳細代碼
這篇文章主要為大家詳細介紹了Tensorflow實現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)的詳細代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-05-05
python調(diào)用有道智云API實現(xiàn)文件批量翻譯
這篇文章主要介紹了python如何調(diào)用有道智云API實現(xiàn)文件批量翻譯,幫助大家更好得理解和使用python,感興趣的朋友可以了解下2020-10-10
1分鐘快速生成用于網(wǎng)頁內(nèi)容提取的xslt
這篇文章主要教大家如何1分鐘快速生成用于網(wǎng)頁內(nèi)容提取的xslt,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-02-02
Python中魔法參數(shù)?*args?和?**kwargs使用詳細講解
這篇文章主要介紹了Python中魔法參數(shù)?*args?和?**kwargs使用的相關(guān)資料,*args和**kwargs是Python中實現(xiàn)函數(shù)參數(shù)可變性的重要工具,分別用于接受任意數(shù)量的位置參數(shù)和關(guān)鍵字參數(shù),文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-12-12

