问题描述
实现一个函数 g = twodConv(f, w), 其中 f 是一个灰度源图像,w 是一个矩形卷积核。要求输出图像 g 与源图像 f 大小(也就是像素的行数和列数)一致。请注意,为满足这一要求,对于源图像f需要进行边界像素填补(padding)。这里请实现两种方案。第一种方案是像素复制,对应的选项定义为’replicate’,填补的像素拷贝与其最近的图像边界像素灰度。第二种方案是补零,对应的选项定义为’zero’, 填补的像素灰度为 0. 将第二种方案设置为缺省选择。
问题分析
卷积公式
w
(
x
,
y
)
⋆
f
(
x
,
y
)
=
∑
s
=
−
a
s
=
a
∑
t
=
−
b
t
=
b
f
(
x
−
s
,
y
−
t
)
w
(
s
,
t
)
w(x,y)\star f(x,y) = \sum_{s=-a}^{s=a}\sum_{t=-b}^{t=b}f(x-s,y-t)w(s,t)
w(x,y)⋆f(x,y)=s=−a∑s=at=−b∑t=bf(x−s,y−t)w(s,t)
注意:卷积比相关操作多一个滤波核反转
代码实现
导库
import numpy as np
import cv2
卷积函数
def twodConv(f, w, method='zero'):
w = np.array(w)
#滤波核反转
w = np.fliplr(np.flipud(w))
print(w)
x, y = w.shape
fh, fw = f.shape
nh = fh + x - 1
nw = fw + y - 1
add_h = int(x) // 2
add_w = int(y) // 2
#零填充边界
n = np.zeros((nh, nw))
g = np.zeros((fh, fw))
#复制原图
n[add_h:nh - add_h, add_w:nw - add_w] = f
if method == 'replicate':
# 边界填充
n[0:add_h,add_w:nw-add_w] = f[0,:]
n[nh-add_h:,add_w:nw-add_w] = f[-1,:]
for i in range(add_w):
n[:,i] = n[:,add_w]
n[:,nw-1-i] = n[:,nw-1-add_w]
# 卷积运算
for i in range(fh):
for j in range(fw):
g[i,j] = np.sum(n[i:i+x,j:j+y] * w)
g = g.clip(0,255)
return g
if method == 'zero':
# 卷积运算
for i in range(fh):
for j in range(fw):
g[i,j] = np.sum(n[i:i+x,j:j+y] * w)
g = g.clip(0,255)
return g
else:
raise Exception("输入格式有误")
主函数
if __name__ == '__main__':
f = cv2.imread("cameraman.tif", cv2.IMREAD_GRAYSCALE)
w = [[1,0,-1],[2,0,-2],[1,0,-1]]
g1 = twodConv(f,w,method='replicate')
g2 = twodConv(f,w)
g3 = np.abs(g1 - g2)
cv2.imshow('f', f)
cv2.imshow('replicate', g1)
cv2.imshow('zero', g2)
cv2.imshow('diff', g3)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果
运行 twodConv.py 文件,滤波核以 sobel 算子为例,得到的卷积运算结果如下所示
通过做差的图也能看出两张图像的边缘部分不同。