功能实现很简单:将任意的视频分解成帧,将这些帧做帧间差分运算,最后将差分运算得到的二值图像连成视频。
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解决。
视频截图:
结果视频截图:
感觉还存在的问题。
还存在的问题是没有解决相机的位移。键盘、桌沿等应该是静态的,但是由于相机本身的移动,它们也被抽取出来了。如果保证相机的静止,效果应该会好非常多。
另外有时间打算试一下三帧差分法。三帧差分法理论上来说适用于视频中有运动较快的目标物体。