帧率可以简单理解为1秒内播放了多少张图片。一般来说,视频中相邻的两帧之间有相同的时间间隔,而修改帧率则需要在响应的间隔中插入相同的帧。
对于构造不存在的帧,我们称之为插帧(Frame Interpolation),以下是一些常见的方法:
- Duplication,复制相近的帧
- Blend,用相邻的两帧进行混合
- Motion Interpolation,结合图像运动来构造中间帧,类似于运动补偿
对于第1种方式,在生成当前的中间帧的过程中涉及到两个输入帧,分别为小于输出时间并且最接近该输出时间的输入帧以及大于输出时间并且最接近输出时间的输入帧。我们可以称之为参考帧。而从这两个参考帧中选取时间上最接近中间帧输出时间的一帧,对这一帧进行复制,作为当前的中间帧进行输出。 而第2种方法是将两帧进行混合,其代码类似如下:
frame = cv2.addWeighted(
prev_frame, 0.7,
next_frame, 0.3,
0
)
而对于第3种方式可以使用类似如下的代码:
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
next_gray = cv2.cvtColor(next_frame, cv2.COLOR_BGR2GRAY)
# 计算光流(运动矢量)
flow = cv2.calcOpticalFlowFarneback(prev_gray, next_gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)
# 生成中间帧(动态补偿)
h, w = flow.shape[:2]
map_x = np.tile(np.arange(w), (h, 1)) + flow[...,0]
map_y = np.tile(np.arange(h), (w, 1)).T + flow[...,1] # map_y = np.swapaxes(np.tile(np.arange(h), (w, 1)), 0, 1) + flow[...,1]
mapped_frame = cv2.remap(next_frame, map_x.astype(np.float32), map_y.astype(np.float32), cv2.INTER_LINEAR)
这里主要采用光流法,其适用于中等运行复杂度的场景,而对于大型运行则可以考虑使用帧间对准技术。此时可以考虑python_video_stab项目。
对于帧率的变化,下面举一个简单的例子。对于25帧的视频,那么每隔1/25=40ms就是一帧,如果将其修改为15帧,那么每帧的间隔为1/15=66.67ms。此时就可以使用如下的代码进行视频流的读取:
while cap.isOpened():
start_time = time.time()
ret,frame = cap.read()
if not ret:
print("no frame")
break
# 跳帧
if frame_count % skip_frame == 0:
# height,width = frame.shape[:2]
frame = cv2.resize(frame,(width//2,height//2))
# 补偿帧
compensated_frame = frame_interpolation(prev_frame, frame, 0.5)
cv2.imshow("Frame", compensated_frame)
cv2.waitKey(20)
cv2.imshow("Frame",frame)
prev_frame = frame
frame_count += 1
elapsed = time.time() - start_time
# if elapsed < frame_interval:
# time.sleep(frame_interval-elapsed)
remaining = max(1, int((frame_interval - elapsed) * 1000))
if cv2.waitKey(remaining) & 0xFF == ord("q"):
break
参考文章:
如果喜欢这篇文章或对您有帮助,可以:[☕] 请我喝杯咖啡 | [💓] 小额赞助

