Python 视频转场特效处理笔记

本文参考Python-OpenCV 实现美图秀秀视频剪辑效果【特效】_opencv 多张图片 视频 特效-CSDN博客

最近研究了点python处理视频相关的东西,本文展示特效包括,竖向开幕/横向开幕,渐隐/渐显,推近/拉远,方形开幕,灰度渐变。不多说,直接上代码。

python 复制代码
import cv2
import numpy as np
import random

def addCardFrame(video_writer,img,backimg=None,fps=18,sec=1,eachtime=0.5):
    """视频特效:卡帧"""
    rows, cols = img.shape[:2]

    '''缩放原图80%'''
    img = cv2.resize(img, (int(cols * 0.8),int(rows * 0.8)))
    rows_new, cols_new = img.shape[:2]

    '''准备更大的画布'''
    cav = None
    if backimg is None:
        cav_np = np.zeros((rows, cols), np.uint8)
        cav = cv2.cvtColor(cav_np, cv2.COLOR_GRAY2BGR)
    else:
        cav = backimg

    '''偏移量准备'''
    dic = {
        0: (int(cols * 0.08), int(rows * 0.12)),
        1: (int(cols * 0.10), int(rows * 0.10)),
        2: (int(cols * 0.12), int(rows * 0.08)),
        3: (int(cols * 0.12), int(rows * 0.07)),
        4: (int(cols * 0.12), int(rows * 0.06)),
        5: (int(cols * 0.14), int(rows * 0.07)),
        6: (int(cols * 0.16), int(rows * 0.07)),
        7: (int(cols * 0.15), int(rows * 0.09)),
        8: (int(cols * 0.14), int(rows * 0.10)),
        9: (int(cols * 0.14), int(rows * 0.07)),
        10: (int(cols * 0.13), int(rows * 0.05)),
        11: (int(cols * 0.14), int(rows * 0.06)),
        12: (int(cols * 0.14), int(rows * 0.08)),
        13: (int(cols * 0.15), int(rows * 0.10)),
        14: (int(cols * 0.14), int(rows * 0.09)),
        15: (int(cols * 0.12), int(rows * 0.12)),
        16: (int(cols * 0.10), int(rows * 0.10)),
        17: (int(cols * 0.08), int(rows * 0.12))
    }

    '''添加特效展示'''
    for _ in range(int(sec)):
        xs, ys = dic[random.randrange(0,18,1)]
        xe, ye = (xs + rows_new, ys + cols_new)
        cav[xs: xe, ys: ye] = img
        for _ in range(int(eachtime*fps)):
            video_writer.write(cav)

