高斯滤波和均值滤波

二维码识别引出的问题

最近在做二维码的识别,其实就是调用微信二维码的opencv接口,但是遇到一些问题,有部分的二维码无法识别,大概是1100张里面有将近70张左右,感觉概率还挺高的。

而且有的二维码直接用手机微信的二维码扫描是可以识别的,但是在程序里是没办法识别的,这就让人摸不着头脑。按道理来说应该用的是一样的代码(如果微信没有偷偷优化的话)。没理由手机能识别,而程序里的没办法识别。经过观察发现,手机微信在静止状态下,其实也很难识别,得是运动状态,带些抖动,造成一点运动模糊,才能快速地将二维码识别出来。又观察了一下扫描上来的二维码,锐化程度很高,而且可能细节有些缺失,所以导致的识别失败。

于是我就在思考,我可不可以在程序里模仿这种运动模糊,来提升识别的成功率。便试着加了一个高斯模糊,发现确实识别成功率提升了,1100多张图片,大概只有7张无法识别了。

虽然,识别成功率确实大幅度提升了,但是我感觉太玄学了(笑),还不清楚其中的原理,如果各位大佬知道原理的话请告诉我。

下面是我接触线性滤波时候的一些笔记。

1 高斯滤波

1.1 参考资料

  • opencv官方文档
  • 图像处理算法其实都很简单
  • 空间相关和卷积操作

关键字:相关操作(correlation),2D高斯核生成,

1.2 API

我们在模糊一张图片的时候,我们使用的是高斯模糊GaussianBlur
下面是C++和python中的函数方法:

C++:
void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT )
Python: 
cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]]) → dst

可以看出来,在python中有6个参数:

  • src:要处理的源图,通道数无所谓,但是深度要CV_8U, CV_16U, CV_16S, CV_32F或者CV_64F
  • ksize:高斯核尺寸
  • sigmaX:x轴方向高斯核的标准差
  • sigmaY:y轴方向高斯核的标准差
  • dst:输出图片(和源图一样的尺寸和类型)
  • borderType:边缘处的处理类型

一般来说,srcksizesigmaX这三个参数是必填的,剩下的sigmaYdstborderType是选填的。

  • ksize必须是奇数,高宽可以不一样,值可以为0,这样就会从sigmaXsigmaY中计算得到宽高.
  • 如果sigmaY是0的话,就会被设定为等于sigmaX,但是如果它们两者都是0,则会从高斯核的宽高中计算得到。
	dst = cv2.GaussianBlur(src, (3, 3), 0)

上面就是最简单的高斯模糊的代码,不过为了避免未知错误,最好还是把ksizesigmaXsigmaY几个值都设定好。

1.2 原理

既然名字叫高斯滤波,高斯体现在哪里呢?

1.2.1 高斯分布

1.2.1.1一元高斯分布

高斯滤波和均值滤波_第1张图片
在概率论的时候我们都学过一维高斯函数,也叫正态分布,其表达式是:
f ( x ) = 1 2 π σ e − ( x − μ ) 2 2 σ 2 , − ∞ < x < ∞ f(x) = \frac{1}{\sqrt{2\pi } \sigma } e^{-\frac{(x-\mu )^2 }{2 \sigma ^2} } , -\infty < x < \infty f(x)=2π σ1e2σ2(xμ)2,<x<

  • σ \sigma σ:是标准差,读作sigma,也就是上面API中的sigmaX和sigmaY
  • μ \mu μ:是平均值,一般为0,这样在高斯分布的中心点就会在0处

所以实际可以设定的参数大概只有 σ \sigma σ,设定好了 σ \sigma σ就可以根据 x x x得到 f ( x ) f(x) f(x)的值了。

1.2.1.2 二元高斯分布

因为我们的处理对象是图像,有着两个维度,所以我们需要的是二维的高斯函数:
f ( x , y ) = 1 2 π σ x σ y 1 − ρ 2 exp ⁡ [ − 1 2 ( 1 − ρ 2 ) ( ( x − μ x ) 2 σ x 2 − 2 ρ ( x − μ x ) ( y − μ y ) σ x σ y + ( y − μ y ) 2 σ y 2 ) ] f(x, y) = \frac{1}{2\pi \sigma_x \sigma _y \sqrt[]{1-\rho^2} } \exp \left[-\frac{1}{2(1- \rho ^2)}\left ( \frac{(x- \mu_x)^2}{\sigma _x^2} - \frac{2\rho (x-\mu_x )(y-\mu_y)}{\sigma _x \sigma _y} +\frac{(y- \mu_y)^2}{\sigma _y^2} \right ) \right ] f(x,y)=2πσxσy1ρ2 1exp[2(1ρ2)1(σx2(xμx)2σxσy2ρ(xμx)(yμy)+σy2(yμy)2)]
我们的高斯卷积核的生成就是根据这个公式来的。在使用GausssianBlur函数的时候,想要得到一个高斯核的话,就肯定要知道 σ x \sigma_x σx σ y \sigma_y σy

