OpenCV图像运算+Moviepy实现视频旋转叠加

☞ ░ 前往老猿Python博客 https://blog.csdn.net/LaoYuanPython

一、引言

在《OpenCV-Python常用图像运算:加减乘除幂开方对数及位运算》介绍了OpenCV主要的图像运算,视频是由一帧帧图像构成,通过OpenCV和Moviepy的灵活运用,可以实现一些特殊的特效。本文将介绍通过OpenCV图像运算+Moviepy实现视频叠加透明效果。

二、程序实现

本案例实现一个可以在视频上面叠加一个旋转视频或旋转图片的通用方法,支持两个内容大小不同的视频叠加。为了支持叠加对象为图片,需要将图片转换成视频,为了尽可能突出图片的表达内容,在将图片转视频前将图片的背景色转换为黑色。
相关程序包括如下函数:

  1. adjustImgAccordingToRefImg:参考底层视频大小调整上层视频大小,被帧生成函数get_frame调用
  2. get_frame:根据两个需要叠加的视频的帧生成结果视频的帧,生成时调用adjustImgAccordingToRefImg调整上层视频大小
  3. ridPicBackground:去掉图片背景色,被convertPicToVideo调用
  4. convertPicToVideo:将图片转成视频,被videoOverlyObjMask调用
  5. videoOverlyObjMask:将视频和叠加对象对应视频叠加,叠加时通过adjustImgAccordingToRefImg参考底层视频帧大小调整上层视频帧大小

上述函数中关键函数为get_frame、videoOverlyObjMask,这二个函数是视频旋转并叠加的主程序代码。相关程序代码如下:



def get_frame(level0Clip,level1Clip,t):
    """
    功能:根据两个大小不同的剪辑生成结果剪辑的帧
    :param level0Clip: 底层的剪辑,一般要求该剪辑的宽和高度不小于上层剪辑的宽和高,如果超过就只剪裁掉超出范围的边缘部分
    :param level1Clip: 上层剪辑,要求该剪辑为黑色的部分不能覆盖底层剪辑的图像
    :param t: 帧对应时刻
    :return: 新剪辑对应t时刻的合成帧,其图像为上层剪辑非透明部分叠加底层剪辑未被上层非透明部分覆盖部分
    """

    img1 = level0Clip.get_frame(t)
    img2 = level1Clip.get_frame(t)
    if img1.size!=img2.size:#如果两个剪辑大小不同
        img2 = adjustImgAccordingToRefImg(img2, img1) #根据底层剪辑的帧大小调整上层剪辑的大小,确保最终两个剪辑大小一致

    #取上层剪辑的非透明部分和底层剪辑未被覆盖部分
    imgGray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) #将上层剪辑帧图像转成灰度图
    retval, imgMask = cv2.threshold(imgGray, 1, 255, type=cv2.THRESH_BINARY) #将灰度图二值化作为掩膜
    maskInv = cv2.bitwise_not(imgMask) #上层剪辑掩膜求反,用于获取底层剪辑需要显示内容
    result = cv2.bitwise_and(img2, img2, mask=imgMask) + cv2.bitwise_and(img1, img1, mask=maskInv)
    return result


def videoOverlyRotateObj(videoFName,objType='self',obj=None):
    """
    剪辑自身叠加一个该剪辑旋转的层,旋转层黑色的部分不能遮挡下层的剪辑内容
    :param videoFName: 剪辑来源视频文件
    :param objType、obj:
        self:剪辑自身叠加自身旋转内容,obj值忽略
        img:图片文件或图片矩阵对象,obj值为图片文件名会图片对象
        video:视频文件或剪辑,obj为视频文件名或剪辑对象
    :return: 参数视频剪辑自叠加一个旋转层对象,旋转层由参数objType、obj决定,对象大小最好小于videoFName对应视频大小,否则会被裁减
    """
    clip = VideoFileClip(videoFName, audio=True)
    if objType=='self':
        objClip = clip
    elif objType=='img':
        objClip = convertPicToVideo(obj, duration=clip.duration, createMask=False).set_fps(clip.fps)
    elif  objType=='video':
        if isinstance(obj,str): objClip = VideoFileClip(obj, audio=False)
        else: objClip = obj

    maskclip = objClip.rotate(angleF,expand=True).fx(vfx.resize,clip.size)

    make_frame = lambda t:get_frame(clip,maskclip,t)
    newclip = VideoClip( make_frame=make_frame,  duration=clip.duration).set_fps(clip.fps)

    return newclip