def addVerticalOpening(video_writer,img,backimg=None,fps=18,sec=1,mode='H'):
    """视频特效:竖向开幕H 横向开幕V"""
    rows, cols = img.shape[:2]

    '''画布准备'''
    cav = None
    if backimg is None:
        cav_np = np.zeros((rows, cols), np.uint8)
        cav = cv2.cvtColor(cav_np, cv2.COLOR_GRAY2BGR)
    else:
        cav = backimg

    '''特效展示'''
    load_f = 1000/fps
    n = 5
    height_half,weight_half = int(rows / 2),int(cols / 2)
    xs1, xs2 = height_half, height_half
    xe1, xe2 = height_half, height_half
    ys1, ys2 = weight_half, weight_half
    ye1, ye2 = weight_half, weight_half
    for t in range(int(sec*1000 // load_f)):
        load_percent = 0.5 / (sec ** n) * ((sec - t * load_f / 1000) ** n)
        if mode=='H':
            load_height = int((0.5 - load_percent) * rows)
            xe1, xe2 = height_half - load_height, height_half + load_height
            cav[xe1:xs1, :] = img[xe1:xs1, :]
            cav[xs2:xe2, :] = img[xs2:xe2, :]
            xs1, xs2 = xe1, xe2
        else:
            load_weight = int((0.5 - load_percent) * cols)
            ye1, ye2 = weight_half - load_weight,weight_half + load_weight
            cav[:, ye1:ys1] = img[:, ye1:ys1]
            cav[:, ys2:ye2] = img[:, ys2:ye2]
            ys1, ys2 = ye1, ye2
        video_writer.write(cav)

def addFadeOut(video_writer,img,backimg=None,fps=18,sec=2):
    """视频特效:渐隐"""

    '''特效展示'''
    load_f = 1000/fps
    n = 1
    for t in range(int(sec * 1000 // load_f)):
        sc = 1 - 1 / (sec ** n) * (t * load_f / 1000) ** n
        img_show = cv2.multiply(img, (1, 1, 1, 1), scale=sc)
        video_writer.write(img_show)

def addFadeIn(video_writer,img,fps=18,sec=2):
    """视频特效:渐隐"""

    '''特效展示'''
    load_f = 1000/fps
    n = 1.5
    for t in range(int(sec * 1000 // load_f)):
        sc = 1 - 1 / (sec ** n) * (t * load_f / 1000) ** n
        sc = 1 - 1 / (sec ** n) * (sec - t * load_f / 1000) ** n
        img_show = cv2.multiply(img, (1, 1, 1, 1), scale=sc)
        video_writer.write(img_show)

def percent_func_gen(a, b, time, n, mode):
    """
    高次多项式计算函数生成器
    :param a: 起始百分比(如:0.25)
    :param b: 结束百分比
    :param time: 动画持续时间
    :param n: 多项式次数
    :param mode: faster(越来越快)、slower(越来越慢)
    :return: 每个时刻到达百分比的计算函数
    """
    if mode == "slower":
        a, b = b, a
    delta = abs(a - b)
    sgn = 1 if b - a > 0 else (-1 if b - a < 0 else 0)
    def percent_calc(ti):
        if mode == "slower":
            ti = time - ti
        return sgn * delta / (time ** n) * (ti ** n) + a
    return percent_calc
    
def addAdvance(video_writer,img,fps=18,sec=2):
    """视频特效:推近"""
    rows, cols = img.shape[:2]

    '''特效展示'''
    load_f = 1000/fps
    percent_func = percent_func_gen(a=0, b=0.2, time=sec, n=4, mode="slower")
    for t in range(int(sec * 1000 // load_f + 1)):
        percent = percent_func(t * load_f / 1000)
        xs, xe = int(percent * rows), int((1 - percent) * rows)
        ys, ye = int(percent * cols), int((1 - percent) * cols)
        img_show = img[xs:xe, ys:ye]
        img_show = cv2.resize(img_show, (cols,rows))
        video_writer.write(img_show)

def addZoomOut(video_writer,img,fps=18,sec=2):
    """视频特效:拉远"""
    rows, cols = img.shape[:2]

    '''特效展示'''
    load_f = 1000/fps
    percent_func = percent_func_gen(a=0.2, b=0, time=sec, n=3, mode="slower")
    for t in range(int(sec * 1000 // load_f + 1)):
        percent = percent_func(t * load_f / 1000)
        xs, xe = int(percent * rows), int((1 - percent) * rows)
        ys, ye = int(percent * cols), int((1 - percent) * cols)
        img_show = img[xs:xe, ys:ye]
        img_show = cv2.resize(img_show, (cols,rows))
        video_writer.write(img_show)

def addSquareOpening(video_writer,img,backimg=None,fps=18,sec=2):
    """视频特效:方形开幕"""
    rows, cols = img.shape[:2]
    '''画布准备'''
    cav = None
    if backimg is None:
        cav_np = np.zeros((rows, cols), np.uint8)
        cav = cv2.cvtColor(cav_np, cv2.COLOR_GRAY2BGR)
    else:
        cav = backimg
        
    '''特效展示'''
    load_f = 1000/fps
    percent_func = percent_func_gen(a=0, b=0.5, time=sec, n=5, mode="faster")
    rows_half = rows // 2
    cols_half = cols // 2
    for t in range(int(sec * 1000 // load_f + 1)):
        percent = percent_func(t * load_f / 1000)
        width, height = int(percent * rows), int(percent * cols)
        xs, xe = rows_half-width, rows_half+width
        ys, ye = cols_half-height, cols_half+height
        cav[xs:xe, ys:ye] = img[xs:xe, ys:ye]
        video_writer.write(cav)
        
def addGradientWipe(video_writer,img,backimg=None,fps=18,sec=2,mode='L'):   
    """视频特效:灰度渐变 L左 R右 U上 D下"""
    rows, cols = img.shape[:2]

    '''灰度准备'''
    img_gray_bgr = None
    if backimg is None:
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        img_gray_bgr = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2BGR)
    else:
        img_gray_bgr = backimg

    '''特效展示'''
    load_f = 1000/fps
    percent_func = percent_func_gen(a=0, b=1, time=sec, n=1, mode="slower")
    if mode=='L':
        ys, ye = 0, 0
        for t in range(int(sec * 1000 // load_f + 1)):
            percent = percent_func(t * load_f / 1000)
            width = int(percent * cols)
            ye = width
            img_gray_bgr[:, ys:ye] = img[:, ys:ye] 
            ys = ye
            video_writer.write(img_gray_bgr)
    if mode=='R':
        ys, ye = cols, cols
        for t in range(int(sec * 1000 // load_f + 1)):
            percent = percent_func(t * load_f / 1000)
            width = int(percent * cols)
            ys = cols-width
            img_gray_bgr[:, ys:ye] = img[:, ys:ye] 
            ye = ys
            video_writer.write(img_gray_bgr)
    if mode=='U':
        xs, xe = 0, 0
        for t in range(int(sec * 1000 // load_f + 1)):
            percent = percent_func(t * load_f / 1000)
            height = int(percent * rows)
            xe = height
            img_gray_bgr[xs:xe, :] = img[xs:xe, :] 
            xs = xe
            video_writer.write(img_gray_bgr)
    if mode=='D':
        xs, xe = rows, rows
        for t in range(int(sec * 1000 // load_f + 1)):
            percent = percent_func(t * load_f / 1000)
            height = int(percent * rows)
            xs = cols-height
            img_gray_bgr[xs:xe, :] = img[xs:xe, :] 
            xe = xs
            video_writer.write(img_gray_bgr)

调用方法进行视频合成

python 复制代码
fps = 25 #视频帧数
sec = 3 # 特效时间
eachtime = 0.5 # 每帧所占时间
video_temp_path= "test.mp4"
img1 = cv2.imread("0.jpg")
img2 = cv2.imread("1.jpg")
img3 = cv2.imread("2.jpg")
video_height,video_weight =img.shape[:2]
video_writer = cv2.VideoWriter(video_temp_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (video_weight,video_height))
addCardFrame(video_writer,img1,fps,sec,eachtime)
addVerticalOpening(video_writer,img2,img1,fps,sec,mode='V')
addFadeOut(video_writer,img3,fps,sec)
addFadeIn(video_writer,img1,fps,sec)
addAdvance(video_writer,img2,fps,sec)
addZoomOut(video_writer,img3,fps,sec)
addSquareOpening(video_writer,img2,img3,fps,sec)
addGradientWipe(video_writer,img1,img2,fps,sec,mode='D')
video_writer.release()

视频效果如下:

相关推荐
Xudde.7 小时前
班级作业笔记报告0x04
笔记·学习·安全·web安全·php
极梦网络无忧9 小时前
OpenClaw 基础使用说明(中文版)
python
codeJinger9 小时前
【Python】操作Excel文件
python·excel
XLYcmy10 小时前
一个针对医疗RAG系统的数据窃取攻击工具
python·网络安全·ai·llm·agent·rag·ai安全
zzh08110 小时前
MySQL高可用集群笔记
数据库·笔记·mysql
Islucas10 小时前
Claude code入门保姆级教程
python·bash·claude
萝卜白菜。10 小时前
TongWeb7.0相同的类指明加载顺序
开发语言·python·pycharm
绛橘色的日落(。・∀・)ノ10 小时前
Matplotlib实践学习笔记
笔记·学习
chase。10 小时前
【学习笔记】AGILE:把人形机器人强化学习从“玄学”变成“工程学”
笔记·学习·敏捷流程