NNDL 作业5:卷积与几种常见的卷积核

作业1

编程实现

NNDL 作业5:卷积与几种常见的卷积核
  1. 图1使用卷积核( 1 − 1 ) \begin{pmatrix} 1 & -1 \end{pmatrix}(1 ​−1 ​),输出特征图
  2. 图1使用卷积核( 1 − 1 ) \begin{pmatrix} 1\ -1\ \end{pmatrix}(1 −1 ​),输出特征图
  3. 图2使用卷积核( 1 − 1 ) \begin{pmatrix} 1 & -1 \end{pmatrix}(1 ​−1 ​),输出特征图
  4. 图2使用卷积核( 1 − 1 ) \begin{pmatrix} 1\ -1\ \end{pmatrix}(1 −1 ​),输出特征图
  5. 图3使用卷积核( 1 − 1 ) \begin{pmatrix} 1 & -1 \end{pmatrix}(1 ​−1 ​),( 1 − 1 ) \begin{pmatrix} 1\ -1\ \end{pmatrix}(1 −1 ​),( 1 − 1 − 1 1 ) \begin{pmatrix} 1 &-1 \ -1&1 \end{pmatrix}(1 −1 ​−1 1 ​)输出特征图

绘制三个图片的源代码:


import numpy as np
from matplotlib import pyplot as plt

img1=np.array([[0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255]
                               ])
img2=np.array([[255,255,255,255,255,0,0,0,0,0],
                [255,255,255,255,255,0,0,0,0,0],
                [255,255,255,255,255,0,0,0,0,0],
                [255,255,255,255,255,0,0,0,0,0],
                [255,255,255,255,255,0,0,0,0,0],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255]
                               ])
img3=np.array([[0,0,0,0,0,0,0,0,0],
                [0,225,0,0,0,0,0,225,0],
                [0,0,225,0,0,0,225,0,0],
                [0,0,0,225,0,225,0,0,0],
                [0,0,0,0,225,0,0,0,0],
                [0,0,0,225,0,225,0,0,0],
                [0,0,225,0,0,0,225,0,0],
                [0,225,0,0,0,0,0,225,0],
                [0,0,0,0,0,0,0,0,0]
                               ])
if __name__=='__main__':
    plt.figure()
    plt.subplot(1,3,1)
    plt.imshow(img1,cmap='gray')
    plt.title('img1')
    plt.subplot(1,3,2)
    plt.imshow(img2,cmap='gray')
    plt.title('img2')
    plt.subplot(1,3,3)
    plt.imshow(img3,cmap='gray')
    plt.title('img3')
    plt.show()

卷积过程:


import numpy as np
import torch
from matplotlib import pyplot as plt

img1=np.array([[0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255]
                               ])
img2=np.array([[255,255,255,255,255,0,0,0,0,0],
                [255,255,255,255,255,0,0,0,0,0],
                [255,255,255,255,255,0,0,0,0,0],
                [255,255,255,255,255,0,0,0,0,0],
                [255,255,255,255,255,0,0,0,0,0],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255],
                [0,0,0,0,0,255,255,255,255,255]
                               ])
img3=np.array([[0,0,0,0,0,0,0,0,0],
                [0,225,0,0,0,0,0,225,0],
                [0,0,225,0,0,0,225,0,0],
                [0,0,0,225,0,225,0,0,0],
                [0,0,0,0,225,0,0,0,0],
                [0,0,0,225,0,225,0,0,0],
                [0,0,225,0,0,0,225,0,0],
                [0,225,0,0,0,0,0,225,0],
                [0,0,0,0,0,0,0,0,0]
                               ])
kernel1=np.array([[1,-1]])
kernel2=np.array([[1],
                  [-1]])
kernel3=np.array([[1,-1],
                 [-1,1]])
