使用词云生成B站小姐姐舞蹈视频

本教程将分为几篇文章讲述如何使用词云生成小姐姐跳舞的视频。使用词云生成的视频的效果如下图所示。
跳舞视频截图

词云小姐姐跳舞视频效果

实现思路

为了达成生成由词云填充的跳舞视频效果,需要由以下几个步骤构成:

  1. 获取需要的资源,我们找到B站上的视频链接(https://www.bilibili.com/video/BV1YE411C76u),下载链接对应的视频文件;
  2. 提取视频中每帧图像,从每帧图像中提取出人体轮廓,并与背景分离;
  3. 获取该视频的弹幕内容;
  4. 使用词云将弹幕内容填充到人体轮廓图片中;
  5. 添加音乐资源,并将词云填充的人体轮廓图生成视频内容;

以下内容将按照上述讲解的步骤来组织内容。

一. 获取资源

获取资源,并下载该资源文件,下载所需的工具为:you-get(https://github.com/soimort/you-get),在安装了pip的机器上,执行命令:pip install you-get 即可完成安装。其余安装方法可以参考链接页面上的“Installation”完成安装。下载该视频时,执行命令,you-get -o 本地地址 链接地址 即可下载视频。下载该视频到本机E盘根目录下载的命令为:you-get -o e: https://www.bilibili.com/video/BV1YE411C76u,示例图如下所示:
下载截图下载失败截图如下:
下载失败下载失败后,可以参考链接(https://github.com/soimort/you-get/pulls)来解决。you-get还可以支持更多的视频下载和其它更有趣的功能,其它功能不在我们讨论的问题之列。

二. 视频处理

以下将进入主要内容的讨论,先需要对视频进行处理,提取出构成视频的每帧图像内容,并对提取出的每帧图像分理出人体轮廓。为了提取出有效的人体轮廓,背景内容最好比较单一。

2.1 提取每帧图像内容

下载的视频为flv格式,下载的视频如下图所示。
下载的视频
为了处理方便,将文件命名为yaya.flv。为了提取每帧图像,将使用opencv-python(https://github.com/opencv/opencv-python)库。opencv是一个强大的图像处理和计算机是视觉库。在使用之前,需要安装opencv-python库,使用pip install opencv-python即可安装,为了保证下载及安装速度,推荐使用国内源进行安装。pip install opencv-python -i https://pypi.doubanio.com/simple ,这里安装时,使用了豆瓣源。
以下为提取每帧图像的代码:

import cv2

num = 0
cap = cv2.VideoCapture(r'yaya.flv')
# 读取800帧内容
while num < 800:
    ret, frame = cap.read()
    if ret:
        cv2.imwrite(f'./pic1/img_{num}.jpg', frame)
        num += 1
    else:
        break
cap.release()

cv2.VideoCapture将读取flv文件,使用read()方法读取每帧内容,我们这里只读取了800帧图片,并使用imwrite()将读取的每帧内容保存成图像内容。
生成的图片如下图所示:
生成的图片

2.2 提取人体轮廓

为了提取人体轮廓,这里使用了百度提供的人体分析功能中的人像分割功能。为了使用该功能,需要注册百度账号。参考人像分割文档(https://cloud.baidu.com/doc/BODY/s/Fk3cpyxua),完成应用创建。
应用参考文档在这里插入图片描述复制应用中创建的APPID、API Key及App Secret信息,创建提取人体轮廓Python代码。

import cv2
import base64
import numpy as np
import os
from aip import AipBodyAnalysis

APP_ID = "your app's app id"
API_KEY = "your app's key"
SECRET_KEY = "your app's secrect key"

client = AipBodyAnalysis(APP_ID, API_KEY, SECRET_KEY)
path = './mask_img1/'

img_files = os.listdir('./pic1')

for num in range(0, len(img_files)):
    img = f'./pic1/img_{num}.jpg'
    img1 = cv2.imread(img)
    height, width, _ = img1.shape

    with open(img, 'rb') as fp:
        img_info = fp.read()

    seg_res = client.bodySeg(img_info)
    labelmap = base64.b64decode(seg_res['labelmap'])
    nparr = np.frombuffer(labelmap, np.uint8)
    labelimg = cv2.imdecode(nparr, 1)
    labelmap = cv2.resize(labelimg, (width, height), interpolation=cv2.INTER_NEAREST)
    new_img = np.where(labelmap == 1, 255, labelimg)
    mask_name = path + 'mask_{}.png'.format(num)
    cv2.imwrite(mask_name, new_img)

在上述代码中,img1 = cv2.imread()表示读取图片信息,并通过img1.shape得到图片的像素信息。
client.bodySeg(img_info)表示将每张图片发送到百度提供的人体分析平台去处理,并得到处理图像的二值信息。以下几行代码就是将得到的二值信息最终生成一张新的图,生成的图片如下所示。
二值图经过上述过程,即将人体轮廓与背景完成了分离。下一步,就可以获取弹幕信息了,将获取的弹幕信息经过分析处理,就可以填充进人体轮廓中了。

三. 内容获取

3.1 弹幕获取分析

为了填充有意义的内容,我们需要获取该视频对应的弹幕信息。因为还存在历史弹幕,我们需要爬取一个时间段的弹幕。爬取弹幕内容,需要找到弹幕对应的链接信息,通过使用浏览器自带的WEB开发工具,可以帮我们来更好地来解决这个问题,这里以Firefox浏览器来举例说明。打开浏览器上的"工具"->“Web开发者”->“Web控制台”,点击"网络"标签,点击"弹幕列表"中的"展开"。
弹幕功能为了找到弹幕对应的链接,我们首先清除掉当前展示信息。
清除信息点击"查看历史弹幕",并选择日期,则控制台将输出请求的信息。
request信息点击这条信息,查看详情信息。
detail详情在右边的"消息头"处,可以看到GET内容,这里就是获取弹幕信息的API,其链接为:
https://api.bilibili.com/x/v2/dm/web/history/seg.so?type=1&oid=126220511&date=2021-01-01,有了这个链接,如果我们需要获取2020年1月1日到2021年1月1日间的弹幕信息,只需要在链接中,date部分,填入我们需要的日期即可。

3.2 弹幕获取代码实现

弹幕获取代码如下所示:

import pandas as pd
import requests
import re
from fake_useragent import UserAgent


# 获取弹幕URL地址
url = 'https://api.bilibili.com/x/v2/dm/web/history/seg.so'
# 获取弹幕时间段
start, end = '20191031', '20210201'
date_list = (x for x in pd.date_range(start, end).strftime('%Y-%m-%d'))


def getdanmu(dates):

    headers = {
        'origin': 'https://www.bilibili.com',
        'referer': 'https://www.bilibili.com/video/BV1YE411C76u',
        'cookie': "your cookie",
        'user-agent': ua.random,
    }

    for date in dates:
        params = {
            'type': 1,
            'oid': '126220407',
            'date': date
        }

        r = requests.get(url, params=params, headers=headers)
        r.encoding = 'utf8'
        # 提取中文内容
        comments = re.findall('.*?([\u4E00-\u9FA5]+).*?', r.text)
        for i in comments:
            with open('./doc/danmu.txt', mode='a', encoding='utf-8') as f:
                f.write(i)
                f.write('\n')


ua = UserAgent()
getdanmu(date_list)
print('#######弹幕获取完成########')

上述代码中,"\u4E00-\u9FA5"为中文内容正则表达式。
为了构造真实的请求,我们需要来构造请求头中的内容,以防止网站后台把我们识别成爬虫而不能获取到弹幕信息。请求头中的内容如下图所示:
请求头内容
其中,最重要的是Origin、Referer、Cookie和User-Agent参数,按照截图内容,Origin和Referer我们按照截图中内容填写即可。Cookie内容是登录B站后生成的内容。如果需要爬取历史记录,则需要有B站账号,登录之后,直接复制请求头中的Cookie内容到代码中。User-Agent是表示登录使用的浏览器的信息,这里我们使用fake_useragent库中的UserAgent提供的方法来模拟浏览器登录。
运行代码后,将弹幕内容存入相应的文件,弹幕内容如图所示:
弹幕内容接下来,将对获取的弹幕内容进行统计分析,最终使用词云填充,并最终生成新的图片。

四. 弹幕内容处理

4.1 概念介绍

对于获取的弹幕内容,需要对弹幕内容进行处理和加工,在处理之前,需要介绍两个概念,一个是词云,一个是停用词。
词云是美国西北大学教授里奇·戈登于2006年提出。词云是通过形成"关键字云层"或"关键词渲染",对网络文本中出现频率较高的关键词的视觉上的突出。词云图过滤掉大量的文本信息,使浏览网页者只要一眼扫过文本就可以领略文本的主旨。
停用词,是指在信息检索中,为节省存储空间和提高搜索效率,在处理孜然语言数据(或文本)之前或之后会自动过滤掉某些字或词,这些字或词即被称为Stop Words(停用词)。并非有一个标准的停用词库来适用于所有的工具。
我们在对获取的弹幕内容进行检索时,需要使用到中文停用词库。我们选用一个常用的中文停用词库(链接:https://github.com/goto456/stopwords),我们使用其中的百度停用词库,将该停用词库下载下来。

4.2 实现过程

我们使用停用词库,筛选出出现频率较高的关键词,使用词云的方式填充到人体轮廓中,并最终生成新的图片。词云库我们使用wordcloud库,对中文分词,我们使用jieba库。在安装了pip之后,可以直接通过: pip install wordcloud 和 pip install jieba完成这两个库的安装。对于代码依赖的PIL库,在python中,已经修改成了pillow库,故安装的命令为:pip install pillow。对于下载的百度停用词库,我们不需要编辑操作该代码,只需要将该停用词库放置到项目工程文件夹中,在代码中使用该停用词库即可。

4.3 代码实现

代码实现如下所示:

from wordcloud import WordCloud
import collections
import jieba
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import os

# 打开弹幕文件
with open('./doc/danmu.txt', encoding='utf-8') as f:
    data = f.read()

# 对弹幕文件进行中文分词
seg_list_exact = jieba.cut(data, cut_all=False)
liststr = "/ ".join(seg_list_exact)
result_list = []

# 使用下载的百度停用词库,对中文进行分词
with open('./stop_words.txt', encoding='utf-8') as f1:
    f_stop_text = f1.read()
    f_stop_seg_list = f_stop_text.splitlines()

# 完成中文分词
for word in liststr.split('/'):
    if not (word.strip() in f_stop_seg_list) and len(word.strip()) > 1:
        result_list.append(word)

# 统计中文分词数量
word_counts = collections.Counter(result_list)
path = './wordcloud/'

# 使用词云生成新的图片
img_files = os.listdir('./mask_img1')
for num in range(0, len(img_files)):
    img = fr'./mask_img1/mask_{num}.png'
    mask_ = 255 - np.array(Image.open(img))
    plt.figure(figsize=(8, 5), dpi=200)
    my_cloud = WordCloud(background_color='black', mask=mask_, mode='RGBA',
                         max_words=500, font_path='simhei.ttf',).generate_from_frequencies(word_counts)
    plt.imshow(my_cloud)
    plt.axis('off')
    word_cloud_name = path + 'wordcloud_{}.png'.format(num)
    my_cloud.to_file(word_cloud_name)

上述代码中,stop_words.txt文件即为我们下载的百度停用词库。执行上述代码,生成的词云文件如下图所示:
词云图片1词云图片二

五. 生成新的视频文件

根据上述生成的词云图片,只需要将所有的图片文件合并成一个新的视频文件即可。
代码如下所示:

import cv2

size = (1920, 1080)

fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')
videoWriter = cv2.VideoWriter('yaya.avi', fourcc, 24, size)

# 把所有的图片合成视频,每秒24帧
for i in range(0, 800):
    image = fr'./wordcloud/wordcloud_{i}.png'
    frame = cv2.imread(image)
    frame = cv2.resize(frame, size)
    videoWriter.write(frame)

videoWriter.release()

六. 添加音频信息

添加音频信息,可以再次生成最新的视频文件。需要的库主要为moviepy。
代码如下:

import moviepy.editor as mpy

my_clip = mpy.VideoFileClip('./yaya.avi')
# 截图一段音频,添加到视频中
audio_background = mpy.AudioFileClip('./feel special.mp3').subclip(6, 50)
final_clip = my_clip.set_audio(audio_background)
final_clip.write_videofile('yaya-dance.mp4')

参考内容:
https://yetingyun.blog.csdn.net/article/details/112209719
https://github.com/soimort/you-get
https://github.com/goto456/stopwords
https://github.com/amueller/word_cloud
百度百科等

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值