从数学角度来看卷积是这样的
卷积是通过两个函数f和g生成第三个函数的一种数学运算,卷积结果可以看作是函数f的修改(过滤)版本。在这个定义中,函数g被称为过滤器filter、卷积函数或卷积核。
第一次看见是在泛函分析,卷积这个东西根本不知道是干什么的有什么用。后来解除了数字图像才明白。
用自然语言举一个物理学中用能量的例子解释:一个物体时刻会受到一个周期性的固定模式的的能量的冲击。并且,物体在受到某个时刻的能量时,会按照一个函数关于时间的函数去变化来自于这个时刻的能量。
更直白的说就是:系统某一时刻的输出是由多个输入共同作用(叠加)的结果。
最左边的图是输入图像没有经过任何处理的,中间的是卷积核,在卷积核的作用下输出最右边的图像,这就是共同作用的结果。
这图不错:
那么卷积在图像上能做什么呢?
检测边缘
卷积在图像上具体实现:卷积核从上到下从左到右地滑动,步长自己设定,每一个滑动窗口卷积与对应图像都做乘积求和。
具体代码:
import numpy as np
input = np.array([[1,1,1,0,0],
[0,1,1,1,0],
[0,0,1,1,1],
[0,0,1,1,0]
])
kernel = np.array([[1,0,1],
[0,1,0],
[1,0,1]
])
print('input.shape')
print(input.shape)
print('输入矩阵的行数:')
x=input.shape[0]
print(input.shape[0])
print('输入矩阵的列数:')
y=input.shape[1]
print(input.shape[1])
print('kernel.shape')
print(kernel.shape)
#坑点:不要照着抄output_size = (len(input)-len(kernel)+1)其中的len(input)不能应用在x,因为x是int型变量
output_size_x=(x-len(kernel)+1)
output_size_y=(y-len(kernel)+1)
def my_conv(input,kernel):
#output_size = (len(input)-len(kernel)+1)
res = np.zeros([output_size_x,output_size_y],np.float32)
for my_conv_x in range(len(res)):
for my_conv_y in range(len(res)):
res[my_conv_x][my_conv_y] = compute_conv(input,kernel,my_conv_x,my_conv_y)
return res
def compute_conv(input,kernel,my_conv_x,my_conv_y):
res = 0
for compute_conv_x in range(3):
for compute_conv_y in range(3):
#print(input[i+kk][j+k])
res +=input[my_conv_x+compute_conv_x][my_conv_y+compute_conv_y]*kernel[compute_conv_x][compute_conv_y] #这句是关键代码,实现了两个矩阵的点乘操作
return res
print('卷积结果')
print(my_conv(input,kernel))
注意:输入地图像不一定是行数等于列数地矩阵,计算卷积用两个for循环就行了very easy
结果如下图,这是用二维数组模拟的卷积,具体图像要对图像做一点处理:
图像处理的卷积,更改卷积核可以实现不同的边缘检测:
import cv2 as cv
from matplotlib import pyplot as plt
import numpy as np
def matrix_conv(arr,kernel):
n = len(kernel)
ans = 0
for i in range(n):
for j in range(n):
ans += arr[i,j]*float(kernel[i,j])
return ans
def conv_2(image,kernel):
#kernel的长度,3
n = len(kernel)
#2*(n-1)=4
image_1 = np.zeros((image.shape[0]+2*(n-1),image.shape[1]+2*(n-1)))#516
image_1[(n - 1):(image.shape[0] + n - 1), (n - 1):(image.shape[1] + n - 1)] = image
image_2 = np.zeros((image_1.shape[0]-n+1,image_1.shape[1]-n+1))#514
for i in range(image_1.shape[0]-n+1):
for j in range(image_1.shape[1]-n+1):
temp = image_1[i:i+n,j:j+n]
image_2[i,j] = matrix_conv(temp,kernel)
new_image = image_2[(n-1):(n+image.shape[0]-1),(n-1):(n+image.shape[1]-1)]
return new_image
img = cv.imread('./EXP1B.bmp',0)
kernel = np.array([[1,0,-1], [1,-1,0], [2,-1,-1]]) #定义的一个卷积核
img_conv = conv_2(img,kernel)
plt.subplot(1,2,1)
plt.imshow(img,cmap='gray')
plt.subplot(1,2,2)
plt.imshow(img_conv,cmap='gray')
plt.show()