if __name__=='__main__':
    plt.figure()
    i=1
    for img in [img1,img2,img3]:
        '''绘制原图'''
        plt.subplot(3, 4, i)
        plt.imshow(img,cmap='gray')
        plt.title('Original')
        i += 1
        img = torch.from_numpy(img.astype(np.float32)).reshape((1,1,img.shape[0],img.shape[1]))
        for j,kernel in enumerate([kernel1,kernel2,kernel3]):
            conv2d=torch.nn.Conv2d(in_channels=1,out_channels=1,kernel_size=kernel.shape)
            kernel = torch.from_numpy(kernel.astype(np.float32)).reshape((1, 1, kernel.shape[0], kernel.shape[1]))
            conv2d.weight.data=kernel
            out_img=conv2d(img)
            '''绘制卷积后的图像'''
            out_img = np.squeeze(out_img.detach().numpy())
            plt.subplot(3, 4, i)
            plt.imshow(out_img,cmap='gray')
            plt.title('kernel{}'.format(j))
            i+=1
    plt.show()

NNDL 作业5:卷积与几种常见的卷积核

作业2

一、概念

用自己的语言描述”卷积、卷积核、特征图、特征选择、步长、填充、感受野”。
自己的理解,如有错误请海涵:
卷积(Convolution):
在二维层面,卷积就是将两个函数(通常是一长一短)先逆向对齐,然后先不管多余的部分,计算两函数的乘积在短的函数的定义域的积分,然后再将短的那个函数逐步向后平移,每次再次进行点积运算。而对于离散函数,每次积分就相当于对两个函数的重合部分做点积运算。
在图像卷积中,那两个函数分别是原图和卷积核,我们先将卷积核和原始图像对齐,然后计算重叠部分的点积结果,计算完一个后,将卷积核按一定步长向后移动,这样一直重复直到卷积核移动到图像的末尾。
卷积核:
在图像卷积中,卷积核就是那个短的函数。
特征图:
就是所有卷积运算完成后的结果。
特征选择:
就是对卷积结果的选择。
步长:
就是那个短函数每次的后移长度。
在图像卷积中,就是卷积核向后移动的长度。
填充:
在图像卷积中,我们对边界的像素点的卷积次数比在中间调像素点要少,为了利用上这些卷积次数比较少的像素点,我们在图像的四周加上一层或多层数值确定的像素点(通常是0),从而把原始图像的边缘给”包裹起来”,这样原本的边缘信息就会被多卷积几次,在一定程度上减少了图片的特征丢失。
感受野:
就是那个短的函数的定义域。在图像卷积中就是卷积核的尺寸。

二、探究不同卷积核的作用

参考:Image Kernels explained visually (setosa.io)
不同的卷积核:
1.blur_kernel(模糊)
( 0.0625 0.125 0.0625 0.125 0.25 0.125 0.0625 0.125 0.0625 ) \begin{pmatrix} 0.0625&0.125&0.0625\ 0.125& 0.25&0.125\ 0.0625&0.125&0.0625 \end{pmatrix}⎝⎛​0 .0 6 2 5 0 .1 2 5 0 .0 6 2 5 ​0 .1 2 5 0 .2 5 0 .1 2 5 ​0 .0 6 2 5 0 .1 2 5 0 .0 6 2 5 ​⎠⎞​

1)权重代数和为一,保证了亮度和输入保持一致。
2)中心的权重为最大值,四周的权重比中心略低,大致处于同一数量级。这表明感受野内中心像素点倾向于与周围点相”融合”,但是也保留大部分的中心点特征。每个像素点的权重值都很小,这主要是防止卷积结果过大。
2.bottom_sobel_kernel(底部索贝尔)
( − 1 − 2 − 1 0 0 0 1 2 1 ) \begin{pmatrix} -1&-2&-1\ 0& 0&0\ 1&2&1 \end{pmatrix}⎝⎛​−1 0 1 ​−2 0 2 ​−1 0 1 ​⎠⎞​
对顶部像素点的特征赋负值,对中间像素点赋零,对底部像素点赋正值。
1)权重代数和为0,标志着卷积核输出亮度为暗。
2)上部和下部的权重代数和为零,意味着上下对应像素点的值都一样时,卷积的结果为零。表现为暗。
3)下正上负,说明只有当感受野底部的像素值比顶部像素值大时,卷积结果才会得到较大值。也就是当感受野的下部比上部亮时,卷积结果才会是正值,卷积结果表现为发亮。

