CNN里面有很关键的步骤就是卷积和池化,所以这里代码实现了一下。这里滑动窗口大小我设置的是3,池化那里我设置的是2,大家可以改成自己想要的大小,之前那个代码只能是特定的步长,现在修改的可以是任意。要注意卷积之后的大小公式要准确表达。然后在做卷积的时候,加入了padding的部分。这里的图片用的是灰色,原因是色彩太多太亮可能不那么容易察觉,这里修改了一下池化的部分,加入了平均池化和最大池化的对比,池化尺寸的大小和步长可以按照自己的想法更改,这里我用的是三阶尺寸和3的滑动步长。这里最后的结果是个二维图像。如果有需要三维图像的uu可以联系我一下,私发三维图像的结果
代码实现
import matplotlib.pyplot as plt
import cv2
import numpy as np
# 导入图像
img = cv2.imread(r"C:/Users/wxc/Desktop/xuexi/matlab/PCA/Lena.jpg")
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
a = np.array([[1, 2, 1], [2, 4, 2], [1, 2, 1]]) / 16 # 卷积核我用的高斯模糊,理论上最后池化过后会比没有经过池化层要模糊一些
c1 = 2 # 这个卷积核滑动步长可以调整自己想要的
# 卷积操作函数
def desprate(matrix, kernel, b):
m, n = matrix.shape
km, kn = kernel.shape
pm = int((km-1)/2)# 进行padding
pdding_m1 = np.zeros((m, pm))
pdding_m2 = np.zeros((m, pm))
pdding_n1 = np.zeros((pm,n+2))
pdding_n2 = np.zeros((pm,n+2))
matrix1 = np.concatenate((pdding_m1, matrix, pdding_m2), axis=1)
matrix2 = np.vstack((pdding_n1, matrix1, pdding_n2))# 将所有的0矩阵和原矩阵拼接在一起
result = np.zeros(((m-km+2*pm)//b+1, (n-kn+2*pm)//b+1), dtype=int) # 建立结果矩阵,这个就是根据卷积后大小的计算公式得到的
for i in range(result.shape[0]):
for j in range(result.shape[1]):
window = matrix2[i*b:i*b+km, j*b:j*b+kn] # 提取窗口
result[i, j] = np.sum(window * kernel) # 卷积操作
return result
# 进行卷积操作
s1 = desprate(gray_img, a, c1)
c2=3
# 最大池化函数
def max_pooling(x,y,b): # x表示输入的矩阵,y表示的是池化的尺寸大小,b表示池化核滑动的大小
max_pool_result = np.zeros(((x.shape[0]-y)//b+1, (x.shape[1]-y)//b+1)) # 初始化池化后的结果矩阵
for i in range(0, max_pool_result.shape[0]):
for j in range(0, max_pool_result.shape[1]):
window = x[i*b:i*b+y, j*b:j*b+y] # 把滑动窗口给表示出来
max_pool_result[i,j] = np.max(window)# 池化操作
return max_pool_result
# 进行最大池化操作
p1 = max_pooling(s1,c2,3)
# 平均池化
def aver_pooling(x,y,b): # x表示输入的矩阵,y表示的是池化的尺寸大小,b表示池化核滑动的大小
aver_pool_result = np.zeros(((x.shape[0]-y)//b+1, (x.shape[1]-y)//b+1)) # 初始化池化后的结果矩阵
for i in range(0, aver_pool_result.shape[0]):
for j in range(0, aver_pool_result.shape[1]):
window = x[i*b:i*b+y, j*b:j*b+y] # 把滑动窗口给表示出来
aver_pool_result[i,j] = np.mean(window)# 平均池化操作
return aver_pool_result
p2 = aver_pooling(s1,c2,3)
# 显示图像
fig, axes = plt.subplots(2, 2, figsize=(25, 10))
# 显示原始图像
axes[0, 0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axes[0, 0].set_title('Original Image')
# 显示卷积后的图像
axes[0, 1].imshow(s1, cmap='gray')
axes[0, 1].set_title('Convolved Image')
# 显示卷积和池化后的图像
axes[1, 0].imshow(p1, cmap='gray')
axes[1, 0].set_title('Convolved + max_Pooling Image')
axes[1, 1].imshow(p2, cmap='gray')
axes[1, 1].set_title('Convolved + aver_Pooling Image')
plt.show()
展示结果
这个是得到的结果,
第二张图片体现的就是卷积的作用,他把典型的特征放大,比如头发比以前变得黑了。这里第三张和第四张图片,他们看上去有些不同,这里是因为最大池化的作用是保留显著特征,忽略掉一些次要特征。平均池化是一些细微特征的丢失,但对于保持整体结构和较大特征的识别能力有一定帮助。所以你回看到比起第三张最大池化,第四张平均池化会更整体清晰一些。大家可以把图片第三张和第四张放大看看,同样是眼睛那里还是有区别的。