说到卷积神经网络,就要提到卷积计算,以上这幅图就是卷积计算的过程。关于卷积方面,这里就不详细说明了,网上资料有很多。
卷积的过程就是通过不同的卷积核提取不同的特征,如一些边缘特征(水平边缘,垂直边缘等)。这里主要通过代码展示通过卷积计算后图片的变化,以可视化的方法为大家展示卷积计算的作用。
代码如下,其中有较为详细的注释,主要需要了解的是函数tf.nn.conv2d()的用法。
import tensorflow as tf
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
img_path = 'input/lena.jpg' # 图片路径
img = Image.open(img_path).convert('L') # 读取图片,并转换为灰度图片
img = np.array(img) # 将<class 'PIL.JpegImagePlugin.JpegImageFile'>类转化为np数组
plt.imshow(img, cmap='gray')
plt.show() # 显示图片
# 原img数组shape为(512,512),为满足conv2d()函数输入参数input的格式,
# 扩展维度为(1, 512, 512, 1),即(图片数,高,宽,通道数)
img = np.expand_dims(img, 0)
img = np.expand_dims(img, 3)
print(img.shape) # shape(1, 512, 512, 1)
kernel = np.array([
# [0, -4, 0], [-4, 16, -4], [0, -4, 0] # 整体边缘滤波器
[1, 2, 1], [0, 0, 0], [-1, -2, -1] # 水平边缘滤波器
# [1, 0, -1], [2, 0, -2], [1, 0, -1] # 垂直边缘滤波器
])
# 原卷积核的shape为(3,3),为满足conv2d()函数输入参数filter的格式,
# 扩展维度为(3, 3, 1, 1),即(卷积核高,卷积核宽,输入通道数,输出通道数)
kernel = np.expand_dims(kernel, 2)
kernel = np.expand_dims(kernel, 3)
print('kernel:', kernel.shape) # shape(3, 3, 1, 1)
# 将img转换为Tensor变量用作输入
input = tf.Variable(img, dtype=tf.float32)
# 将卷积核转换为Tensor变量用作输入
filter = tf.Variable(kernel, dtype=tf.float32)
strides = [1, 2, 2, 1] # 横向,纵向步长均设为2
output = tf.nn.conv2d(input, filter, strides=strides, padding='VALID')
print('output', output)
init_op = tf.global_variables_initializer() # 初始化变量
with tf.Session() as sess:
sess.run(init_op)
out = (sess.run(output))
print('out', out.shape) # shape(1, 255, 255, 1)
print(type(out)) # <class 'numpy.ndarray'>
pic_arr = np.squeeze(out) # shape(255, 255)
plt.imshow(pic_arr, cmap='gray')
plt.show()
以上代码以输入一张512*512的灰度图片为例,也可以读取不同的图片以观察对图片中边缘的提取效果。代码中的kernel数组定义了3个卷积核(或称为滤波器,每次运行时只使用一个即可,其它两行被注释了),分别为整体边缘滤波器,水平边缘滤波器和垂直边缘滤波器,以下以lena.jpg为例展示其效果。
输入图片为:
分别使用3种滤波器后输出图片如下: