CNN - 卷积

01 基本概念

卷积:简单来讲,就是把一个 n*m 的二维矩阵通过一个卷积核将其变为n1*m1的二维矩阵的过程称为卷积。
卷积核:可以看作对某个局部的加权求和;它是对应局部感知,它的原理是在观察某个物体时我们既不能观察每个像素也不能一次观察整体,而是先从局部开始认识,这就对应了卷积。卷积核的大小一般有1x1,3x3和5x5的尺寸(一般是奇数x奇数)。
多通道:即输入矩阵的维度。
特征图:卷积操作处理后的结果。

s是strides(滑动步长)
输入特征图宽高为 i (一般预处理成正方形)
卷积核大小为 k(一般高宽相同)
p是padding大小
卷积结果大小:( i - k + 2 * p ) / s + 1

特征选择:人工选取特征,然后计算机利用这些特征进行分类,在选择正确特征情况下,信噪比(signal-to-noise ration)将会提高,分类正确率也会提高。
Eg:多通道多卷积核的CNN(3通道2卷积核)
CNN - 卷积_第1张图片

02 卷积核

2.1 高斯模糊

通常用它来减少图像噪声以及降低细节层次。常用在图像预处理阶段,以增强图像在不同比例下的表达效果。所谓模糊就是每个像素都去周围像素的平均值。
关于卷积核的权值分配,高斯分布是一种很好的分配方式。它使得距离中心点越近的像素点的权值会越高。
f ( x , y ) = 1 σ 2 π e − ( x 2 + y 2 ) 2 σ 2 f(x, y) = {1 \over {\sigma}\sqrt {2\pi}}e^{{-(x^2+y^2)}\over{2\sigma^2}} f(x,y)=σ2π 1e2σ2(x2+y2)

2.2 Sobel

Sobel 算子常常用于边缘检测领域。
在中心点的梯度可以通过邻域内方向导数的幅值乘以对应的单位向量所对应的向量求和求的。
因此这就引出了重要步骤:如何计算梯度。
我们可以在笛卡尔网格下,通过中心差分方式计算出导数,注意此导数就是方向导数,因为是正交向量相加减,因此最后的方向导数一定会指向变化幅度最大的方向。单位向量可以通过欧式距离获得。

2.3 Emboss

算法的原理是通过计算相邻像素点的差值再加上一个灰度值常量而产生浮雕效果的算法。和左上像素点的差值为浮雕,和右下像素点的差值为雕刻。还可以通过控制cos来改变角度。

2.4 Ontline

用于边缘检测。
Ontline 算子(也称为“边缘”内核)用于突出显示像素值之间的巨大差异。在新图像中,邻近灰度接近相同的像素点的像素点将显示为黑色,而邻近灰度差异较大的像素点的像素点将显示为白色。

2.5 Shapen

图像锐化是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰。锐化处理在增强图像边缘的同时也增加了图像的噪声。方法通常有微分法和高通滤波法。

03 编程实现

3.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 = 'img/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')  # 定义轮廓检测算子
#sharpen_kernel = np.array([[0, -1, 0],
#                 [-1, 5, -1],
#                 [0, -1, 0]], dtype="float32")  
# blur_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()
效果:
原图
原图 CNN - 卷积_第2张图片
blur CNN - 卷积_第3张图片
锐化 CNN - 卷积_第4张图片
边缘检测 CNN - 卷积_第5张图片

3.2 调整经典卷积核参数

blur:
将3*3的卷积核修改为5*5时,图像会变得更加模糊。


增大像素点的权重时,图像会变得更亮。

3.3 使用不同尺寸图片

大图像 小图像
CNN - 卷积_第6张图片 CNN - 卷积_第7张图片
CNN - 卷积_第8张图片 CNN - 卷积_第9张图片
CNN - 卷积_第10张图片 CNN - 卷积_第11张图片
CNN - 卷积_第12张图片 CNN - 卷积_第13张图片

可以看出大图像比较平均,小图像亮的地方会更亮,暗的地方会更暗。

3.4 探索更多类型卷积核

3.4.1 Emboss

CNN - 卷积_第14张图片

3.5 彩色图片边缘检测

一般对彩色图片边缘检测会先把彩色图片转换成灰度图或者二值图像。当使用CNN进行边缘检测时优先考虑将其转成灰度图然后进行边缘检测。
原图像:
CNN - 卷积_第15张图片
边缘检测:

CNN - 卷积_第16张图片

04 总结

使用pytorch实现的图像边缘检测和https://setosa.io/ev/image-kernels/上的边缘检测有所差异。网站上的效果会更好,因此有部分图会使用网站上的图。

你可能感兴趣的:(cnn,计算机视觉,算法)