帧差法+三帧差法原理与实现

jupiter
2021-09-13 / 0 评论 / 2,255 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2021年12月07日,已超过869天没有更新,若内容或图片失效,请留言反馈。

帧差法原理

移动侦测即是根据视频每帧或者几帧之间像素的差异,对差异值设置阈值,筛选大于阈值的像素点,做掩模图即可选出视频中存在变化的桢。帧差法较为简单的视频中物体移动侦测,帧差法分为:单帧差三桢差。随着帧数的增加是防止检测结果的重影。

单帧差法

算法原理

以视频为例进行单帧差法移动侦测

算法实现

import cv2
import pandas as pd
import numpy as np

video_path = "./test.mp4"

cam = cv2.VideoCapture(video_path) # 打开一个视频
input_fps = cam.get(cv2.CAP_PROP_FPS) # 获取视频帧率  
ret_val, input_image = cam.read() # 读取视频第一帧

gray_lwpCV = cv2.cvtColor(input_image, cv2.COLOR_BGR2GRAY)  # 将第一帧转为灰度
gray_lwpCV = cv2.GaussianBlur(gray_lwpCV, (21, 21), 0) # 对转换后的灰度图进行高斯模糊
background=gray_lwpCV # 将高斯模糊后的第一帧作为初始化背景

area_threh = 100 # 物体bbox面积阈值

while(cam.isOpened()) and ret_val == True:
    ret_val, input_image = cam.read() # 继续读取视频帧
    gray_lwpCV = cv2.cvtColor(input_image, cv2.COLOR_BGR2GRAY)
    gray_lwpCV = cv2.GaussianBlur(gray_lwpCV, (21, 21), 0) # 对读取到的视频帧进行灰度处理+高斯模糊
    diff = cv2.absdiff(background, gray_lwpCV) # 将最新读取的视频帧和背景做差
    
    #跟着图像变换背景,如果背景变化区域小于20%或者75%,则将当前帧作为新得背景区域
    tem_diff=diff.flatten()
    tem_ds=pd.Series(tem_diff)
    tem_per=1-len(tem_ds[tem_ds==0])/len(tem_ds)
    if (tem_per <0.2 )| (tem_per>0.75): 
        background=gray_lwpCV 
    else:
        ret,diff_binary = cv2.threshold(diff, 10, 255, cv2.THRESH_BINARY)# 对差值diff进行二值化
        contours, hierarchy = cv2.findContours(diff_binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) # 对二值化之后得结果进行轮廓提取
        for c in contours:
            if (cv2.contourArea(c) < area_threh): # 对于矩形区域,只显示大于给定阈值的轮廓(去除微小的变化等噪点)
                continue
            (x, y, w, h) = cv2.boundingRect(c) # 该函数计算矩形的边界框
            cv2.rectangle(input_image, (x, y), (x+w, y+h), (0, 255, 0), 2) 
        
        cv2.imshow('frame diff', np.hstack((input_image,cv2.cvtColor(diff,cv2.COLOR_GRAY2BGR))))
        if cv2.waitKey(50)&0xFF==ord("q"):
            break

cam.release()
cv2.destroyAllWindows()

实现效果

算法分析

  • 优点

    • 实现简单,运行速度快
  • 缺点

    • 存在"鬼影"问题(指在物体原来得位置和现在得位置都出现了该物体),

三帧差法

算法原理

连续三帧,12相减,23相减,结果做与运算。相减公式:

其中阈值T需要手动调整。结果得到一个二值图,对二值图进行形态学处理,再进行轮廓提取。

算法实现


import cv2
import numpy as np

video_path = "./test.mp4"
cap = cv2.VideoCapture(video_path)
width =int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height =int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

# 初始化第1.2.3帧
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)

area_threh = 100 # 物体bbox面积阈值

while cap.isOpened():
    ret,frame = cap.read()
    frame_gray =cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    if not ret:
        break
    one_frame,two_frame,three_frame = two_frame,three_frame,frame_gray
    
    # 1.2帧做差
    abs1 = cv2.absdiff(one_frame,two_frame)#相减
    _,thresh1 = cv2.threshold(abs1,15,255,cv2.THRESH_BINARY)#二值,大于40的为255,小于0
    
    # 2.3帧做差
    abs2 =cv2.absdiff(two_frame,three_frame)
    _,thresh2 =cv2.threshold(abs2,15,255,cv2.THRESH_BINARY)
    
    
    binary =cv2.bitwise_and(thresh1,thresh2)#与运算
    
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
#     erode = cv2.erode(binary,kernel)#腐蚀
#     dilate =cv2.dilate(binary,kernel)#膨胀
#     dilate =cv2.dilate(dilate,kernel)#膨胀
    
    # 轮廓提取
    contours, hierarchy = cv2.findContours(binary.copy(),mode=cv2.RETR_EXTERNAL,method=cv2.CHAIN_APPROX_SIMPLE)#寻找轮廓
    for contour in contours:
        if cv2.contourArea(contour)>area_threh:
            x,y,w,h =cv2.boundingRect(contour)#找方框
            cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0), 2)
    
    img_show = np.hstack((frame,cv2.cvtColor(binary,cv2.COLOR_GRAY2BGR)))
    cv2.imshow('three frame diff',img_show)
               
    if cv2.waitKey(50)&0xFF==ord("q"):
        break
cap.release()
cv2.destroyAllWindows()

实现效果

  • 不进行形态学处理

  • 膨胀一次

  • 膨胀两次

  • 先腐蚀一次,再膨胀两次

算法分析

  • 优点

    • 实现简单,运行速度快
    • 解决了帧差法存在的“鬼影”问题
    • 能大致检测出物体的运动区域
  • 缺点

    • 不进行膨胀会存在“空洞”问题
    • 进行膨胀之后会存在着多个物体的”牵连“问题
    • 对物体的运动区域的检测不够全面

      • eg:对于部分人运动区域的检测会存在着只检测出半个人的情况

参考资料

  1. python+opencv实现移动侦测(帧差法):https://www.jb51.net/article/183203.htm
  2. opencv python 三帧差法实现运动目标区域检测与完整代码:https://blog.csdn.net/pengpengloveqiaoqiao/article/details/89487049
0

评论 (0)

打卡
取消