Python 使用 OpenCV 进行图像神经风格迁移

萝らか妹 提交于 2020-08-17 07:39:14

Neural Style Transfer with OpenCV

src: https://www.pyimagesearch.com/2018/08/27/neural-style-transfer-with-opencv/
source code: https://app.monstercampaigns.com/c/tortsem7qkvyuxc4cyfi
author: Adrian Rosebrock

学完这篇教程你将掌握通过 OpenCV、Python 还有深度学习来对 图片进行神经风格迁移(neural style transfer),到了本文最后你将能够制作自己的风格迁移图片。

最初的神经风格迁移算法是由 Gatys 等人于 2015 年的 A Neural Algorithm of Artistic Style [1] 论文中发布。

到了 2016 年 Johnson 等人发表了 Perceptual Losses for Real-Time Style Transfer and Super-Resolution(实时风格转移和超分辨率的感知损失)[2] 这将神经网络描述为使用感知损失的超分辨率问题。最终的结果是使一个神经风格迁移算法比 Gatys 等人的方法要快上三个数量级(其中也存在一些缺陷,我将在后文说到)。

使用 OpenCV 的神经风格迁移

我今天提到的方法能够在 CPU 上运行,并且还将在 GPU 上获得更好的表现。

我们将从对神经风格迁移的简短讨论开始,包括它是什么以及它的机制。之后我们将应用 OpenCV 和 Python 来实际应用神经风格迁移。

什么是神经风格迁移(neural style transfer)


图像 1:内容图片(左);风格图片(中);风格化输出(右)

神经风格迁移的处理过程如下:

  1. 获取一幅图像的风格;
  2. 之后将其应用到另一幅图片的内容上。

图 1 中展示了一个处理的例子,左边是我们的内容图片 —— 原作者本人在德国黑森林山顶喝啤酒眺望巴登。

中间的是我们用于获取风格的图片,Vincent van Gogh [3] 的 Starry Night

右边的是将梵高的星夜风格应用到原作者本人照片后的输出。请注意我们是如何在应用过星夜的风格后,还能保留住起伏的山丘、森林、原作者甚至是啤酒的,就好像是梵高本人亲手绘出的一样。

问题是,我们该如何定义神经网络进行神经风格迁移?这有可能吗?

神经风格迁移的机制


到此处你可能挠破头皮还在想刚才那句话:“我们该如何定义神经网络进行神经风格迁移?”

有趣的是在最早 2015 年 Gatys 等人的论文中提出了一种根本不需要新结构的神经风格迁移算法,因此我们才能使用一个已预先训练过的网络,并定义一个损失函数,来实现我们风格迁移的最终目标并且能够优化损失函数。

现在的问题已不再是我们应该使用什么神经网络了,而是我们应该使用什么损失函数?

答案是一个三分量(three-component)的损失函数,包括有:

  1. Content loss
  2. Style loss
  3. Total-variation loss

其中每一 component 都被独立计算,并且之后被结合为一个单独的 meta-loss function。通过最小化 meta-loss function 我们也同时将一起优化了 content, style and total-variation loss。

虽然 Gatys 等人的方法可以产生很好的神经风格迁移结果,但问题是这样真是太慢了。

2016 年 Johnson 等人在 Gatys 等人的基础上提出了一种快上前者三个数量级的神经风格迁移算法,Johnson 等人将神经网络描述为了基于感知损失的超分辨率问题。

Johnson 等人的方法确实很快,但其最大的弊端是你不能随意选择你的风格图片。

取而代之的是您首先需要对网络进行训练,使其重现你想要图片的风格。一旦网络训练完成,你就可以将其应用到任何你想要的内容上了。你应该将 Johnson 等人的方法看作是对风格图像的投资,你最好要喜欢你所选的风格图像,因为你将一直训练你的网络来让其更好的在内容图片上重现出来。

Johnson 等人官方的神经风格模型训练文档可以在 GitHub 上找到。[4]

最后还有值得一看的是 Ulyanov 等人在2017 年发表的 Instance Normalization: The Missing Ingredient for Fast Stylization [5],将批标准化(batch normalization)改为实例正则化(instance normalization)将获得更快的实时性能也更具美感。

Johnson 与 Ulyanov 等人的模型都已经包含在了 “下载” 部分,一定要下载下来才能跟进本指南的剩余部分。

你还可以在原作者的书中 Deep Learning for Computer Vision with Python [6] 学到更多有关神经风格迁移的内容。

项目结构

项目中的文件你都可以在 ”下载“ 部分找到,下载之后你就可以使用 tree 命令来探查文件结构:

