作业1
编程实现
卷积神经网络工作原理的直观理解_superdont的博客-CSDN博客
1. 图1使用卷积核,输出特征图
import numpy as np
import torch
from torch import nn
from torch.autograd import Variable
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 #有中文出现的情况,需要u'内容
# https://blog.csdn.net/weixin_40123108/article/details/83510592
#图1
im = np.array([[0,0,0,255,255,255],
[0,0,0,255,255,255],
[0,0,0,255,255,255],
[0,0,0,255,255,255],
[0,0,0,255,255,255],
[0,0,0,255,255,255],
[0,0,0,255,255,255]], dtype='float32') # 将其转换为一个矩阵
print(im.shape[0], im.shape[1])
plt.imshow(im.astype('uint8'), cmap='gray') # 可视化图片
plt.title('原图')
plt.show()
im = torch.from_numpy(im.reshape((1, 1, im.shape[0], im.shape[1])))
conv1 = nn.Conv2d(1, 1, (1,2), bias=False) # 定义卷积
sobel_kernel = np.array([[1,-1]], dtype='float32') # 定义轮廓检测算子
sobel_kernel = sobel_kernel.reshape((1, 1, 1, 2)) # 适配卷积的输入输出
conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值
edge1 = conv1(Variable(im)) # 作用在图片上
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
卷积后:
2. 图1使用卷积核,输出特征图
conv1 = nn.Conv2d(1, 1, (1, 2), bias=False) # 定义卷积
sobel_kernel = np.array([[1, -1],
[-1, 1]], dtype='float32') # 定义轮廓检测算子
sobel_kernel = sobel_kernel.reshape((1, 1, 2, 2)) # 适配卷积的输入输出
3. 图2使用卷积核,输出特征图
import numpy as np
import torch
from torch import nn
from torch.autograd import Variable
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 #有中文出现的情况,需要u'内容
# https://blog.csdn.net/weixin_40123108/article/details/83510592
#图2
im = np.array([[0, 0, 0, 255, 255, 255],
[0, 0, 0, 255, 255, 255],
[0, 0, 0, 255, 255, 255],
[255, 255, 255, 0, 0, 0],
[255, 255, 255, 0, 0, 0],
[255, 255, 255, 0, 0, 0]], dtype='float32') # 将其转换为一个矩阵
print(im.shape[0], im.shape[1])
plt.imshow(im.astype('uint8'), cmap='gray') # 可视化图片
plt.title('原图')
plt.show()
im = torch.from_numpy(im.reshape((1, 1, im.shape[0], im.shape[1])))
conv1 = nn.Conv2d(1, 1, (1,2), bias=False) # 定义卷积
sobel_kernel = np.array([[1,-1]], dtype='float32') # 定义轮廓检测算子
sobel_kernel = sobel_kernel.reshape((1, 1, 1, 2)) # 适配卷积的输入输出
conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值
edge1 = conv1(Variable(im)) # 作用在图片上
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
卷积后:
4. 图2使用卷积核,输出特征图
5. 图3使用卷积核,, ,输出特征图
import numpy as np
import torch
from torch import nn
from torch.autograd import Variable
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 #有中文出现的情况,需要u'内容
# https://blog.csdn.net/weixin_40123108/article/details/83510592
#图3
im = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 255, 0, 0, 0, 0, 0, 255, 0],
[0, 0, 255, 0, 0, 0, 255, 0, 0],
[0, 0, 0, 255, 0, 255, 0, 0, 0],
[0, 0, 0, 0, 255, 0, 0, 0, 0],
[0, 0, 0, 255, 0, 255, 0, 0, 0],
[0, 0, 255, 0, 0, 0, 255, 0, 0],
[0, 255, 0, 0, 0, 0, 0, 255, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],], dtype='float32') # 将其转换为一个矩阵
print(im.shape[0], im.shape[1])
plt.imshow(im.astype('uint8'), cmap='gray') # 可视化图片
plt.title('原图')
plt.show()
im = torch.from_numpy(im.reshape((1, 1, im.shape[0], im.shape[1])))
conv1 = nn.Conv2d(1, 1, (1,2), bias=False) # 定义卷积
sobel_kernel = np.array([[1,-1]], dtype='float32') # 定义轮廓检测算子
sobel_kernel = sobel_kernel.reshape((1, 1, 1, 2)) # 适配卷积的输入输出
conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值
edge1 = conv1(Variable(im)) # 作用在图片上
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
作业2
一、概念
卷积:
将图像矩阵中,从左到右,由上到下,取与滤波器同等大小的一部分,每一部分中的值与滤波器中的值对应相乘后求和,最后的结果组成一个矩阵,其中没有对核进行翻转。
卷积核:
卷积核就是图像处理时,给定输入图像,输入图像中一个小区域中像素加权平均后成为输出图像中的每个对应像素,其中权值由一个函数定义,这个函数称为卷积核。卷积神经网络中"卷积”,是为了提取图像的特征。
特征图:
每层卷积结束后得到的卷积值的组合就是特征图。
特征选择:
就是用来对原图像选择不同的卷积核进行特征提取的过程。
步长:
在进行卷积时,卷积核(滤波器)每次移动的像素单位。
填充:
在进行卷积操作前,对原矩阵进行边界填充,也就是在矩阵的边界上填充一些值,以增加矩阵的大小,通常都用“0”来进行填充的。
通过填充的方法,当卷积核扫描输入数据时,它能延伸到边缘以外的伪像素,从而使输出和输入size相同。
感受野:
卷积神经网络每一层输出的特征图(feature map)上的像素点在原始图像上映射的区域大小。指的是神经网络中神经元“看到的”输入区域。
二、探究不同卷积核的作用
参考Image Kernels explained visually
锐化:
锐化实际上就是计算当前点和周围点的差别,然后将这个差别加到原来的位置上
如果核的中心值是负数,就是在强调边缘,在锐化边缘
边缘检测:
浮雕:
浮雕滤波器可以给图像一种3D阴影的效果。
只要将中心一边的像素减去另一边的像素就可以了。这时候,像素值有可能是负数,我们将负数当成阴影,将正数当成光,然后我们对结果图像加上128的偏移。这时候,图像大部分就变成灰色了。
45度的浮雕滤波器
三、编程实现
1、实现灰度图的边缘检测、锐化、模糊。(必做)
import numpy as np
import torch
from torch import nn
from torch.autograd import Variable
from PIL import Image
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 #有中文出现的情况,需要u'内容
# https://blog.csdn.net/weixin_40123108/article/details/83510592
file_path = 'klm.jpg'
im = Image.open(file_path).convert('L') # 读入一张灰度图的图片
im = np.array(im, dtype='float32') # 将其转换为一个矩阵
print(im.shape[0], im.shape[1])
plt.imshow(im.astype('uint8'), cmap='gray') # 可视化图片
plt.title('原图')
plt.show()
im = torch.from_numpy(im.reshape((1, 1, im.shape[0], im.shape[1])))
conv1 = nn.Conv2d(1, 1, 3, bias=False) # 定义卷积
sobel_kernel = np.array([[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]], dtype='float32') # 定义轮廓检测算子
'''
# 锐化
sobel_kernel = np.array([[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]], dtype='float32') # 定义轮廓检测算子
# 模糊
sobel_kernel = np.array([[0.0625, 0.125, 0.0625],
[0.125, 0.25, 0.125],
[0.0625, 0.125, 0.0625]], dtype='float32') # 定义轮廓检测算子
'''
sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3)) # 适配卷积的输入输出
conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值
edge1 = conv1(Variable(im)) # 作用在图片上
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
锐化:
模糊:
2、调整卷积核参数,测试并总结。(必做)
以锐化为例
当步长为1时:
当步长为5时:
当步长为10时:
当步长为20时:
步长越长,图像越模糊,图像的特征越不明显,可能有损失。
3、使用不同尺寸图片,测试并总结。(必做)
边缘检测:
锐化:
模糊:
对不同的图片,卷积的效果也有差异,该题中图片的边缘检测效果很清晰,不如前面的图片效果。模糊卷积后的效果也不是很好,模糊的效果不明显。
4、探索更多类型卷积核。(选做)
# 浮雕卷积核
sobel_kernel = np.array([[-2, -1, 0],
[-1, 1, -1],
[0, 1, 2]], dtype='float32') # 定义轮廓检测算子
# bottom sobel卷积核
sobel_kernel = np.array([[-1, -2, -1],
[0, 0, 0],
[1, 2, 1]], dtype='float32') # 定义轮廓检测算子
5、尝试彩色图片边缘检测。(选做)
import numpy as np
import torch
from torch import nn
from torch.autograd import Variable
import torch.nn.functional as F
from PIL import Image
import matplotlib.pyplot as plt
im = Image.open('皮卡丘1.jpg').convert('L') # 读入一张灰度图的图片
im = np.array(im, dtype='float32') # 将其转换为一个矩阵
plt.imshow(im.astype('uint8'), cmap='gray')
im = torch.from_numpy(im.reshape((1, 1, im.shape[0], im.shape[1])))
conv1 = nn.Conv2d(1, 1, (3,3), bias=False) # 定义卷积
sobel_kernel = np.array([[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]], dtype='float32') # 定义轮廓检测算子
sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3)) # 适配卷积的输入输出
conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值
edge1 = conv1(Variable(im)) # 作用在图片上
edge1 = edge1.data.squeeze().numpy() # 将输出转换为图片的格式
plt.imshow(edge1, cmap='gray')
plt.show()
总结
实验过程中通过调整卷积核参数进行实验研究,不同的图片不同的操作变化效果不同。
卷积神经网络CNN实际上是通过带有label的训练数据来train由一个个特征判断系统中的运算法则,对于图像特征提取而言,系统的运算法则可能比较复杂,通过卷积的方式将复杂判断系统的运算法则变为一个个易于计算的卷积核,从而更方便地提取图像特征,完成对图像的分析与处理。
参考代码
import numpy as np
import torch
from torch import nn
from torch.autograd import Variable
from PIL import Image
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 #有中文出现的情况,需要u'内容
# https://blog.csdn.net/weixin_40123108/article/details/83510592
file_path = 'deer.jpg'
im = Image.open(file_path).convert('L') # 读入一张灰度图的图片
im = np.array(im, dtype='float32') # 将其转换为一个矩阵
print(im.shape[0], im.shape[1])
plt.imshow(im.astype('uint8'), cmap='gray') # 可视化图片
plt.title('原图')
plt.show()
im = torch.from_numpy(im.reshape((1, 1, im.shape[0], im.shape[1])))
conv1 = nn.Conv2d(1, 1, 3, bias=False) # 定义卷积
sobel_kernel = np.array([[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]], dtype='float32') # 定义轮廓检测算子
sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3)) # 适配卷积的输入输出
conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值
edge1 = conv1(Variable(im)) # 作用在图片上
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()