Python-OpenCV 实现美图秀秀视频剪辑效果【转场】

前言

上一篇 我们讨论了单张图片的特效实现,这一篇我们讨论两张图片的转场实现

以下是练习时用到的两张图片素材(当然,只是简单练习嘛,图像尺寸都是一样的,还都是正方形)


001.jpg

002.jpg

一、闪黑

效果对比


美图秀秀【闪黑】

OpenCV实现【闪黑】

实现思路

思路很简单,就是把上一篇的渐隐和渐显组合起来使用就行

实现代码

import cv2
import numpy as np


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


'''读入图像'''
img1 = cv2.imread("001.jpg")
img2 = cv2.imread("002.jpg")
rows, cols = img1.shape[:2]

'''特效展示'''
load_f = 20
tim = 0.2
percent_func1 = percent_func_gen(a=1, b=0, time=tim, n=1, mode="null")
percent_func2 = percent_func_gen(a=0, b=1, time=tim, n=1, mode="null")
for t in range(int(tim * 1000) // load_f + 1):
    percent = percent_func1(t * load_f / 1000)
    img_show = cv2.multiply(img1, (1, 1, 1, 1), scale=percent)
    cv2.imshow("show", img_show)
    cv2.waitKey(load_f)
for t in range(int(tim * 1000) // load_f + 1):
    percent = percent_func2(t * load_f / 1000)
    img_show = cv2.multiply(img2, (1, 1, 1, 1), scale=percent)
    cv2.imshow("show", img_show)
    cv2.waitKey(load_f)

'''关闭窗口'''
cv2.waitKey(1500)
cv2.destroyAllWindows()

二、上移/下移/左移/右移

这里以左移为例

效果对比


美图秀秀【左移】

OpenCV实现【左移】

实现思路

思路也很简单,左右拼接好形成一张图,然后利用仿射变换平移、在有限大小的画布内展示即可

实现代码

import cv2
import numpy as np


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


'''读入图像'''
img1 = cv2.imread("001.jpg")
img2 = cv2.imread("002.jpg")
rows, cols = img1.shape[:2]

'''画布准备'''
img = np.hstack([img1, img2])

'''特效展示'''
load_f = 20
tim = 0.3
percent_func = percent_func_gen(a=0, b=1, time=tim, n=2, mode="faster")
for t in range(int(tim * 1000) // load_f + 1):
    percent = percent_func(t * load_f / 1000)
    x = int(percent * cols)
    M = np.float32([[1, 0, -x], [0, 1, 0]])
    res = cv2.warpAffine(img, M, (rows, cols))
    cv2.imshow("show", res)
    cv2.waitKey(load_f)

'''关闭窗口'''
cv2.waitKey(1500)
cv2.destroyAllWindows()

三、向上擦除/向下擦除/向左擦除/向右擦除

这里以向下擦除为例

效果对比


美图秀秀【向下擦除】

OpenCV实现【向下擦除】

实现思路

以第一张图为背景,将第二张图的局部不断覆盖

实现代码

import cv2
import numpy as np


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


'''读入图像'''
img1 = cv2.imread("001.jpg")
img2 = cv2.imread("002.jpg")
rows, cols = img1.shape[:2]

'''特效展示'''
load_f = 20
tim = 0.3
percent_func = percent_func_gen(a=0, b=1, time=tim, n=1, mode="null")
for t in range(int(tim * 1000) // load_f + 1):
    percent = percent_func(t * load_f / 1000)
    height = int(percent * rows)
    img1[:height, :] = img2[:height, :]
    cv2.imshow("show", img1)
    cv2.waitKey(load_f)

'''关闭窗口'''
cv2.waitKey(1500)
cv2.destroyAllWindows()

四、横向拉幕/竖向拉幕

这里以横向拉幕为例

效果对比


美图秀秀【横向拉幕】

OpenCV实现【横向拉幕】

实现思路

思路很简单,就是把上一篇的横向开幕的画布换成第二张图片即可

实现代码

import cv2
import numpy as np


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


'''读入图像'''
img1 = cv2.imread("001.jpg")
img2 = cv2.imread("002.jpg")
rows, cols = img1.shape[:2]

'''特效展示'''
load_f = 20
tim = 0.3
half = int(rows / 2)
percent_func = percent_func_gen(a=0, b=0.5, time=tim, n=1, mode="null")
for t in range(int(tim * 1000) // load_f + 1):
    percent = percent_func(t * load_f / 1000)
    width = int(percent * rows)
    ys, ye = half - width, half + width
    img1[:, ys:ye] = img2[:, ys:ye]
    cv2.imshow("show", img1)
    cv2.waitKey(load_f)

'''关闭窗口'''
cv2.waitKey(1500)
cv2.destroyAllWindows()

五、旋转

效果对比


美图秀秀【旋转】

OpenCV实现【旋转】

实现思路

拼接好左上、右上、左下、右下四张图作为一张图,利用仿射变换的旋转实现效果

对图一: { 左上 原图 右上 左右翻转 左下 上下翻转 右下 上下左右翻转 对图一: \begin{cases} 左上 & 原图 \\ 右上 & 左右翻转 \\ 左下 & 上下翻转 \\ 右下 & 上下左右翻转 \\ \end{cases} 对图一: 左上右上左下右下原图左右翻转上下翻转上下左右翻转

对图二: { 左上 左右翻转 右上 原图 左下 上下左右翻转 右下 上下翻转 对图二: \begin{cases} 左上 & 左右翻转 \\ 右上 & 原图 \\ 左下 & 上下左右翻转 \\ 右下 & 上下翻转 \\ \end{cases} 对图二: 左上右上左下右下左右翻转原图上下左右翻转上下翻转

要想和美图秀秀做到很相近的效果,需要能够确定好旋转中心,这一点有点难,暂定图像中心为旋转中心

同时,为了避免旋转过程中边角出现黑边,将图像再次扩充为 3 × 3 3 \times 3 3×3

实现代码

import cv2
import numpy as np


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


'''读入图像'''
import cv2
import numpy as np


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


'''读入图像'''
img1 = cv2.imread("001.jpg")
img2 = cv2.imread("002.jpg")
rows, cols = img1.shape[:2]

'''画布准备'''
img1_ru = cv2.flip(img1, 1)
img1_ld = cv2.flip(img1, 0)
img1_rd = cv2.flip(img1, -1)
img1_u = np.hstack([img1, img1_ru])
img1_d = np.hstack([img1_ld, img1_rd])
img1_res_tmp = np.vstack([img1_u, img1_d])
img1_res_tmp = np.hstack([img1_res_tmp] * 3)
img1_res = np.vstack([img1_res_tmp] * 3)

img2_lu = cv2.flip(img2, 1)
img2_rd = cv2.flip(img2, 0)
img2_ld = cv2.flip(img2, -1)
img2_u = np.hstack([img2_lu, img2])
img2_d = np.hstack([img2_ld, img2_rd])
img2_res_tmp = np.vstack([img2_u, img2_d])
img2_res_tmp = np.hstack([img2_res_tmp] * 3)
img2_res = np.vstack([img2_res_tmp] * 3)

res_rows, res_cols = img1_res.shape[:2]

'''特效展示'''
load_f = 20
tim = 0.2
angle_all = 150
point1 = (rows * 3, cols * 3)
point2 = (rows * 3, cols * 4)
percent_func1 = percent_func_gen(a=0, b=1, time=tim, n=4, mode="faster")
percent_func2 = percent_func_gen(a=1, b=0, time=tim, n=4, mode="slower")
for t in range(int(tim * 1000) // load_f + 1):
    percent = percent_func1(t * load_f / 1000)
    angle = percent * angle_all
    M1 = cv2.getRotationMatrix2D(point1, angle, 1)
    res = cv2.warpAffine(img1_res, M1, (res_rows, res_cols))
    M2 = np.float32([[1, 0, -cols * 2], [0, 1, -rows * 2]])
    res = cv2.warpAffine(res, M2, (rows, cols))
    cv2.imshow("show", res)
    cv2.waitKey(load_f)
for t in range(int(tim * 1000) // load_f + 1):
    percent = percent_func2(t * load_f / 1000)
    angle = -percent * angle_all
    M2 = cv2.getRotationMatrix2D(point2, angle,  1)
    res = cv2.warpAffine(img2_res, M2, (res_rows, res_cols))
    M2 = np.float32([[1, 0, -cols * 3], [0, 1, -rows * 2]])
    res = cv2.warpAffine(res, M2, (rows, cols))
    cv2.imshow("show", res)
    cv2.waitKey(load_f)

'''关闭窗口'''
cv2.waitKey(1500)
cv2.destroyAllWindows()

六、上下切割/左右切割

这里以左右切割为例

效果对比


美图秀秀【左右切割】

OpenCV实现【左右切割】

实现思路

上下两个部分分别使用仿射变换进行不同的平移操作

实现代码

import cv2
import numpy as np


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


'''读入图像'''
img1 = cv2.imread("001.jpg")
img2 = cv2.imread("002.jpg")
rows, cols = img1.shape[:2]

'''画布准备'''
img_u = np.hstack([img1, img2])
img_d = np.hstack([img2, img1])

'''特效展示'''
load_f = 20
tim = 0.4
percent_func = percent_func_gen(a=0, b=1, time=tim, n=3, mode="slower")
for t in range(int(tim * 1000) // load_f + 1):
    percent = percent_func(t * load_f / 1000)
    x = int(percent * cols)
    M1 = np.float32([[1, 0, -x], [0, 1, 0]])
    res1 = cv2.warpAffine(img_u, M1, (rows, cols))[:rows // 2, :]
    M2 = np.float32([[1, 0, x - cols], [0, 1, 0]])
    res2 = cv2.warpAffine(img_d, M2, (rows, cols))[rows // 2:, :]
    res = np.vstack([res1, res2])
    cv2.imshow("show", res)
    cv2.waitKey(load_f)

'''关闭窗口'''
cv2.waitKey(1500)
cv2.destroyAllWindows()
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

God-Excious

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值