python-opencv实现图片卷积
什么是图像卷积
在计算机视觉领域中,数字图像是一个二维的离散信号,对数字图像做卷积操作其实就是利用卷积核(卷积模板)在图像上滑动,将图像点上的像素灰度值与对应的卷积核上的数值相乘,然后将所有相乘后的值相加作为卷积核中间像素对应的图像上像素的灰度值,并最终滑动完所有图像的过程。
下面是一个示意图:
①卷积核是什么:通俗来说,卷积核就是一个二维的滤波器矩阵
②卷积核的移动:通常我们设定step=1,但是也可以改变。当卷积核移动到图像边缘时,这个时候我们需要向图像的边缘进行填充,这样更加方便我们获取到边缘特征信息。
③卷积核计算,原图像乘以卷积核对应位置的数据然后相加
卷积核的规则
1.卷积核的大小一般是奇数,这样的话它是按照中间的像素点中心对称的,所以卷积核一般都是3×3,5×5或者7×7。有中心了,也有了半径的称呼,例如5×5大小的核的半径就是2。
2.卷积核所有的元素之和一般要等于1,这是为了原始图像的能量(亮度)守恒。其实也有卷积核元素相加不为1的情况。
3.如果滤波器矩阵所有元素之和大于1,那么滤波后的图像就会比原图像更亮,反之,如果小于1,那么得到的图像就会变暗。如果和为0,图像不会变黑,但也会非常暗。
4.对于滤波后的结构,可能会出现负数或者大于255的数值。对这种情况,我们将他们直接截断到0(小于0时)或255(大于255时)即可。对于负数,也可以取绝对值。
当然不一定非要按照这个规则来:
就比如,你非要整个2x2的卷积核也是可以的,但是奇数相对于偶数,更有中心点,对边沿、对线条更加敏感,可以更有效的提取边沿信息,所以俺们大部分时候都是选择3x3呐,5x5啥的。
代码部分:
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):
n = len(kernel)
image_1 = np.zeros((image.shape[0]+2*(n-1),image.shape[1]+2*(n-1)))
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))
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('./169.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()
结果的图片:
图片左边为原图,右边为卷积核等于kernel = np.array([[1,0,-1], [1,-1,0], [2,-1,-1]]) 的效果图,卷积核不同每次的效果就不一样。例如:
kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])
效果图:
图像锐化也就是使用上面的卷积核。
所以你可以自己去调试不同的卷积核去处理自己的图片。
干饭时间!!!
溜哒。。。
注:文中若有错误部分,劳烦指正,谢谢