探索解决opencv保存视频变快变慢的问题
opencv
OpenCV: 开源计算机视觉库
项目地址:https://gitcode.com/gh_mirrors/opencv31/opencv

·
目录
问题描述
用opencv的
cv2.VideoWriter()
去将图片实时保存为视频,总会出现视频变快或变慢。
问题分析
初步理解是因为该命令不能按照设置的帧率自动按照一定时间间隔保存视频,也就是说要求你的输入帧数和保存帧数要一致才能保存。
但是我们在应用中经常要对获得的视频图像做处理,之后再保存,处理的时间是不一定的。因此,如果直接用这个命令会出现视频时快时慢的问题。
从道理上讲应该是获得一秒需要的帧数后保存一秒的视频,opcv内部应该有相应的定时器,但我没找到,就自己探索了一个方法。
解决思路
由于我这边只是需要完成保存模块,保存的代码要在一个进程里实现。所以这里我用两个进程,一个进程获取摄像机图像信息,一个进程进行保存。
获取涉嫌头视频代码如下
import cv2
import time
import threading
import ffmpeg
import numpy as np
from pandas import DataFrame
import chardet
class Get_rtsp():
def __init__(self, cam_adrs, pipe):
self.count = 0
self.cam_rul = cam_adrs
self.pipe = pipe
# 用ffmpeg将摄像机图像拉下来
def img_get(self):
out = (
ffmpeg
.input(self.cam_rul, rtsp_transport='tcp')
.output('pipe:', format='rawvideo', pix_fmt='bgr24', loglevel="quiet", g=0, r=60)
.run_async(pipe_stdout=True)
)
while True:
a = time.perf_counter()
# 接到的图像是bytes,需要转换为frame
in_bytes = out.stdout.read(1080 * 1920 * 3)
frame = np.frombuffer(in_bytes, dtype=np.uint8).reshape(1080, 1920, 3)
# 放入管道
self.pipe.send(frame)
# print('a', round((time.perf_counter() - a) * 1000))
# 记录获得帧数
self.count += 1
df = DataFrame([[self.count, round((time.perf_counter() - a) * 1000)]], columns=['count', 'img_get_time'])
df.to_csv('time_waste_getrtsp.csv', encoding='gbk', mode='a', index=False,
header=False)
两个进程之间用管道通信
下载的代码如下
import cv2
import time
import multiprocessing as mp
import subprocess as sp
from pandas.core.frame import DataFrame
import ffmpeg
import threading
import gc
class DLPrces():
def __init__(self):
self.localtime = time.strftime("%Y%m%d%H%M%S", time.localtime())
self.frame_hub = []
self.fps = 20
self.time_iter = round((1 / self.fps), 4)
self.lock_1 = threading.Lock()
def down(self, q_dl_img):
# 这个线程就不停的读管道写进列表
count = 0
while True:
t_start = time.time()
a = q_dl_img.recv()
self.lock_1.acquire()
self.frame_hub.append(a)
# 如果读的太快,就清空列表,一般没有这么快
if len(self.frame_hub) > 100:
self.frame_hub.clear()
# print('获得帧数超过保存帧数')
self.lock_1.release()
count += 1
time_consume = round((time.time() - t_start) * 1000)
t_1 = time.strftime("%Y%m%d%H%M%S", time.localtime())
df = DataFrame([[count, t_1, time_consume]], columns=['count', 't_tmp', 'dl_img_time'])
df.to_csv('time_get_pipe.csv', encoding='gbk', mode='a', index=False,
header=False)
def write(self):
out_radpg = cv2.VideoWriter('./' + '/rad_video_' + str(self.localtime) + '.avi',
cv2.VideoWriter_fourcc(*'XVID'), self.fps, (1920, 1080), True)
print("——————————DLPrces———————————— 开始压视频")
t_loop = 0
count = 0
while True:
tmp_img = time.perf_counter()
while True:
# 开始循环计时
if (time.perf_counter()-tmp_img) - (self.time_iter - t_loop) <= 0:
continue
else:
t_lostart = time.time()
# 如果列表为空就继续等待
if len(self.frame_hub) != 0:
t_start = time.time()
# 利用opencv保存视频
self.lock_1.acquire()
out_radpg.write(self.frame_hub.pop(-1))
# 清空列表避免获得过去的帧数
self.frame_hub.clear()
self.lock_1.release()
count += 1
# print(time.perf_counter())
time_consume = time.time()
time_consume_save = round((time_consume - t_start) * 1000)
t_1 = time.strftime("%Y%m%d%H%M%S", time.localtime())
df = DataFrame([[count, t_1, time_consume_save]], columns=['count', 't_tmp', 'dl_img_time'])
df.to_csv('time_save.csv', encoding='gbk', mode='a', index=False,
header=False)
t_loop = time.time() - t_lostart
else:
continue
break
def run(self, q_dl_img):
threads = [threading.Thread(target=DLPrces.down, args=(self, q_dl_img)),
threading.Thread(target=DLPrces.write, args=(self,))]
[thread.start() for thread in threads]
[thread.join() for thread in threads]
开启了两个线程,去按照20帧的时间间隔保存图像
存在的问题
用ffmpeg取20,40,60帧的视频,保存也基本是20帧。但是取20帧的保存的视频很流畅,帧数越高越不流畅,优点是不流畅的很稳定........不会因为获得帧数高保存帧数低就慢速很多
存取20帧的时候会出现帧数变少,平均只有18帧。丢的还是很多的。原因是ffmpeg取流时不会按照50ms的间隔去拿,他是平均50ms的拿,就是说有时候100ms拿一次,有时候10ms拿一次。我们保存的固定计时器在100ms的时候保存一帧,在10ms的时候还要等50ms,这时候再来一帧20ms的我们存了前面的10ms的就被清除了。
问题分析
应该是跳帧的问题,一卡一卡的。不知道怎么解决
最终结论
请直接使用ffmpeg进行拉流,干净又卫生




OpenCV: 开源计算机视觉库
最近提交(Master分支:19 天前 )
edfa999b
Added option to wrap opencv_contrib into JS too. 1 天前
5755d4f2 - 2 天前
更多推荐
所有评论(0)