实验目录
前言
一、作业1
1、编程实现
2、需准备的知识点
下边来看一下,生成图像的代码。
同样,上边的对比可以看出,图二的表示为:
图三要把每个方格看成一个像素点,然后来进行输出,才能变成的这样的:
卷积运算的实现(互相关运算)
1. 图1使用卷积核编辑,输出特征图
2. 图1使用卷积核编辑,输出特征图
3. 图2使用卷积核编辑,输出特征图
4. 图2使用卷积核编辑,输出特征图
5. 图3使用卷积核编辑,编辑,编辑 ,输出特征图
这里说下一各个卷积核的作用(查了好久也有官方的解释,只能从实验中得结论了):
二、作业2
1、概念
卷积:
卷积核:
特征图:
特征选择:
步长:
填充:
感受野:
2.探究不同卷积核的作用
1、边缘检测:标识数字图像中亮度变化明显的点,这些点往往是轮廓或边缘。
2、锐化:快速聚焦模糊边缘,提高图像中某一部位的清晰度或者焦距程度,使图像特定区域的色彩更加鲜明。
3、模糊:处理图中与周围亮度差异过大的点,使其和周围点相似,以此消除或模糊轮廓。
3、编程实现
1、实现灰度图的边缘检测、锐化、模糊。(必做)
边缘检测(原理在上边):
锐化(原理在上边):
模糊(原理在上边):
2、 调整卷积核参数,测试并总结。(必做)
1、边缘检测增加中心权重边缘更加清晰(改为[[-1,-1, -1],[-1, 12, -1],[-1, -1,-1]])
2、锐化提升周围权重,锐化度增加(改为[0,5, 0],[5, 5, 5],[0, 5,0])
3、模糊卷积核增大周围权重,模糊度增加(改为[3, 5, 3], [5, 0.25, 5], [3, 5,3])
3、使用不同尺寸图片,测试并总结。(必做)
4、探索更多类型卷积核。(选做)
1、浮雕效果编辑
2、底部索贝尔
解决图像灰色的问题
总结
前言
这次我还是写的很细,有好多东西查了好多资料,有的我给出链接,真的学到很多,而且这次是和舍友研究了研究问题,一口气写的真的感觉很连贯,很通畅。
在此鸣谢我的舍友(真不想再学了),写的不太好,请老师和各位大佬多交交我。
一、作业1
1、编程实现
2、需准备的知识点
由黑白灰生成的是一个专门叫灰度图像的东西。也就是如果只用普通的matplotlib是不行。
下边来看一下,生成图像的代码。
# coding=gbk
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch
from torch import nn
解码的方式的问题,最好和我一样的调用,然后其实只要是生成的矩阵,不管是tensor类型还是array类型,都可以转化为图像,然后看一下,下边的代码。
pic = torch.zeros((7,6))
x=pic
pic[:,3:6]=255
print(pic)
plt.imshow(pic,cmap='Greys_r')
plt.show()
运行结果为:
tensor([[ 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.]])
上边要注意0是黑色,255是白色,并且一定要注意输出的时候用imshow函数,并且要用cmap='Greys_r', 表明是灰度图。
同样,上边的对比可以看出,图二的表示为:
x = torch.zeros((14,12))
x[7:14,0:6]=255
x[0:7,6:12]=255
plt.imshow(x,cmap='Greys_r')
plt.show()
运行结果为:
图三要把每个方格看成一个像素点,然后来进行输出,才能变成的这样的:
x3 = torch.zeros((9,9))
for i in range(0,7):
x3[i+1,i+1]=255
x3[i+1,7-i]=255
plt.imshow(x3,cmap='Greys_r')
plt.show()
运行结果为:
卷积运算的实现(互相关运算)
但是,咱们没有想过,实现的原理是什么,下边是李沐大神的代码(我看了感觉十分有用,拜一拜)。
def corr2d(X, K): #@save
"""计算二维互相关运算"""
h, w = K.shape
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i + h, j:j + w] * K).sum()
return Y
虽然简单,但是我感觉核心思想就是这样的,nn里边只是多了一些复杂的定义啥的。
1. 图1使用卷积核
,输出特征图
# coding=gbk
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch
from torch import nn
def corr2d(X, K): #@save
"""计算二维互相关运算"""
h, w = K.shape
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i + h, j:j + w] * K).sum()
return Y
pic = torch.zeros((7,6))
x=pic
pic[:,3:6]=255
print(pic)
plt.imshow(pic,cmap='Greys_r')
plt.show()
K = torch.tensor([[1, -1]])
jieguo=corr2d(pic, K)
print(jieguo)
plt.imshow(jieguo,cmap='Greys_r')
plt.show()
运算结果为:
2. 图1使用卷积核
,输出特征图
# coding=gbk
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch
from torch import nn
def corr2d(X, K): #@save
"""计算二维互相关运算"""
h, w = K.shape
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i + h, j:j + w] * K).sum()
return Y
pic = torch.zeros((7,6))
x=pic
pic[:,3:6]=255
print(pic)
plt.imshow(pic,cmap='Greys_r')
plt.show()
K = torch.tensor([[1, -1]])
jieguo=corr2d(pic, K.T)
print(jieguo)
plt.imshow(jieguo,cmap='Greys_r')
plt.show()
运行结果为:
3. 图2使用卷积核
,输出特征图
# coding=gbk
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch
from torch import nn
def corr2d(X, K): #@save
"""计算二维互相关运算"""
h, w = K.shape
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i + h, j:j + w] * K).sum()
return Y
x = torch.zeros((14,12))
x[7:14,0:6]=255
x[0:7,6:12]=255
plt.imshow(x,cmap='Greys_r')
plt.show()
K = torch.tensor([[1, -1]])
jieguo=corr2d(x, K)
print(jieguo)
plt.imshow(jieguo,cmap='Greys_r')
plt.show()
运行结果为:
4. 图2使用卷积核
,输出特征图
# coding=gbk
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch
from torch import nn
def corr2d(X, K): #@save
"""计算二维互相关运算"""
h, w = K.shape
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i + h, j:j + w] * K).sum()
return Y
x = torch.zeros((14,12))
x[7:14,0:6]=255
x[0:7,6:12]=255
plt.imshow(x,cmap='Greys_r')
plt.show()
K = torch.tensor([[1, -1]])
jieguo=corr2d(x, K.T)
print(jieguo)
plt.imshow(jieguo,cmap='Greys_r')
plt.show()
运行结果为:
5. 图3使用卷积核
,
,
,输出特征图
# coding=gbk
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch
from torch import nn
def corr2d(X, K): #@save
"""计算二维互相关运算"""
h, w = K.shape
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i + h, j:j + w] * K).sum()
return Y
x3 = torch.zeros((9,9))
for i in range(0,7):
x3[i+1,i+1]=255
x3[i+1,7-i]=255
plt.imshow(x3,cmap='Greys_r')
plt.show()
K = torch.tensor([[1, -1]])
jieguo=corr2d(x3, K.T)
print(jieguo)
plt.imshow(jieguo,cmap='Greys_r')
plt.show()
K1 = torch.tensor([[1, -1]])
jieguo=corr2d(x3, K1)
print(jieguo)
plt.imshow(jieguo,cmap='Greys_r')
plt.show()
运行结果为:
这里说下一各个卷积核的作用(查了好久也有官方的解释,只能从实验中得结论了):
:从上各个图像的结果中可以看出,它是寻找左右的分界,要是左黑右白,会把边界变为黑,要是左白右黑会把边界变为白
:从上各个图像的结果中可以看出,它是寻找上下的分界,要是上黑下白,会把边界变为黑,要是上白下黑会把边界变为白。
:这个相当于上边两个的综合,也相当于是找分界,但是这个是所有的分界。
二、作业2
1、概念
用自己的语言描述“卷积、卷积核、特征图、特征选择、步长、填充、感受野”。
我会每个说说我的理解和比较官方的理解
卷积:
先说一下,我的理解,我感觉这个其实就是一种高级的w*x+b的预算,为啥说高级,因为它训练起来比全连接层好,只是运算法则上的不同,核心思想上还是一样的。
卷积,是我们学习高等数学之后,新接触的一种运算,因为涉及到积分、级数,所以看起来觉得很复杂。
卷积的运算
二维卷积的实例
卷积核:
感觉这个就像是高级一点的w*x+b中的w,因为卷积相较于w*x+b高级一点,所以w也就高级一点,并且实际的操作中也是将卷积核直接赋值给w。
卷积核就是图像处理时,给定输入图像,输入图像中一个小区域中像素加权平均后成为输出图像中的每个对应像素,其中权值由一个函数定义,这个函数称为卷积核。又称滤波器。
同样提取某个特征,经过不同卷积核卷积后效果也不一样
(1)原始图像通过与卷积核的数学运算,可以提取出图像的某些指定特征(features)。
(2)不同卷积核,提取的特征也是不一样的。
(3)提取的特征一样,不同的卷积核,效果也不一样。
下边圈出来就是卷积核的例子
特征图:
感觉这个就是,把卷积层中学出来的特征做了一下可视化,并且规律,这个前边的卷积层,卷积出来的可能就是一些点和线,越后边的卷积层,学习的特征越多,越接近真实的图像
通过可视化特征图可以让我们较为直观地认识到神经网络到底学到了什么东西(配以卷积核参数更佳),尽管这种认识基本都是经验性的,但也常常可以给人以灵感,促使人们改进算法。
从下边的图中就可以看出,越深层的学到的特征越多。
特征选择:
这个我感觉最直观就是下边这张图,最直观的就是图像的眼睛与卷积核(眼睛)相同,就会导致相同,这样就会导致只有相同的地方是100,不同的地方是零或者说数值比较小1。
步长:
我感觉,步长就是滑动的长度,也就是向右移,移多少,向下移,移多少,一般的规律是从左到右,从上到下。
下边这个步长为2的,最直观的体现了出来。
填充:
感觉这个就是为了,怕卷积学不到图像边缘的特征,所以在图像周边补领,padding参数是即就是补几个零。
感受野:
感觉这个就是,把特征图上的点,相当于通过一种溯源的东西,把它溯源回原图像,看和原图像对应的是哪。
就是下边这种感觉,相当于回溯回去。
2.探究不同卷积核的作用
1、边缘检测:标识数字图像中亮度变化明显的点,这些点往往是轮廓或边缘。
2、锐化:快速聚焦模糊边缘,提高图像中某一部位的清晰度或者焦距程度,使图像特定区域的色彩更加鲜明。
3、模糊:处理图中与周围亮度差异过大的点,使其和周围点相似,以此消除或模糊轮廓。
3、编程实现
1、实现灰度图的边缘检测、锐化、模糊。(必做)
边缘检测(原理在上边):
# coding=gbk
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'内容
#
file_path = '小猫.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,padding=1) # 定义卷积
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)) # 作用在图片上
for i in range(edge1.shape[2]):
for j in range(edge1.shape[3]):
if edge1[0][0][i][j]>255:
edge1[0][0][i][j]=255
if edge1[0][0][i][j]<0:
edge1[0][0][i][j]=0
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
运行结果为:
锐化(原理在上边):
# coding=gbk
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'内容
#
file_path = '小猫.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,padding=1) # 定义卷积
sobel_kernel = np.array([[0, -1, 0],
[-1, 5, -1],
[0, -1,0]], dtype='float32') # 定义轮廓检测算子
sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3)) # 适配卷积的输入输出
conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值
edge1 = conv1(Variable(im)) # 作用在图片上
for i in range(edge1.shape[2]):
for j in range(edge1.shape[3]):
if edge1[0][0][i][j]>255:
edge1[0][0][i][j]=255
if edge1[0][0][i][j]<0:
edge1[0][0][i][j]=0
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
运行结果:
模糊(原理在上边):
# coding=gbk
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'内容
#
file_path = '小猫.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,padding=1) # 定义卷积
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)) # 作用在图片上
for i in range(edge1.shape[2]):
for j in range(edge1.shape[3]):
if edge1[0][0][i][j]>255:
edge1[0][0][i][j]=255
if edge1[0][0][i][j]<0:
edge1[0][0][i][j]=0
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
运行结果:
2、 调整卷积核参数,测试并总结。(必做)
1、边缘检测增加中心权重边缘更加清晰(改为[[-1,-1, -1],[-1, 12, -1],[-1, -1,-1]])
# coding=gbk
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'内容
#
file_path = '小猫.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,padding=1) # 定义卷积
sobel_kernel = np.array([[-1,-1, -1],
[-1, 12, -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)) # 作用在图片上
for i in range(edge1.shape[2]):
for j in range(edge1.shape[3]):
if edge1[0][0][i][j]>255:
edge1[0][0][i][j]=255
if edge1[0][0][i][j]<0:
edge1[0][0][i][j]=0
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
运行结果为:
2、锐化提升周围权重,锐化度增加(改为[0,5, 0],[5, 5, 5],[0, 5,0])
# coding=gbk
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'内容
#
file_path = '小猫.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,padding=1) # 定义卷积
sobel_kernel = np.array([[0,5, 0],
[5, 5, 5],
[0, 5,0]], dtype='float32') # 定义轮廓检测算子
sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3)) # 适配卷积的输入输出
conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值
edge1 = conv1(Variable(im)) # 作用在图片上
for i in range(edge1.shape[2]):
for j in range(edge1.shape[3]):
if edge1[0][0][i][j]>255:
edge1[0][0][i][j]=255
if edge1[0][0][i][j]<0:
edge1[0][0][i][j]=0
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
运行结果为:
3、模糊卷积核增大周围权重,模糊度增加(改为[3, 5, 3], [5, 0.25, 5], [3, 5,3])
# coding=gbk
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'内容
#
file_path = '小猫.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,padding=1) # 定义卷积
sobel_kernel = np.array([[3, 5, 3],
[5, 0.25, 5],
[3, 5,3]], 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()
for i in range(edge1.shape[2]):
for j in range(edge1.shape[3]):
if edge1[0][0][i][j]>255:
edge1[0][0][i][j]=255
if edge1[0][0][i][j]<0:
edge1[0][0][i][j]=0
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
运行结果为:
3、使用不同尺寸图片,测试并总结。(必做)
# coding=gbk
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'内容
#
file_path = 'csdn.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,padding=1) # 定义卷积
sobel_kernel = np.array([[3, 5, 3],
[5, 0.25, 5],
[3, 5,3]], 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()
for i in range(edge1.shape[2]):
for j in range(edge1.shape[3]):
if edge1[0][0][i][j]>255:
edge1[0][0][i][j]=255
if edge1[0][0][i][j]<0:
edge1[0][0][i][j]=0
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
运行结果为:
卷积核对于尺寸越小的图像越明显,首先因为这是人眼的视觉差异,但是其实卷积操作完都是一样的,也就是尺寸越小越明显,上边的图片要是小猫需要卷积好几次才能达到这种效果。
下边是我搜集到的影响(大家可以看一看,就是一种吸取经验的东西)
直观看,图片越大,其纹理和上下文就越多,越能捕捉到更好的特征。另外,当图片变大的时候,有些判别性特征更好获得。但是,当尺寸变大到一定程度,分类性能可能反而会不变,甚至变坏,毕竟现在的卷积核大多是3*3的。另外,当尺寸变大时,计算的开销也会相应的变大很多,这里面也是有个trade off 的。
4、探索更多类型卷积核。(选做)
1、浮雕效果
# coding=gbk
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'内容
#
file_path = 'csdn.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,padding=1) # 定义卷积
sobel_kernel = np.array([[-2, 1, 0],
[-1, 1, 1],
[0, 1,2]], 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()
for i in range(edge1.shape[2]):
for j in range(edge1.shape[3]):
if edge1[0][0][i][j]>255:
edge1[0][0][i][j]=255
if edge1[0][0][i][j]<0:
edge1[0][0][i][j]=0
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
运行结果为:
2、底部索贝尔
# coding=gbk
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'内容
#
file_path = 'csdn.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,padding=1) # 定义卷积
sobel_kernel = np.array([[-1, -2, -1],
[0, 0, 0],
[1, 2,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()
for i in range(edge1.shape[2]):
for j in range(edge1.shape[3]):
if edge1[0][0][i][j]>255:
edge1[0][0][i][j]=255
if edge1[0][0][i][j]<0:
edge1[0][0][i][j]=0
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
运行结果为:
5、尝试彩色图片边缘检测。(选做)
这个真的研究了好久(呜呜)。
# coding=gbk
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
from torchvision import transforms
import cv2
# 读⼊照⽚
im = Image.open('日出.jpg')
# 将照⽚变成 np
plt.imshow(im, cmap='gray')
plt.show()
im = np.array(im, dtype='float32')
print(im.shape)
print(im[:][1][:].shape)
plt.imshow(im[:][:][1].astype('uint8'), cmap='gray')
plt.show()
# 将图⽚矩阵转化为pytorch tensor ,并适配卷积输⼊要求
im = np.transpose(im, (2, 1, 0))
im = im[np.newaxis, :]
print(im.shape)
conv1 = nn.Conv2d(3, 3, 3, bias= False) # 定义卷积
# sobel_kernel = np.array([[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]], dtype='float32') # 定义轮廓检测
sobel_kernel = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], dtype='float32') / 3
# 将sobel算⼦转换为适配卷积操作的卷积核
sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3))
# 卷积输出通道,这⾥我设置为3
# np.repeats(a,repeats, axis=None)
# 其中a为数组,repeats为重复的次数,axis表⽰数组维度
sobel_kernel = np.repeat(sobel_kernel, 3, axis=1)
# 输⼊图的通道,这⾥我设置为3
print(sobel_kernel.shape)
sobel_kernel = np.repeat(sobel_kernel, 3, axis=0)
print(sobel_kernel.shape)
conv1.weight.data = torch.from_numpy(sobel_kernel)# 给卷积的 kernel 赋值
edge1 = conv1(Variable(torch.from_numpy(im)))# 作⽤在图⽚上
print(edge1.shape)
edge1 = edge1.data.squeeze().detach().numpy()# # 将输出转换为图⽚的格式
#edge1= edge1.reshape(3, 298, 299)
print('------')
print(edge1.shape)
edge1 = np.transpose(edge1,(2,1,0))
print(edge1.shape)
cv2.imshow('edge.jpg', edge1)
cv2.waitKey(0)
运行结果为:
由于RGB图像会把三个通道分别运算完之后,堆叠在一起,就会导致这种情况,但是还是能大致看出来。
解决图像灰色的问题
首先在此鸣谢我的室友(真不想再,学了),对本实验的大力支持(在我做了大量测试的基础上,我舍友终于发现了为啥,感谢大佬,拜一拜)。
大家可能在输出的发现,原图像会出现一种灰色的现象,也就是下边的现象。
大家会发现图像,蒙上了一层灰色,这样的原因是在卷积完之后,出现了大于255,小于0的情况,对此最好的解决,其实是归一化的东西,也就是,找一种类似于映射的东西,把它全都投影到0到255,这样临近点之间的关系并不会丢失,这样一定会有完整的图像。
由于图像是由像素点之间的关系体现出来的,所以最好打的解决办法是映射,其次是换一个卷积核,再其次是就是我下边说的比较偷懒的方法。
也就是下边的代码
# coding=gbk
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'内容
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,padding=1) # 定义卷积
sobel_kernel = np.array([[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]], dtype='float32') # 定义轮廓检测算子
sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3)) # 适配卷积的输入输出
conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值
edge1 = conv1(Variable(im)) # 作用在图片上
for i in range(edge1.shape[2]):
for j in range(edge1.shape[3]):
if edge1[0][0][i][j]>255:
edge1[0][0][i][j]=255
if edge1[0][0][i][j]<0:
edge1[0][0][i][j]=0
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
区别是下边的代码
for i in range(edge1.shape[2]):
for j in range(edge1.shape[3]):
if edge1[0][0][i][j]>255:
edge1[0][0][i][j]=255
if edge1[0][0][i][j]<0:
edge1[0][0][i][j]=0
因为只是一层卷积,所以这样强制限制一下,并不会有多大的区别,但是多层的话,最好还是找一下映射,虽然只和最后一层有关,但是保险一点。
运行结果: