手把手教你用OpenCV和Python實現圖像和視頻神經風格遷移(代碼)

2021-02-14 機器學習研究組訂閱

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

首先說明的一點是,今天討論的方法在一個CPU上可以達到近乎實時的效果,如果在GPU上則完全可以實現實時效果。

首先我們會簡單塔倫下什麼是神經風格遷移,以及它是如何運作的。之後我們會用OpenCV和Python動手操作。

從左至右:我們的內容圖像;風格圖像;輸出的風格遷移圖像

神經風格遷移主要有兩個過程:

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

問題就是,我們應該如何定義一個神經網絡,讓它執行神經風格遷移呢?

在Gatys等人提出的首篇論文中,神經風格遷移算法不需要新的架構。相反,我們可以用一個預訓練網絡(通常在ImageNet上進行的預訓練),並且定義一個損失函數,能讓我們達到風格遷移的目標,然後對損失函數不斷優化。

那麼,這裡的問題就不是「該用什麼神經網絡」了,而是「該用什麼損失函數」。

答案包括:內容損失、風格損失和總變差損失。每個部分都是單獨計算,然後在一個元損失函數中結合。通過將元損失函數最小化,我們將依次對內容、風格和總變差損失進行優化。

雖然Gatys等人的方法能生成不錯的神經風格遷移結果,但是它的速度非常慢。2016年,Johnson等人在Gatys的基礎上提出的全新算法速度快了三倍,但同時也存在著缺點,即用戶不能隨機選擇想要應用的風格圖像。用戶首先要訓練一個網絡,生成你想要的風格。網絡訓練好後,你可以將它應用到任意內容圖像上。

然而到了2017年,Ulyanov等人發表了Instance Normalization: The Missing Ingredient for Fast Stylization一文,他們表示將batch normalization替換成instance normalization(然後在訓練和測試時都應用instance normalization),可以達到更快的效果,並且藝術效果也更好。

在開始今天的教程前,請先下載我提供的資料(點擊文末原文地址獲取資料)。準備好了腳本、模型和圖像後,你可以用tree指令檢查項目的結構:

1$ tree --dirsfirst
2.
3├── images
4│   ├── baden_baden.jpg
5│   ├── giraffe.jpg
6│   ├── jurassic_park.jpg
7│   └── messi.jpg
8├── models
9│   ├── eccv16
10│   │   ├── composition_vii.t7
11│   │   ├── la_muse.t7
12│   │   ├── starry_night.t7
13│   │   └── the_wave.t7
14│   └── instance_norm
15│       ├── candy.t7
16│       ├── feathers.t7
17│       ├── la_muse.t7
18│       ├── mosaic.t7
19│       ├── starry_night.t7
20│       ├── the_scream.t7
21│       └── udnie.t7
22├── neural_style_transfer.py
23├── neural_style_transfer_examine.py
24└── neural_style_transfer_video.py

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

接下來讓我們用OpenCV和Python進行神經風格遷移的實踐。

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

1# import the necessary packages
2import argparse
3import imutils
4import time
5import cv2
6
7# construct the argument parser and parse the arguments
8ap = argparse.ArgumentParser()
9ap.add_argument("-m", "--model", required=True,
10    help="neural style transfer model")
11ap.add_argument("-i", "--image", required=True,
12    help="input image to apply neural style transfer to")
13args = vars(ap.parse_args())

首先,我們導入所需的包並解析命令行參數。

導入的有:

該腳本下需要兩個命令行:

你不需要改變命令行代碼,參數會在運行過程中進行處理。如果你不熟悉這一過程,可以閱讀我另一篇文章:

www.pyimagesearch.com/2018/03/12/python-argparse-command-line-arguments/

接下來的部分比較有趣,我們要下載圖像和模型,然後計算神經風格遷移:

15# load the neural style transfer model from disk
16print("[INFO] loading style transfer model...")
17net = cv2.dnn.readNetFromTorch(args["model"])
18
19# load the input image, resize it to have a width of 600 pixels, and
20# then grab the image dimensions
21image = cv2.imread(args["image"])
22image = imutils.resize(image, width=600)
23(h, w) = image.shape[:2]
24
25# construct a blob from the image, set the input, and then perform a
26# forward pass of the network
27blob = cv2.dnn.blobFromImage(image, 1.0, (w, h),
28    (103.939, 116.779, 123.680), swapRB=False, crop=False)
29net.setInput(blob)
30start = time.time()
31output = net.forward()
32end = time.time()

在這部分代碼中,我們進行了:

接下來,重要的是對輸出圖像進行後處理:

34# reshape the output tensor, add back in the mean subtraction, and
35# then swap the channel ordering
36output = output.reshape((3, output.shape[2], output.shape[3]))
37output[0] += 103.939
38output[1] += 116.779
39output[2] += 123.680
40output /= 255.0
41output = output.transpose(1, 2, 0)

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

