使用OpenCV实现抖音“蓝线挑战”特效。原理比较简单,当蓝线在视频画面中滑动,然后从滑过的每一帧中截取部分画面生成一幅静态图片,由于上一帧画面已经定格,那么通过调整下一帧画面可以生成各种奇怪的场景。
处理过程可分为几个步骤:
- 读取原始视频信息(宽、高、fps和总帧数);
- 计算蓝线在视频中的移动速度,横向移动:宽÷总帧数,纵向移动:高÷总帧数;
- 分解原视频每一帧画面,计算蓝线在当前帧中的位置;
- 绘制当前静态画面和蓝线;
- 将绘制后的画面作为帧生成视频文件。
以蓝线从左往右为例:
- 首先使用OpenCV读取原始视频,获取视频信息并通过视频宽与总帧数计算蓝线移动速度;
- 蓝线从左往右移动,当蓝线滑过第一帧,第一帧画面上滑过的部分将作为静态画面保留到下一帧。因此需要定义一个img来保留之前帧生成的画面;
- 当读取到下一帧画面frame后,根据当前蓝线所处位置对当前帧frame进行裁切,用裁切后的画面替换掉img上相同位置的画面。(需要注意的是image_block=frame[0:height,x:width],这里是图像高在前宽在后);
- 生成画面之后再使用OpenCV绘制蓝线cv2.line(img,(int(x + 3),0),(int(x + 3),height),(255,0,0),3),蓝线宽度设定为3个像素,最后将处理好的画面写入视频文件。
一、蓝线从左往右滑动:
from cv2 import cv2
#绘制静态画面和蓝线
def drawline(frame,img,x,width,height,bluelinespeed):
bulelinelocation = int(x + bluelinespeed + 2)
if bulelinelocation < width:
image_block = frame[0:height,int(x):width]
tempimg[0:height,int(x):width] = image_block
cv2.line(img,(bulelinelocation,0),(bulelinelocation,height),(255,0,0),2)
videoCapture = cv2.VideoCapture('C:/Users/admin/Desktop/test/video/2.avi')
fps = videoCapture.get(cv2.CAP_PROP_FPS)
width = int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(videoCapture.get(cv2.CAP_PROP_FRAME_HEIGHT))
totalCount = videoCapture.get(cv2.CAP_PROP_FRAME_COUNT)
size = (width,height)
bluelinespeed = width / totalCount
videoWriter = cv2.VideoWriter('C:/Users/admin/Desktop/test/video/222.avi',cv2.VideoWriter_fourcc('X','V','I','D'),fps,size)
success,frame = videoCapture.read()
tempimg = frame
img = frame
remianing = totalCount
x = 0
while success and remianing > 0:
x = x + bluelinespeed
drawline(frame,img,x,width,height,bluelinespeed)
videoWriter.write(img)
success,frame = videoCapture.read()
remianing -= 1
效果:
二、蓝线从右往左
from cv2 import cv2
#绘制静态画面和蓝线
def drawline(frame,img,x,width,height,bluelinespeed):
bulelinelocation = int(x - bluelinespeed - 2)
if bulelinelocation > 0:
image_block = frame[0:height,0:int(x)]
tempimg[0:height,0:int(x)] = image_block
cv2.line(img,(bulelinelocation,0),(bulelinelocation,height),(255,0,0),2)
videoCapture = cv2.VideoCapture('C:/Users/admin/Desktop/test/video/2.avi')
fps = videoCapture.get(cv2.CAP_PROP_FPS)
width = int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(videoCapture.get(cv2.CAP_PROP_FRAME_HEIGHT))
totalCount = videoCapture.get(cv2.CAP_PROP_FRAME_COUNT)
size = (width,height)
bluelinespeed = width / totalCount
videoWriter = cv2.VideoWriter('C:/Users/admin/Desktop/test/video/222.avi',cv2.VideoWriter_fourcc('X','V','I','D'),fps,size)
success,frame = videoCapture.read()
tempimg = frame
img = frame
remianing = totalCount
x = width
while success and remianing > 0:
x = x - bluelinespeed
drawline(frame,img,x,width,height,bluelinespeed)
videoWriter.write(img)
success,frame = videoCapture.read()
remianing -= 1
效果:
三、蓝线从上往下
from cv2 import cv2
#绘制静态画面和蓝线
def drawline(frame,img,x,width,height,bluelinespeed):
bulelinelocation = int(x + bluelinespeed + 2)
if bulelinelocation < height:
image_block = frame[int(x):height,0:width]
tempimg[int(x):height,0:width] = image_block
cv2.line(img,(0,bulelinelocation),(width,bulelinelocation),(255,0,0),2)
videoCapture = cv2.VideoCapture('C:/Users/admin/Desktop/test/video/2.avi')
fps = videoCapture.get(cv2.CAP_PROP_FPS)
width = int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(videoCapture.get(cv2.CAP_PROP_FRAME_HEIGHT))
totalCount = videoCapture.get(cv2.CAP_PROP_FRAME_COUNT)
size = (width,height)
bluelinespeed = height / totalCount
videoWriter = cv2.VideoWriter('C:/Users/admin/Desktop/test/video/222.avi',cv2.VideoWriter_fourcc('X','V','I','D'),fps,size)
success,frame = videoCapture.read()
tempimg = frame
img = frame
remianing = totalCount
x = 0
while success and remianing > 0:
x = x + bluelinespeed
drawline(frame,img,x,width,height,bluelinespeed)
videoWriter.write(img)
success,frame = videoCapture.read()
remianing -= 1
效果:
四、蓝线从下往上滑动:
from cv2 import cv2
#绘制静态画面和蓝线
def drawline(frame,img,x,width,height,bluelinespeed):
bulelinelocation = int(x - bluelinespeed - 2)
if bulelinelocation < height:
image_block = frame[0:int(x),0:width]
tempimg[0:int(x),0:width] = image_block
cv2.line(img,(0,bulelinelocation),(width,bulelinelocation),(255,0,0),2)
videoCapture = cv2.VideoCapture('C:/Users/admin/Desktop/test/video/1.avi')
fps = videoCapture.get(cv2.CAP_PROP_FPS)
width = int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(videoCapture.get(cv2.CAP_PROP_FRAME_HEIGHT))
totalCount = videoCapture.get(cv2.CAP_PROP_FRAME_COUNT)
size = (width,height)
bluelinespeed = height / totalCount
videoWriter = cv2.VideoWriter('C:/Users/admin/Desktop/test/video/11.avi',cv2.VideoWriter_fourcc('X','V','I','D'),fps,size)
success,frame = videoCapture.read()
tempimg = frame
img = frame
remianing = totalCount
x = height
while success and remianing > 0:
x = x - bluelinespeed
drawline(frame,img,x,width,height,bluelinespeed)
videoWriter.write(img)
success,frame = videoCapture.read()
remianing -= 1
效果: