11月份的頭條,是屬於馬保國的。
一位69歲的老同志,慘遭年輕人偷襲,不講武德。
看看把老同志欺負的...
要不是馬老師講仁義講道德,甩手就是一個五連鞭。
哈哈哈,所以本期我們就用Python給馬保國老師做一個閃電五連鞭動態詞雲圖。
詞雲數據來自B站,使用stylecloud詞雲庫繪製。
主要參考百度AI Studio上的一個開源項目,使用PaddleSeg對人像進行分割。
年輕小F,不講武德。這樣好嗎,耗子尾汁。
/ 01 / 彈幕數據獲取
沒從B站上直接爬取,使用第三方庫bilibili_api。
這是一個用Python寫的調用Bilibili各種API的庫,範圍涵蓋視頻、音頻、直播、動態、專欄、用戶、番劇等。
地址:https://passkou.com/bilibili_api/docs/
使用video模塊下面的兩個方法,可以獲取11月每天的視頻彈幕。
首先需要獲取SESSDATA和CSRF(bili_jct)的值。
谷歌瀏覽器可以通過下圖查看,域名選擇bilibili.com。
以點擊量為排序,選取排行第一的視頻獲取彈幕。沒想到馬老師老早就火了,耗子尾汁。
點擊排名第一的視頻,然後在瀏覽器的訪問欄獲取BV號,BV1HJ411L7DP。
獲取彈幕代碼如下。
from bilibili_api import video, Verifyimport datetime# 參數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對彈幕數據進行分詞處理。
import jiebadef get_text_content(text_file_path):''' 獲取填充文本內容 ''' text_content = '' with open(text_file_path, encoding='utf-8') as file: text_content = file.read() # 數據清洗,只保存字符串中的中文,字母,數字 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_contenttext_content = get_text_content('danmu.txt')
選取馬保國原版素材視頻,B站上有高清的。
地址:https://www.bilibili.com/video/BV1JV41117hq
參考網上的資料,運行如下代碼即可下載B站視頻。
from bilibili_api import video, Verifyimport requestsimport urllib3# 參數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相關依賴包。
# 下載PaddleSeggit clone https://hub.fastgit.org/PaddlePaddle/PaddleSeg.gitcd PaddleSeg/# 安裝所需依賴項pip install -r requirements.txt
通常去「GitHub」上下載東西,速度都比較慢,可以使用加速連結。
這裡的fastgit.org一加,下載速度就能從幾十K飆升到幾兆每秒。
# 新建文件夾mkdir work/videosmkdir work/textsmkdir work/mp4_imgmkdir work/mp4_img_maskmkdir 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 fpsinput_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下。
由於預訓練模型較大,就不放網盤上了,直接訪問下面這個連結即可下載。
# 下載預訓練模型deeplabv3p_xception65_humanseghttps://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庫無法自定義詞雲圖片,所以小F修改了它的代碼。
給gen_stylecloud添加了mask_img這個參數,最終作用在gen_mask_array這個函數上。
如此就能將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的安裝及使用就得靠大夥自己百度啦~
視頻結果如下。
到這裡了,不給小F來個贊嗎,來,炫,來偷吸,我這...
/ 04 / 總結
好了,到此本期的實踐就結束了。
相關代碼及文件已上傳,公眾號回復「馬老師」即可獲取。
感興趣的小夥伴也可以動手試一試。
這裡需要注意,在使用PaddleSeg進行人像分割和生成詞雲圖,這期間耗費的時間比較多,慢慢等就好了。
還有就是可以自己修改一下stylecloud庫的代碼,自定義一下mask_img圖片的大小以及顏色。
這兩項小F是沒有修改的,所以生成的圖片是512×512尺寸,導致最後視頻需要裁剪。
顏色主要是將mask圖片變成白底的圖片,小F這裡是黑底的。
可以通過圖片灰度二值化的方法。
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詞雲圖的要求。
如此便可以繪製出白底彩色文字的詞雲圖。