年輕人不講武德,竟用Python讓馬老師表演閃電五連鞭!
11月份的頭條,是屬于馬保國的。
11月份的頭條,是屬于馬保國的。
? 一位69歲的老同志,慘遭年輕人偷襲,不講武德。

看看把老同志欺負的...
要不是馬老師講仁義講道德,甩手就是一個五連鞭。

哈哈哈,所以本期我們就用Python給馬保國老師做一個閃電五連鞭動態(tài)詞云圖。
詞云數(shù)據(jù)來自B站,使用stylecloud詞云庫繪制。

主要參考百度AI Studio上的一個開源項目,使用PaddleSeg對人像進行分割。
年輕人,不講武德。這樣好嗎,耗子尾汁。
/ 01 / 彈幕數(shù)據(jù)獲取
沒從B站上直接爬取,使用第三方庫bilibili_api。
這是一個用Python寫的調用Bilibili各種API的庫,范圍涵蓋視頻、音頻、直播、動態(tài)、專欄、用戶、番劇等。
地址:https://passkou.com/bilibili_api/docs/
使用video模塊下面的兩個方法,可以獲取11月每天的視頻彈幕。

首先需要獲取SESSDATA和CSRF(bili_jct)的值。
谷歌瀏覽器可以通過下圖查看,域名選擇bilibili.com。

以點擊量為排序,選取排行第一的視頻獲取彈幕。沒想到馬老師老早就火了,耗子尾汁。

點擊排名第一的視頻,然后在瀏覽器的訪問欄獲取BV號,BV1HJ411L7DP。
獲取彈幕代碼如下。
from?bilibili_api?import?video,?Verify
import?datetime
#?參數(shù)
verify?=?Verify("你的SESSDATA值",?"你的bili_jct值")
#?獲取存在歷史彈幕的日期列表
days?=?video.get_history_danmaku_index(bvid="BV1HJ411L7DP",?verify=verify)
print(days)
#?獲取彈幕信息,并保存
for?day?in?days:
????danmus?=?video.get_danmaku(bvid="BV1HJ411L7DP",?verify=verify,?date=datetime.date(*map(int,?day.split('-'))))
????print(danmus)
????f?=?open(r'danmu.txt',?'a')
????for?danmu?in?danmus:
????????print(danmu)
????????f.write(danmu.text?+?'\n')
????f.close()
得到結果。

