前言
最近在补《吐槽大会》第三季,突然发现弹幕们似乎变得智能了,能够自动识别人物前景和背景,不会再遮挡住人物,看起来好像从人物身后穿过去一样。这样既保留了弹幕的趣味性,也不会被遮住画面中的重要内容。
本来我也只是感叹一下腾讯视频的功能强大,结果之后在逛知乎时偶然刷到一位大佬Crossin的文章《弹幕君,别挡着我看小姐姐!》(是不是很熟悉的名字?没错,我想不到什么更好的名字,就把这位大佬的文章标题也抄过来了),讲解了怎么通过Python实现视频的前景识别和文字叠加等功能。
原来B站这位弹幕祖师网站也支持了这样的功能,虽然只有部分视频开启了这个功能,估计复杂的背景可能会影响识别效果。
开发环境安装
先说一下会用到哪些第三方库和他们的部署方法吧,以下基于Python3.5.3版本。
OpenCV, 一个用于图像处理、分析、机器视觉方面的开源函数库 ,主要拿来提取画面内容制作蒙版。
PIL,用于给图片加文字。
NumPy,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
matplotlib,用于图像处理。
pip install opencv-python pip install pillow python -m pip install --user numpy scipy matplotlib ipython jupyter pandas sympy nose
需要注意的是:
1.PIL 库已停止维护,新的库叫 Pillow,但在使用时仍然是 import PIL。
2.默认的字体不支持中文,因此需要提供字体文件并指定。py2 也不支持中文,需要额外使用 freetype 库。
3.OpenCV 库的 putText 方法也可以实现给图片加文字,但缺少对中文的支持。
代码
首先制作弹幕方面,给图片加文字的代码如下:
from PIL import Image, ImageDraw, ImageFont setFont = ImageFont.truetype(r"HKSNT.TTF", 50) #设置字体 fillColor = "#ff0000" #设置文字颜色 image = Image.open("timg.jpg") draw = ImageDraw.Draw(image) #创建绘图对象 width, height = image.size draw.text((40, height - 90), u'文字测试!!', font=setFont, fill=fillColor) #在图上绘制文字 image.save("out.jpg", 'jpeg') #输出图片
提取图片前景部分核心代码如下:
import numpy as np import cv2 mask = np.zeros(img.shape[:2],np.uint8) bgdModel = np.zeros((1,65),np.float64) fgdModel = np.zeros((1,65),np.float64) rect = (10, 10, img.shape[1]-10, img.shape[0]-10) cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
有了蒙版之后,就可以对图像进行运算。分别取出带弹幕图像的背景部分(其实直接拿带弹幕图像就可以),和原图像的前景部分,两个叠加一起,就是我们最终需要的效果。
img = img * (1-mask)[:,:,np.newaxis] + img * mask[:,:,np.newaxis]
注意
1. 前景提取的速度比较慢,为了能达到实时效果,在提取前景时,将图片缩小,获取蒙版之后,再将其放大至原尺寸。蒙版不需要太高精度,通过这个方法就可以做到实时。
2. 每一帧的处理速度有快有慢,为了稳定帧率,我加入了每帧时间的计算,如果时间不足设定时长,就 sleep 剩下的时间。
3. 一些过渡帧的识别效果会比较差,导致中间少数蒙版出现类似“跳帧”的效果。为了平滑这些帧,我在程序里记录每一帧蒙版中前景像素的数量,如果当前帧与之前 20 帧的平均值差距超过 50%,那就认为这一帧的前景提取不合格,直接使用之前的蒙版。
完整的代码太长,直接放大佬的git地址。
总有些人觉得你怎么做都不对,
也许你唯一的不对就是理会他们。
《脱线森林》
——狐狸阿北
评论
还没有任何评论,你来说两句吧!