用Python制作灯光秀短视频的思路详解


Posted in Python onApril 13, 2021

一、引言

2021年4月8日武汉重启一周年,这是个值得庆祝的日子,作为一个武汉人和一个死宅程序员,老猿也想在这个日子留下点什么。想起武汉长江两岸的灯光秀,顿时有了主意,那就用程序实现一个武汉重启庆祝的灯光秀短视频吧,于是在4月7日晚开始构思和着手开发,4月8日晚终于顺利完成,并且通过使用OpenCV、OpenCV+Moviepy两种方式进行了实现。

本文介绍结合Python+OpenCV+Moviepy实现的思路和过程,Python+OpenCV实现的思路和过程将在另外的博文中单独介绍。

二、实现思路

2.1、视频内容设计

老猿是个没有艺术细胞的人,因此这个视频内容只能说仅能代表是个视频而已,对最终的内容表现大家就不需要过多评价。

在创作该视频前,对视频进行了简单规划,将创作视频分为片头、视频内容和片尾三部分:

  • 片头:5秒时间,展现一幅黄鹤楼的照片,并带上“武汉重启一周年灯光秀”的标题
  • 视频内容:全长35秒,每隔2秒随机展现一张武汉灯光秀景观图,并在视频中附上向上滚动的文字“热烈庆祝武汉重启一周年!”、“武汉万岁!中国万岁!”,并在视频的左下角和右下角用红绿蓝三色画三条向上晃动的线条表示彩色激光
  • 片尾:25秒,每隔2秒随机展现武汉的一张风景照,并展现“制作:老猿Python”等制作信息。

 2.2、开发设计

 2.2.1、视频图片处理

视频中用到的图片都来源于互联网,为了确保视频输出,所有图片都调整到了统一大小。
在程序中通过全局变量将片头使用图像使用了全局变量进行保存,视频内容使用图像、片尾使用图像分别通过两个全局生成器进行访问,两个全局生成器能从列表中顺序取出图片,并在到达列表结尾时回到第一个元素。当然生成器访问的方法也可以不使用生成器而使用多个全局变量来实现。

2.2.2、灯光效果处理

在视频内容部分,左下角和右下角发射的彩色激光,采用在背景图片中根据时间动态绘制彩色线条,实现彩色激光晃动照射的效果,为了限制晃动范围,设定了激光终点的x值的最小值和最大值。激光终点的位置根据时间动态计算,并在到达x值的最小值或最大值时自动回扫。

2.2.3、帧图像的生成

为了符合Moviepy剪辑get_frame函数仅带一个时间参数t的要求,上面介绍的图像处理,全部集中在一个帧图像生成函数中处理,该函数仅带一个参数时间t。

帧图像生成函数判断时间来决定现在生成的内容是片头、内容还是片尾,然后据此来进行帧图像的生成。生成时,需要判断图像是否切换,因此需要记录上一次切换的时间和切换后的图像,确保未达到切换时间前用上次图像作为帧图像的背景,达到切换时间要求后切换新的图像作为后续帧图像生成的背景。为此在该函数中使用了两个全局变量来记录当前帧图像背景图片和上次切换时间。

2.2.4、输出到视频

为了将视频输出到文件,通过Moviepy构建剪辑,指定帧图像生成函数,并给视频附加音频,然后使用剪辑输出的方法将视频输出到指定文件,最终得到一个完整的视频。

三、具体实现

 3.1、总流程

  • 加载片头图像,构造视频内容、片尾需要使用图像访问的生成器;
  • 构建帧图像生成函数,根据帧图像生成逻辑生成帧图像
  • 加载并绑定音频音频、指定帧率、时长、帧图像生成函数构造视频剪辑对象;
  • 将视频剪辑输出到文件。

3.2、定义两个图片获取生成器函数

两个图片获取生成器为构造视频内容、片尾提供背景图像;

