真沒想到,Python還能實現5毛特效

2021-01-11 AI科技大本營

圖源 | 視覺中國

Python牛已經不是一天兩天的事了,但是我開始也沒想到,Python能這麼牛。前段時間接觸了一個批量摳圖的模型庫,而後在一些視頻中找到靈感,覺得應該可以通過摳圖的方式,給視頻換一個不同的場景,於是就有了今天的文章。

我們先看看能實現什麼效果,先來個正常版的,先看看原場景:

下面是我們切換場景後的樣子:

看起來效果還是不錯的,有了這個我們就可以隨意切換場景,墳頭蹦迪不是夢。另外,我們再來看看另外一種效果,相比之下要狂放許多:

實現步驟

我們都知道,視頻是由一幀一幀的畫面組成的,每一幀都是一張圖片,我們要實現對視頻的修改就需要對視頻中每一幀畫面進行修改。所以在最開始,我們需要獲取視頻每一幀畫面。

在我們獲取幀之後,需要摳取畫面中的人物。

摳取人物之後,就需要讀取我們的場景圖片了,在上面的例子中背景都是靜態的,所以我們只需要讀取一次場景。在讀取場景之後我們切換每一幀畫面的場景,並寫入新的視頻。

這時候我們只是生成了一個視頻,我們還需要添加音頻。而音頻就是我們的原視頻中的音頻,我們讀取音頻,並給新視頻設置音頻就好了。

具體步驟如下:

讀取視頻,獲取每一幀畫面批量摳圖讀取場景圖片對每一幀畫面進行場景切換寫入視頻讀取原視頻的音頻給新視頻設置音頻因為上面的步驟還是比較耗時的,所以在視頻完成後通過郵箱發送通知,告訴我視頻製作完成。

模塊安裝

我們需要使用到的模塊主要有如下幾個:

pillowopencvmoviepypaddlehub我們都可以直接用pip安裝:

pip install pillowpip install opencv-pythonpip install moviepy其中OpenCV有一些適配問題,建議選取3.0以上版本。

在我們使用paddlehub之前,我們需要安裝paddlepaddle:具體安裝步驟可以參見官網。用paddlehub摳圖參考:別再自己摳圖了,Python用5行代碼實現批量摳圖。我們這裡直接用pip安裝cpu版本的:

# 安裝paddlepaddlepython -m pip install paddlepaddle -i https://mirror.baidu.com/pypi/simple# 安裝paddlehubpip install -i https://mirror.baidu.com/pypi/simple paddlehub有了這些準備工作就可以開始我們功能的實現了。

具體實現

我們導入如下包:

import cv2 # opencvimport mail # 自定義包,用於發郵件import mathimport numpy as npfrom PIL import Image # pillowimport paddlehub as hubfrom moviepy.editor import *其中Pillow和opencv導入的名稱不太一樣,還有就是我自定義的mail模塊。另外我們還要先準備一些路徑:

# 當前項目根目錄,系統自動獲取當前目錄BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "."))# 每一幀畫面保存的地址frame_path = BASE_DIR + '\\frames\\'# 摳好的圖片位置humanseg_path = BASE_DIR + '\\humanseg_output\\'# 最終視頻的保存路徑output_video = BASE_DIR + '\\result.mp4'接下來我們按照上面說的步驟一個一個實現。

(1)讀取視頻,獲取每一幀畫面

在OpenCV中提供了讀取幀的函數,我們只需要使用VideoCapture類讀取視頻,然後調用read函數讀取幀,read方法返回兩個參數,ret為是否有下一幀,frame為當前幀的ndarray對象。完整代碼如下:def getFrame(video_name, save_path):"""讀取視頻將視頻逐幀保存為圖片,並返回視頻的解析度size和幀率fps:param video_name: 視頻的名稱:param save_path: 保存的路徑:return: fps幀率,size解析度"""# 讀取視頻video = cv2.VideoCapture(video_name)# 獲取視頻幀率fps = video.get(cv2.CAP_PROP_FPS)# 獲取畫面大小width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))size = (width, height)# 獲取幀數,用於給圖片命名frame_num = str(video.get(7))name = int(math.pow(10, len(frame_num)))# 讀取幀,ret為是否還有下一幀,frame為當前幀的ndarray對象ret, frame = video.readwhile ret:cv2.imwrite(save_path + str(name) + '.jpg', frame)ret, frame = video.readname += 1video.releasereturn fps, size在標處,我獲取了幀的總數,然後通過如下公式獲取比幀數大的整十整百的數:

