任务描述
本关任务:编写一个利用帧差法进行目标检测的程序
相关知识
帧差法
摄像机采集的视频序列具有连续性的特点。如果场景中没有任何目标在运动,那么连续帧的变化会很微弱,如果有目标在运动中,连续的帧和帧之间会发生明显变化
帧差法目标检测就是利用了上述思想。当场景中的目标在运动中时,目标会出现在不同帧的不同位置。帧差法对时间上连续的两帧或者三帧进行差分运算,不同帧对应的像素点相减,判断灰度差的绝对值,当绝对值超过一定阈值的时候,可以判断物体为运动物体,从而可以实现运动物体的检测
帧差法分为两帧差法和三帧差法
两帧差法
两帧差法的运算过程:
设当前序列帧为n,则当前序列帧的上一帧为n-1,那么可以将两帧图像对于像素点的灰度值进行减法运算,并取其中的绝对值,得到差分图像Dn:
Dn=∣灰度n−灰度n−1∣
设定阈值为T对得到的差分图像进行阈值处理,超过阈值的设置为255,低于阈值的设置为0,接着对得到的图像进行连通性分析,就可以得到含有完整运动目标的图像
两帧差法opencv实现
import cv2
cap = cv2.VideoCapture(r"video_20210506_183642.mp4")
if not cap.isOpened():
print("Error opening video stream or file")
frameNum = 0
previousframe = None
while cap.isOpened():
ret, frame = cap.read()
frameNum += 1
if ret:
tempframe = frame
if frameNum == 1:
previousframe = cv2.cvtColor(tempframe, cv2.COLOR_BGR2GRAY)
if frameNum >= 2:
# 首先得到原图的灰度图
currentframe = cv2.cvtColor(tempframe, cv2.COLOR_BGR2GRAY)
# 再将两张灰度图进行差值处理并取绝对值
currentframe = cv2.absdiff(currentframe, previousframe)
# 对进行差值处理的图像进行中值滤波处理取出干扰项
median = cv2.medianBlur(currentframe, 3)
# 展示处理后的图像
cv2.imshow('median', median)
if cv2.waitKey(33) & 0xFF == ord('q'):
break
previousframe = cv2.cvtColor(tempframe, cv2.COLOR_BGR2GRAY)
else:
break
cap.release()
cv2.destroyAllWindows()
三帧差法
两帧差法适用于目标运动较为缓慢的情况,当运动过快的时候,由于目标在相邻帧图像上的位置相差比较大,两帧图像相减之后并不能得到完整的运动目标,因此,人们在两帧差法的基础上又提出了三帧差法
三帧差法的运算过程
设当前序列帧为n,则当前序列帧的上一帧为n-1,下一帧为n+1,将三帧图像对于像素点的灰度值分别进行减法运算,然后得到的两个差分图像再进行与操作,得到新的差分图像D′ 然后再进行阈值处理和连通性分析
理论上三帧差法比两帧差法更好,可以在一定程度上消除帧间差法的“双影”现象,但是也需要根据实际场景进行选择
三帧差法具体实现过程
第一步:对第二幅图像减去第一幅图像的值与第三幅图像减去第二幅图像的值作交集运算 第二步:对第一步产生的运算结果进行滤波处理 第三步:对第二步产生的运算结果做形态学处理 最后一步:对第三步产生的运算结果做二值化处理
编程要求
本实验从视频中取出三帧图像,对真实场景进行模拟,请根据相关知识中三帧差法具体实现的流程对三个帧进行处理,程序会对处理后的结果进行处理,只要处理后的结果与标准答案有90%相似即可通过
测试说明
平台会对你编写的代码进行测试:
预期输出:
通关成功
参考答案:
import cv2
import numpy as np
import pandas as pd
this_answer = None
tmp_time = 0
cap = cv2.VideoCapture(r"step1/video_20210506_183642.mp4")
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# 初始化第一帧
one_frame = np.zeros((height, width), dtype=np.uint8)
# 初始化第二帧
two_frame = np.zeros((height, width), dtype=np.uint8)
# 初始化第三帧
three_frame = np.zeros((height, width), dtype=np.uint8)
while cap.isOpened():
ret, frame = cap.read()
if ret:
# ********** Begin ********** #
# 将当前帧转换成灰度图
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 更新三帧图像
one_frame, two_frame, three_frame = two_frame, three_frame, frame_gray
# 第一步对第二幅图像减去第一幅图像的值与第三幅图像减去第二幅图像的值作交集运算
currenframe1 = cv2.absdiff(one_frame, two_frame)
currenframe2 = cv2.absdiff(two_frame, frame_gray)
thresh = cv2.bitwise_and(currenframe1, currenframe2)
# 第二步 对第一步产生的运算结果进行滤波处理
thresh = cv2.medianBlur(thresh, 3)
# 第三步 对第二步产生的运算结果做形态学处理
thresh = cv2.dilate(thresh, None, iterations=3)
thresh = cv2.erode(thresh, None, iterations=1)
# 第四步 对第三步产生的运算结果做二值化处理
thresh = cv2.threshold(thresh, 25, 255, cv2.THRESH_BINARY)[1]
# ********** end ********** #
cv2.waitKey(30)
tmp_time += 30
if tmp_time == 300:
this_answer = thresh
else:
break
cap.release()
cv2.destroyAllWindows()
df = pd.read_csv(r"step1/answer.csv", index_col=0)
old_answer = df.values
if np.sum(old_answer == this_answer) / (width * height) >= 0.7:
print("测试通过")
else:
print("测试失败")
参考资料
可以参考大佬的python图像差分法目标检测_运动目标检测(2)—帧间差分法—CSDN博客
https://blog.csdn.net/weixin_39761255/article/details/110751680
(里面有详细讲解相邻帧间差分法和三帧差分法的python实现代码)