43# show information on how long inference took
44print("[INFO] neural style transfer took {:.4f} seconds".format(
45    end - start))
46
47# show the images
48cv2.imshow("Input", image)
49cv2.imshow("Output", output)
50cv2.waitKey(0)

當你下載好文件後,打開終端執行以下命令:

1$ python neural_style_transfer.py --image images/giraffe.jpg \
2    --model models/eccv16/the_wave.t7
3[INFO] loading style transfer model...
4[INFO] neural style transfer took 0.3152 seconds

現在,對命令行參數做簡單改變,然後用《侏羅紀公園》中的截圖作為內容圖像,進行風格遷移:

1$ python neural_style_transfer.py --image images/jurassic_park.jpg \
2    --model models/instance_norm/the_scream.t7
3[INFO] loading style transfer model...
4[INFO] neural style transfer took 0.1202 seconds

另一個例子:

1$ python neural_style_transfer.py --image images/messi.jpg \
2    --model models/instance_norm/udnie.t7 
3[INFO] loading style transfer model...
4[INFO] neural style transfer took 0.1495 seconds

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

上面我們講了如何在單一圖像上應用風格遷移,現在我們要把這一過程放在視頻上。

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

利用一個特殊的Python迭代器,它可以讓我們在模型路徑中循環使用所有可用的神經風格遷移模型。

啟動網絡攝像頭視頻流,我們會(近乎)實時處理攝像頭的幀。對於某些較大的模型,系統可能會慢一些。

在每一幀上應用風格遷移,對輸出進行後處理,並將結果顯示在屏幕上。

如果用戶按下「n」鍵,我們將把迭代器循環運用到下一個神經風格遷移模型上,不用重啟腳本。

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

1# import the necessary packages
2from imutils.video import VideoStream
3from imutils import paths
4import itertools
5import argparse
6import imutils
7import time
8import cv2
9
10# construct the argument parser and parse the arguments
11ap = argparse.ArgumentParser()
12ap.add_argument("-m", "--models", required=True,
13    help="path to directory containing neural style transfer models")
14args = vars(ap.parse_args())

之後,創建模型路徑迭代器:

16# grab the paths to all neural style transfer models in our 'models'
17# directory, provided all models end with the '.t7' file extension
18modelPaths = paths.list_files(args["models"], validExts=(".t7",))
19modelPaths = sorted(list(modelPaths))
20
21# generate unique IDs for each of the model paths, then combine the
22# two lists together
23models = list(zip(range(0, len(modelPaths)), (modelPaths)))
24
25# use the cycle function of itertools that can loop over all model
26# paths, and then when the end is reached, restart again
27modelIter = itertools.cycle(models)
28(modelID, modelPath) = next(modelIter)

一旦我們開始在while循環中處理幀,「n」按鍵就會在迭代器中下載「下一個」模型。

為了創建模型迭代器,我們:

讓我們開始下載第一個模型並對視頻進行處理:

30# load the neural style transfer model from disk
31print("[INFO] loading style transfer model...")
32net = cv2.dnn.readNetFromTorch(modelPath)
33
34# initialize the video stream, then allow the camera sensor to warm up
35print("[INFO] starting video stream...")
36vs = VideoStream(src=0).start()
37time.sleep(2.0)
38print("[INFO] {}. {}".format(modelID + 1, modelPath))

在32行,我們讀取了第一個模型利用的路徑。在36和37行,啟動了視頻,從攝像頭中採集幀。

之後在幀與幀之間進行循環:

40# loop over frames from the video file stream
41while True:
42    # grab the frame from the threaded video stream
43    frame = vs.read()
44
45    # resize the frame to have a width of 600 pixels (while
46    # maintaining the aspect ratio), and then grab the image
47    # dimensions
48    frame = imutils.resize(frame, width=600)
49    orig = frame.copy()
50    (h, w) = frame.shape[:2]
51
52    # construct a blob from the frame, set the input, and then perform a
53    # forward pass of the network
54    blob = cv2.dnn.blobFromImage(frame, 1.0, (w, h),
55        (103.939, 116.779, 123.680), swapRB=False, crop=False)
56    net.setInput(blob)
57    output = net.forward()

接著進行後處理並將輸出圖像展示出來:

59# reshape the output tensor, add back in the mean subtraction, and
60    # then swap the channel ordering
61    output = output.reshape((3, output.shape[2], output.shape[3]))
62    output[0] += 103.939
63    output[1] += 116.779
64    output[2] += 123.680
65    output /= 255.0
66    output = output.transpose(1, 2, 0)
67
68    # show the original frame along with the output neural style
69    # transfer
70    cv2.imshow("Input", frame)
71    cv2.imshow("Output", output)
72    key = cv2.waitKey(1) & 0xFF

