人工智能卷积算法

news2024/11/19 23:33:31



前言

卷积运算实际上是一种常见的数学方法,与加法,乘法等运算类似,都是由两个输入的到一个输出。不同的是,卷积运算输入的是两个信号,输出第三个信号。除了信号处理外,卷积运算也常用于概率论与数理统计等其他诸多领域。在线性系统中,卷积用于描述信号(Input Signal),冲激响应(Impulse Response),以及输出信号(Output Signal)3者之间的关系。

数字信号处理与卷积运算

卷积运算符号一般用*来表示,故表达式为:
y[n]=x[n]*h[n]
x[n]为输入信号,h[n]为冲激响应,y[n]为输出信号。卷积的常见用途是信号滤波。
在这里插入图片描述
(a)低通滤波器
在这里插入图片描述
(b)高通滤波器
在数字信号处理的各种应用中,输入信号的长度可能会有成百上千乃至数百万个采样点。冲激响应信号的长度通常要短得多,例如,只有几个或几百个采样点。虽然卷积运算并不限制这些信号的长度,然而,我们仍然需要搞清楚信号长度。
假设输入信号x[n]的长度为N(采样点的下标为0——N——1),冲激响应信号h[n]的长度为M(采样点的下标设为0——M-1),则输出信号y[n]长度为N+M-1

卷积公式与计算过程

卷积计算示意图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

边缘卷积计算与0填充

当我们计算y0或y11等信号边缘处点的卷积时,会发现有些问题。例如,计算y0时,则将h0与x0对齐,此时我们会发现,h3,h2,h1的对应采样点应为x(-1),x(-2),x(-3),而这些点却根本不存在。类似的,当计算y11时,我们也会面对不存在的x9,x10,x11。
在这里插入图片描述

在这里插入图片描述
对于以上所描述的卷积计算过程,我们可以通过下列代码实现:

import numpy as np
def MyConvolve(input,kernel):
    #对h[n]进行180度翻转
    kernel_flipped=np.array([kernel[len(kernel)-1-i] for i in range(len(kernel))])
    #kernel_flipped=kernel[::-1]也可以翻转
    len_input=len(input) #x[n]的长度
    len_kernel=len(kernel) #h[n]的长度


    #对输入数组进行0填充来解决卷积计算过程中的边缘对齐
    padding=np.zeros(len_kernel-1,dtype='int') #填充数值为0
    temp_pad=np.append(padding,input)
    input_pad=np.append(temp_pad,padding) #0填充后的数据

    #定义一个数组保存卷积结果,数组长度为:x[n]的长度+h[n]的长度-1
    con_array=np.array(range(len_input+len_kernel-1))

    #对x[n]与h[n]进行卷积计算
    for m in range(len(con_array)):
        sum_con=0
        for n in range(len(kernel_flipped)):
            sum_con=sum_con+input_pad[n+m]*kernel_flipped[n]
        con_array[m]=sum_con
    
    #输出卷积结果
    print('Input Signal:',input)
    print("Convolution Kernel:",kernel)
    print('Convolution:',con_array)
if __name__=='__main__':
    input=[1,3,5,7,9,11,13]
    kernel=[2,3,6,8]
    MyConvolve(input,kernel)


结果展示:

Input Signal: [1, 3, 5, 7, 9, 11, 13]
Convolution Kernel: [2, 3, 6, 8]
Convolution: [  2   9  25  55  93 131 169 177 166 104]

NumPy卷积函数