$ tree --dirsfirst
.
├── images
│   ├── baden_baden.jpg
│   ├── giraffe.jpg
│   ├── jurassic_park.jpg
│   └── messi.jpg
├── models
│   ├── eccv16
│   │   ├── composition_vii.t7
│   │   ├── la_muse.t7
│   │   ├── starry_night.t7
│   │   └── the_wave.t7
│   └── instance_norm
│       ├── candy.t7
│       ├── feathers.t7
│       ├── la_muse.t7
│       ├── mosaic.t7
│       ├── starry_night.t7
│       ├── the_scream.t7
│       └── udnie.t7
├── neural_style_transfer.py
├── neural_style_transfer_examine.py
└── neural_style_transfer_video.py
4 directories, 18 files

有了这些之后你就不用继续寻找别的东西了,我为在 images 目录中你准备了一些内容图片,也在 models 目录中为你准备好了由 Johnson 等人训练过的模型了,还有三个你将会用到的 Python 文件。

实现神经风格迁移

现在就是用 OpenCV 和 Python 来实现神经风格迁移的部分了,打开你的 neural_style_transfer.py 文件并且加入以下代码:

# import the necessary packages
import argparse
import imutils
import time
import cv2

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-m", "--model", required=True,
    help="neural style transfer model")
ap.add_argument("-i", "--image", required=True,
    help="input image to apply neural style transfer to")
args = vars(ap.parse_args())

首先我们导入了必要的包并且进行了命令行参数的解析,要注意的有:

  • imutils:这是可用包管理器 pip 安装的,并且我们需要 imutils==0.5.1,别忘了进行升级:
    pip install --upgrade imutils
  • OpenCV:你需要 3.4 或者更新。

执行程序时我们还需加上两个命令行参数:

  • --model:需要指明神经风格迁移模型的路径,下载部分中我为你准备了十一个;
  • --image:需要被作用的内容图片路径,当然也要尝试使用自己的图片。

参数都是在程序运行时被传递与处理的,如果你还不熟悉命令行参数的解析原理,你一定要读读原作者的命令行参数解析一文。[7]

现在有意思的部分来了,我们将加载我们的图片与模型并且来计算出神经风格迁移的结果:

# load the neural style transfer model from disk
print("[INFO] loading style transfer model...")
net = cv2.dnn.readNetFromTorch(args["model"])

# load the input image, resize it to have a width of 600 pixels, and
# then grab the image dimensions
image = cv2.imread(args["image"])
image = imutils.resize(image, width=600)
(h, w) = image.shape[:2]

# construct a blob from the image, set the input, and then perform a
# forward pass of the network
blob = cv2.dnn.blobFromImage(image, 1.0, (w, h),
    (103.939, 116.779, 123.680), swapRB=False, crop=False)
net.setInput(blob)
start = time.time()
output = net.forward()
end = time.time()

这个代码块中我们进行了如下的处理:

  • 将预先训练过的神经风格迁移模型以变量 net 加载至内存当中;
  • 加载图像并且重新天正其大小;
  • 通过均值减法(mean subtraction)来构造一个 blob,你可以看原作者之前的文章 [8]来了解 cv2.dnn.blobFromImage 的用法;
  • 倒数第二行通过 forward 方法来获得我们期望的输出图像也就是神经风格迁移的结果,在其处理前后我还加入了时间戳。

接下来,我们必须对输出图像进行后期处理:

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

举例 NumPy 数组的值为 (1, 3, 452, 600):

  • 数字 1 表明我们向网络中传递了某数量的图片;
  • OpenCV 以通道优先表示输出图像中有 3 个通道;
  • 最后两值即为输出图像的行和列。

上表代码的非注释第一行,我们将图像重塑简化为 (3, H, W) 后继续处理:

  • 加上我们减去了的平均值(非注释的第二到四行);
  • 缩放处理;
  • 转置矩阵使其通道排在最后。

最后一步就是向我们的屏幕输出结果了:

# show information on how long inference took
print("[INFO] neural style transfer took {:.4f} seconds".format(
    end - start))

# show the images
cv2.imshow("Input", image)
cv2.imshow("Output", output)
cv2.waitKey(0)

结果

在你都下载齐全后,打开你的终端执行如下命令:

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

这样我们就创造了深度学习的艺术品,终端的输出结果将显示出不同模型的不同处理时间。

Links

[1] https://arxiv.org/abs/1508.06576

[2] https://cs.stanford.edu/people/jcjohns/eccv16/

[3] https://en.wikipedia.org/wiki/Vincent_van_Gogh

[4] https://github.com/jcjohnson/fast-neural-style

[5] https://arxiv.org/abs/1607.08022

[6] https://pyimagesearch.com/deep-learning-computer-vision-python-book/

[7] https://pyimagesearch.com/2018/03/12/python-argparse-command-line-arguments/

[8] https://pyimagesearch.com/2017/11/06/deep-learning-opencvs-blobfromimage-works/

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!