flyfish
cv2.accumulateWeighted
主要用于实现自适应背景更新。
在视频处理中,背景通常是相对稳定的部分,而前景则是在背景上移动或变化的物体。自适应背景更新的目的是根据视频帧的变化动态地更新背景模型,以适应光照变化、背景缓慢移动等情况。cv2.accumulateWeighted
函数可以帮助我们逐步更新背景模型,使得背景模型能够更好地反映当前的背景状态。
cv2.accumulateWeighted
函数基于加权平均的方法来更新背景模型。对于每一帧视频图像,它会将当前帧与之前存储的背景模型进行加权平均,得到新的背景模型。具体的计算公式如下:
B n e w = α × F + ( 1 − α ) × B o l d B_{new} = \alpha \times F + (1 - \alpha) \times B_{old} Bnew=α×F+(1−α)×Bold
其中:
下面是一个使用 cv2.accumulateWeighted
进行自适应背景更新的示例代码:
import cv2
# 打开视频文件
cap = cv2.VideoCapture('input_video.mp4')
# 读取第一帧作为初始背景
ret, frame = cap.read()
if not ret:
print("无法读取视频帧")
exit()
# 将第一帧转换为灰度图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 创建一个与帧大小相同的背景模型,初始化为第一帧
background = gray.copy().astype("float")
# 定义加权系数
alpha = 0.01
while True:
# 读取下一帧
ret, frame = cap.read()
if not ret:
break
# 将当前帧转换为灰度图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 使用 cv2.accumulateWeighted 更新背景模型
cv2.accumulateWeighted(gray, background, alpha)
# 将背景模型转换为 8 位无符号整数类型
background_vis = cv2.convertScaleAbs(background)
# 计算当前帧与背景模型的差值
diff = cv2.absdiff(gray, background_vis)
# 对差值图像进行阈值处理,得到前景掩码
_, thresh = cv2.threshold(diff, 25, 255, cv2.THRESH_BINARY)
# 显示原始帧、背景模型和前景掩码
cv2.imshow('Original Frame', frame)
cv2.imshow('Background Model', background_vis)
cv2.imshow('Foreground Mask', thresh)
# 按 'q' 键退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放视频捕获对象并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
简单写
import cv2
import numpy as np
video_path = 'input_video.mp4'
cap = cv2.VideoCapture(video_path)
# 初始化背景模型
ret, first_frame = cap.read()
background = np.zeros_like(first_frame[:, :, 0], dtype=np.float32) # 初始化为全0或第一帧
alpha = 0.05 # 学习率
while True:
ret, frame = cap.read()
if not ret:
break
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 转为 float32 类型(与背景模型类型一致)
frame_gray = frame_gray.astype(np.float32)
# 自适应更新背景
cv2.accumulateWeighted(frame_gray, background, alpha)
background_uint8 = background.astype(np.uint8)
# 显示背景模型
cv2.imshow('Background', background_uint8)
if cv2.waitKey(1) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
cv2.accumulateWeighted(frame_gray, background, alpha)
frame_gray
与历史背景模型 background
结合,逐步更新背景,使其适应场景中的缓慢变化(如光线变化、轻微移动的物体等)。frame_gray
:当前帧的灰度图像(单通道,通常为 float32
类型)。background
:背景模型(初始化为与 frame_gray
相同大小的 float32
数组)。alpha
:学习率(取值范围 0 < alpha < 1
),控制新帧与旧背景的权重:
alpha
越小:背景更新越慢,对缓慢变化(如光线)更鲁棒,但对快速变化(如新物体进入)反应较慢。alpha
越大:背景更新越快,能更快适应新变化,但可能对噪声更敏感。cv2.accumulateWeighted
的计算公式为:
KaTeX parse error: Expected 'EOF', got '_' at position 47: …mes \text{frame_̲gray} + (1 - \a…
background
需要先初始化为第一帧的灰度值(或全零)。background_uint8 = background.astype(np.uint8)
background
(float32
类型)转换为 uint8
类型(0-255 的整数),以便后续显示或处理。cv2.accumulateWeighted
函数是基于指数加权平均(Exponential Moving Average,EMA)的原理来更新背景模型,其核心公式如下:
S t = α × X t + ( 1 − α ) × S t − 1 S_{t}=\alpha\times X_{t}+(1 - \alpha)\times S_{t - 1} St=α×Xt+(1−α)×St−1
cv2.accumulateWeighted(gray, background, alpha)
其中 gray
对应公式里的 X t X_{t} Xt,background
对应 S t − 1 S_{t - 1} St−1 和 S t S_{t} St(更新前后的背景模型),alpha
就是公式中的 α \alpha α。每次调用该函数时,就会按照上述公式更新背景模型。
虽然在原始的递推公式 S t = α × X t + ( 1 − α ) × S t − 1 S_{t}=\alpha\times X_{t}+(1 - \alpha)\times S_{t - 1} St=α×Xt+(1−α)×St−1 里没有直接呈现指数,但通过展开公式就能发现 ( 1 − α ) (1 - \alpha) (1−α) 的指数形式。
从该公式出发,若持续迭代展开这个式子,就能清晰看到指数的存在。
对于第 t t t 时刻的背景模型 S t S_{t} St,通过不断代入前一时刻的公式进行展开:
以此类推,对于第 t t t 时刻的 S t S_{t} St,可以得到展开式:
S t = α ∑ i = 0 t − 1 ( 1 − α ) i X t − i + ( 1 − α ) t S 0 S_{t}=\alpha\sum_{i = 0}^{t - 1}(1 - \alpha)^iX_{t - i}+(1 - \alpha)^tS_{0} St=αi=0∑t−1(1−α)iXt−i+(1−α)tS0