前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >梦幻风图片?我用Python分分钟做出来!!

梦幻风图片?我用Python分分钟做出来!!

作者头像
快学Python
发布2021-08-09 14:57:10
4390
发布2021-08-09 14:57:10
举报
文章被收录于专栏:快学Python快学Python

每日一句:人生苦短,快学Python!

本期我们利用卷积神经网络制作一个处理图片的小工具,最终效果对比如下:

原图:

效果图(多张,可以左右滑动):

具体原理简单来说就是,训练一个神经网络,每层网络逐步提取越来越高级的图像特征,通过分析一些特定层的输出发现,当它识别到了一些特定的模式,就会将这些特征显著地增强,而且层数越高,识别的模式就越复杂。

然后网络将识别到的复杂特征组合起来形成完整的解释,并将这些信息反向传播到网络,每个神经元再显示出它想增强的模式或特征。通过以上过程,我们就可以迫使神经网络在图片中产生一些原本不存在的内容,即达到了梦幻的效果~

下面是实战演练环节。

本文代码在以下环境通过测试:

代码语言:javascript
复制
python == 3.6.13

numpy == 1.16.4
scipy == 1.2.1
Pillow == 8.2.0
matplotlib == 3.3.4
tensorflow == 1.2.0

首先,导入相关的库

代码语言:javascript
复制
import numpy as np
import PIL.Image
import scipy.misc
import tensorflow as tf

忽略无关的警告

代码语言:javascript
复制
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

定义网络模型

代码语言:javascript
复制
# 导入inception模型
# tensorflow提供了以“.pb”为扩展名的文件,可以事先将模型导入到pb文件中,在需要的时候导出
model_fn = 'tensorflow_inception_graph.pb'

# 创建图和会话
graph = tf.Graph()
sess = tf.InteractiveSession(graph=graph)
with tf.gfile.FastGFile(model_fn, 'rb') as f:
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())

# 定义输入图像的占位符
t_input = tf.placeholder(np.float32, name='input')

# 图像预处理——减均值
# 训练inception模型时做了减均值预处理,此处也需减同样的均值以保持一致
imagenet_mean = 117.0

# 图像预处理——增加维度
# 图像数据格式一般是(height,width,channels),为同时将多张图片输入网络而在前面增加一维,变为(batch,height,width,channel)
t_preprocessed = tf.expand_dims(t_input - imagenet_mean, 0)

# 导入模型并将预处理图像送入网络中
tf.import_graph_def(graph_def, {'input': t_preprocessed})

找出卷积层

代码语言:javascript
复制
layers = [op.name for op in graph.get_operations() if op.type == 'Conv2D']
# 输出卷积层层数和卷积层名称
print('Number of layers', len(layers))
print(layers)

运行之前的内容可以得到如下输出:

代码语言:javascript
复制
Number of layers 59
['import/conv2d0_pre_relu/conv', 'import/conv2d1_pre_relu/conv', 'import/conv2d2_pre_relu/conv', 'import/mixed3a_1x1_pre_relu/conv', 'import/mixed3a_3x3_bottleneck_pre_relu/conv', 
.......
.......
'import/mixed5b_3x3_pre_relu/conv', 'import/mixed5b_5x5_bottleneck_pre_relu/conv', 'import/mixed5b_5x5_pre_relu/conv', 'import/mixed5b_pool_reduce_pre_relu/conv', 'import/head0_bottleneck_pre_relu/conv', 'import/head1_bottleneck_pre_relu/conv']

是不是很有规律呢?没错,忽略一些次要词语,剩下的12个词就是咱们要用的部分,分别为:

代码语言:javascript
复制
'conv2d0', 'conv2d1', 'conv2d2', 'mixed3a', 'mixed3b', 'mixed4a', 'mixed4b', 'mixed4c', 'mixed4d', 'mixed4e','mixed5a', 'mixed5b'

这12个词,便是预训练模型里的12个卷积层,不同的卷积层对图片进行处理,我们可以得到风格不同的图片。后面会用到这部分内容。

接下来是相关函数的定义:

(篇幅原因,这里这罗列部分函数,完整代码下载方式见文末)

代码语言:javascript
复制
# 判断文件夹是否存在,若不存在则创建
def mkdir(path):
    folder = os.path.exists(path)
    if not folder:
        os.makedirs(path)

# 把numpy.ndarray保存成图像文件
def savearray(img_array, img_name):
    scipy.misc.toimage(img_array).save(img_name)

# 调整图像尺寸
def resize(img, hw):
    min = img.min()
    max = img.max()
    img = (img - min) / (max - min) * 255
    img = np.float32(scipy.misc.imresize(img, hw))
    img = img / 255 * (max - min) + min
    return img

# 原始图像尺寸可能很大,从而导致内存耗尽,每次只对 tile_size * tile_size 大小的图像计算梯度,避免内存问题
def calc_grad_tiled(img, t_grad, tile_size=512):

接下来便是主程序部分。关于这部分的图片风格定义,其实是笔者将许多张图片分别用12个卷积层进行处理,然后把处理结果拿给一位艺术细胞和审美能力比较良好的小姐姐,让她帮忙将风格相似的图片整理在一起,并给对应风格取一个文艺又小清新的名字,也就是说,尽管每次选择同样的风格,但是结果还是会有细微的差别,这就是惊喜了。总之,,在此再次感谢她~

代码语言:javascript
复制
# 打印提示信息
print('嗨,我是你的小小魔法师,我可以为你的图片生成超级梦幻的效果~')
print('请将待处理的图片放入"preprocess_image"文件夹中,复制当前要处理的图片名称')

