上面通过代码构造了高斯算子,并且使用二维的卷积运算来平滑图像,也达到了目标,不过还有一个问题,就是当你处理比较大的图片,或者比较大的高斯矩阵时,就会发现计算的时间很长。这时候我们就要考虑有没有高效快速的算法了,再回过头来审视一下二维高斯函数:
可以看到最后的等式,再考虑指数的运算法则:
根据(1)指数运算公式,反向使用它,就可以变换为两个指数相乘,这样就有意义了,表明高斯算子是可以分离的,并且是可以先作一维的水平的卷积运算,再作一维的垂直的卷积运算,这样的结果是一样的。
下面先来探讨一下卷积计算可分离性,演示的例子如下:
#python 3.7.4,opencv4.1
#蔡军生 https://blog.****.net/caimouse/article/details/51749579
#
import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
#计算卷积
image = np.array([[1,2,3],[4,5,6],[7,8,9]])
k1 = np.array([[1],[1],[1]])
k2 = np.array([[1,0,-1]])
k3 = signal.convolve2d(k1, k2)
print(k1,k2,k3)
输出结果如下:
[[1]
[1]
[1]]
分离矩阵1
[[ 1 0 -1]]
分离矩阵2
[[ 1 0 -1]
[ 1 0 -1]
[ 1 0 -1]]
卷积计算后的总矩阵
下面来做这样的实验,让一个矩阵先与一维水平方向的卷积运算,再与一维垂直方向上的卷积运算;接着让一个矩阵与二维矩阵卷积运算,代码如下:
#python 3.7.4,opencv4.1
#蔡军生 https://blog.****.net/caimouse/article/details/51749579
#
import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
#计算卷积
image = np.array([[1,2,3],[4,5,6],[7,8,9]])
k1 = np.array([[1],[1],[1]])
k2 = np.array([[1,0,-1]])
k3 = signal.convolve2d(k1, k2)
print(k1,k2,k3)
image = np.array([[1,2,3],[4,5,6],[7,8,9]])
#先一维分两次计算
out1 = signal.convolve2d(image, k1)
out2 = signal.convolve2d(out1, k2)
print(out2)
#二维一次计算
out3 = signal.convolve2d(image, k3)
print(out3)
结果输出如下:
[[ 1 2 2 -2 -3]
[ 5 7 4 -7 -9]
[ 12 15 6 -15 -18]
[ 11 13 4 -13 -15]
[ 7 8 2 -8 -9]]
[[ 1 2 2 -2 -3]
[ 5 7 4 -7 -9]
[ 12 15 6 -15 -18]
[ 11 13 4 -13 -15]
[ 7 8 2 -8 -9]]
从上面可以看到可分离的卷积核,分为两次一维的计算和一次二维的计算结果是一样的。利用这个性质,就可以加速高斯平滑的计算,因为两次一维的计算量为(图像高度*图像宽度)*(卷积核1高度+卷积核2宽度),而二维的情况计算量为(图像高度*图像宽度)*(卷积核1高度*卷积核2宽度),可以看到一维计算情况要少一些。
https://blog.****.net/caimouse/article/details/51749579