對按鍵的處理:

74# if the `n` key is pressed (for "next"), load the next neural
75    # style transfer model
76    if key == ord("n"):
77        # grab the next neural style transfer model model and load it
78        (modelID, modelPath) = next(modelIter)
79        print("[INFO] {}. {}".format(modelID + 1, modelPath))
80        net = cv2.dnn.readNetFromTorch(modelPath)
81
82    # otheriwse, if the `q` key was pressed, break from the loop
83    elif key == ord("q"):
84        break
85
86# do a bit of cleanup
87cv2.destroyAllWindows()
88vs.stop()

兩種不同的按鍵會對腳本運行產生不同的影響:

執行以下命令就可以在視頻上運用風格遷移啦:

1$ python neural_style_transfer_video.py --models models

可以看到,只需要按一個按鍵就能輕鬆地進行循環。下面是我自己做的demo視頻:

今天的教程是教大家如何用OpenCV和Python在圖片和視頻上運用神經風格遷移。具體來說,我們用的模型是Johnson等人於2016年提出的,你可以在我提供的連結中下載。希望這篇教程對你有用!

想要了解更多資訊,請掃描下方二維碼,關注機器學習研究會

                                          

轉自: 新智元

相關焦點

  • 「Python+cv2」Python安裝opencv及圖像的基本操作
    如果對Python安裝有疑問的可以參考我的文章:手把手教你搭建Python3開發環境手把手教你安裝python編輯器pycharm2、檢查pip3是否安裝3、安裝opencvpython環境下opencv的安裝:pip3 install opencv-python
  • 使用Python+OpenCV實現神經網絡預處理人臉圖像的快速指南
    這通常意味著需要應用深度學習,因此在將圖像注入到我們的神經網絡之前需要一個特殊的預處理階段。為了提高我們的模型精度,這是一項非常重要的任務,通過以下幾個簡單的步驟可以很好地完成。對於本文,我們使用OpenCV:一個高度優化的計算機視覺開源庫,在C++、java和Python中都可用。這是一篇簡短的文章,包含了一些基本的指導原則、示例和代碼,你可以根據需求將它們應用到人臉分類或識別問題上。
  • 使用Python+OpenCV實現圖像數據採集
    在Anaconda或命令提示符中鍵入conda create -n opencv python=3.6這將在Python版本3.6中創建一個名為opencv的新環境,可以用正在使用的任何版本替換它。下一步,輸入pip install opencv-python你已經成功安裝了cv2! 現在你可以開始拍照了。
  • Python 圖像處理 OpenCV (1):入門
    安裝OpenCV 在 Python 中有兩個類庫,一個是 opencv-python ,另一個是 opencv-contrib-python 。opencv-python 是只包含了主要模塊的包,而 opencv-contrib-python 包含了主要模塊以及一些擴展模塊,帶一些收費或者專利的算法,還有一些比較新的算法的高級版本。
  • Python不超過10行代碼就可實現人臉識別,教你辨別真假
    一般我們考慮使用OpenCV、dlib等開源庫的人臉檢測功能(基於專家經驗的傳統特徵值方法計算量少從而速度更快),也可以使用基於深度學習實現的技術如MTCNN(在神經網絡較深較寬時運算量大從而慢一些)。下面環境搭建:1. 安裝 Ubuntu17.10 > 安裝步驟在這裡2.
  • Python+OpenCV的基礎圖像處理操作匯總
    圖像處理是對圖像進行的技術操作與分析,比如為了得到增強的圖像或提取一些有用的信息而進行的一系列操作。隨著我們的發展,許多應用程式使用圖像/幀/視頻作為輸入,對它們進行預處理,並將其輸入到設備或軟體或腳本中。圖像處理也可以是娛樂性的,可以用於許多應用。
  • OpenCV入門及應用案例:手把手教你做DNN圖像分類
    OpenCV成為最主要的圖像處理工具包,是因為它功能齊全,支持目前主流的圖像、視頻處理算法,而且對外提供C++、Python和Java的接口,用戶調用方便。本書的代碼分析、示例程序及環境搭建基於OpenCV 4.1版本,原始碼位於GitHub的OpenCV倉庫。
  • 用OpenCV和Python模糊和匿名化人臉
    在這裡,我們將討論用OpenCV和Python模糊人臉的四步方法。然後,我們將回顧我們的項目結構,並使用OpenCV實現兩種面部模糊方法:使用高斯模糊對圖像和視頻流中的人臉進行匿名化將「像素模糊」效果應用於圖像和視頻中的匿名人臉考慮到我們的兩個實現,我們將創建Python腳本來將這些面部模糊方法應用於圖像和視頻。
  • python利用opencv實現證件照換底
    opencv今天就給大家介紹一下python利用opencv庫進行藍底換紅底或者白底照片的操作。1.強大的opencv庫說到圖像處理,不得不提opencv庫。它是一個跨平臺的計算機視覺庫,可以運行在不同作業系統上,它由一些列c函數和少量c++函數組成,並提供python,matlab等語言的接口,實現了圖像處理和計算機視覺方面的很多通用算法。我們這裡用的opencv-python 就是opencv的python API接口。
  • 手把手教你搭建能夠實現 Prisma 風格遷移效果的 iOS 酷炫應用
    一種已經提出並實施的想法,稱為「神經風格轉換」,允許你能夠利用預訓練的深度神經網絡模型,並將某一圖像的風格,例如或梵谷或莫尼特的任何杰作,遷移到另一個圖像,例如你的個人資料圖片或你最喜歡的小狗的圖片,從而創造了一個混合你的圖片內容和名作風格的圖像。
  • opencv-python獲取圖像:面向對象與面向過程
    Lena圖像在科研領域流行的原因:1.該圖適度的混合了細節、平滑區域、陰影和紋理,從而能很好的測試各種圖像處理算法。2.Lenna是個美女,對於圖像處理界的研究者(大部分都是男性)來說,美女圖可以有效地吸引他們來做研究。
  • opencv-python圖像預處理-濾波
    為了消除外界環境對圖像採集的幹擾,增強圖像的邊緣及灰度跳變的部分,使圖像變得清晰以及提高圖像處理速度需要對圖像進行預處理操作,主要是對圖像進行濾波和增強操作。使用的方法可以分為空間域處理和頻率域處理兩類。空間域指圖像平面本身,這類圖像處理方法用各種模板直接與圖像進行卷積運算,實現對圖像的處理。
  • 神經風格遷移(NST)的基本機制及實現
    深度學習可以捕獲一個圖像的內容並將其與另一個圖像的風格相結合,這種技術稱為神經風格遷移。但是,神經風格遷移是如何運作的呢?在這篇文章中,我們將研究神經風格遷移(NST)的基本機制。神經風格遷移概述我們可以看到,生成的圖像具有內容圖像的內容和風格圖像的風格。可以看出,僅通過重疊圖像不能獲得上述結果。
  • 手把手教你使用圖像處理利器OpenCV
    下面依次說明在不同作業系統中OpenCV的安裝方法:$ pip install opencv-python$ brew install opencv3 --with-contrib --with-python3
  • 基於opencv 的圖像處理入門教程
    /代碼和樣例圖片的地址:https://github.com/ccc013/CodesNotes/tree/master/opencv_noteshttps://github.com/ccc013/CodesNotes/blob/master/opencv_notes/opencv_image_process_tutorial.ipynb
  • 目標檢測必須要OpenCV?10行Python代碼也能實現,親測好用!
    大數據文摘出品編譯:朱一輝、雪清、小魚短短10行代碼就可以實現目標檢測?!本文作者和他的團隊構建了一個名為ImageAI 的Python庫,集成了現今流行的深度學習框架和計算機視覺庫。本文將手把手教你構建自己的第一個目標檢測應用,而且文摘菌已經幫你踩過坑了,親測有效!
  • 【視覺與圖像】Python+OpenCV教程入門篇
    OpenCV-Python就是用Python包裝了C++的實現,背後實際就是C++的代碼在跑,所以代碼的運行速度跟原生C/C++速度一樣快。舉兩個簡單的例子就一目了然了:一個是讀入圖片,另一個是調整圖片的對比度和亮度:
  • 獨家 | 手把手教你使用OpenCV庫(附實例、Python代碼解析)
    假設你和你的朋友去度假,然後你上傳了很多照片到Facebook上。但是現在在每張照片中找到你朋友的臉並標記它們要花費很多時間。實際上,Facebook已經足夠智能,它可以幫你標記人物。 那麼,你認為自動的特徵標記是如何工作的呢? 簡單來說,它通過計算機視覺來實現。
  • 用Python快速實現圖片的風格遷移
    在這各種神奇的背後,最核心的就是基於深度學習的風格遷移(style transfer)技術。我將在這篇博客帶領大家學習如何使用Python來快速實現圖片的風格遷移。閱讀完本博客後,相信你也能夠創造出漂亮的藝術品。什麼是圖片的風格遷移?
  • 【Python3+OpenCV】實現圖像處理—基本操作篇
    在Python中常使用OpenCV庫實現圖像處理。本文將介紹如何在Python3中使用OpenCV實現對圖像處理的基礎操作:Opencv中如果想要將目前的圖像複製,可以使用以下語句實現:img1 = img.copy():img1是新圖像,img是原圖像import cv2img = cv2.imread