無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移

作者:Adrian Rosebrock

編譯:Bing

2015年,Gatsys等人在論文A Neural Algorithm of Artistic Style中提出了最初的神經(jīng)風(fēng)格遷移算法。2016年,Johnson等人發(fā)表了Perceptual Losses for Real-Time Style Transfer and Super-Resolutioin一文,將神經(jīng)網(wǎng)絡(luò)遷移作為用感知損失處理超分辨率問題的框架。結(jié)果表明該算法比Gatys等人的方法快了三倍。接下來,我將介紹如何在自己的圖像和視頻流中應(yīng)用神經(jīng)風(fēng)格遷移。

用OpenCV進(jìn)行神經(jīng)風(fēng)格遷移

首先說明的一點(diǎn)是,今天討論的方法在一個(gè)CPU上可以達(dá)到近乎實(shí)時(shí)的效果,如果在GPU上則完全可以實(shí)現(xiàn)實(shí)時(shí)效果。

首先我們會(huì)簡(jiǎn)單塔倫下什么是神經(jīng)風(fēng)格遷移,以及它是如何運(yùn)作的。之后我們會(huì)用OpenCV和Python動(dòng)手操作。

什么是神經(jīng)風(fēng)格遷移?

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖1
從左至右:我們的內(nèi)容圖像;風(fēng)格圖像;輸出的風(fēng)格遷移圖像

神經(jīng)風(fēng)格遷移主要有兩個(gè)過程:

  • 提取某張圖片的風(fēng)格

  • 將該種風(fēng)格應(yīng)用到另一張圖片上

上圖就是將梵高著名的畫作《星夜》的風(fēng)格應(yīng)用到普通的生活照上,我們保留了原照片中的山、人物和啤酒等所有內(nèi)容,但全部替換成了梵高的油畫風(fēng)格。

問題就是,我們應(yīng)該如何定義一個(gè)神經(jīng)網(wǎng)絡(luò),讓它執(zhí)行神經(jīng)風(fēng)格遷移呢?

神經(jīng)風(fēng)格遷移如何工作?

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖2

在Gatys等人提出的首篇論文中,神經(jīng)風(fēng)格遷移算法不需要新的架構(gòu)。相反,我們可以用一個(gè)預(yù)訓(xùn)練網(wǎng)絡(luò)(通常在ImageNet上進(jìn)行的預(yù)訓(xùn)練),并且定義一個(gè)損失函數(shù),能讓我們達(dá)到風(fēng)格遷移的目標(biāo),然后對(duì)損失函數(shù)不斷優(yōu)化。

那么,這里的問題就不是“該用什么神經(jīng)網(wǎng)絡(luò)”了,而是“該用什么損失函數(shù)”。

答案包括:內(nèi)容損失、風(fēng)格損失和總變差損失。每個(gè)部分都是單獨(dú)計(jì)算,然后在一個(gè)元損失函數(shù)中結(jié)合。通過將元損失函數(shù)最小化,我們將依次對(duì)內(nèi)容、風(fēng)格和總變差損失進(jìn)行優(yōu)化。

雖然Gatys等人的方法能生成不錯(cuò)的神經(jīng)風(fēng)格遷移結(jié)果,但是它的速度非常慢。2016年,Johnson等人在Gatys的基礎(chǔ)上提出的全新算法速度快了三倍,但同時(shí)也存在著缺點(diǎn),即用戶不能隨機(jī)選擇想要應(yīng)用的風(fēng)格圖像。用戶首先要訓(xùn)練一個(gè)網(wǎng)絡(luò),生成你想要的風(fēng)格。網(wǎng)絡(luò)訓(xùn)練好后,你可以將它應(yīng)用到任意內(nèi)容圖像上。

然而到了2017年,Ulyanov等人發(fā)表了Instance Normalization: The Missing Ingredient for Fast Stylization一文,他們表示將batch normalization替換成instance normalization(然后在訓(xùn)練和測(cè)試時(shí)都應(yīng)用instance normalization),可以達(dá)到更快的效果,并且藝術(shù)效果也更好。

項(xiàng)目結(jié)構(gòu)

在開始今天的教程前,請(qǐng)先下載我提供的資料(點(diǎn)擊文末原文地址獲取資料)。準(zhǔn)備好了腳本、模型和圖像后,你可以用tree指令檢查項(xiàng)目的結(jié)構(gòu):

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖3

如果你從下載了.zip文件,就無需上網(wǎng)找其他素材了。我在其中提供了很多測(cè)試用的圖像和模型。同時(shí)還有三種Python腳本。

開始神經(jīng)風(fēng)格遷移

接下來讓我們用OpenCV和Python進(jìn)行神經(jīng)風(fēng)格遷移的實(shí)踐。

首先打開neural_style_transfer.py文件,插入如下代碼:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖4

我們導(dǎo)入所需的包并解析命令行參數(shù)。