def getLightShowImgFun():#定义灯光秀图片访问生成器函数
    lightShowImgList = [cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-一桥俯瞰.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-一桥激光.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-二七桥.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-二桥.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-晴川桥.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-月湖.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-汉口.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-汉口3.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-汉口江景.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-远光青山.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-隔江看汉口.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-青山.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-黄鹤楼.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀-龟山电视塔.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_一桥.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_一桥底部.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_一桥远景.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_桥.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_桥上灯.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_武汉江边.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_远桥.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀江景.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀江滩.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀激光.jpg'), (800, 600)),
                        cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀远观汉口.jpg'), (800, 600))]
    index = 0
    count = len(lightShowImgList)
    while True:
        index += 1
        if index>=count:index = 1
        yield lightShowImgList[index-1]


def getWHImgFunc():#定义片尾图片访问生成器函数
    # 片尾背景图片
    whImgList = [cv2.resize(readImgFile(r'f:\pic\武汉\东湖1.jpg'), (800, 600)),
                 cv2.resize(readImgFile(r'f:\pic\武汉\东湖2.jpg'), (800, 600)),
                 cv2.resize(readImgFile(r'f:\pic\武汉\东湖樱园樱花.jpg'), (800, 600)),
                 cv2.resize(readImgFile(r'f:\pic\武汉\武大牌楼.jpg'), (800, 600)),
                 cv2.resize(readImgFile(r'f:\pic\武汉\武大牌楼远观.jpg'), (800, 600)),
                 cv2.resize(readImgFile(r'f:\pic\武汉\武大樱花2.jpg'), (800, 600)),
                 cv2.resize(readImgFile(r'f:\pic\武汉\武大樱园顶高拍照.jpg'), (800, 600)),
                 cv2.resize(readImgFile(r'f:\pic\武汉\武大樱园门洞.jpg'), (800, 600)),
                 cv2.resize(readImgFile(r'f:\pic\武汉\武大樱园入口.jpg'), (800, 600)),
                 cv2.resize(readImgFile(r'f:\pic\武汉\武大老图书馆.jpg'), (800, 600))]

    index = 0
    count = len(whImgList)
    while True:
        index += 1
        if index>=count:index = 1
        yield whImgList[index-1]

3.3、全局变量初始化

全局变量主要是视频片头使用图片hhlImg、两个生成器,以及preImg,preTime用于记录上次切换视频图片的图片和切换时间。

#片头背景图片
hhlImg = cv2.resize(readImgFile(r'f:\pic\武汉\黄鹤楼.jpg'),(800,600))

#灯光秀背景图片和片尾图片全局生成器初始化
getLightShowImg = getLightShowImgFun()
getWHImg = getWHImgFunc()

#上次切换背景图片和切换时间全局变量初始化
preImg,preTime = None,0

3.4、实现给背景图像添加彩色激光照射效果

lightShowImg函数实现给背景图像指定点发射彩色激光的特效,激光发射点固定,由参数lightStartPos指定,终点随参数t在一定范围内变化,终点x坐标受参数minX, maxX控制,同一个发射源的三激光之间的间距受参数distance控制。

def lightShowImg(bg,minX, maxX,distance,lightStartPos,t):
    """
    实现在背景图像上添加当前散发彩色激光的处理
    :param bg: 背景图像
    :param minX:灯光终点的最大x坐标
    :param maxX:灯光终点的最小x坐标
    :param distance: 不同灯光之间的间距
    :param lightStartPos: 灯光发射点
    :param t: 时间t
    :return: 添加了发射灯光的图像
    """
    x =  (minX+int(t*200))%(maxX*2) #按时间t计算灯光终点的x坐标,该坐标可以超出背景图像范围
    img = np.array(bg)
    if x>maxX: #到达最大范围,需要回扫
        x = 2*maxX-x
    color1,color2,color3 = (255,0,0),(0,255,0),(0,0 ,255 ) #蓝、绿、红三色

    cv2.line(img, lightStartPos, (x, 0), color1, 4)
    cv2.line(img, lightStartPos, (x + distance, 0), color2, 4)
    cv2.line(img, lightStartPos, (x - distance, 0), color3, 4)

    return img

3.4、帧图片生成

makeframe函数实现帧图片生成,带一个参数t表示当前帧对应的剪辑时间,在函数内根据剪辑时间来判断是生成片头内容、灯光秀内容还是片尾内容生成t时刻对应帧图像返回。

def makeframe(t):
    """
    makeframe函数实现帧图片生成,带一个参数t表示当前帧对应的剪辑时间,在函数内根据剪辑时间来判断是生成片头内容、灯光秀内容还是片尾内容生成t时刻对应帧图像返回:
    1. 对于片头,采用黄鹤楼照片作为背景,并在图片中央显示“武汉重启一周年灯光秀”;
    2. 对于视频内容,则每2秒从灯光秀图片队列中随机取一张图片作为当前背景图像,并调用lightShowImg增加左下角和右下角的彩色激光效果,同时动态向上滚动显示“热烈庆祝武汉重启一周年”、“武汉万岁!中国万岁!”等标语;
    3. 对于片尾,则每2秒从武汉风景图片队列中随机取一张图片作为当前背景图像,同时动态向上滚动显示制作信息。
    :param t: 生成帧对应剪辑的时间位置
    :return: 对应帧图像
    """
    #生成t时刻的视频帧图像
    global preImg,preTime
    print(f"\rt={t:4.2f}", end='')
    if t<5:#5秒片头
        img = imgAddText(hhlImg,'武汉重启一周年灯光秀',64,(255,0,0),vRefPos='C')
    elif t<40:#5-40秒灯光秀
        minX, maxX = 200, 1200  # 灯光横向扫射范围
        lightStartPos1 = (0, 600)  # 灯光1的发射点坐标设置为左下角
        lightStartPos2 = (800, 600)  # 灯光2的发射点坐标设置为右下角
        if (t-preTime)>2 or preImg is None:
            img = next(getLightShowImg)
            preImg,preTime  = img,t
        else:
            img = preImg
        img = lightShowImg(img, minX, maxX, 80,lightStartPos1, t)
        img = lightShowImg(img, minX-100, maxX+100,48, lightStartPos2, t)
        t = int((t-4)*40)%img.shape[0]
        img = imgAddText(img,'热烈庆祝武汉重启一周年!',48,(0,0,255),vRefPos=-80-t,)
        img = imgAddText(img, '武汉万岁!中国万岁!',48,(255,0,255),vRefPos=-t)
    else:#片尾
        if (t-preTime)>2 or preImg is None:
            img = next(getWHImg)
            preImg,preTime  = img,t
        else:
            img = preImg

        t = int((t - 39) * 20) % img.shape[0]
        img = imgAddText(img,"制作:老猿Python",36,(255,255,255),vRefPos=-120-t)
        img = imgAddText(img, "https://blog.csdn.net/LaoYuanPython",24,(255,255,255),vRefPos= -60-t)
        img = imgAddText(img, "2021年4月8日", 24, (255,255,255), vRefPos=-t)
    img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)

    return img