我大E了啊,沒有閃。
使用jieba對彈幕數(shù)據(jù)進行分詞處理。
import?jieba
def?get_text_content(text_file_path):
????'''
????獲取填充文本內容
????'''
????text_content?=?''
????with?open(text_file_path,?encoding='utf-8')?as?file:
????????text_content?=?file.read()
????#?數(shù)據(jù)清洗,只保存字符串中的中文,字母,數(shù)字
????text_content_find?=?re.findall('[\u4e00-\u9fa5a-zA-Z0-9]+',?text_content,?re.S)
????text_content?=?'?'.join(jieba.cut(str(text_content_find).replace("?",?""),?cut_all=False))
????print(text_content)
????return?text_content
text_content?=?get_text_content('danmu.txt')
選取馬保國原版素材視頻,B站上有高清的。
地址:https://www.bilibili.com/video/BV1JV41117hq
參考網(wǎng)上的資料,運行如下代碼即可下載B站視頻。
from?bilibili_api?import?video,?Verify
import?requests
import?urllib3
#?參數(shù)
verify?=?Verify("你的SESSDATA值",?"你的bili_jct值")
#?獲取下載地址
download_url?=?video.get_download_url(bvid="BV1JV41117hq",?verify=verify)
print(download_url["dash"]["video"][0]['baseUrl'])
baseurl?=?'https://www.bilibili.com/video/BV1JV41117hq'
title?=?'馬保國'
def?get_video():
????urllib3.disable_warnings()
????headers?=?{
????????'user-agent':?'Mozilla/5.0?(Macintosh;?Intel?Mac?OS?X?10_13_6)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/86.0.4240.198?Safari/537.36',
????????'Accept':?'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
????????'Accept-Encoding':?'gzip,?deflate,?br',
????????'Accept-Language':?'zh-CN,zh;q=0.9,en;q=0.8'
????}
????headers.update({'Referer':?baseurl})
????res?=?requests.Session()
????begin?=?0
????end?=?1024?*?1024?-?1
????flag?=?0
????temp?=?download_url
????filename?=?"./"?+?title?+?".flv"
????url?=?temp["dash"]["video"][0]['baseUrl']
????while?True:
????????headers.update({'Range':?'bytes='?+?str(begin)?+?'-'?+?str(end)})
????????res?=?requests.get(url=url,?headers=headers,?verify=False)
????????if?res.status_code?!=?416:
????????????begin?=?end?+?1
????????????end?=?end?+?1024?*?1024
????????else:
????????????headers.update({'Range':?str(end?+?1)?+?'-'})
????????????res?=?requests.get(url=url,?headers=headers,?verify=False)
????????????flag?=?1
????????with?open(filename,?'ab')?as?fp:
????????????fp.write(res.content)
????????????fp.flush()
????????if?flag?==?1:
????????????fp.close()
????????????break
????print('--------------------------------------------')
????print('視頻下載完成')
????filename?=?"./"?+?title?+?".mp3"
????url?=?temp["dash"]["audio"][0]['baseUrl']
????while?True:
????????headers.update({'Range':?'bytes='?+?str(begin)?+?'-'?+?str(end)})
????????res?=?requests.get(url=url,?headers=headers,?verify=False)
????????if?res.status_code?!=?416:
????????????begin?=?end?+?1
????????????end?=?end?+?1024?*?1024
????????else:
????????????headers.update({'Range':?str(end?+?1)?+?'-'})
????????????res?=?requests.get(url=url,?headers=headers,?verify=False)
????????????flag?=?1
????????with?open(filename,?'ab')?as?fp:
????????????fp.write(res.content)
????????????fp.flush()
????????if?flag?==?1:
????????????fp.close()
????????????break
????print('音頻下載完成')
記得添加SESSDATA和CSRF(bili_jct)的值
/?02 / PaddleSeg人像分割
基于百度AI Studio的項目,項目地址:
https://aistudio.baidu.com/aistudio/projectdetail/1176398
首先下載解壓安裝PaddleSeg相關依賴包。
#?下載PaddleSeg
git?clone?https://hub.fastgit.org/PaddlePaddle/PaddleSeg.git
cd?PaddleSeg/
#?安裝所需依賴項
pip?install?-r?requirements.txt
通常去「GitHub」上下載東西,速度都比較慢,可以使用加速鏈接。
這里的fastgit.org一加,下載速度就能從幾十K飆升到幾兆每秒。
#?新建文件夾
mkdir?work/videos
mkdir?work/texts
mkdir?work/mp4_img
mkdir?work/mp4_img_mask
mkdir?work/mp4_img_analysis
新建一些文件夾,主要用來存放相關文件的。
這里可以將之前爬取到的視頻和音頻放置在videos中。
先對素材視頻進行抽幀,就是獲取視頻每幀的圖片。
def?transform_video_to_image(video_file_path,?img_path):
????'''
????將視頻中每一幀保存成圖片
????'''
????video_capture?=?cv2.VideoCapture(video_file_path)
????fps?=?video_capture.get(cv2.CAP_PROP_FPS)
????count?=?0
????while?(True):
????????ret,?frame?=?video_capture.read()
????????if?ret:
????????????cv2.imwrite(img_path?+?'%d.jpg'?%?count,?frame)
????????????count?+=?1
????????else:
????????????break
????video_capture.release()
????filename_list?=?os.listdir(img_path)
????with?open(os.path.join(img_path,?'img_list.txt'),?'w',?encoding='utf-8')?as?file:
????????file.writelines('\n'.join(filename_list))
????print('視頻圖片保存成功,?共有?%d?張'?%?count)
????return?fps
input_video?=?'work/videos/Master_Ma.mp4'
fps?=?transform_video_to_image(input_video,?'work/mp4_img/')
一共是獲取到了564張圖片。

然后使用PaddleSeg將所有的視頻圖片,進行人像分割,生成mask圖片。
#?生成mask結果圖片
python?你的路徑/PaddleSeg/pdseg/vis.py?\
???????????--cfg?你的路徑/work/humanseg.yaml?\
???????????--vis_dir?你的路徑/work/mp4_img_mask
使用模型進行預測,其中humanseg.yaml文件是作者提供的,可以進行圖像分割。
預訓練模型deeplabv3p_xception65_humanseg,需下載解壓安裝放在PaddleSeg/pretrained_model下。
由于預訓練模型較大,就不放網(wǎng)盤上了,直接訪問下面這個鏈接即可下載。
#?下載預訓練模型deeplabv3p_xception65_humanseg
https://paddleseg.bj.bcebos.com/models/deeplabv3p_xception65_humanseg.tgz
記得需要將humanseg.yaml文件中的路徑信息,修改成你自己的路徑。