frame_name = math.pow(10, len(frame_num))這樣做是為了讓畫面逐幀排序,這樣讀取的時候就不會亂。另外我們獲取了視頻的幀率和解析度,這兩個參數在我們創建視頻時需要用到。這裡需要注意的是opencv3.0以下版本獲取幀率和畫面大小的寫法有些許差別。

(2)批量摳圖

批量摳圖需要用到paddlehub中的模型庫,代碼很簡單,這裡就不多說了:

def getHumanseg(frames):"""對幀圖片進行批量摳圖:param frames: 幀的路徑:return:"""# 加載模型庫humanseg = hub.Module(name='deeplabv3p_xception65_humanseg')# 準備文件列表files = [frames + i for i in os.listdir(frames)]# 摳圖humanseg.segmentation(data={'image': files})我們執行上面函數後會在項目下生成一個humanseg_output目錄,摳好的圖片就在裡面。

(3)讀取場景圖片

這也是簡單的圖片讀取,我們使用pillow中的Image對象:

def readBg(bgname, size):"""讀取背景圖片,並修改尺寸:param bgname: 背景圖片名稱:param size: 視頻解析度:return: Image對象"""im = Image.open(bgname)return im.resize(size)這裡的返回的對象並非ndarray對象,而是Pillow中定義的類對象。

(4)對每一幀畫面進行場景切換

簡單來說就是將摳好的圖片和背景圖片合併,我們知道摳好的圖片都在humanseg_output目錄,這也就是為什麼最開始要準備相應的變量存儲該目錄的原因:

def setImageBg(humanseg, bg_im):"""將摳好的圖和背景圖片合併:param humanseg: 摳好的圖:param bg_im: 背景圖片,這裡和readBg函數返回的類型一樣:return: 合成圖的ndarray對象"""# 讀取透明圖片im = Image.open(humanseg)# 分離色道r, g, b, a = im.split# 複製背景,以免源背景被修改bg_im = bg_im.copy# 合併圖片bg_im.paste(im, (0, 0), mask=a)return np.array(bg_im.convert('RGB'))[:, :, ::-1]在標處,我們複製了背景,如果少了這一步的話,生成的就是我們上面的「千手觀音效果」了。

其它步驟都很好理解,只有返回值比較長,我們來詳細看一下:

# 將合成圖轉換成RGB,這樣A通道就沒了bg_im = bg_im.convert('RGB')# 將Image對象轉換成ndarray對象,方便opencv讀取im_array = np.array(bg_im)# 此時im_array為rgb模式,而OpenCV為bgr模式,我們通過下面語句將rgb轉換成bgrbgr_im_array = im_array[:, :, ::-1]最後bgr_im_array就是我們最終的返回結果。

(5)寫入視頻

為了節約空間,我並非等將寫入圖片放在合併場景後面,而是邊合併場景邊寫入視頻:

def writeVideo(humanseg, bg_im, fps, size):""":param humanseg: png圖片的路徑:param bgname: 背景圖片:param fps: 幀率:param size: 解析度:return:"""# 寫入視頻fourcc = cv2.VideoWriter_fourcc(*'mp4v')out = cv2.VideoWriter('green.mp4', fourcc, fps, size)# 將每一幀設置背景files = [humanseg + i for i in os.listdir(humanseg)]for file in files:# 循環合併圖片im_array = setImageBg(file, bg_im)# 逐幀寫入視頻out.write(im_array)out.release上面的代碼也非常簡單,執行完成後項目下會生成一個green.mp4,這是一個沒有音頻的視頻,後面就需要我們獲取音頻然後混流了。

(6)讀取原視頻的音頻

因為在opencv中沒找到音頻相關的處理,所以選用moviepy,使用起來也非常方便:

def getMusic(video_name):"""獲取指定視頻的音頻:param video_name: 視頻名稱:return: 音頻對象"""# 讀取視頻文件video = VideoFileClip(video_name)# 返回音頻return video.audio然後就是混流了。

(7)給新視頻設置音頻

這裡同樣使用moviepy,傳入視頻名稱和音頻對象進行混流:

def addMusic(video_name, audio):"""實現混流,給video_name添加音頻"""# 讀取視頻video = VideoFileClip(video_name)# 設置視頻的音頻video = video.set_audio(audio)# 保存新的視頻文件video.write_videofile(output_video)其中output_video是我們在最開始定義的變量。