導(dǎo)入的有:

  • imutils:這個(gè)包可以通過pip install --upgrade imutils安裝。最近我發(fā)布了imutils==0.5.1,所以不要忘記更新!

  • OpenCV:你需要一個(gè)OpenCV 3.4或者更高版本。

該腳本下需要兩個(gè)命令行:

  • --model:神經(jīng)風(fēng)格遷移的模型路徑。在“下載”區(qū)中,我加入了11中經(jīng)過與訓(xùn)練的模型。

  • --image:需要進(jìn)行風(fēng)格遷移的圖像(輸入圖像)。在其中我放入了四張圖片。

你不需要改變命令行代碼,參數(shù)會(huì)在運(yùn)行過程中進(jìn)行處理。如果你不熟悉這一過程,可以閱讀我另一篇文章:www.pyimagesearch.com/2018/03/12/python-argparse-command-line-arguments/

接下來的部分比較有趣,我們要下載圖像和模型,然后計(jì)算神經(jīng)風(fēng)格遷移:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖5

在這部分代碼中,我們進(jìn)行了:

  • 將下載的預(yù)訓(xùn)練神經(jīng)風(fēng)格遷移模型稱為net(第17行);

  • 下載輸入圖像并調(diào)整尺寸(21和22行);

  • 用均值減法創(chuàng)建blob(27和28行);

  • 執(zhí)行forward,獲取output圖像(31行)。

接下來,重要的是對(duì)輸出圖像進(jìn)行后處理:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖6

最后一步是將輸出圖像顯示在屏幕上:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖7

神經(jīng)風(fēng)格遷移結(jié)果

當(dāng)你下載好文件后,打開終端執(zhí)行以下命令:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖8
無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖9

現(xiàn)在,對(duì)命令行參數(shù)做簡(jiǎn)單改變,然后用《侏羅紀(jì)公園》中的截圖作為內(nèi)容圖像,進(jìn)行風(fēng)格遷移:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖10
無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖11

另一個(gè)例子:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖12
無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖13

這是我最喜歡的案例,感覺都能當(dāng)做酒吧的裝飾畫了。

實(shí)時(shí)神經(jīng)風(fēng)格遷移

上面我們講了如何在單一圖像上應(yīng)用風(fēng)格遷移,現(xiàn)在我們要把這一過程放在視頻上。

大致流程和圖像處理差不多,在這一腳本中,我們將:

  • 利用一個(gè)特殊的Python迭代器,它可以讓我們?cè)谀P吐窂街醒h(huán)使用所有可用的神經(jīng)風(fēng)格遷移模型。

  • 啟動(dòng)網(wǎng)絡(luò)攝像頭視頻流,我們會(huì)(近乎)實(shí)時(shí)處理攝像頭的幀。對(duì)于某些較大的模型,系統(tǒng)可能會(huì)慢一些。

  • 在每一幀上應(yīng)用風(fēng)格遷移,對(duì)輸出進(jìn)行后處理,并將結(jié)果顯示在屏幕上。

  • 如果用戶按下“n”鍵,我們將把迭代器循環(huán)運(yùn)用到下一個(gè)神經(jīng)風(fēng)格遷移模型上,不用重啟腳本。

首先,打開neural_style_transfer_video.py文件,插入以下代碼:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖14

之后,創(chuàng)建模型路徑迭代器:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖15

一旦我們開始在while循環(huán)中處理幀,“n”按鍵就會(huì)在迭代器中下載“下一個(gè)”模型。

為了創(chuàng)建模型迭代器,我們:

  • 搜集所有神經(jīng)風(fēng)格遷移模型并分類(18和19行)

  • 為每種模型分配ID(23行)

  • 利用itertoolscycle創(chuàng)建迭代器(27行)。

讓我們開始下載第一個(gè)模型并對(duì)視頻進(jìn)行處理:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖16

在32行,我們讀取了第一個(gè)模型利用的路徑。在36和37行,啟動(dòng)了視頻,從攝像頭中采集幀。

之后在幀與幀之間進(jìn)行循環(huán):

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖17

接著進(jìn)行后處理并將輸出圖像展示出來:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖18

對(duì)按鍵的處理:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖19

兩種不同的按鍵會(huì)對(duì)腳本運(yùn)行產(chǎn)生不同的影響:

  • “n”:抓取下一個(gè)模型的路徑和ID,并進(jìn)行下載。如果我們已經(jīng)獲取上一個(gè)模型,迭代器就會(huì)從頭開始循環(huán)。

  • “q”:按下q會(huì)退出while循環(huán)。

實(shí)時(shí)風(fēng)格遷移的結(jié)果

執(zhí)行以下命令就可以在視頻上運(yùn)用風(fēng)格遷移啦:

無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖20
無需GPU,用OpenCV和Python實(shí)現(xiàn)圖/視頻風(fēng)格遷移的圖21

登錄后免費(fèi)查看全文
立即登錄
App下載
技術(shù)鄰APP
工程師必備
  • 項(xiàng)目客服
  • 培訓(xùn)客服
  • 平臺(tái)客服

TOP

1