# 图片风格定义及选择
pattern_name = input('\n请选择图像风格:1.失真印象;2.青铜秘纹;3.克鲁苏之眼;4.迷幻乐园;5.随机(输入对应数字即可):')

if pattern_name == '1':
    name_list = ['conv2d0', 'conv2d1', 'conv2d2']
    name = name_list[np.random.randint(0, 3)]
elif pattern_name == '2':
    name_list = ['mixed3a', 'mixed3b']
    name = name_list[np.random.randint(0, 2)]
elif pattern_name == '3':
    name_list = ['mixed4a', 'mixed4b', 'mixed4c']
    name = name_list[np.random.randint(0, 3)]
elif pattern_name == '4':
    name_list = ['mixed4d', 'mixed4e', 'mixed5a', 'mixed5b']
    name = name_list[np.random.randint(0, 4)]
elif pattern_name == '5':
    name_list = (
        'conv2d0', 'conv2d1', 'conv2d2', 'mixed3a', 'mixed3b', 'mixed4a', 'mixed4b', 'mixed4c', 'mixed4d', 'mixed4e',
        'mixed5a', 'mixed5b')
    name = name_list[np.random.randint(0, 12)]
else:
    print('请看清楚规则!!')

# 获取卷积层对应的通道数
layer_output = graph.get_tensor_by_name('import/%s:0' % name)
# 读取预处理的图片
image_name = input('\n请输入图片名称(附带图片格式,例如:test.jpg):')
file_path = 'preprocess_image/' + image_name
img0 = PIL.Image.open(file_path)
img0 = np.float32(img0)

# 定义图片输出路径
mkdir('processed_image')
file_save_path = 'processed_image/' + image_name.split(sep='.')[0] + '_' + name + '.jpg'

print('\n图片处理过程需要1~2分钟,请耐心等待……')
# 调用render_deepdream函数渲染
render_deepdream(tf.square(layer_output), img0, iter_n=10, step=1.0)
print('\n已完成!生成的图片保存在“processed_image”文件夹下')

至此,图片处理部分结束。

打包

最后,我们可以将它进行简单的打包,这样没有安装python或者配置tensorflow的人也可以使用这个小工具~

我们使用conda创建虚拟环境,用pyinstaller这个库来打包。如果想详细了解Python打包,可以看我之前的文章《别再问我Python打包成exe了!(终极版)

为什么非要创建一个虚拟环境呢?

这是因为在打包的时候,会将当前环境里所有已安装的包打包进去,如果当前环境里已经安装了很多当前代码用不到的库,这样打包好的可执行文件就显得十分臃肿,非常占地方。

接下来我将详细展示打包过程~

没有安装conda的朋友可以先装一个Anaconda或者Mini Conda,因为用它做环境管理真的太方便了。

首先,打开终端,新建一个虚拟环境:

代码语言:javascript
复制
conda create -n tensorflow python=3.6

这里tensorflow是虚拟环境的名称,也可以按照自己的意愿自定义,python=3.6用于指定虚拟环境中python解释器的版本。

创建成功后,使用以下命令激活虚拟环境:

代码语言:javascript
复制
conda activate tensorflow

虚拟环境就相当于重新安装了一个python,此时环境中除了pip和setuptools没有其他的包。因此我们先安装需要用的几个包,这里不要忘了安装pyinstaller这个包。

代码语言:javascript
复制
pip install pyinstaller

pip install numpy==1.16.4
pip install pillow==8.2.0
pip install scipy==1.2.1
pip install matplotlib==3.3.4
pip install tensorflow==1.2.0

接下来,在终端使用命令切换到代码所在目录:

代码语言:javascript
复制
cd D:\Dreamscape\

然后就可以使用pyinstaller进行打包:

代码语言:javascript
复制
pyinstaller -F Dreamscape.py 

-F表示打包成一个单独的文件,Dreamscape.py是主程序名称。

打包成功之后,会在当前目录生成文件夹,可执行文件在dist目录下,注意,exe文件应该和其他依赖文件放在一起,如下图所示:

什么,才67.8MB??其实笔者还删掉了一些不必要的依赖库,才使得打包的exe比较小。因为tensorflow本来就是一个超级大的库,在执行该代码时候部分依赖项用不到,但是笔者也不清楚具体哪个用不到。于是使用pip list列出了该环境下的所有库,然后挨个删除,看程序能否正常能够运行,不能运行就再装回来。。。功夫不负有心人,最终,还是成功地删掉了几个库。

至此,我们完成了该小工具的制作。下面是笔者测试过程中的一些比较成功的作品:

效果图(多张,可以左右滑动):

那么,失败的作品该长啥样呢?

原图:

效果图:

原本魅力无限的迷人小姐姐,硬是被玩坏了。。。

剧终……


Tips:如果想要获得更加细致的图像,可以修改渲染函数里的iter_n参数,增大迭代次数,或者减小step,也可以二者同时调整,使得网络学习到输入图像的更多特征。当然了,这样也会增加图像处理时长……

代码语言:javascript
复制
render_deepdream(tf.square(layer_output), img0, iter_n=10, step=1.0)
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 快学Python 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 打包
相关产品与服务
图片处理
图片处理(Image Processing,IP)是由腾讯云数据万象提供的丰富的图片处理服务,广泛应用于腾讯内部各产品。支持对腾讯云对象存储 COS 或第三方源的图片进行处理,提供基础处理能力(图片裁剪、转格式、缩放、打水印等)、图片瘦身能力(Guetzli 压缩、AVIF 转码压缩)、盲水印版权保护能力,同时支持先进的图像 AI 功能(图像增强、图像标签、图像评分、图像修复、商品抠图等),满足多种业务场景下的图片处理需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档