OpenCV将视频分解成帧,用帧间差分法生成二值图像,再连接成视频

 功能实现很简单:将任意的视频分解成帧,将这些帧做帧间差分运算,最后将差分运算得到的二值图像连成视频。

import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取视频
#选取两帧
#灰度化
#滤波
#帧间做差
#二值化
#形态学操作

def absdiff_(frames,sThre):
    c_frames = []
    for i in range(len(frames)-2):
        #将图片灰度化
        gray_frame_front = cv2.cvtColor(frames[i],cv2.COLOR_BGR2GRAY)
        #高斯滤波 (平滑了一些)
        gray_frame_front = cv2.GaussianBlur(gray_frame_front,(3,3),0)

        gray_frame_later = cv2.cvtColor(frames[i+1],cv2.COLOR_BGR2GRAY)
        gray_frame_later = cv2.GaussianBlur(gray_frame_later,(3,3),0)

        #帧间做差
        d_frame = cv2.absdiff(gray_frame_front,gray_frame_later)

        #对灰度值图像进行阈值操作得到二值图像
        ret,d_frame = cv2.threshold(d_frame,sThre,255,cv2.THRESH_BINARY)
        c_frames.append(d_frame)
        
    return c_frames
        
 
def Video_to_image(Videopath):
    capture = cv2.VideoCapture(Videopath)
    #得到视频的帧率,即每一秒刷新图片的数量,framesNum是一整段视频中总的图片数
    fps = capture.get(cv2.CAP_PROP_FPS)
    #得到整个视频的帧数
    framesNum = capture.get(cv2.CAP_PROP_FRAME_COUNT)

    print("fps=",fps,"frames=",framesNum)
    frames = []

    for i in range(int(framesNum)-1):
        #获取下一帧
        ret,frame = capture.read()
        frames.append(frame)
    return frames


def Image_to_video(frames):
    #表示视频流格式
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    #30表示输出视频每秒30帧,(544,960)表示输出的视频的尺寸
    videoWriter = cv2.VideoWriter(outPath,fourcc,30,(544,960),isColor=0)

    for i in range(len(frames)-1):
        videoWriter.write(frames[i])


inpath = "E:\\testvideo.mp4"
outPath = './output_video.mp4'
#阈值
sThre = 5 
frames = []
frames = Video_to_image(inpath)
c_frames = absdiff_(frames,sThre)
Image_to_video(c_frames)
print("down!")

 

这里注意:

一个是列表数组都常见的下标问题,在使用len()函数时且用其循环时,注意是不是循坏到长度之外了;

一个是cv2.VideoWriter()的参数设置问题。这里踩了两个坑,①输出视频的尺寸必须符合你要连接的帧的大小,②输出视频是否为彩色图。

 

由于我在实验时,先把彩色视频分解成帧,再将帧连成视频时没有问题,后来连接二值图像时得到的outvideo为空,因为VideoWriter函数默认是彩色图为写入内容,此时设置isColor=0解决。

 

视频截图:

OpenCV将视频分解成帧,用帧间差分法生成二值图像,再连接成视频

结果视频截图:

OpenCV将视频分解成帧,用帧间差分法生成二值图像,再连接成视频

 

 

感觉还存在的问题。

视频中移动的物体只有鼠标和手,还有光线的变化(鼠标会变光),键盘和桌沿是没有移动的。但是结果将许多并没有移动的物体都作为差分的结果显示出来了。

有童鞋知道原因请告知我,感谢~

另外有时间打算试一下三帧差分法。三帧差分法理论上来说适用于视频中有运动较快的目标物体。