图像处理 之 矩阵一维卷积
先来几张图认识什么是一维数组卷积:
卷积的应用,图像处理很多地方都会用到卷积运算,具体用在哪方面我也不知道,坐等老师讲解,百度:图像中滤波、均值滤波、锐化等都是在空间域里进行卷积,也就是二维卷积
进入正题,一维数组卷积,用一个例子讲解。
数组 f = [ 0, 1, 2, 3, 4 ] ,g = [0, 1, 2]
设数组h 为 f 和 g 卷积后的结果,则 数组的长度为 len( f ) + len ( g ) – 1 = 7
如下图所示,
可以得出:
Len(h) = Len(f) + Len(g) - 1
实现此函数
定义函数 def convolution( f , g ) 为实现数组f 与数组 g的卷积,并将结果数组h返回
def convolution ( f, g):
#第一步创建并初始化结果数组h
#使用numpy.zeros( num )函数,其功能主要创建一个长度为num的数组,并将数组数据初始化为0
h = numpy.zeros( len(f) + len(g) – 1) #初始化一个长度为 f和g数组的长度之和-1
#实现卷积运算,我们将其分为三部分:
#实现卷积运算,我们将其分为三部分:
#第一部分为数组g刚开始进入数组f的过程
#第二部分为数组g在数组f中
#第三部分为数组g出数组f的过程
第一部分:
#即上图k从0到2的状态为第一部分
#k从3到4为第二部分
#k从5到6为第三部分
#首先实现第一部分
#由图可知,
for k in range( len(g) ):
#range()函数为创建一个数组[0, len(g) ),
#即0到len(g)的左闭右开数组,此条语句k将依次取该数组元素进行循环,
#即k从0到len(g) 循环
h[k] =sum (f[:k+1] * g_[len(g) - 1 - k:])
#sum(range) 中,range为数组,sum(range)为计算一个数组所有元素之和
#即sum( [ 1, 2, 3,4 ]) = 10
#先看f数组 f[:k+1]
#f[ :k+1] 等价于 f[0:k+1]
#右下图可知,上标一直在最头部up = 0,而下标为down = k+1
# 再看g_[len(g) - 1 - k:]
# 首先g函数原本是[0, 1, 2],如图所示,
#卷积需要将其反转为[2, 1, 0],也就是从右到左,即g_ = g[::-1] = [2, 1, 0]
#g_数组下标down不变为尾部,头部up 从len(g)-1的位置往前移动k,即up=len(g)-1-k
所以 h[k] =sum (f[:k+1] * g_[len(g) - 1 - k:])
第二部分:即整个数组g进入数组f
第二部分
for k in range(len(g), len(f)):
h[k] = sum(f[k + 1 - len(g) : k + 1 ] * g[::-1])
第二部中g数组整个数组的所有元素都被用到即 g[::-1]
再看f[k + 1 - len(g) : k + 1 ]
如上图,f数组与g数组的重合的三个数有效,
先看f数组的下标 down = k+1 此下标与第一部分一样。
因为f数组参加运算元素的长度与g数组长度一样,下标确定,那么上标为up=down-len(g) 即: up=k+1-len(g)
第一二步理解了第三步也就容易理解了
第三部分:G数组出f数组,
h[k] = sum(f[k + 1 - len(g):]*g_[: len(g) - (k + 1 - len(f))])
先看g数组,首先取反 即g_=g[::-1]
然后上标不变为最前,下标每次随着k的增大1而减少最尾部1个元素
而在第三部分 k的范围是 len(f) - 1 <k <len(f)+len(g)-1
k增大多少次,尾部减少多少个元素 如和判断k增加了多少,那就是 k-len(f)+1
即减少个范围为 0<k-len(f)+1<len(g) 也就是
减少到只剩下一个元素那么卷积就结束了,整个g数组就出去了
即 原本没减是g’[:len(g)],现在尾部减少k-len(f)+1个元素,
那么就是:g_[: len(g) - (k - len(f) + 1)]
f[k + 1 - len(g):]
和 g数组差不多,但是f是取尾部,g数组是取头部
尾部其实和头部道理一样,取头部修改下标,取尾部修改上标,让 k的关系和取得位置对应起来就可以了
原本为 f[len(f)-len(g):len(f)] 现在随着k的增大,数组左边元素减少k-len(f)+1个
即:
f[len(f)-len(g)+(k-len(f)+1):len(f)]=f[k-len(g)+1:]
所以:
h[k] = sum(f[k + 1 - len(g):]*g_[: len(g) - (k - len(f) + 1)])
最后返回数组 h
完整代码(3个版本):
#这个函数也不重要了,可以理解就可以了,知道是做了什么事情
def conv1d_v0010_kdy(f, g):
#创建并初始化数组,长度为f数组和g数组长度之和-1,
h = numpy.zeros((len(f) + len(g) - 1, ))#数组数据都为0
# g_ = g[::-1]
for k in range(len(g)):
h[k] = sum(f[:k+1] * g[ -len(g) + k::-1])
#h[k] =sum (f[:k+1] * g_[len(g) - 1 - k:])
for k in range(len(g), len(f)):
h[k] = sum(f[k + 1 - len(g) : k + 1 ] * g[::-1])
for k in range(len(f), len(f) + len(g) - 1):
h[k] = sum(f[k + 1 - len(g):]*g[: k - len(f) - len(g):-1])
#h[k] = sum(f[k + 1 - len(g):]*g_[: len(g) - (k - len(f) + 1)])
return h
#这个函数也不重要了,可以理解就可以了
#老师这份代码是先把f反转,g不反转,而我做的上面那个是g反转,f不反转,道理是一样的,
#但正常来说应该是g反转,也就是小的数组反转,我问了老师,老师好像是说反转f比较容易讲。。。
def conv1d_v0010(f,g):
h = numpy.zeros((len(f)+len(g)-1,))
for k in range(len(g)):
h[k] = (f[k::-1]*g[:k+1]).sum()
for k in range(len(g), len(f)):
h[k] = (f[k:k-len(g):-1]*g).sum()
for k in range(len(f), len(h)):
#h[11] = f[10:9] *g[2:3]=9*2=18
h[k] = (f[:k-len(g):-1]*g[k-len(f)+1:]).sum()
return h
#最重要的是这个函数
def conv1d(f_, g_):
#创建卷积后的存放数组
h = numpy.zeros((len(f_)+len(g_)-1,))
#反转数组g
g = g_[::-1]
#创建一个和g数组一模一样大的数组,全部初始化为0
zeroblock = numpy.zeros_like(g)
#在f数组前后接上 zeroblock数组 也就是 假使原来数组f为
#1, 2, 3, 4 那么接后就是:0, 0,0 ,1,2,3,4,0,0,0
# 例如 0, 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 0
# 与 2,1,0 这样卷积起来就很容易了
f = numpy.hstack((zeroblock, f_, zeroblock))
#下面就是卷积的操作
for k in range(len(g_)+len(f_)-1):
h[k]=(f[k+1:k+1+len(g)]*g).sum()
return h
测试用例:
if __name__ == "__main__":
f_shape, g_shape = 15, 3
f, g = numpy.arange(f_shape), numpy.arange(g_shape)
h = conv1d_v0010(f,g)
print (h)
i = conv1d(f,g)
print (i)
j = conv1d_v0010_kdy(f, g)
print (j)
f, g = numpy.arange(f_shape, f_shape), numpy.arange(g_shape, g_shape)
(完)