神经风格迁移(NST)是一种技术,涉及利用深度卷积神经网络和算法从一幅图像中提取内容信息并从另一幅参考图像中提取风格信息。在提取风格和内容之后,将生成一个组合图像,其中生成的图像的内容和风格来自不同的图像。 NST是一种图像风格化方法,它是一种使用输入参考图像来提供从输入图像导出的风格变化的输出图像的过程。
Leon A Gatys等人在论文 “艺术风格的神经算法”中(https://arxiv.org/pdf/1508.06576.pdf) 介绍了NST技术。
深度神经网络(DNN),更具体地说,卷积神经网络(CNN)的关键特征是能够学习图像中内容和风格的空间表示。此特性使NST技术得以实现。
CNN生成的输入图像的空间表示形式捕获图像的风格和内容统计信息。NST将提取的风格和内容组合到生成的输出图像中。
CNN层结构内的中间层中的激活函数提供了捕获输入图像的内容和风格统计信息的功能。
CNN图层在卷积操作之后输出特征图,该卷积操作涉及在输入图像上有一个滤波器滑动。图像的内容实际上在每个图层的生成的特征图中。
从中间层的特征图中提取内容将提供输入图像的高级结构和几何信息。 特征图获取输入图像的风格。为了导出图像的风格,需要评估中间层中特征图的均值和相关性。此过程提供的信息提供输入图像的纹理图案信息。
好东西来了。 我们将使用下面图像的内容和风格创建图像。
左:内容画面,右:风格图片
为了使用两个参考图像成功实现神经风格迁移的过程,我们将利用TensorFlow Hub(https://www.tensorflow.org/hub) 上的模块
TensorFlow Hub提供了一套可重用的机器学习组件,例如数据集,权重,模型等。
对于本文的实现部分,我们将利用一套工具和库来加载图像和执行数据转换。
它们的地址如下:
我们将使用Jupyter Notebook(https://jupyter.org/) 进行代码实现。本文末尾还包括指向notebook的Github存储库的链接。
首先,我们将导入所需的工具和库。
import tensorflow as tfimport matplotlib.pyplot as pltimport numpy as npimport PIL.Imageimport tensorflow_hub as hub
接下来,我们声明两个变量,这些变量保存了图像的目录路径,以表示输出结果的内容和风格。另外,我们也将显示图像。
content_path = 'images/human.jpg'style_path = 'images/painting.jpg'content_image = plt.imread(content_path)style_image = plt.imread(style_path)plt.subplot(1, 2, 1)plt.title('Content Image')plt.axis('off')imshow(content_image)plt.subplot(1, 2, 2)plt.title('Style Image')plt.axis('off')imshow(style_image)
要求将图像转换为张量表示。对于下一步,我们将利用TensorFlow的图像处理方法。
我们将创建一个接受图像路径为参数的函数,然后使用“tf.io.read_file”将图像转换为张量。我们进一步使用'tf.image.decode_image'将张量中值的数据类型更改为在0和1之间的浮点数。
def image_to_tensor(path_to_img): img = tf.io.read_file(path_to_img) img = tf.image.decode_image(img, channels=3, dtype=tf.float32) # Resize the image to specific dimensions img = tf.image.resize(img, [720, 512]) img = img[tf.newaxis, :] return img
需要执行与上述相反的操作才能可视化来自TensorFlow Hub模块的结果。我们需要将返回的张量转换为可以可视化的图像。
我们只需将每个元素乘以255,即可将包含0到1之间的值的张量反归一化为实际像素值。下一步是使用Numpy创建一个数组,其中包含我们需要的数据类型。
我们从张量返回一个图像对象。
def tensor_to_image(tensor): tensor = tensor*255 tensor = np.array(tensor, dtype=np.uint8) tensor = tensor[0] plt.figure(figsize=(20,10)) plt.axis('off') return plt.imshow(tensor)
到目前为止,我们已经完成了以下工作:
现在,我们将图像转换为张量并通过TensorFlow Hub包中的.load()方法将其传递给模块。
我们期望从参考图像中获得风格和内容的组合结果;因此,我们将创建一个变量来保存来自模块的运算结果。
为了可视化结果,我们仅使用我们先前创建的tensor_to_image函数。
content_image_tensor = image_to_tensor(content_path)style_image_tensor = image_to_tensor(style_path)hub_module = hub.load('https://tfhub.dev/google/magenta/arbitrary-image-stylization-v1-256/2')combined_result = hub_module(tf.constant(content_image_tensor), tf.constant(style_image_tensor))[0]tensor_to_image(combined_result)
我们设法结合了两个参考图像的风格和内容,并生成了网格图像。
展望未来,我建议你更详细地探讨“神经风格迁移”主题。 以下是本文中提供的代码的GitHub存储库链接。
https://github.com/RichmondAlake/tensorflow_2_tutorials/blob/master/03_neural_style_transfer.ipynb