(8)刪除過渡文件

在我們生產視頻時,會產生許多過渡文件,在視頻合成後我們將它們刪除:

def deleteTransitionalFiles:"""刪除過渡文件"""frames = [frame_path + i for i in os.listdir(frame_path)]humansegs = [humanseg_path + i for i in os.listdir(humanseg_path)]for frame in frames:os.remove(frame)for humanseg in humansegs:os.remove(humanseg)最後就是將整個流程整合一下。

(8)整合

我們將上面完整的流程合併成一個函數:

def changeVideoScene(video_name, bgname):""":param video_name: 視頻的文件:param bgname: 背景圖片:return:"""# 讀取視頻中每一幀畫面fps, size = getFrame(video_name, frame_path)# 批量摳圖getHumanseg(frame_path)# 讀取背景圖片bg_im = readBg(bgname, size)# 將畫面一幀幀寫入視頻writeVideo(humanseg_path, bg_im, fps, size)# 混流addMusic('green.mp4', getMusic(video_name))# 刪除過渡文件deleteTransitionalFiles

(9)在main中調用

我們可以把前面定義的路徑也放進了:

if __name__ == '__main__':# 當前項目根目錄BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "."))# 每一幀畫面保存的地址frame_path = BASE_DIR + '\\frames\\'# 摳好的圖片位置humanseg_path = BASE_DIR + '\\humanseg_output\\'# 最終視頻的保存路徑output_video = BASE_DIR + '\\result.mp4'if not os.path.exists(frame_path):os.makedirs(frame_path)try:# 調用函數製作視頻changeVideoScene('jljt.mp4', 'bg.jpg')# 當製作完成發送郵箱mail.sendMail('你的視頻已經製作完成')except Exception as e:# 當發生錯誤,發送錯誤信息mail.sendMail('在製作過程中遇到了問題' + e.__str__)這樣我們就完成了完整的流程。

發送郵件

郵件的發送又是屬於另外的內容了,我定義了一個mail.py文件,具體代碼如下:

import smtplibfrom email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipart # 一封郵件def sendMail(msg):#sender = '發件人'to_list = ['收件人']subject = '視頻製作情況'# 創建郵箱em = MIMEMultipartem['subject'] = subjectem['From'] = senderem['To'] = ",".join(to_list)# 郵件的內容content = MIMEText(msg)em.attach(content)# 發送郵件# 1、連接伺服器smtp = smtplib.SMTPsmtp.connect('smtp.163.com')# 2、登錄smtp.login(sender, '你的密碼或者授權碼')# 3、發郵件smtp.send_message(em)# 4、關閉連接smtp.close裡面的郵箱我是直接寫死了,大家可以自由發揮。為了方便,推薦發件人使用163郵箱,收件人使用QQ郵箱。另外在登錄的時候直接使用密碼比較方便,但是有安全隱患。

總結

老實說上述程序的效率非常低,不僅佔空間,而且耗時也比較長。在最開始我切換場景選擇的是遍歷圖片每一個像素,而後找到了更加高效的方式取代了。但是幀畫面的保存,和png圖片的存儲都很耗費空間。

另外程序設計還是有許多不合理的地方,像是ndarray對象和Image的區分度不高,另外有些函數選擇傳入路徑,而有些函數選擇傳入文件對象也很容易讓人糊塗。

最後說一下,我們用上面的方式不僅可以做靜態的場景切換,還可以做動態的場景切換,這樣我們就可以製作更加豐富的視頻。當然,效率依舊是個問題。

完整代碼已提交GitHub:

https://github.com/IronSpiderMan/VideoSpecialEffects

AI修復100年前晚清影像喜提熱搜,這兩大算法立功了CycleGan人臉轉為漫畫臉,牛掰的知識又增加了 | 附代碼作詞家下崗系列:教你用 AI 做一個寫歌詞的軟體用大白話徹底搞懂 HBase RowKey 詳細設計為什麼黑客無法攻擊公開的區塊鏈?百萬人學AI 萬人在線大會, 15+場直播搶先看!自動化神經網絡理論進展緩慢,AutoML 算法的邊界到底在哪?

