
#优质创作者# 基于单高斯视频背景估计的运动目标分割原理与实现 原创 精华
【本文正在参加优质创作者激励计划】
@[toc]
单高斯视频背景估计的运动目标分割
原理
上图为单高斯视频背景估计的运动目标分割流程图,主要包括以下步骤:
(1)单高斯背景模型的初始化。
将背景模型初始化为均值$\mu(x,y)$和方差$\sigma^2(x,y)=1$的高斯分布。
(2)运动目标分割
利用如下公式对当前帧的每个像素点$I^t(x,y)$进行判断,如果像素点的概率值大于阈值$T$:
$$P\left[I^{t}(x, y)\right]=\frac{1}{\sqrt{2 \pi\left[\sigma^{\prime}(x, y)\right]^{2}}} \exp \left{-\frac{\left[I^{t}(x, y)-\mu^{t}(x, y)\right]^{2}}{2\left[\sigma^{\prime}(x, y)\right]^{2}}\right}>T$$
则判定该像素点为背景点,否则为前景点。实际实现中,可以用以下公式代替判断:
$$\left|I(x, y)-\mu^{t}(x, y)\right|<\beta \sigma^{t}(x, y)$$
表示认为正态分布离均值中心$\pm \beta \sigma^{t}(x, y)$范围内的像素点属于背景。在掩码中将属于背景的像素点置零,其他置1,得到运动目标的分割掩码。用掩码对当前帧分割,即可得到运动目标。
(3) 单高斯背景模型的更新
$$\begin{array}{c}
\mu^{t}(x, y)=(1-\alpha) \mu^{t-1}(x, y)+\alpha I^{t}(x, y) \
{\left[\sigma^{t}(x, y)\right]^{2}=(1-\alpha)\left[\sigma^{t-1}(x, y)\right]^{2}+\alpha\left[I^{t}(x, y)-\mu \mu^{t}(x, y)\right]^{2}}
\end{array}$$
式中$\alpha$为更新参数,表示背景更新的速度快慢,取值范围为0~1。 $t-1$表 示 前一 帧,$t$表示当前帧。可以指定到达一定帧数时停止更新。
改进
针对单高斯背景估计算法容易误判背景(将背景点判定为运动目标)的问题,对其进行改进:
(1)使用形态学方法对掩码进行处理,填补掩码的各个非零区域。
(2)对输入进行高斯滤波,平滑输入的图像,从而减少因为形态学处理导致的更明显的掩码误判。
(3) 帧差法:将连续两帧的图像数据进行差分法,即进行相减操作, 如果其相减后的绝对值小于阈值,则认为其为背景点,令像素点变为0。 通过帧差法减少背景点的误判。
结果
代码
import cv2
import numpy as np
np.set_printoptions(precision=2, suppress=True)
beta = 1.5 # 前后景区分常数
alpha = 0.015 # 学习率
# 读取视频
cap = cv2.VideoCapture('高速公路.AVI')
isFirst = True
i = 0
while cap.isOpened():
ret, frame = cap.read()
if frame is not None:
i += 1
print(i)
gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
if i == 1:
mu = np.zeros(gray.shape)
var = np.ones(gray.shape)
last = np.zeros(gray.shape)
else:
# 标识目标
gray = cv2.GaussianBlur(gray, (3, 3), 0, 1)
gray1 = gray.copy()
gray1[np.abs(gray - mu) > beta * np.sqrt(var)] = 1
gray1[np.abs(gray - mu) < beta * np.sqrt(var)] = 0
gray2 = gray1.copy()
kernel = np.ones((3, 3), np.uint8)
kernel2 = np.ones((5, 5), np.uint8)
gray2 = cv2.dilate(gray2, kernel, iterations=3)
gray2 = cv2.erode(gray2, kernel2, iterations=1)
gray2[np.abs(gray - last) < 10] = 0
gray2 = cv2.dilate(gray2, kernel, iterations=1)
# 更新参数
if i<200:
mu = (1 - alpha) * mu + alpha * gray
var = (1 - alpha) * var + alpha * (gray - mu) ** 2
cv2.imshow('RGB', frame)
cv2.imshow('tracking_gray', gray1 * 255)
cv2.imshow('tracking2_gray', gray2 * 255)
cv2.imshow('tracking', np.expand_dims(gray1, -1).repeat(3, axis=2) * frame)
cv2.imshow('tracking2', np.expand_dims(gray2, -1).repeat(3, axis=2) * frame)
cv2.waitKey(0)
last = gray.copy()
if 0xFF == ord('q'):
break
else:
cap = cv2.VideoCapture('高速公路.AVI')
