full
,full嘛,全部的意思,将边界填充,使得,kernel四个角的像素点能与原图像的像素点刚好对应重合,output会变大same
,same嘛,相同的意思,原图像的四个角像素点与kernel中心像素点重合,output与原图一样大valid
,图片不需要填充,直接进行运算,会使图片变小接下来再上手边界条件
Reflect
为了减少代码冗余,我写了一个装饰器filterDecorator
,在我写的函数boundaryZeroPadding
和boundaryWrapAround
中,留存了部分注释以帮助大家理解
# 为减少部分代码,定义装饰器函数
def filterDecorator(someFilter):
'''
someFilter : 传入的滤波器函数
'''
def inner(img, kernel_size, shape='same'):
# 1.检查 shape 参数正确与否
assert shape in ['full', 'same','valid'], "弟弟, shape参数填错了!"
# 2.valid 情况无需填充
if shape == 'valid':
return img.copy()
if shape == 'full':
# k -> 2K 即和 'same' 一样
kernel_size = np.array(kernel_size) * 2 - 1
# 调用被装饰函数
result_img = someFilter(img, kernel_size, 'same')
return result_img
return inner
# 全零填充函数
@filterDecorator
def boundaryZeroPadding(img, kernel_size, shape):
'''
img : 要填充的img
kernel_size : 你kernel的形状,(先行后列)与kernel.shape顺序相反
shape : 填充的类型, 你懂得:full, same, valid
返回值为 padding 后的图片
'''
# # -------------------------代码冗余,转至装饰器中----------------------------
# # 检查 shape 参数正确与否
# assert shape in ['full', 'same','valid'], "弟弟, shape参数填错了!"
# if shape == 'valid':
# # 此情况无需 padding
# return img.copy()
# # -------------------------代码冗余,转至装饰器中----------------------------
# 获取图片的高,宽
img_height, img_width = img.shape
# 获得 K 值
kx, ky = kernel_size[1]//2, kernel_size[0]//2
if shape == 'same': # 不加 if 非常可
# 左右需要填充的 zero
# 此处必须加上 dtype=np.uint8,否则 cv2 float 显示全白
zeros_array = np.zeros((img_height, kx), dtype=np.uint8)
# 给图片左右两边添加 0
img_copy = np.concatenate([zeros_array, img, zeros_array], axis=1)
# 上下需要填充的 zero
zeros_array = np.zeros((ky, 2*kx + img_width), dtype=np.uint8)
# 给图片上下两边添加 0
img_result = np.concatenate([zeros_array, img_copy, zeros_array], axis=0)
return img_result
# # -------------------------代码冗余,转至装饰器中----------------------------
# else:
# # k -> 2K 即和 'same' 一样
# kernel_size = np.array(kernel_size) * 2 - 1
# return boundaryZeroPadding(img, kernel_size, 'same')
# # -------------------------代码冗余,转至装饰器中----------------------------
# 块复制,相当于搞一个周期函数
@filterDecorator
def boundaryWrapAround(img, kernel_size, shape):
'''
img : 要填充的img
kernel_size : 你kernel的形状,(先行后列)与kernel.shape顺序相反
shape : 填充的类型, 你懂得:full, same, valid
返回值为 WrapAround 后的图片
'''
# 获取图片的高,宽
img_height, img_width = img.shape
# 获得 K 值
kx, ky = kernel_size[1]//2, kernel_size[0]//2
'''
块复制 位置分布定义, X为原图片
E | D | F
--------------------
| 1 | 2 | 3 |
| - | - | - |
A | 4 | X | 5 | B
| - | - | - |
| 6 | 7 | 8 |
--------------------
G | C | H
'''
if shape == 'same': # 不加 if 非常可
# 求上下
part_D = img[-ky:]
part_C = img[: ky]
# part_A = img[:, -kx:]
# part_B = img[:, :kx]
# 中间合并
part_DXC = np.concatenate([part_D, img, part_C], axis=0)
# 复制 DXC 的 右边
part_EAG = part_DXC[:, -kx:]
# 复制 DXC 的 左边
part_FBH = part_DXC[:, :kx]
# 整体合并
img_result = np.concatenate([part_EAG, part_DXC, part_FBH], axis=1)
return img_result
# # -------------------------代码冗余,转至装饰器中----------------------------
# else:
# # k -> 2K 即和 'same' 一样
# kernel_size = np.array(kernel_size) * 2 - 1
# return boundaryWrapAround(img, kernel_size, 'same')
# # -------------------------代码冗余,转至装饰器中----------------------------
# 边界复制,就是把边界拉出去
@filterDecorator
def boundaryEdgeCopy(img, kernel_size, shape):
'''
img : 要填充的img
kernel_size : 你kernel的形状,(先行后列)与kernel.shape顺序相反
shape : 填充的类型,你懂得:full, same, valid
返回值为 EdgeCopy 后的图片
'''
# 获取图片的高,宽
img_height, img_width = img.shape
# 获得 K 值
kx, ky = kernel_size[1]//2, kernel_size[0]//2
'''
边界复制 位置分布 X为图片
| 1 | 2 | 3 |
| - | - | - |
| 4 | X | 5 |
| - | - | - |
| 6 | 7 | 8 |
'''
if shape == 'same': # 不加 if 非常可
# 求上下左右
part_2 = np.concatenate([img[ 0].reshape(1, -1)]*ky, axis=0)
part_7 = np.concatenate([img[-1].reshape(1, -1)]*ky, axis=0)
part_4 = np.concatenate([img[:, 0].reshape(-1, 1)]*kx, axis=1)
part_5 = np.concatenate([img[:,-1].reshape(-1, 1)]*kx, axis=1)
# 求四个角
# 此处必须加上 dtype=np.uint8,否则 cv2 float 显示全白
part_1 = np.ones(shape=(kx, ky), dtype=np.uint8) * img[0,0]
part_3 = np.ones_like(part_1, dtype=np.uint8) * img[0, -1]
part_6 = np.ones_like(part_1, dtype=np.uint8) * img[-1, 0]
part_8 = np.ones_like(part_1, dtype=np.uint8) * img[-1,-1]
# 三列合并
part_146 = np.concatenate([part_1, part_4, part_6], axis=0)
part_2X7 = np.concatenate([part_2, img , part_7], axis=0)
part_358 = np.concatenate([part_3, part_5, part_8], axis=0)
# 整体合并
img_result = np.concatenate([part_146, part_2X7, part_358], axis=1)
return img_result
# 边界镜像对称函数
@filterDecorator
def boundaryReflect(img, kernel_size, shape):
'''
img : 要填充的img
kernel_size : 你kernel的形状,(先行后列)与kernel.shape顺序相反
shape : 填充的类型
返回值为 Reflect 后的图片
'''
# 获取图片的高,宽
img_height, img_width = img.shape
# 获得 K 值
kx, ky = kernel_size[1]//2, kernel_size[0]//2
'''
镜像对称 位置分布定义, X为原图片
E | D | F
--------------------
| 1 | 2 | 3 |
| - | - | - |
A | 4 | X | 5 | B
| - | - | - |
| 6 | 7 | 8 |
--------------------
G | C | H
'''
if shape == 'same': # 不加 if 非常可
# 先通过堆成求 DC
part_D = img[(ky-1)::-1, :]
part_C = img[-1:-(ky+1):-1, :]
# DC 与 X 合并
part_DXC = np.concatenate([part_D, img, part_C], axis=0)
# 通过对称求 EAG 和 FBH
part_EAG = part_DXC[:, (kx-1)::-1]
part_FBH = part_DXC[:, -1:(-kx-1):-1]
# 合并
img_result = np.concatenate([part_EAG, part_DXC, part_FBH], axis=1)
return img_result