文章转载自https://zhuanlan.zhihu.com/p/67935932,如需了解更多,请查看原文。
概述
✔️ 背景减除(Background Subtraction)是许多基于计算机视觉的任务中的主要预处理步骤。
✔️ 如果有完整的静止的背景帧,可以通过帧差法来计算像素差从而获取到前景对象。但是在大多数情况下,没有这样的图像,所以需要从拥有的任何图像中提取背景。当运动物体有阴影时,由于阴影也在移动,情况会变的变得更加复杂。为此引入了背景减除算法,通过这一方法我们能够从视频中分离出运动的物体前景,从而达到目标检测的目的。
背景消除
✔️ OpenCV中常用的两种背景消除方法,一种是基于高斯混合模型GMM实现的背景提取,另外一种是基于最近邻KNN实现的。
GMM模型
背景:
- MOG2算法,高斯混合模型分离算法,基于Z.Zivkovic发布的两篇论文,即2004年发布的“Improved adaptive Gausian mixture model for background subtraction”和2006年发布的“Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction”中提出
- 它为每个像素选择适当数量的高斯分布,它可以更好地适应不同场景的照明变化等
API:
cv2.createBackgroundSubtractorMOG2(
int history = 500,
double varThreshold = 16,
bool detectShadows = true
)
参数解释如下: - history表示过往帧数,500帧,选择history = 1就变成两帧差 - varThreshold表示像素与模型之间的马氏距离,值越大,只有那些最新的像素会被归到前景,值越小前景对光照越敏感。 - detectShadows 是否保留阴影检测,请选择False这样速度快点。
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."中提出。
API:
cv2.createBackgroundSubtractorKNN()
实例分析
背景
✔️ 引用Opencv官方Example里的视频 vtest.mp4 来实现背景消除和ROI行人提取。
方法
✔️ 主要通过视频中的背景进行建模,实现背景消除,生成mask图像,通过对mask二值图像分析实现对前景活动对象的区域的提取,整个步骤如下: 1. 初始化背景建模对象GMM 2. 读取视频一帧 3. 使用背景建模消除生成mask 4. 对mask进行轮廓分析提取ROI 5. 绘制ROI对象
代码
import numpy as np
import cv2
# read the video
cap = cv2.VideoCapture('vtest.avi')
# create the subtractor
fgbg = cv2.createBackgroundSubtractorMOG2(
history=500, varThreshold=100, detectShadows=False)
def getPerson(image, opt=1):
# get the front mask
mask = fgbg.apply(frame)
# eliminate the noise
line = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 5), (-1, -1))
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, line)
cv2.imshow("mask", mask)
# find the max area contours
out, contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in range(len(contours)):
area = cv2.contourArea(contours[c])
if area < 150:
continue
rect = cv2.minAreaRect(contours[c])
cv2.ellipse(image, rect, (0, 255, 0), 2, 8)
cv2.circle(image, (np.int32(rect[0][0]), np.int32(rect[0][1])), 2, (255, 0, 0), 2, 8, 0)
return image, mask
while True:
ret, frame = cap.read()
cv2.imwrite("input.png", frame)
cv2.imshow('input', frame)
result, m_ = getPerson(frame)
cv2.imshow('result', result)
k = cv2.waitKey(50)&0xff
if k == 27:
cv2.imwrite("result.png", result)
cv2.imwrite("mask.png", m_)
break
cap.release()
cv2.destroyAllWindows()
Input
Front Mask
Result