Opencv 图像平滑基础二维离散卷积 python API
Opencv 图像平滑基础二维离散卷积
二维离散卷积
要进行二维离散卷积运算首先需要对矩阵边界进行扩充,opencv提供了函数copyMakeBorder
import cv2
import numpy as np
src = np.array([[5,1,7],[1,5,9],[2,6,2]])
dst = cv2.copyMakeBorder(src,2,2,2,2,cv2.BORDER_REFLECT_101)
dst
array([[2, 6, 2, 6, 2, 6, 2],
[9, 5, 1, 5, 9, 5, 1],
[7, 1, 5, 1, 7, 1, 5],
[9, 5, 1, 5, 9, 5, 1],
[2, 6, 2, 6, 2, 6, 2],
[9, 5, 1, 5, 9, 5, 1],
[7, 1, 5, 1, 7, 1, 5]], dtype=int32)
实现二维离散卷积运算
使用Python的科学计算包Scipy提供的函数:convolve2d(in1m in2m mode = ‘full’, boundary = ‘fill’, fillvalue = 0)
#计算任意卷积核且任意指定的锚点的same卷积
import numpy as np
from scipy import signal
#主函数
if __name__ == "__main__":
#输入矩阵
I = np.array([[1,2],[3,4]],np.float32)
# I 的高和宽
H1, W1 = I.shape[:2]
#卷积核
K = np.array([[-1,-2],[2,1]],np.float32)
# K的高、宽
H2, W2 = K.shape[:2]
#计算full卷积
c_full = signal.convolve2d(I,K,mode = 'full')
#指定锚点位置
kr, kc = 0,0
#更具锚点位置,从full卷积中截取得到same卷积
c_same = c_full[H2-kr-1:H1+H2-kr-1,W2-kc-1:W1+W2-kc-1]
print(c_same)
[[-5. -6.]
[11. 4.]]
可分离卷积核
一个卷积核至少由两个尺寸比它小的卷积核full卷积而成,并且在计算过程中在所有边界处均进行扩充0的操作
full卷积不满足交换律,但是一维水平方向和一维垂直方向上的卷积核的full卷积是满足交换律的
import numpy as np
from scipy import signal
# 主函数
if __name__ == "__main__":
kernel1 = np.array([[1,2,3]], np.float32)
kernel2 = np.array([[4],[5],[6]], np.float32)
#计算两个核的全卷积
kernel = signal.convolve2d(kernel1,kernel2,mode = 'full')
print(kernel)
[[ 4. 8. 12.]
[ 5. 10. 15.]
[ 6. 12. 18.]]
离散卷积核的性质
1、full卷积的性质
如果卷积核可以分离则满足结合利率
import numpy as np
from scipy import signal
I = np.array([[1,2,3,10,12],
[32,43,12,4,190],
[12,234,78,0,12],
[43,90,32,8,90],
[71,12,4,98,123]],np.float32)
K = np.array([[1,0,-1],
[1,0,-1],
[1,0,-1]],np.float32)
#计算两者的full卷积
I_Kernel = signal.convolve2d(I,K,mode='full',boundary = 'fill',fillvalue = 0)
print(I_Kernel)
[[ 1. 2. 2. 8. 9. -10. -12.]
[ 33. 45. -18. -31. 187. -14. -202.]
[ 45. 279. 48. -265. 121. -14. -214.]
[ 87. 367. 35. -355. 170. -12. -292.]
[ 126. 336. -12. -230. 111. -106. -225.]
[ 114. 102. -78. 4. 177. -106. -213.]
[ 71. 12. -67. 86. 119. -98. -123.]]
kernel1 = np.array([[1],[1],[1]],np.float32)
kernel2 = np.array([[1,0,-1]],np.float32)
I_k1 = signal.convolve2d(I,kernel1,mode='full',boundary = 'fill',fillvalue = 0)
I_k1_k2 = signal.convolve2d(I_k1,kernel2,mode='full',boundary = 'fill',fillvalue = 0)
print(I_k1_k2)
[[ 1. 2. 2. 8. 9. -10. -12.]
[ 33. 45. -18. -31. 187. -14. -202.]
[ 45. 279. 48. -265. 121. -14. -214.]
[ 87. 367. 35. -355. 170. -12. -292.]
[ 126. 336. -12. -230. 111. -106. -225.]
[ 114. 102. -78. 4. 177. -106. -213.]
[ 71. 12. -67. 86. 119. -98. -123.]]
2、same卷积的性质
讨论一种情况:Kernel的宽和高均为奇数,并且可以分离为水平和垂直方向一维卷积核,则满足结合律,利用此规律可以降低运算量
c_same = signal.convolve2d(I,K,mode='same',boundary = 'fill',fillvalue = 0)
print(c_same)
[[ 45. -18. -31. 187. -14.]
[ 279. 48. -265. 121. -14.]
[ 367. 35. -355. 170. -12.]
[ 336. -12. -230. 111. -106.]
[ 102. -78. 4. 177. -106.]]
#利用卷积核的分离性进行same卷积运算,且采用0扩充边界,如果不采用0扩充边界卷积结果的上下左右边界的值会不同,在图像处理中可以忽略
c_same1 = signal.convolve2d(I,kernel1,mode='same',boundary = 'fill',fillvalue = 0)
c_same2 = signal.convolve2d(c_same1,kernel2,mode='same',boundary = 'fill',fillvalue = 0)
print(c_same2)
[[ 45. -18. -31. 187. -14.]
[ 279. 48. -265. 121. -14.]
[ 367. 35. -355. 170. -12.]
[ 336. -12. -230. 111. -106.]
[ 102. -78. 4. 177. -106.]]