很早之前写过pillow中的滤镜处理,当时主要还是利用滤镜公式实现的,今天用矩阵试一下模糊滤镜。
直接调用pillow的库实现非常简单。
效果:
查看pillow库滤镜的源代码,可以看见核心就是一个数字矩阵,
那这个矩阵数字是如何产生模糊效果的呢?
下面这边文章讲了高斯模糊的原理,里面说了图片模糊本质上是一种数据平滑技术,所谓模糊,可以简单理解成每一个像素都去周边像素的平均值。
传送门:
https://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html
现在有一个如下的图像数字矩阵(图像的数字化):
为了让它模糊,我们可以用一个3*3的矩阵与其元素对应相乘再相加(这里都是0.1,接近和的平均数),这样就会得到一个模糊后的数值。
不好理解的话可以看下面这张图。
从左到右,从上到下,依次滑动计算,就可以得到全部模糊计算后的数据。
上面的计算过程就叫做卷积。
细心的你可能会发现,经过卷积后,模糊图片变小了,从6*6变成4*4了。为了解决这个问题,我们可以将原图扩充一圈在卷积,这个操作叫做填充,padding。
具体该填什么呢?这里有很多种填法,我们就直接填充 0,没影响。
比如将4*4的扩充1圈就可以得到6*6的效果。
用numpy的方法可以这样实现扩充。
接下来就可以计算了。
# new_img 保存处理后的结果,img 表示扩充后的图片矩阵,kernel表示卷积核矩阵
new_img = np.zeros((4,4))
for y in range(len(img)-2):
for x in range(len(img[0])-2):
print(img[y:y+3,x:x+3])
new_img[y,x] = np.sum(kernel * img[y:y + 3, x:x + 3])
封装成函数:
def my_filter(kernel,src):
src = np.pad(src, ((1, 1), (1, 1)), 'constant', constant_values=((0, 0)))
new_img = np.zeros((len(src)-2, len(src[0])-2))
for y in range(len(src) - 2):
for x in range(len(src[0]) - 2):
new_img[y, x] = np.sum(kernel * src[y:y + 3, x:x + 3])
return new_img
调用,传入一张图片试试。
更改卷积核大小,范围越大,图像就会越模糊。
同理,使用其它卷积核进行运算,可以得到其它模糊效果。