顶部索贝尔、左索贝尔和右索贝尔和这个原理一样。
3.emboss_kernel(浮雕)
( − 2 − 1 0 − 1 1 1 0 1 2 ) \begin{pmatrix} -2&-1&0\ -1&1&1\ 0&1&2 \end{pmatrix}⎝⎛​−2 −1 0 ​−1 1 1 ​0 1 2 ​⎠⎞​
对右下角像素点的特征赋正值,对左上像素点赋负值,对中心像素点赋1。
1)权重代数和为一,保证了亮度和输入保持一致。
2)左上角和右下角权重代数和为零,中心为1,标志着感受野左上角和右下角像素点的值都一样时,卷积的输出为中心点像素值。
3)右下为正,左上为负,说明只有当感受野右下角的像素值比左上角像素值大时,卷积结果才会输出更大值。表现为对感受野中心点的提亮。
4.identify_kernel(识别)
( 0 0 0 0 1 0 0 0 0 ) \begin{pmatrix} 0&0&0\ 0& 1&0\ 0&0&0 \end{pmatrix}⎝⎛​0 0 0 ​0 1 0 ​0 0 0 ​⎠⎞​
四周为0,中心为1,意味着只采取感受野中心点的图像信息。
5.left_sobel_kernel(左索贝尔)
( 1 0 − 1 2 0 − 2 1 0 − 1 ) \begin{pmatrix} 1&0&-1\ 2& 0&-2\ 1&0&-1 \end{pmatrix}⎝⎛​1 2 1 ​0 0 0 ​−1 −2 −1 ​⎠⎞​
和底部索贝尔原理一样。
6.outline_kernel(边缘检测)
( − 1 − 1 − 1 − 1 8 − 1 − 1 − 1 − 1 ) \begin{pmatrix} -1&-1&-1\ -1&8&-1\ -1&-1&-1 \end{pmatrix}⎝⎛​−1 −1 −1 ​−1 8 −1 ​−1 −1 −1 ​⎠⎞​
为感受野中心点赋极大的一个权重,为四周的点赋负值。
1)权重代数和为0,标志着卷积核输出亮度为暗。
2)中心点为极大正值,四周为负值,说明当中心点值大于四周值的平均值时,卷积结果才会是正数,表现为发亮。
7.right_sobel_kernel(右索贝尔)
( − 1 0 1 − 2 0 2 − 1 0 1 ) \begin{pmatrix} -1&0&1\ -2& 0&2\ -1&0&1 \end{pmatrix}⎝⎛​−1 −2 −1 ​0 0 0 ​1 2 1 ​⎠⎞​
和底部索贝尔原理一样。
8.sharpen_kernel(锐化)
( 0 − 1 0 − 1 5 − 1 0 − 1 0 ) \begin{pmatrix} 0&-1&0\ -1& 5&-1\ 0&-1&0 \end{pmatrix}⎝⎛​0 −1 0 ​−1 5 −1 ​0 −1 0 ​⎠⎞​
1)权重代数和为一,保证了亮度和输入保持一致。
2)中心点为正值,四周为负值,说明当中心点值大于四周值的平均值的5/4时,卷积结果才会是大于原本的中心像素值,表现为对中心点的提亮。和边缘检测的原理有些类似。
9.top_sobel_kernel(顶部索贝尔)
( 1 2 1 0 0 0 − 1 − 2 − 1 ) \begin{pmatrix} 1&2&1\ 0& 0&0\ -1&-2&-1 \end{pmatrix}⎝⎛​1 0 −1 ​2 0 −2 ​1 0 −1 ​⎠⎞​
和底部索贝尔原理一样。

三、编程实现

实现灰度图的边缘检测、锐化、模糊。(必做)
源代码:


import numpy as np
import torch
from matplotlib import pyplot as plt

