写点什么

两个视频内容的透明化融合处理

用户头像
老猿Python
关注
发布于: 刚刚
两个视频内容的透明化融合处理

一、引言

在《moviepy音视频剪辑:使用rotate函数实现视频变换处理以及参数expand取值为True时的花屏问题解决方案》介绍了视频旋转的方法和花屏问题解决方案,Baby CY 博友提了个问题:“旋转后会出现黑色的背景填充,请问能把黑色去掉变成透明吗?”,该问题是视频旋转时,由于视频内容为矩形,旋转时部分区域有内容,部分区域无内容为黑色透明色,且随着旋转这部分的范围是变化的,Baby CY 希望当该视频和其他视频叠加时,旋转视频的黑色部分不遮挡下层视频的内容。

老猿以前没有对这个进行过研究,但觉得用使用遮罩是可以的,后来仔细研究了一下,发现可以使用遮罩或图像处理技术都可以实现,下面分别介绍这两种实现方式。


二、相关素材介绍


  • WinBasedWorkHard_src.mp4:周星驰的“爱拼才会赢”MV 抖音视频

  •  mydream.mp4:张靓颖的“我的梦”抖音视频

  •  Lotus.jpg:荷花图片


三、使用 mask 遮罩实现视频叠加透明效果

2.1、概述

在《moviepy音视频剪辑:mask clip遮罩剪辑、遮片、蒙版的作用以及其包含的构成内容》中介绍:“mask 遮罩是一种只有灰度值的像素构成的帧组成的剪辑,其作用就是在带 mask 的剪辑与其他剪辑合成时确认是否显示带 mask 剪辑的对应像素。”因此可以支持实现一个视频增加一个遮罩,遮罩剪辑透明部分就可以允许下层的视频显示。


2.2、程序实现

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


相关程序包括如下函数

  • ridPicBackground:去掉图片背景色,被 convertPicToVideo 调用

  • convertPicToVideo:将图片转成视频,被 videoOverlyObjMask 调用

  • videoOverlyObjMask:将视频和叠加对象叠加

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


def videoOverlyObjMask(videoFName,objType='self',obj=None): """ 剪辑自身叠加一个该剪辑旋转的层,旋转层带自身转换的遮罩剪辑 :param videoFName: 剪辑来源视频文件 :return: 参数视频剪辑自身叠加一个该剪辑旋转层剪辑 """ clip = VideoFileClip(videoFName, audio=True) objClip = clip if 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
rotateClip = objClip.rotate(angleF,expand=True).fx(vfx.resize,clip.size) maskclip = rotateClip.to_mask() rotateClip = rotateClip.set_mask(maskclip)
clipVideo = CompositeVideoClip([clip, rotateClip]) return clipVideo if __name__=='__main__': #实现剪辑和自身旋转剪辑叠加 result2 = videoOverlyObjMask(r"F:\video\WinBasedWorkHard_src.mp4") result2.write_videofile(r"F:\video\WinBasedWorkHard_mask_self.mp4", threads=8) #实现剪辑和图片构造的旋转剪辑叠加 result3 = videoOverlyObjMask(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 = videoOverlyObjMask(r"F:\video\mydream.mp4", 'video',r"F:\video\WinBasedWorkHard_src.mp4") result4.write_videofile(r"F:\video\WinBasedWorkHard_mask_video.mp4", threads=8)

复制代码

2.3、案例效果

2.3.1、剪辑和自身旋转剪辑叠加效果


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



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



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

3.1、概述

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

3.2、程序实现

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


相关程序包括如下函数:

  • adjustImgAccordingToRefImg:参考底层视频大小调整上层视频大小,被帧生成函数 get_frame 调用

  • get_frame:根据两个需要叠加的视频的帧生成结果视频的帧,生成时调用 adjustImgAccordingToRefImg 调整上层视频大小

  • ridPicBackground:去掉图片背景色,被 convertPicToVideo 调用

  • convertPicToVideo:将图片转成视频,被 videoOverlyObjMask 调用

  • 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)
复制代码


3.3、案例效果


3.3.1、剪辑和自身旋转剪辑叠加效果


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



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


四、小结

本文介绍了通过 moviepymask 遮罩或 OpenCV 图像融合实现两个剪辑的叠加融合,实现了上层剪辑背景色部分不遮挡下层剪辑内容的效果。通过实现案例的介绍,可以理解遮罩剪辑和 OpenCV 图像运算的作用,并在视频特效制作中使用相关方法。


更多关于 Moviepy 的介绍请大家参考《Python音视频剪辑库MoviePy1.0.3中文教程导览及可执行工具下载》。

用户头像

老猿Python

关注

学问无遗力,功夫老始成。 2020.08.21 加入

InfoQ签约作者,CSDN 2020年博客之星季军、高级程序员、超50万行C语言项目开发经验 擅长领域:Python语言、PyQt界面程序开发、Moviepy音视频剪辑、OpenCV-Python图像处理、爬虫、5G、区块链、人工智能数学基础

评论

发布
暂无评论
两个视频内容的透明化融合处理