效果展示
本项目通过Python-OpenCV实现抖音的“蓝线挑战”功能,即跟随视频中滑动的指示线实现多帧延迟,在视觉上出现上半部分图像停留的效果。
功能复现
- 采集视频,包括从本地读取视频格式和启动摄像头两种方式;
- 提取帧,对每一帧单独处理;
- 根据视频分辨率,绘制区域:上半部分绘制图片,下半部分绘制视频;
- 根据需求添加辅助;
- 测试并完成创意视频录制。
获取视频帧
通过OpenCV内建函数cv2.VideoCapture实现视频帧截取。使用命令行参数解析包argparse设置程序的调用指令:无输入时打开摄像头,有输入的情况下打开路径下的视频文件。
import cv2
import os
import numpy as np
path = '/Users/PycharmProjects/blue-line-challenge/output/grab_frames/'
cap = cv2.VideoCapture('/Users/panyining/PycharmProjects/blue-line-challenge/video/3.gif')
i = 1
height = 0
if not os.path.exists(path):
os.makedirs(path)
while (cap.isOpened()):
ret, frame = cap.read()
print(frame.shape)
if ret == False: #
break
cv2.imencode('.jpg', frame)[1].tofile(path + 'frame_' + str(i) + '.jpg')
cv2.imshow('frame', frame)
i += 1
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.waitKey(0)
cap.release()
cv2.destroyAllWindows()
帧处理
主体思路是将每一帧的上半部分绘制图片、下半部分绘制视频,通过一个全局的参数height定位每次图像和视频的分界线。在循环中不断叠加高度,由
h
e
i
g
h
t
=
0
height=0
height=0到
h
e
i
g
h
t
=
l
e
n
(
f
r
a
m
e
.
s
h
a
p
e
[
0
]
)
height=len(frame.shape[0])
height=len(frame.shape[0])即从图像帧的顶部到底部,实现蓝线的扫描的效果。
由于分界线的存在,我们可以方便地实现对图像的处理。由于需要实现多帧延迟的效果,因此需要在每一次迭代时调用上一帧的图像old_frame用于处理。
以3通道的RGB的图像为例,每次取height位置的、长度为1、宽度为图像帧的宽W的长方形区域作为ROI,其值为上一帧old_frame对应位置的色彩值,如B通道的数字替换可以表示为: f r a m e [ h e i g h t : h e i g h t + 1 , : , 0 ] = 255 frame[height:height + 1, :, 0] = 255 frame[height:height+1,:,0]=255。至此,完成本项目核心算法的解析和实现。
import cv2
import os
import numpy as np
import time
height = 0
old_frame = np.ones((372, 500, 3), dtype=np.uint8)
old_frame[:, :, 0] = 0
old_frame[:, :, 1] = 0
old_frame[:, :, 1] = 0
cap = cv2.VideoCapture('/Users/panyining/PycharmProjects/blue-line-challenge/video/3.gif')
while cap.isOpened():
frame = vs.read()
frame = frame[1] if args.get("input", False) else frame
frame = imutils.resize(frame, width=500)
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame[:height, :, :] = old_frame[:height, :, :]
line = old_frame[height:height + 1, :, :]
# frame[height:height + 1, :, 0] = 240 # B
# frame[height:height + 1, :, 1] = 127 # G
# frame[height:height + 1, :, 2] = 0 # R
cv2.imshow('frame', frame)
i += 1
height += 2
old_frame = frame
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.waitKey(0)
cap.release()
cv2.destroyAllWindows()