blur_kernel=np.array([[0.0625,0.125,0.0625],
                      [0.125,0.25,0.125],
                      [0.0625,0.125,0.0625]])
bottom_sobel_kernel=np.array([[-1,-2,-1],
                              [0,0,0],
                              [1,2,1]])
emboss_kernel=np.array([[-2,-1,0],
                        [-1,1,1],
                        [0,1,2]])
identify_kernel=np.array([[0,0,0],
                          [0,1,0],
                          [0,0,0]])
left_sobel_kernel=np.array([[1,0,-1],
                            [2,0,-2],
                            [1,0,-1]])
outline_kernel=np.array([[-1,-1,-1],
                         [-1,8,-1],
                         [-1,-1,-1]])
right_sobel_kernel=np.array([[-1,0,1],
                             [-2,0,2],
                             [-1,0,1]])
sharpen_kernel=np.array([[0,-1,0],
                         [-1,5,-1],
                         [0,-1,0]])
top_sobel_kernel=np.array([[1,2,1],
                          [0,0,0],
                          [-1,-2,-1]])

def rgb_to_gray(rgb):
    r, g, b = rgb[:, :, 0], rgb[:, :,1], rgb[:, :, 2]
    gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
    return gray

def adjust(img):
    '''将像素值大于255的记为255,小于0的记为0'''
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            if img[i][j] > 255:
                img[i][j] = 255
            elif img[i][j] < 0:
                img[i][j] = 0
            else:
                continue
    return img

if __name__=='__main__':
    img_path='cat.jpg'
    img=plt.imread(img_path)
    img=np.array(img)
    img=rgb_to_gray(img)
    plt.figure()
    labels=['outline_kernel','sharpen_kernel','blur_kernel']
    for j,kernel in enumerate([outline_kernel,sharpen_kernel,blur_kernel]):
        i = 1
        '''绘制原图'''
        plt.subplot(1, 2, i)
        plt.imshow(img, cmap='gray')
        plt.title('Original')
        i += 1
        in_img = torch.from_numpy(img.astype(np.float32)).reshape((1, 1, img.shape[0], img.shape[1]))
        conv2d=torch.nn.Conv2d(in_channels=1,out_channels=1,kernel_size=kernel.shape)
        kernel = torch.from_numpy(kernel.astype(np.float32)).reshape((1, 1, kernel.shape[0], kernel.shape[1]))
        conv2d.weight.data=kernel
        out_img=conv2d(in_img)
        '''绘制卷积后的图像'''
        out_img = np.squeeze(out_img.detach().numpy())
        out_img=adjust(out_img)
        plt.subplot(1,2, i)
        plt.imshow(out_img,cmap='gray')
        plt.title('{}'.format(labels[j]))
        plt.show()

NNDL 作业5:卷积与几种常见的卷积核
NNDL 作业5:卷积与几种常见的卷积核
NNDL 作业5:卷积与几种常见的卷积核
从上到下分别是边缘检测、锐化和模糊。效果很好。
调整卷积核参数,测试并总结。(必做)
将边缘检测、锐化和模糊卷积核的中心点权重增加了1,再次运行上述程序。
NNDL 作业5:卷积与几种常见的卷积核

NNDL 作业5:卷积与几种常见的卷积核
可见图像明显变亮了,这很符合预期。因为改变了图像的代数和。
1)为中心点加1后,边缘检测的效果和锐化效果一样了,因为他的代数和为一,具体参考上面对锐化卷积核的分析。
2)为锐化和模糊中心点加1后,代数和变为了2,这导致中心点信息被多叠加了一次,图像明显变亮。
使用不同尺寸图片,测试并总结。(必做)
400×400:
NNDL 作业5:卷积与几种常见的卷积核
NNDL 作业5:卷积与几种常见的卷积核
NNDL 作业5:卷积与几种常见的卷积核
1904×1072:
NNDL 作业5:卷积与几种常见的卷积核
NNDL 作业5:卷积与几种常见的卷积核
NNDL 作业5:卷积与几种常见的卷积核
实验发现图像越小,卷积的效果越明显,图像越大,卷积完成需要的时间越多,效果也更不明显。
探索更多类型卷积核。(选做)
1.均值滤波
( 1 / 9 1 / 9 1 / 9 1 / 9 1 / 9 1 / 9 1 / 9 1 / 9 1 / 9 ) \begin{pmatrix} 1/9&1/9&1/9\ 1/9&1/9&1/9\ 1/9&1/9&1/9 \end{pmatrix}⎝⎛​1 /9 1 /9 1 /9 ​1 /9 1 /9 1 /9 ​1 /9 1 /9 1 /9 ​⎠⎞​