相關焦點

  • 用Python做特效,分分鐘碾壓五毛黨
    Python厲害已經不是一天兩天的事了,但是我怎麼也沒想到,Python還能做特效!因為之前接觸過Python一個批量摳圖的模型庫,然後最近看視頻突然就靈光一現,為啥不用Python給視頻摳圖換個背景?
  • Python實現視頻裁剪添加水印功能
    python目前我們實現的是將單獨一個視頻進行裁剪。本次我們將目前視頻截取一小段內容,並為其添加一個水印圖片。我們使用python的moviepy類庫,首先安裝moviepy類庫,使用pip進行安裝,命令如下:pip install moviepy簡短的介紹一下,MoviePy是一個用於視頻編輯的python模塊,可以用它實現一些基本的操作(比如視頻剪輯,視頻拼接,插入標題),還可以實現視頻合成,還有視頻處理,或用它加入一些自定義的高級的特效。
  • 劇情空洞5毛特效,再好的演員也沒法救場
    然而最近有的網友發現《龍嶺迷窟》的豆瓣評分只有2.9分,去看過的人說劇情空洞,特效只有5毛,甚至感慨再好的演員也沒法救場。然而豆瓣評分破8的網劇如何能降到2.9呢?後來發現部分網友慕名而來,點開的並不是電視劇《龍嶺迷窟》,而是電影版。
  • 一直以為你是「真皮」的,沒想到是毛……茸茸的
    一直以為你是真皮的,沒想到你是真的皮!一直以為海豹是「真皮」的和海豚一樣光滑沒想到是其實海豹一直都是有毛的*圖源網絡但也因為胎毛能吸收大量水分不利於它們在水中遊泳因此,幼仔在出生一段時間後皮下脂肪漸漸形成時就開始脫換胎毛慢慢地換成了短、粗、硬光亮而有斑點的新毛
  • 美翻朋友圈:用Python生成蒙太奇馬賽克圖片
    這就是我們經常聽到了蒙太奇手法,在電影《飛屋環遊記》中皮克斯運用蒙太奇手法,用一個不到5分鐘的短片展現了主角的大半人生,感動無數觀眾。下面我們就看看今天的內容同蒙太奇有何關係。效果展示說這麼多都是虛的,下面我們看看實現的效果,到底什麼是蒙太奇馬賽克圖片,這裡用小松菜奈的照片作為測試:原圖效果圖對比最左邊的是蒙太奇圖縮小的效果,第二個則是正常大小顯示的效果,第三張是原圖,第四張是截取的某個區域的細節。
  • 馬雲花錢打造的「螞蟻森林」,4年種了多少真樹?網友:真沒想到
    馬雲花錢打造的「螞蟻森林」,4年種了多少真樹?網友:真沒想到眾所周知,在網際網路時代下,中國的經濟發展速度,確實還是一流的,至少在全球範圍來看,確實如此!那既然如此,馬雲花錢打造的「螞蟻森林」,4年種了多少真樹?網友紛紛表示:真沒想到!據筆者獲悉,螞蟻森林在2016年被正式推出,用戶通過步行、騎車線上付款等節省碳排放量的行為,就能夠獲得虛擬的「綠色能量」,收集一定的能量之後,支付寶螞蟻森林就會為我們在荒漠化地區,種下一棵真樹。
  • 吃碗泡麵就知道,比5毛特效還高級!
    吃碗泡麵就知道,比5毛特效還高級!東北也屬於北方,北方人愛吃麵食,尤其是到了過年的時候,餃子就是一種不可少的主食,東北人更加的豪爽,一家家都是成包成包的做餃子,各種餡的都有,而零下30度的東北,室外就是一個天然大冰箱,把包好的餃子放到室外,攤開一會的功夫就凍成冷凍餃子了,比放冰箱還快速,凍好了之後裝到袋子裡放到門口的缸裡,天天吃餃子。
  • 用Python做一隻真·多足機器人,鋼鐵蜈蚣能彎曲還能蠕動
    然而,一位名叫Adimin的外國小哥用python做了一隻可爬行可彎曲的蜈蚣型機器人。  問:為什麼要做設計成蜈蚣型呢?  小哥答:蜈蚣在體型上具有相當的長度,而通過向上彎曲身體還可以具有一定的高度。但是重點是——從來沒人做過!蜈蚣機器人夠酷、夠怪、夠有趣!
  • python基礎課程 第5章 奇妙的內建函數
    然而人生遠遠比計算機世界複雜,我們可以用python在計算機中實現這個原則,卻很難在人生中實現它。有人說工程師相對比較單純也是如此吧,工作久了,難免受機器的一些影響。畢竟作為高級動物的我們內心世界太過複雜和敏感,到現在為止甚至未來的很長的時間裡也沒辦法被人工智慧所取代。
  • 小蘿莉荒島大戰巨蟒,誰說國產猛片都是5毛特效!
    這類影片的標誌特點就是:不在影院上映,只在優酷、騰訊、愛奇藝等平臺上線投資小,意味著在特效上,容易受到觀眾吐槽詬病。但隨著中國電影工業水平的日益成熟,國產網絡大電影的質量也日漸提高。加之產年逐年增長,網絡大電影正成為華語電影不可或缺的存在。
  • 用Python實現職工信息管理系統
    想要實現一個職工管理系統首先我們看一下想要實現什麼功能最基礎的增刪改查肯定要實現的然後增加一下數據顯示、數據排序、數據統計功能下面直接上代碼1.input('請輸入電話')money = input('請輸入工資')# 修改數據data[ids.index(id)] = [id, name, sex, age, education, address, photonumber, money]print('修改成功')save()```)5.
  • Python:把視頻轉為Gif圖片
    今天,我就隆重給大家介紹下Python視頻製作利器:MoviePy,利用MoviePy就可以輕輕鬆鬆地實現。首先,我們先了解下,什麼是MoviePy。MoviePy是一個用於視頻編輯的python模塊,你可以用它實現一些基本的操作(比如視頻剪輯,視頻拼接,插入標題),實現視頻合成,也可以用它加入一些自定義的高級的特效。
  • 如何使用python語言代碼實現判斷是否為回文
    工具Visual Studio 2019python運行環境技術python回文回文,是按照中心對稱,從左到右或從右到左,字符串都一樣的。如果想要python語言代碼實現回文判斷,若為回文,列印回文,否則列印不是回文。
  • 如何在Python中實現交互兩個數
    如何在Python中實現交互兩個數【原理】生活中我們要交互兩個杯中的水,小朋友們都知道我們需要再拿一個空杯子來倒換水,今天我們來探索一下python中如何實現交互兩個數【編程】首先我們需要輸入兩個數x=int(input("x="))
  • Python學習步驟
    算法和數據結構是很多大公司面試的不二選擇,我們這裡講解內容的同時,手把手帶你實現一個個底層算法,將內功練紮實。3. 手寫神經網絡。Python是人工智慧的第一語言。我們創造性的在基礎課程中就加入了如何編寫一個自己的神經網絡,為踏入神經網絡的大門打下「堅實基礎」。
  • 吉林嚴查扶貧腐敗 村民:沒想到肉進狼嘴裡還能摳出來
    吉林嚴查扶貧腐敗 村民:沒想到肉進狼嘴裡還能摳出來 2017-02 2017年02月14日 05:55 來源:人民日報 參與互動    「真沒想到肉進了狼嘴裡
  • Python視頻教程網課編程零基礎入門數據分析網絡爬蟲全套Python...
    4-08交叉分析方法與實現 4-09交叉分析方法與實現 4-10相關分析與實現 4-11因子分析與實現 4-12本章小結 5-01特徵工程概述 5-02數據樣本採集 5-03異常值處理 5-04標註 5-05特徵選擇 5-06特徵變換-對指化
  • 廢紙箱成了香餑餑 回收價從4毛5漲到8毛5
    廢紙板回收價從4毛5漲到8毛5    紙價上漲影響零食、家電、媒體行業,對快遞業暫未形成壓力  部分用紙企業已有應對之策,或研發新包裝材料,或儘量減少包裝成本本報記者 陳婕 朱銀玲  昨天早上7點多,古墩路附近一家廢品收購站已經開門營業了。
  • 「python學習手冊-筆記」003.數值類型
    >In [6]: float(5)Out[6]: 5.0python的數值比較數值的比較會輸出一個布爾值,比如:In [10]: 1<2Out[10]: TrueIn [11]: 2.0>3
  • 如何在 i5 上實現 20 倍的 Python 運行速度?
    他對外宣布:在配備四核 i5 的 iMAC 上實現了 20 倍的性能加速!至於他是怎麼做到的,請繼續往下看(含代碼)。James ReindersJames Reinders:利用 Intel Distribution for Python,我實現了 Python 的 20 倍加速,並且可用單個命令關閉/啟用。