NumPy模块也内置了卷积函数,函数原型为:numpy.convolve(a,v,mode='full).
a`:输入一维数组,长度为N.
v:输入的第二个一位数组,长度为M。
mode:有三个参数(full,valid,same)
full,默认值。计算每一个采样点的卷积值,返回的数组长度为N+M-1.在卷积的边缘处,此信号不重叠,存在边缘效应
valid,返回的数组长度为max(M,N)-min(M,N)+1.此时返回的是完全重叠的点,边缘点无效,因此无边缘效应
same,返回的数组长度为max(M,N),边缘效应依然存在
NumPy卷积函数示例代码:


import numpy as np
a=[1,3,5,7,9,11,13]
b=[2,4,6,8]
c1=np.convolve(a,b,mode='full')
print("full卷积计算",c1)
c2=np.convolve(a,b,mode='same')
print('same计算',c2)
c3=np.convolve(a,b,mode='valid')
print('valid计算',c3)

计算结果:

>>> import numpy as np
>>> a=[1,3,5,7,9,11,13]
>>> b=[2,4,6,8]
>>> c1=np.convolve(a,b,mode='full')
>>> print("full卷积计算",c1)
full卷积计算 [  2  10  28  60 100 140 180 190 166 104]
>>> c2=np.convolve(a,b,mode='same')
>>> print('same计算',c2)
same计算 [ 10  28  60 100 140 180 190]
>>> c3=np.convolve(a,b,mode='valid')
>>> print('valid计算',c3)
valid计算 [ 60 100 140 180]
>>>

二维矩阵卷积计算

在进行数字图像处理时,每幅图像对应的是二维离散信号。我们经常会将一些具有某种特征的二维数组作为模板与图像进行卷积操作。使得新的图像具有某种特征,诸如模糊,锐化,浮雕等,这些模板统称为卷积核(Convolution Kernel).图像与卷积核之间的卷积操作从原理上与上文所述的一维信号卷积计算过程基本类似:将卷积核视为一个m*n大小的窗口一次在图像上滑动,将图像每个像素点上的灰度值与对应的卷积核上的数值相乘,然后将所有相乘后的值累加作为卷积核中间像素对应像素的灰度值,以此类推,计算所有像素点的卷积值。
例如,如图:
(0*4)+(0*0)+(0*0)+(0*0)+(1*0)+(1*0)+(0*0)+(1*0)+(2*-4)=-8
在这里插入图片描述图像卷积时一般不进行边缘填充,因此,卷积操作可能导致图像变小(损失图像边缘)。在进行卷积操作计算之前,卷积核也需要180°翻转。例如,卷积核为[[1,2,3],[4,5,6],[7,8,9]],反转后则为[[9,8,7],[6,5,4],[3,2,1]].二维数组的180°翻转可通过数组切片(Slice)与重塑(Reshape)操作来完成。示例代码如下:

import numpy as np
def ArrayRotate180(matrix):
    new_arr=matrix.reshape(matrix.size)  #将二维数组重塑为一维数组
    new_arr=new_arr[::-1] #一维数组实现翻转
    new_arr=new_arr.reshape(matrix.shape) #将一维数组重塑为二维数组
    return new_arr
if __name__=='__main__':
    m=np.array([[1,2,3],[4,5,6],[7,8,9]])
    print(ArrayRotate180(m))

结果展示:
[[9 8 7]
 [6 5 4]
 [3 2 1]]

二维数组卷积计算涉及矩阵运算和矩阵求和,卷积计算的步骤:
①.先将卷积核翻转180°
②.将翻转后的卷积核中心与输入二维矩阵数组第一个元素对齐,并将相乘后得到的矩阵所有元素进行求和,得到结果矩阵的第一个元素。如果考虑边缘效应,那么卷积核与输入矩阵不重叠部分用0填充
③.依此类推,完成其他所有元素的卷积运算,直至输出结果矩阵
完成上述过程代码示例:

import numpy as np
def ArrayRotate180(matrix):
    new_arr=matrix.reshape(matrix.size)  #将二维数组重塑为一维数组
    new_arr=new_arr[::-1] #一维数组实现翻转
    new_arr=new_arr.reshape(matrix.shape) #将一维数组重塑为二维数组
    return new_arr

def My2Dconv(matrix,kernel):
    #对矩阵数组进行深复制作为输出矩阵,而输出矩阵将改变其中参与卷积计算的元素。
    new_martix=matrix.copy()
    m,n=new_martix.shape #输入二维矩阵的行列数
    p,q=kernel.shape #卷积核的行列数
    kernel=ArrayRotate180(kernel) #对卷积核进行180杜翻转;
    #将卷积核与输入二维矩阵进行卷积计算
    for i in range(1,m):
        for j in range(1,n-1):
            new_martix[i,j]=(matrix[(i-1):(p-1+i),(j-1):(j+q-1)]*kernel).sum()
    return new_martix
if __name__=='__main__':
    input=np.array([[1,2,3,4],[5,7,8,8],[6,9,0,2],[11,22,33,44]])
    kernel=np.array([[1,0,1],[-1,-1,-1]]) #示例卷积核
    print(My2Dconv(input,kernel))





结果展示:

[[  1   2   3   4]
 [  5   7   6   8]
 [  6 -14 -12   2]
 [ 11  29  55  44]]

图像卷积应用实例

对于二维矩阵卷积计算,诸如SciPy,OpenCV等等第三方Python模块同样也内置了该功能,以下示例代码利用OpenCV内置的filter2D()对一幅输入图像进行边缘检测。卷积核在很大程度上决定了输出图像的效果。例如,[[-1,-1,-1],[-1,8,-1],[-1,-1,-1]]可实现对一幅图像进行边缘化检测,[[-1,-1,-1],[-1,9,-1],[-1,-1,-1]]可实现对图像进行锐化操作.[[-6,-3,0],[-3,1,-3],[0,3,6]]可实现对图像进行浮雕处理。
下面展示对图像锐化处理:

#图像卷积应用示例
import matplotlib.pyplot as plt
import pylab
import cv2
import numpy as np
img=plt.imread('D:\csdn专用图片\cb967cce-56cd-45de-ba96-ffb05edabd8b_batchwm.jpg')
plt.imshow(img)
pylab.show()
#定义卷积核
kernel=np.array([[-1,-1,-1],[-1,8,-1],[-1,-1,-1]])
res=cv2.filter2D(img,-1,kernel)
plt.imshow(res)
plt.imsave('result.jpg',res)
pylab.show()

代码结果展示:
在这里插入图片描述在这里插入图片描述

总结

卷积运算是一种基于二维数组矩阵之间的一种操作算法,认识卷积运算,可以很方便的实现一些功能。熟练掌握filter2D()卷积函数,是本节的重点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/163194.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

迷宫问题---数据结构实践作业

迷宫问题—数据结构实践作业 ✅作者简介:大家好,我是新小白2022,让我们一起学习,共同进步吧🏆 📃个人主页:新小白2022的CSDN博客 🔥系列专栏:算法与数据结构 💖如果觉得博…

什么是HAL库和标准库,区别在哪里?

参考文章https://blog.csdn.net/u012846795/article/details/122227823 参考文章 https://zhuanlan.zhihu.com/p/581798453 STM32的三种开发方式 通常新手在入门STM32的时候,首先都要先选择一种要用的开发方式,不同的开发方式会导致你编程的架构是完全…

Java 面向对象程序设计 消息、继承与多态实验 课程设计研究报告

代码:Java计算机课程设计面向对象程序设计对战游戏SwingGUI界面-Java文档类资源-CSDN文库 一、课程设计内容 一个游戏中有多种角色(Character),例如:国王(King)、皇后(Queen)、骑士&#xff0…

【Linux多线程】

Linux多线程Linux线程概念什么是线程线程的优点线程的缺点线程异常线程用途Linux进程VS线程进程和线程进程的多个线程共享Linux线程控制POSIX线程库线程创建线程等待线程终止分离线程线程ID及进程地址空间布局Linux线程概念 什么是线程 在一个程序里的一个执行路线就叫做线程…

JavaScript 如何正确的分析报错信息

文章目录前言一、报错类型1.控制台报错2.终端报错二、错误追查总结前言 摸爬滚打了这么长时间…总结了一些排查错误的经验, 总的来说, 这是一篇JavaScript新手向文章. 里面会有些不那么系统性的, 呃, 知识? 一、报错类型 报错信息该怎么看, 怎么根据信息快速的追查错误. 1.…

瑞吉外卖项目

技术选型: 1、JAVA版本:JDK11 2、数据库:mysql5.7 Navicat 3、后端框架:SpringBoot SpringMVC MyBatisPlus 4、工具类:发邮件工具类、生成验证码工具类 5、项目优化:Nginx、Redis、读写分离 项目来…

2022. 12 青少年机器人技术等级考试理论综合试卷(五级)

2022.年12月青少年机器人技术等级考试理论综合试卷(五级) 分数: 100 题数: 30 一、 单选题(共 20 题, 共 80 分) 1.下列程序执行后,串口监视器显示的相应内容是? ( ) A.1 B.2 C.4 D.…

WPF绑定(Binding)下的数据验证IDataErrorInfo

绑定下的数据验证 WPF中Binding数据校验、并捕获异常信息的三种方式讲到了三种方式,其中使用ValidatinRule的方式比较推荐,但是如果一个类中有多个属性,要为每个属性都要声明一个ValidatinRule,这样做非常麻烦。可以让类继承自ID…

【High 翻天】Higer-order Networks with Battiston Federico (8)

目录传播与社会动力学(2)Opinion and cultural dynamicsVoter modelMajority modelsContinuous models of opinion dynamicsCultural dynamics传播与社会动力学(2) 在本节将讨论一些观点和文化动力学模型,它们基于物理…

【JavaSE】反射

一、概念反射是在运行期间,动态获取对象的属性和方法二、相关的类在Java的反射里主要有以下几个类:Class类,这是反射的起源,反射必须要先获取Class对象,其次是Field类,当我们需要通过反射获取私有字段时就需…

老杨说运维 | 2023,浅谈智能运维趋势(一)

(文末附视频回顾,一键直达精彩内容) 前言: 2022年,是经济被影响的一年,这一年无论是企业还是个人经济形势都呈下滑趋势,消费降级状态或许不会因为2022的结束而改观。 全球经济紧缩的状态下&am…

不仅会编程还要会英语(博主英语小笔记)1.1名词

目录 1-1名词的概念和分类 1、名词的概念 2.名词根据其意义可以分为专有名词和普通名词 (1)专有名词: (2)普通名词: 1-1名词的概念和分类 1、名词的概念 名词是表示人、动物、地点、物品以…

字符串常用函数介绍及模拟实现

🐎作者的话 本文介绍字符串常用的函数如何使用及其模拟实现~ 跳跃式目录strlen介绍strcpy介绍strcat介绍strcmp介绍strncpy介绍strncat介绍strncmp介绍strstr介绍strchr介绍strrchr介绍memcpy介绍memmove介绍memcmp介绍memset介绍strtok介绍strlen介绍 函数原型&…

GO语言配置和基础语法应用(二)

Go 语言结构 在我们开始学习 Go 编程语言的基础构建模块前,让我们先来了解 Go 语言最简单程序的结构。 Go Hello World 实例 Go 语言的基础组成有以下几个部分: 包声明引入包函数变量语句 & 表达式注释 接下来让我们来看下简单的代码 package ma…

Allegro如何导出placement操作指导

Allegro如何导出placement操作指导 在做PCB布局的时候,有时需要导出和导入Placement,placement文件是板上所有器件的坐标以及所在层面的文件 具体操作如下 导出placement文件,选择File

实现用户进程

文章目录前言前置知识实验操作实验一实验二前言 博客记录《操作系统真象还原》第十一章实验的操作~ 实验环境:ubuntu18.04VMware , Bochs下载安装 实验内容: 定义并初始化 TSS。实现用户进程。 前置知识 TSS 简介 TSS,即 Tas…

time和datetime之类的东西

这篇文章是学习数据可视化的记录,原视频链接 B站视频连接 time 先来看一张图 struct_time(时间元组)是作为时间戳和格式化后的字符串的桥梁的 mktime(t)是将指定时间元组转换为时间戳的 localtime()是将指定时间戳转换为时间元组的,可以不写时间戳&…

【一文教你学会动态内存管理】

1.为什么会存在动态内存分配? 2. 动态内存函数的介绍 2.1 malloc函数和free函数 2.2 calloc函数 2.3 realloc 3. 常见的动态内存错误 3.1 对NULL指针的解引用操作 3.2 对动态开辟空间的越界访问 3.3 对非动态开辟内存使用free释放 3.4 使用free释放一块动态开…

Uniswap v3 详解(一):设计原理

刚看完 Uniswap v2 的代码,本来打算写一个 Uniswap v2 设计与实现,结果 Uniswap v3 就发布了。趁着这个机会就先写一个 Uniswap v3 设计与实现吧。 因为 v3 版本的实现复杂度和 v2 已经不在一个量级了,难免会有理解上的偏差,本文…

ESP8266-01s+STM32+MQTT+ONNET+EMQX实现定时发送心跳包并配置MQTT断开连接后进行重连

目录:1.情况介绍2.发送心跳包和MQTT重连实现步骤3.运行效果1.情况介绍 硬件通过ESP8266-01s连接自己的MQTT服务器EMQX的时候,发现连上后没过多久就自动断开了,由于硬件代码使用的是ONNET的案例代码改的,所以发现该案例代码并没有发送心跳包和…