背景差法目标识别python_运动目标检测(4)—背景差分法
背景減法利用圖像序列中的當(dāng)前幀和事先確定的背景參考模型間的差異比較,來確定運(yùn)動物體位置,是一種基于統(tǒng)計(jì)學(xué)原理的運(yùn)動目標(biāo)檢測的方法。這種方法的性能取決于背景建模技術(shù),Gloyer等人使用單高斯模型的思路,但常常不能準(zhǔn)確地描述背景模型。
1999年Stauffer等人提出了經(jīng)典的混合高斯背景建模法,這種方法不僅對復(fù)雜場景的適應(yīng)強(qiáng),而且能通過自動計(jì)算的模型參數(shù)來對背景模型調(diào)整,雖然增加了高斯分布的個數(shù),造成計(jì)算量增大,但檢測速度很快,且檢測準(zhǔn)確,容易實(shí)現(xiàn)。基于混合高斯模型建模的背景減法已是運(yùn)動檢測的主流方法。OpenCv中有三種三種比較容易使用的方法。
1. BackgroundSubtractorMOG
這是一個以混合高斯模型為基礎(chǔ)的前景/背景分割算法。它是 P.KadewTraKuPong和 R.Bowden 在 2001 年提出的。它使用 K(K=3 或 5)個高斯分布混合對背景像素進(jìn)行建模。使用這些顏色(在整個視頻中)存在時間的長短作為混合的權(quán)重。背景的顏色一般持續(xù)的時間最長,而且更加靜止。一個像素怎么會有分布呢?在 x,y 平面上一個像素就是一個像素沒有分布,但是我們現(xiàn)在講的背景建模是基于時間序列的,因此每一個像素點(diǎn)所在的位置在整個時間序列中就會有很多值,從而構(gòu)成一個分布。
在編寫代碼時,我們需要使用函數(shù)cv2.createBackgroundSubtractorMOG()創(chuàng)建一個背景對象。這個函數(shù)有些可選參數(shù),比如要進(jìn)行建模場景的時間長度,高斯混合成分的數(shù)量,閾值等。將他們?nèi)吭O(shè)置為默認(rèn)值。然后在整個視頻中 我們是需要使用 backgroundsubtractor.apply() 就可以得到前景的掩模了。
2. BackgroundSubtractorMOG2
這個也是以高斯混合模型為基礎(chǔ)的背景/前景分割算法。它是以 2004 年和 2006 年 Z.Zivkovic 的兩篇文章為基礎(chǔ)的。這個算法的一個特點(diǎn)是它為每一個像素選擇一個合適數(shù)目的高斯分布。(上一個方法中我們使用是 K 高斯分布)。這樣就會對由于亮度等發(fā)生變化引起的場景變化產(chǎn)生更好的適應(yīng)。
和前面一樣我們需要創(chuàng)建一個背景對象。但在這里我們我們可以選擇是否檢測陰影。如果 detectShadows = True(默認(rèn)值),它就會檢測并將影子標(biāo)記出來,但是這樣做會降低處理速度。影子會被標(biāo)記為灰色。
3. BackgroundSubtractorGMG
此算法結(jié)合了靜態(tài)背景圖像估計(jì)和每個像素的貝葉斯分割。這是 2012 年Andrew_B.Godbehere,Akihiro_Matsukawa 和 Ken_Goldberg 在文章中提出的。
它使用前面很少的圖像(默認(rèn)為前 120 幀)進(jìn)行背景建模。使用了概率前景估計(jì)算法(使用貝葉斯估計(jì)鑒定前景)。這是一種自適應(yīng)的估計(jì),新觀察到的對象比舊的對象具有更高的權(quán)重,從而對光照變化產(chǎn)生適應(yīng)。一些形態(tài)學(xué)操作如開運(yùn)算閉運(yùn)算等被用來除去不需要的噪音。在前幾幀圖像中你會得到一個黑色窗口。
對結(jié)果進(jìn)行形態(tài)學(xué)開運(yùn)算對與去除噪聲很有幫助。
4. 三種方法的效果
代碼實(shí)現(xiàn)如下:
import numpy as np
import cv2
import imageio
cap = cv2.VideoCapture("E:/opencv_vs/opencv/sources/samples/data/vtest.avi")
fgbg1 = cv2.bgsegm.createBackgroundSubtractorMOG()
fgbg2 = cv2.createBackgroundSubtractorMOG2()
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
fgbg3 = cv2.bgsegm.createBackgroundSubtractorGMG(60) # initializationFrames=120
# 保存gif參數(shù)設(shè)置
gif1 = 'E:/video/v1.gif'
gif2 = 'E:/video/v2.gif'
gif3 = 'E:/video/v3.gif'
frames1 = []
frames2 = []
frames3 = []
while True:
ret, frame = cap.read()
if not ret:
print('not found')
break
frame = cv2.resize(frame, (400, 400), interpolation=cv2.INTER_CUBIC)
# 前景掩碼
fgmask1 = fgbg1.apply(frame)
fgmask2 = fgbg2.apply(frame)
fgmask3 = fgbg3.apply(frame)
fgmask4 = cv2.morphologyEx(fgmask3, cv2.MORPH_OPEN, kernel, iterations=1) # 形態(tài)學(xué)開運(yùn)算
cv2.imshow('frame1', fgmask1)
cv2.imshow('frame2', fgmask2)
cv2.imshow('frame3', fgmask3)
cv2.imshow('frame4', fgmask4)
# 加入幀
frames1.append(fgmask1)
frames2.append(fgmask2)
frames3.append(fgmask4)
# 保存gif
imageio.mimsave(gif1, frames1, 'GIF', duration=0.1)
imageio.mimsave(gif2, frames2, 'GIF', duration=0.1)
imageio.mimsave(gif3, frames3, 'GIF', duration=0.1)
k = cv2.waitKey(100) & 0xff
if k == 27 or k == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
BackgroundSubtractorMOGBackgroundSubtractorMOG2BackgroundSubtractorGMG(噪聲未保存到)BackgroundSubtractorGMG(經(jīng)形態(tài)學(xué)運(yùn)算)
下面是采用BackgroundSubtractorGMG方法處理選取的兩組圖片BackgroundSubtractorGMG原圖1BackgroundSubtractorGMG修圖1BackgroundSubtractorGMG原圖2BackgroundSubtractorGMG修圖2
5. 檢測運(yùn)動目標(biāo)
運(yùn)動目標(biāo)檢測流程圖
代碼實(shí)現(xiàn)如下:
#使用BackgroundSubtractorMOG
import cv2 as cv
import numpy as np
# 設(shè)置文件
file_test = "E:/opencv_vs/opencv/sources/samples/data/vtest.avi"
cap = cv.VideoCapture(file_test)
# 設(shè)置變量
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (2, 2)) # 定義結(jié)構(gòu)元素
color_m = (255, 0, 0)
# 背景差法
fgbg = cv.bgsegm.createBackgroundSubtractorMOG()
# 視頻文件輸出參數(shù)設(shè)置
out_fps = 12.0 # 輸出文件的幀率
fourcc = cv.VideoWriter_fourcc('M', 'P', '4', '2')
out = cv.VideoWriter('E:/video/v9.avi', fourcc, out_fps, (500, 500))
while True:
# 讀取一幀
ret, frame = cap.read()
# 如果視頻結(jié)束,跳出循環(huán)
if not ret:
break
frame = cv.resize(frame, (500, 500), interpolation=cv.INTER_CUBIC)
frame_motion = frame.copy()
# 計(jì)算前景掩碼
fgmask = fgbg.apply(frame_motion)
draw1 = cv.threshold(fgmask, 25, 255, cv.THRESH_BINARY)[1] # 二值化
draw1 = cv.dilate(draw1, kernel, iterations=1)
# 查找檢測物體的輪廓,只檢測外輪廓,只需4個點(diǎn)來保存輪廓信息
image_m, contours_m, hierarchy_m = cv.findContours(draw1.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in contours_m:
if cv.contourArea(c) < 300:
continue
(x, y, w, h) = cv.boundingRect(c)
cv.rectangle(frame_motion, (x, y), (x + w, y + h), color_m, 2)
cv.imshow("source", frame_motion)
cv.imshow("apply", fgmask)
cv.imshow("draw", draw1)
k = cv.waitKey(200)
if k == ord('q'):
break
out.write(frame_motion) # 保存
out.release()
cap.release()
cv.destroyAllWindows()
運(yùn)動目標(biāo)檢測https://www.zhihu.com/video/1016748414142455808
6. 參考資料
[1]opencv官網(wǎng)教程
總結(jié)
以上是生活随笔為你收集整理的背景差法目标识别python_运动目标检测(4)—背景差分法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python- re模块(正则表达式)
- 下一篇: jvm 性能调优之 jmap