• 【2022 CCF BDCI 文心大模型创意项目】中秋款文心带你轻松搞定MV制作


    【2022 CCF BDCI 文心大模型创意项目】中秋款文心带你轻松搞定MV制作

    项目效果先知

    项目地址:
    https://aistudio.baidu.com/aistudio/projectdetail/4506607

    视频展示:

    https://www.bilibili.com/video/BV1ie4y1o743

    [中秋特别版] 文心带你分分钟制作MV

    夜幕有了星星,显得迷人

    大海有了涛声,显得渊博

    冬季有了雪花,让人备感浪漫

    朋友中有了你,使我深感荣幸

    iterhui在这里,用一曲水调歌头,把最美的祝福送给你

    祝大家中秋节快乐!

    项目背景

    这个项目的启发,当然是来自我们无敌的磊哥

    ninetailskim

    看到磊哥用剪辑软件做出来的MV,我想着,我们可以用python来实现一款相对自动化的全流程MV生成工具。

    在这里项目,我们只需要放入歌曲and歌曲的lrc文件以及一张首页图即可得到最终的MV

    话不多说,肝着!

    导入一些必备的包

    # 用来剪切音频和转换mp3为wav
    !pip install pydub
    !pip install moviepy
    !pip install auditok
    
    • 1
    • 2
    • 3
    • 4

    文本处理

    我们要拿到音频的时间点,以及文本,才能去进行一个文生图

    我本来写了一个自动智能化根据静默时间切分音频的代码,结果,因为歌曲有背景曲效果很差,那就算了吧

    有兴趣尝试自动切分音频并提取文本的可以参考我之前的项目:

    [PaddleSpeech]助力视频字幕生成演讲稿提取

    这里直接使用Lrc文件看效果,后续找到解决方案再去实现这个坑

    目标:

    1. 时间节点
    2. 时间节点对应的文本

    时间节点、歌词 获取

    # 暂时没有找到比较合适的文本提取并且找到对应时间戳的工具
    # 已有的 import auditok auditok.split这样的效果都不好
    # 我暂且我找的歌曲的Lrc歌词文件
    def readLrc(path = '水调歌头.lrc'):
        lines = []
        texts = []
        f = open(path,'r')
        while True:
            line = f.readline()  #包括换行符
            line = line[:-1]   #去掉换行符
            if line:
                if ('.' in line):
                    timeMin = line.strip().split(']')[0][1:3]
                    timeSec = line.strip().split(']')[0][4:6]
                    text = line.strip().split(']')[1]
                    lines.append([timeMin,timeSec])
                    texts.append(text)
            else:
                break
        f.close()
        
        return lines,texts
        
    info,text = readLrc('水调歌头.lrc')
    
    print(info[0])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    ['00', '01']
    
    • 1
    text
    
    • 1
    ['水调歌头',
     '作詞∶苏轼',
     '作曲∶梁弘志',
     '演唱∶王菲',
     '明月几时有  把酒问青天',
     '不知天上宫阙 今夕是何年',
     '我欲乘风归去 唯恐琼楼玉宇',
     '高处不胜寒 起舞弄清影 何似在人间',
     '转朱阁 低绮户 照无眠',
     '不应有恨 何事长向别时圆',
     '人有悲欢离合 月有阴晴圆缺',
     '此事古难全 但愿人长久 千里共婵娟',
     '^_^  ~~~MUSIC~~~  ^_^',
     '我欲乘风归去 唯恐琼楼玉宇',
     '高处不胜寒 起舞弄清影 何似在人间',
     '转朱阁 低绮户 照无眠',
     '不应有恨 何事长向别时圆(别时圆)',
     '人有悲欢离合 月有阴晴圆缺',
     '此事古难全 但愿人长久 千里共婵娟',
     '~END']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    文心大模型

    AK和SK的获取:

    https://wenxin.baidu.com/moduleApi/key

    当然因为这里要生成很多的图片,要等待很久!

    生成图片

    !pip install wenxin-api
    
    • 1
    from tqdm import tqdm
    import wenxin_api
    from wenxin_api.tasks.text_to_image import TextToImage
    # 下面我们安装并导入ernie_vilg模块
    # 因为需要发送请求,并等待数据返回,所以,会很慢,这取决于歌词条目的数量
    
    pro= [] # 记录单片段歌词
    
    def get_img(texts):
        # 你的prompt 我这里发现用逗号连接词语效果更佳
        # text_prompt = "程序员,写代码"
        imgs = []
        img_num = [] # 统计这一行歌词生成了几张图片的列表
        for i in tqdm(range(len(texts))):
            t = texts[i].replace(' ',',').split(',')
            img_num.append(len(t))
            for j in t:
                pro.append(j)
                text_prompt = j + ',圆月亮,夜晚,古风'
                wenxin_api.ak = "RgCyG5U1o9CsRr2T9exS4F47TZCgswnV"
                wenxin_api.sk = "PobN54TGDMwuFY0iens5bqsQWQxq8F44"
                input_dict = {
                    "text": text_prompt,
                    "style": "油画"
                }
                rst = TextToImage.create(**input_dict)
    
                imgs.append(rst['imgUrls'][0])
    
        return imgs,img_num
    
    img_list,img_num = get_img(text)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    下载图片

    import requests
    import os
    from PIL import Image
    import matplotlib.pyplot as plt
    %matplotlib inline
    
    # 生成存图的目录
    def init_mkdir(data_path):
        if not os.path.exists(data_path): # 判断文件夹是否存在
            os.makedirs(data_path) # 不存在则新建文件夹
    
    init_mkdir('output-img')
    
    # 展示生成的图片并保存
    for i in range(len(img_list)):
        #使用requests直接get 下载图片使用
        r = requests.get(img_list[i])
        ii = '%02d'%i +'.png'
        out_ii = 'output-img/' + ii
        with open(out_ii, 'wb') as f:
            f.write(r.content)
        f.close()
        img_ = Image.open(out_ii)
        plt.show()
        plt.imshow(img_) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    import os
    import cv2
    
    file_dir = 'output-img'
    
    # 返回path下所有文件构成的一个list列表
    filelist = os.listdir(file_dir)
    # 保证读取按照文件的顺序
    filelist.sort()
    if ('.ipynb_checkpoints' in filelist):
        del filelist[0]
    
    print(filelist)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    ['00.png', '01.png', '02.png', '03.png', '04.png', '05.png', '06.png', '07.png', '08.png', '09.png', '10.png', '11.png', '12.png', '13.png', '14.png', '15.png', '16.png', '17.png', '18.png', '19.png', '20.png', '21.png', '22.png', '23.png', '24.png', '25.png', '26.png', '27.png', '28.png', '29.png', '30.png', '31.png', '32.png', '33.png', '34.png', '35.png', '36.png', '37.png', '38.png', '39.png', '40.png', '41.png', '42.png', '43.png', '44.png']
    
    • 1

    图片加歌词

    给图片加歌词

    每一张图片的歌词如下:

    前面以及存储过了

    pro变量中

    from PIL import ImageFont
    from PIL import Image
    from PIL import ImageDraw
    
    font = ImageFont.truetype("simhei.ttf",58)#设置字体和字体大小
    font1 = ImageFont.truetype("STHUPO.TTF",36)#设置字体和字体大小
    font2 = ImageFont.truetype("STXINGKA.TTF",55)#设置字体和字体大小
    
    changed = 'output-text-img'
    
    init_mkdir(changed)
    
    def addTexttoImg():
        for i in range(len(pro)):
            imageFile = file_dir + '/' + filelist[i]
            tp=Image.open(imageFile)
            # 在图片上添加文字
            draw = ImageDraw.Draw(tp)
            draw.text((50, 50),'本歌曲由文心大模型生成图片',(255, 153, 0),font=font1) #分别设置文字的xy坐标,文字内容,文字颜色,字体
            draw.text((100, 850),pro[i],(0, 153, 255),font=font2) #分别设置文字的xy坐标,文字内容,文字颜色,字体
            draw.text((102, 852),pro[i],(255,255,255),font=font2) #分别设置文字的xy坐标,文字内容,文字颜色,字体
            draw = ImageDraw.Draw(tp)
            # 保存
            tp.save(changed + '/' + filelist[i]) #图片保存路径
    
    addTexttoImg()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    视频生成

    这里是真的花了我好多的时间去设计如何让时间节点把所有的歌词对应的比较完美一些

    处理时间节点

    这个时间决定了我们需要插入多少张图片

    PS 先知: 这里我们可以设置视频的帧数为5,后续视频生成也会用的到

    因为我们图片不多

    其次,要计算好时间需要多少张图片
    如下:

    # 总共262秒左右
    4*60+22
    
    • 1
    • 2
    262
    
    • 1
    # 我们最终需要1310张的图片才行
    5*262
    
    • 1
    • 2
    1310
    
    • 1

    生成策略

    合成视频

    我这里采取的策略是一秒的五帧都是相同的图片

    然后我们上面有提取的时间节点,卡点加入后面的图片

    # 时间序列
    info
    
    • 1
    • 2
    [['00', '01'],
     ['00', '04'],
     ['00', '06'],
     ['00', '08'],
     ['00', '11'],
     ['00', '22'],
     ['00', '32'],
     ['00', '44'],
     ['01', '03'],
     ['01', '14'],
     ['01', '27'],
     ['01', '38'],
     ['01', '56'],
     ['02', '27'],
     ['02', '38'],
     ['02', '57'],
     ['03', '08'],
     ['03', '30'],
     ['03', '41'],
     ['04', '15']]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    # 求出每个时间段需要多少张图片
    time_img = []
    start = 0
    for i in info:
        # 时间差
        end = int(i[0])*60 +int(i[1])
        time_img.append((end-start)*5)
        start = end
    
    time_img.append(7*5) # 最后一段不要忘记了
    
    sum(time_img)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1310
    
    • 1
    # 第一段时间留给首页 一秒 删除第一段,我们自行加首页,我已经放在了左侧的目录中
    del time_img[0]
    
    • 1
    • 2

    综上

    我们的处理逻辑如下:

    在这里插入图片描述

    此外:我采取时间段内的图片均分填充

    视频所需要的图片列表

    import os
    import cv2
    
    #造新的图片列表 1310 + 5(首页面) 张的
    new_list = []
    for i in range(5):
        new_list.append("home.png")
    
    num = 0
    #  0-20          
    for j in range(len(time_img)): # 总共有多少个时间段 len(time_img) = 21 同时,前面还记录了每个时间段有多少张图片,就是 img_num
        #  0-5             5
        #  0-15           15
        for n in range(time_img[j]): # 每个时间段需要多少张图片
            if (img_num[j] == 1):
                new_list.append(changed + '/' + filelist[sum(img_num[:j])])
    
            if (img_num[j] == 2):
                if (n < (time_img[j]//2)):
                    new_list.append(changed + '/' + filelist[sum(img_num[:j])])
                else:
                    new_list.append(changed + '/' + filelist[sum(img_num[:j])+1])
            if (img_num[j] == 3):
                if (n < (time_img[j]//3)):
                    new_list.append(changed + '/' + filelist[sum(img_num[:j])])
                elif (n < (time_img[j]//3)*2):
                    new_list.append(changed + '/' + filelist[sum(img_num[:j])+1])
                else:
                    new_list.append(changed + '/' + filelist[sum(img_num[:j])+2])
            if (img_num[j] == 5):
                if (n < (time_img[j]//5)):
                    new_list.append(changed + '/' + filelist[sum(img_num[:j])])
                elif (n < (time_img[j]//5)*2):
                    new_list.append(changed + '/' + filelist[sum(img_num[:j])+1])
                elif (n < (time_img[j]//5)*3):
                    new_list.append(changed + '/' + filelist[sum(img_num[:j])+2])
                elif (n < (time_img[j]//5)*4):
                    new_list.append(changed + '/' + filelist[sum(img_num[:j])+3])
                else:
                    new_list.append(changed + '/' + filelist[sum(img_num[:j])+4])
    
    new_list
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    len(new_list)
    
    • 1
    1310
    
    • 1

    图片列表转视频

    import cv2
    # VideoWriter是cv2库提供的视频保存方法,将合成的视频保存到该路径中
    # 'MJPG'意思是支持jpg格式图片
    # fps = 5代表视频的帧频为5,如果图片不多,帧频最好设置的小一点
    # (1280,720)是生成的视频像素1280*720,一般要与所使用的图片像素大小一致,否则生成的视频无法播放
    # 定义保存视频目录名称和压缩格式,像素为1280*720
    video = cv2.VideoWriter('test.mp4',cv2.VideoWriter_fourcc(*'mp4v'),5,(1080,980))
    
    for i in range(len(new_list)):
        #读取图片
        img = cv2.imread(new_list[i]) 
       	# resize方法是cv2库提供的更改像素大小的方法
        # 将图片转换为1024*720像素大小
        img = cv2.resize(img,(1080,980))
        # 写入视频
        video.write(img)
    
    # 释放资源
    video.release()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    音视频合并

    from moviepy import *
    from moviepy.editor import *
    # pip install moviepy
    
    def merge():
        video_path = 'test.mp4'
        audio_path = 'sdgt_wf.mp3'
        # 提取音轨
        audio = AudioFileClip(audio_path)
        # 读入视频
        video = VideoFileClip(video_path)
        # 将音轨合并到视频中
        video = video.set_audio(audio)
        # 输出
        video.write_videofile(f"output.mp4")
    
    if __name__ == '__main__':
    deo = video.set_audio(audio)
        # 输出
        video.write_videofile(f"output.mp4")
    
    if __name__ == '__main__':
        merge()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    项目总结

    整个 项目的流程完成还是非常的费事

    1. 文本的提取
    2. 图片的生成
    3. 文本合并
    4. 图片列表生成
    5. 视频合成
    6. 音频合成

    目前的视频生成还没有做到全自动,并且细节是不够完善的

    个人总结

    全网同名:

    iterhui

    我在AI Studio上获得至尊等级,点亮10个徽章,来互关呀~

    https://aistudio.baidu.com/aistudio/personalcenter/thirdview/643467

  • 相关阅读:
    阿里飞猪电话面一个小时9分钟
    大学生第一款浏览器怎么选,这款浏览器适合学生用
    7.11 特征值
    「Java开发指南」如何在Spring中使用JAX-WS注释器?
    Elasticsearch7.8.1集群安装手册
    五子棋对战简单介绍
    虚拟化与Docker基本概念与Docker的安装
    Linux 命令行——网络系统、ping、netstat、ftp、wget、ssh
    mysql的多表查询
    OpenSSL 密码库实现证书签发流程详解
  • 原文地址:https://blog.csdn.net/qq_41976613/article/details/126754652