时间为友,记录点滴。
媳妇生病住院了,当了一阵子的男保姆,知乎都断更了。赶紧补一补。
这个《数字图像处理》的第二章举的例子可真多啊,还没搞完。今天来聊一聊邻域处理。
直奔主题,如何通过邻域来实现滤波。作为一名有科学素养的程序员都知道,在研究一个主题之前,一定要字字珠玑。这个主题中有两个名词:
邻域
啥是邻域?其实就是我们研究目标像素周边的像素,一张图直观解释:
更多的内容可以查看我的另外一个专题:
lowkeyway:第二章 数字图像基础-(五)像素间的基本关系zhuanlan.zhihu.com滤波
滤波是我们这个专栏的新概念,先画个结构图
- 基础
- 频率
- 高频(其实就是目标像素跟周边像素相差比较大)
- 中频
- 低频(目标像素跟周边像素相差不大)
- 频率
- 目的
- 模糊(低通滤波=模糊;高通滤波=锐化)
- 消噪
- 方法
- 线性滤波
- 方框滤波
- 均值滤波(这个是我们今天要说的)
- 高斯滤波
- 高斯低通滤波器(通低频,阻高频)
- 高斯高通滤波器(通高频,阻低频)
- 非线性滤波
- 中值滤波
- 双边滤波
- 线性滤波
好了,我们通过上面的这个结构图,知道了什么是图像的高频和低频,什么是低通和高通滤波器,知道了什么是模糊。那就简单了,那今天讲的均值滤波其实就是设计一个低通滤波器来处理图像,实现模糊的目的。没毛病吧?
下面我么认为基础都打好了,聊一聊什么是均值滤波。
均值滤波
均值滤波其实就是对目标像素及周边像素取平均值后再填会目标像素来实现滤波目的的方法。
邻域滤波
我们先通过一张图了解一下什么是邻域滤波。
邻域运算是一个概念的泛称,如上图所示,是通过对目标像素的邻域进行加权得到新的目标像素的值,其中这个加权矩阵我们叫做邻域算子(局部算子)。你们也许看出来了,这不就是卷积的过程吗?没错,我们把动图的一个像素的运算拿出来:
其中g(x, y)就是我们滤波后希望得到的函数,h(x, y)就是邻域算子,f(x, y)就是原图。那么有公式可以表示:
可以简单的记做:
拓展:什么是卷积?
视频
https://www.bilibili.com/video/av16187470?from=search&seid=8988027371731538619www.bilibili.com文字
如何通俗易懂地解释卷积?www.zhihu.com说一千,道一万。感觉咱们作为非数学专业的工程人员,只要认为卷积=加权和就好了。
均值滤波
一句话,就是邻域算子都是1/M*N的一种特殊形式的邻域滤波。
C++
额,OpenCV中提供了现成的均值函数,blur().
CV_EXPORTS_W void blur( InputArray src, OutputArray dst,
Size ksize, Point anchor = Point(-1,-1),
int borderType = BORDER_DEFAULT );
滤波代码:
#include
运行结果:
Python:
#!/usr/bin/env python
运行结果:
打完收工?总感觉有点意犹未尽。在code的时候发现邻域算子的大小设定对处理结果起决定性的作用,要是有什么办法可以直观的看到就好了。不如用滑动进度条来。
貌似没有什么难度,只贴C++的吧:
#include
写在后面
前戏做足了,代码也写完了,不知道你有没有感觉少了点什么东西?我们讲了那么多滤波的铺垫,那么为什么均值滤波可以做到模糊呢?这个问题等价于,均值滤波为什么是一个低通滤波器呢?
我们先做出均值滤波的kernel h(x, y)函数表达式
怎么看一个函数是否可以做滤波器?做什么滤波器呢?傅里叶变换:
因此频域上就是
而且空域上这个方向的窗长越大,频域上从低频到高频过渡越陡峭,这也就是为什么做均值滤波的时候kernel的尺寸越大滤波结果越模糊的原因。但是由于sinc函数有波动性,一些高频的成分还是会残留,因此均值滤波给人感觉还是不太平滑。