3.5、制作视频文件

函数buildVideo用于制作视频文件:

def buildVideo():
    #构建视频
    audio = AudioFileClip(r"F:\video\友谊之光.mp3").set_duration(65)
    clip = VideoClip(makeframe, False, 65).set_fps(24).set_audio(audio)
    clip.write_videofile(r"F:\video\lightShow.avi", codec='png', threads=8)

调用buildVideo函数即可完成视频制作。

3.6、视频效果

用Python制作灯光秀短视频的思路详解

四、小结

本文完整介绍了用Python+OpenCV+Moviepy制作一个庆祝武汉重启一周年的武汉灯光秀短视频的实现思路、过程、关键函数等,有助于理解OpenCV的图像操作、Moviepy生成视频的实现。

到此这篇关于用Python制作灯光秀短视频的文章就介绍到这了,更多相关python制作短视频内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python基于回溯法子集树模板实现8皇后问题
Sep 01 Python
Django重装mysql后启动报错:No module named ‘MySQLdb’的解决方法
Apr 22 Python
numpy中的delete删除数组整行和整列的实例
May 09 Python
python os用法总结
Jun 08 Python
基于Python的微信机器人开发 微信登录和获取好友列表实现解析
Aug 21 Python
wxpython多线程防假死与线程间传递消息实例详解
Dec 13 Python
TensorFlow使用Graph的基本操作的实现
Apr 22 Python
Python unittest单元测试框架实现参数化
Apr 29 Python
keras 自定义loss层+接受输入实例
Jun 28 Python
Python延迟绑定问题原理及解决方案
Aug 04 Python
python多线程semaphore实现线程数控制的示例
Aug 10 Python
python执行js代码的方法
May 13 Python
python实现socket简单通信的示例代码
使用Selenium实现微博爬虫(预登录、展开全文、翻页)
python用字节处理文件实例讲解
Apr 13 #Python
Python中相见恨晚的技巧
Apr 13 #Python
利用python做表格数据处理
python glom模块的使用简介
Apr 13 #Python
Python的flask接收前台的ajax的post数据和get数据的方法
You might like
PHP 加密/解密函数 dencrypt(动态密文,带压缩功能,支持中文)
2009/01/30 PHP
php提交表单时判断 if($_POST[submit])与 if(isset($_POST[submit])) 的区别
2011/02/08 PHP
Yii2实现ajax上传图片插件用法
2016/04/28 PHP
PHP判断密码强度的方法详解
2017/05/26 PHP
thinkphp5 migrate数据库迁移工具
2018/02/20 PHP
JS测试显示屏分辨率以及屏幕尺寸的方法
2013/11/22 Javascript
JS中的构造函数详细解析
2014/03/10 Javascript
javascript使用正则表达式检测IP地址
2014/12/03 Javascript
node.js实现BigPipe详解
2014/12/05 Javascript
jQuery实现在下拉列表选择时获取json数据的方法
2015/04/16 Javascript
jQuery实现鼠标滚动图片延迟加载效果附源码下载
2016/06/28 Javascript
JavaScript中最容易混淆的作用域、提升、闭包知识详解(推荐)
2016/09/05 Javascript
JS调用打印机功能简单示例
2016/11/28 Javascript
json数据处理及数据绑定
2017/01/25 Javascript
node.js 发布订阅模式的实例
2017/09/10 Javascript
element form 校验数组每一项实例代码
2019/10/10 Javascript
VUE项目axios请求头更改Content-Type操作
2020/07/24 Javascript
Python读写Excel文件的实例
2013/11/01 Python
Python中的FTP通信模块ftplib的用法整理
2016/07/08 Python
视觉直观感受若干常用排序算法
2017/04/13 Python
Python3.X 线程中信号量的使用方法示例
2017/07/24 Python
浅谈django url请求与数据库连接池的共享问题
2019/08/29 Python
使用Python的networkx绘制精美网络图教程
2019/11/21 Python
python中seaborn包常用图形使用详解
2019/11/25 Python
四方通行旅游网:台湾订房、出国旅游
2017/09/20 全球购物
澳大利亚领先的在线美容商店:Facial Co
2017/10/22 全球购物
大专自我鉴定范文
2013/10/23 职场文书
怎样填写就业意向
2014/04/02 职场文书
高中生操行评语
2014/04/25 职场文书
大学生就业自荐书
2014/06/16 职场文书
法院干警四风问题个人对照检查材料思想汇报
2014/10/07 职场文书
给领导的感谢信范文
2015/01/23 职场文书
2016情人节宣传语
2015/07/14 职场文书
《穷人》教学反思
2016/02/19 职场文书
党组织结对共建协议书
2016/03/23 职场文书
MySQL去除重叠时间求时间差和的实现
2021/08/23 MySQL