1.2.1.3 多元高斯分布

多元高斯分布完全解析

1.2.2 高斯核生成

1.2.2.1 σ \sigma σ值求解 -> 1D高斯核

getGaussianKernel:生成1D高斯核的函数,参数是ksize和 σ \sigma σ标准差

我们回到一维,就像官方文档里写的,两个 σ \sigma σ值可以通过高斯核的尺寸来获得,也就是官方提供了一个预设值,这个预设值和尺寸有着某种数量关系,在getGaussianKernel函数里可以发现:
σ = 0.3 ⋅ ( ( ksize − 1 ) ⋅ 0.5 − 1 ) + 0.8 \sigma = 0.3 \cdot ((\text{ksize}-1) \cdot 0.5 - 1) + 0.8 σ=0.3((ksize1)0.51)+0.8这样的话,在一个维度上,一维高斯函数可以表示为: f ( x ) = α ⋅ e − ( x − ksize-1 2 ) 2 2 σ 2 f(x) = \alpha \cdot e ^{-\frac{\left(x-\frac{\text{ksize-1}}{2} \right)^2}{2 \sigma ^2} } f(x)=αe2σ2(x2ksize-1)2

  • μ = ksize − 1 2 \mu = \frac{\text{ksize}-1}{2} μ=2ksize1:相当于求高斯核的中心的位置
  • α \alpha α:是一个归一化参数,使得 ∑ x f ( x ) = 1 \sum_x{f(x)}=1 xf(x)=1

为什么要进行归一化?

目标图像的亮度:如果卷积核的各行各列元素之和为1,则经过处理后输出的目标图像和源图像的亮度一致。

1.2.2.2 两个1D高斯核 -> 2D高斯核

通过 x x x y y y两个方向的1D高斯核的相乘,我们可以生成一个2D高斯核,如果两者是相同的话,就相当于:与自己的转置相乘。
举个例子,生成ksize为3, σ \sigma σ为1的2D高斯核

	print(cv2.getGaussianKernel(3, 1).T * cv2.getGaussianKernel(3, 1))
	[[0.07511361 0.1238414  0.07511361]
 	[0.1238414  0.20417996 0.1238414 ]
 	[0.07511361 0.1238414  0.07511361]]

*这个只是测试,和GausssianBlur生成的高斯核肯定是不一样的。

1.2.2.3 利用高斯核对源图进行处理

相关与卷积

在高斯模糊中采用的是滑动加权平均,是一种协相关操作(correlation)。

这里涉及到我们在图像处理中常见的两种操作:协相关(correlation)和卷积(convolution)

  • 相同点:协相关和卷积非常接近,两者的本质都是乘积之和。
  • 不同点:但是两者唯一区别在于,卷积要先将卷积核旋转180°(如果卷积核是对称的,则两者无区别)。

高斯滤波和均值滤波_第2张图片
上图就是一个协相关的操作过程。

2 均值滤波

均值滤波,和高通滤波一样,也是一种低通滤波,用于模糊图像。

原理也是非常简单,计算一个窗口内像素的平均值,然后输出到目标图像的锚点。

其实本质和高斯滤波一样,都要对高斯核内的数值进行归一化,只不过高斯滤波的卷积核为不同的区域根据高斯分布分配了不同的权重,而均匀滤波的卷积核中全部区域的数值都是相等的。

2.1 API

C++和python中的函数方法:

C++: 
void blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT )
Python: 
cv2.blur(src, ksize[, dst[, anchor[, borderType]]]) → dst

其他的参数都已经比较熟悉了,单独来说一下anchor

  • anchor:有一个默认值 ( − 1 , − 1 ) (-1, -1) (1,1),表示锚点在核的中心

2.2 高通和低通滤波

既然均值滤波本身没啥可以讲的,我们可以拓展的说一下高通和低通滤波。就我们所知,均值滤波和高斯滤波都属于低通滤波,所以会对图像进行模糊处理。(与之相反,高通滤波,则会对图像进行锐化处理)

高通和低通其实都是频域上的概念,通过对核函数求傅里叶变化,就可以得到卷积核的频域表达形式,也就能直观的看出滤波器的特性了。

  • (十五)初识滤波之均值滤波:在这篇文章的最后有均值滤波核函数的傅里叶变换。

如果想相比较直观的看出一个滤波器是高通还是低通,还是得看频域的曲线图,以后有时间再补吧。

这么看的话,边缘信息算是高频的信息了,在经过低通滤波器的处理之后,会被去除。

你可能感兴趣的:(图像处理,均值算法,opencv,python,图像处理)