if __name__=='__main__':
    result1 = videoOverlyRotateObj(r"F:\video\WinBasedWorkHard_src.mp4",'img',r'F:\pic\Lotus.JPG')
    result1.write_videofile(r"F:\video\WinBasedWorkHard_new.mp4", threads=8)
    result2 = videoOverlyRotateObj(r"F:\video\WinBasedWorkHard_src.mp4")
    result2.write_videofile(r"F:\video\WinBasedWorkHard_mask_self.mp4", threads=8)
    result3 = videoOverlyRotateObj(r"F:\video\WinBasedWorkHard_src.mp4",'img',r'F:\pic\Lotus.JPG')
    result3.write_videofile(r"F:\video\WinBasedWorkHard_mask_pic.mp4", threads=8)
    result4 = videoOverlyRotateObj(r"F:\video\mydream.mp4", 'video',r"F:\video\WinBasedWorkHard_src.mp4")
    result4.write_videofile(r"F:\video\WinBasedWorkHard_mask_video.mp4", threads=8)

为了与付费专栏的文章有所差别,其他次要函数在此就不提供代码了。本文对应的付费专栏文章为《使用OpenCV图像运算+Moviepy实现视频叠加案例》。

三、案例效果

3.1、相关素材介绍
  • WinBasedWorkHard_src.mp4:周星驰的“爱拼才会赢”MV抖音视频
  • mydream.mp4:张靓颖的“我的梦”抖音视频
  • Lotus.jpg:荷花图片
    在这里插入图片描述
3.2、剪辑和自身旋转剪辑叠加效果

在这里插入图片描述

3.3、视频和图片构造的旋转剪辑叠加

在这里插入图片描述

3.4、剪辑和另一个旋转剪辑叠加效果

在这里插入图片描述

四、小结

本文详细了使用OpenCV图像运算+Moviepy实现视频叠加后,最终结果剪辑中的上层剪辑和下层剪辑叠加后,上层剪辑背景色部分被下层剪辑内容所呈现替代的方案。通过该实现案例的介绍,可以理解OpenCV图像运算在图像处理中的作用,并在多个剪辑制作特效中使用该方法制作视频特效。

如果觉得本文可以给您带来帮助,请大家帮忙点个赞、加个收藏,谢谢!

更多OpenCV-Python的介绍请参考专栏《OpenCV-Python图形图像处理 》
专栏网址https://blog.csdn.net/laoyuanpython/category_9979286.html

更多moviepy的介绍请参考《PyQt+moviepy音视频剪辑实战文章目录》或《moviepy音视频开发专栏》。这2个专栏内容的导读请参考《Python音视频剪辑库MoviePy1.0.3中文教程导览及可执行工具下载》。

本文对应的付费专栏文章为《使用OpenCV图像运算+Moviepy实现视频叠加案例》。

关于老猿的付费专栏

老猿的付费专栏《使用PyQt开发图形界面Python应用 》(https://blog.csdn.net/laoyuanpython/category_9607725.html)专门介绍基于Python的PyQt图形界面开发基础教程,付费专栏《moviepy音视频开发专栏》 (https://blog.csdn.net/laoyuanpython/category_10232926.html)详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,两个专栏都适合有一定Python基础但无相关知识的小白读者学习。

付费专栏文章目录:《moviepy音视频开发专栏文章目录》(https://blog.csdn.net/LaoYuanPython/article/details/107574583)、《使用PyQt开发图形界面Python应用专栏目录 》(https://blog.csdn.net/LaoYuanPython/article/details/107580932)。

对于缺乏Python基础的同仁,可以通过老猿的免费专栏《专栏:Python基础教程目录》(https://blog.csdn.net/laoyuanpython/category_9831699.html)从零开始学习Python。

如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。

跟老猿学Python、学OpenCV!

☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython
  • 8
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

LaoYuanPython

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

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

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

打赏作者

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

抵扣说明:

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

余额充值