運行上面那三行命令,最后就會生成564張mask文件。

/?03 / 詞云生成
使用stylecloud詞云庫生成詞云,使用字體方正蘭亭刊黑。
def?create_wordcloud():
????for?i?in?range(564):
????????file_name?=?os.path.join("mp4_img_mask/",?str(i)?+?'.png')
????????#?print(file_name)
????????result?=?os.path.join("work/mp4_img_analysis/",?'result'?+?str(i)?+?'.png')
????????#?print(result)
????????stylecloud.gen_stylecloud(text=text_content,
??????????????????????????????????font_path='方正蘭亭刊黑.TTF',
??????????????????????????????????output_name=result,
??????????????????????????????????background_color="black",
??????????????????????????????????mask_img=file_name)
因為stylecloud庫無法自定義詞云圖片,所以修改了它的代碼。
給gen_stylecloud添加了mask_img這個參數(shù),最終作用在gen_mask_array這個函數(shù)上。

如此就能將mask圖片轉化成詞云圖!

將這些詞云圖片合并成視頻。
def?combine_image_to_video(comb_path,?output_file_path,?fps=30,?is_print=False):
????'''
????????合并圖像到視頻
????'''
????fourcc?=?cv2.VideoWriter_fourcc(*'mp4v')
????file_items?=?[item?for?item?in?os.listdir(comb_path)?if?item.endswith('.png')]
????file_len?=?len(file_items)
????#?print(comb_path,?file_items)
????if?file_len?>?0:
????????print(file_len)
????????temp_img?=?cv2.imread(os.path.join(comb_path,?file_items[0]))
????????img_height,?img_width,?_?=?temp_img.shape
????????out?=?cv2.VideoWriter(output_file_path,?fourcc,?fps,?(img_width,?img_height))
????????for?i?in?range(file_len):
????????????pic_name?=?os.path.join(comb_path,?'result'?+?str(i)?+?".png")
????????????print(pic_name)
????????????if?is_print:
????????????????print(i?+?1,?'/',?file_len,?'?',?pic_name)
????????????img?=?cv2.imread(pic_name)
????????????out.write(img)
????????out.release()
combine_image_to_video('work/mp4_img_analysis/',?'work/mp4_analysis.mp4',?30)
使用ffmpeg對視頻進一步的處理,裁剪+重疊。
#?視頻裁剪
ffmpeg??-i??mp4_analysis_result.mp4??-vf??crop=iw:ih/2:0:ih/5??output.mp4
#?視頻重疊
ffmpeg?-i?output.mp4?-i?viedeos/Master_Ma.mp4?-filter_complex?"[1:v]scale=500:270[v1];[0:v][v1]overlay=1490:10"?-s?1920x1080??-c:v?libx264?merge.mp4
#?添加音頻
ffmpeg?-i?merge.mp4?-i??videos/Master_Ma.mp4?-c:v?copy?-c:a?copy?work/mp4_analysis_result2.mp4?-y
#?生成gif圖
ffmpeg?-ss?00:00:22?-t?3?-i?merge.mp4?-r?15?a.gif
ffmpeg的安裝及使用就得靠大伙自己百度啦~
視頻結果如下。
到這里了,不來個贊嗎,來,炫,來偷吸,我這...
好了,到此本期的實踐就結束了。
感興趣的小伙伴也可以動手試一試。
這里需要注意,在使用PaddleSeg進行人像分割和生成詞云圖,這期間耗費的時間比較多,慢慢等就好了。
還有就是可以自己修改一下stylecloud庫的代碼,自定義一下mask_img圖片的大小以及顏色。
這兩項是沒有修改的,所以生成的圖片是512×512尺寸,導致最后視頻需要裁剪。
顏色主要是將mask圖片變成白底的圖片,這里是黑底的。
可以通過圖片灰度二值化的方法。
import?cv2
#?灰度圖
img?=?cv2.imread('work/mp4_img_mask/240.png',?0)
#?二值化
ret,?thresh?=?cv2.threshold(img,?30,?255,?cv2.THRESH_BINARY_INV)
#?顯示
cv2.imshow("img",?thresh)
#?保存圖片
cv2.imwrite('0.png',?thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
就能得到白底的png圖,符合stylecloud詞云圖的要求。

如此便可以繪制出白底彩色文字的詞云圖。
相關代碼及文件已上傳,掃下方公眾號回復「馬老師」即可獲取。
戀習Python 關注戀習Python,Python都好練 好文章,我在看??