1)权重代数和为一,保证了亮度和输入保持一致。
2)每个元素值都一样,效果和模糊类似。比高斯模糊更’模糊’一些。
尝试彩色图片边缘检测。(选做)
应注意rgb图像的信息存储是在最后一维增加了两个维度而不是在第一维并排了三个维度。
源代码:


import numpy as np
import torch
from matplotlib import pyplot as plt

outline_kernel=np.array([[-1,-1,-1],
                         [-1,8,-1],
                         [-1,-1,-1]]
                        )

def rgb_to_gray(rgb):
    r, g, b = rgb[:, :, 0], rgb[:, :,1], rgb[:, :, 2]
    gray = 0.2989 * r + 0.5870 * g + 0.1140 * b
    return gray

def adjust(img):
    '''将像素值大于255的记为255,小于0的记为0'''
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            if img[i][j] > 255:
                img[i][j] = 255
            elif img[i][j] < 0:
                img[i][j] = 0
            else:
                continue
    return img

if __name__=='__main__':
    img_path='cat.jpg'
    img=plt.imread(img_path)
    img=np.array(img)
    '''print(img.shape)'''
    plt.figure()
    labels=['outline_kernel']
    '''绘制原图'''
    plt.subplot(1, 2, 1)
    plt.imshow(img)
    plt.title('Original')
    rgb=[]
    for j,kernel in enumerate([outline_kernel]):
        for img_ in [img[:,:,i] for i in range(3)]:
            '''print(img_)'''
            in_img = torch.from_numpy(img_.astype(np.float32)).reshape((1, 1, img_.shape[0], img_.shape[1]))
            conv2d = torch.nn.Conv2d(in_channels=1, out_channels=1, kernel_size=kernel.shape)
            kernel_ = torch.from_numpy(kernel.astype(np.float32)).reshape((1, 1, kernel.shape[0], kernel.shape[1]))
            conv2d.weight.data = kernel_
            out_img = conv2d(in_img)
            '''绘制卷积后的图像'''
            out_img = np.squeeze(out_img.detach().numpy())
            out_img = adjust(out_img)
            rgb.append(out_img)

    o_img=np.stack((rgb[0],rgb[1],rgb[2]),axis=2)
    plt.subplot(1, 2, 2)
    plt.imshow(o_img)
    plt.title('{}'.format(labels[0]))
    plt.show()

运行结果

NNDL 作业5:卷积与几种常见的卷积核

总结:
1)深入分析并理解了各种常见卷积核的特征和原理,并实现了实例化。
2)尝试了修改卷积核的权重、修改输入图片尺寸,了解了其对卷积过程和结果的影响。
3)用pytorch实现了rbg图像的卷积。

对于其他尚未测试的卷积核的测试结果会在以后补充。
ref:
come from:
https://blog.csdn.net/qq_38975453/article/details/127174881?spm=1001.2014.3001.5502
RGB 转灰度图:
https://blog.csdn.net/qq_38635841/article/details/105153690
https://blog.csdn.net/weixin_33693070/article/details/93750473
其他卷积核:
https://blog.csdn.net/qq_62932195/article/details/126337971
实验所用图片来自互联网,供学术交流使用,侵删。

Original: https://blog.csdn.net/qq_58153224/article/details/127338502
Author: 真不想再学了
Title: NNDL 作业5:卷积与几种常见的卷积核

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/757821/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球