opencv高斯滤波(opencv高斯滤波函数)

本篇文章给大家谈谈opencv高斯滤波,以及opencv高斯滤波函数对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

OpenCV 中的滤波函数

也称为 box filter、均值滤波器,就是简单地将每个像素的值替换成邻域平均值。

如果用 kernel (也称为 mask) 表示,就是

如果采用积分图的方法,可以更快的计算这种 box filter 的结果。

在积分图中,只需要三次加法运算,一次乘法运算即可,即通过积分图,算出 kernel 内部区域的像素和,然后取平均。

积分图中每一点 的值是原图中对应位置左上角区域所有值的和:

积分图的计算可以很高效:

每次计算只需要新增一个像素值,其他值都是之前已经计算出来的。

积分图一旦计算出来,对任意矩形区域内 像素和 的计算都可以在常数时间(即计算时间固定,与区域的大小无关)内完成,例如:

在高斯滤波器中,当前像素值取邻域的 加权平均 ,离当前像素越近,权重越大,权重服从高斯分布。

在实际应用中,几乎总是首选高斯滤波器,很少直接用 box filter.

上述命令中,最后两个参数 kernel size 和 如果只设置一个,则另一个可以通过以下公式推出:

第二个式子很好理解,就是借助高斯函数的性质(距离均值 3 个标准差范围内的取值占总数的 99.7%),因此窗口大小就是 3 倍的 *2 (两边)然后再加上 1 (自身)。

第一个式子与第二个非常近似,但是又做了一些微调。

上述高斯滤波器内部实际上是先调用如下函数,产生服从高斯分布的一系列权重:

上述 9 个权重是经过归一化的,即和为 1,其公式为

其中 满足归一化的要求,ksize 必须是奇数。如果要生成二维的高斯矩阵权重,则是先产生一个权重列向量,然后令该列向量与自身的转置相乘,得到高斯矩阵权重,最后再统一进行归一化,保证矩阵所有元素和为 1。

另外,还可以分别产生两个不同的高斯权重向量,对应行和列方向上的高斯模糊权重,然后把它们相乘得到高斯矩阵。由于满足这种分离的性质,高斯滤波器被称为可分离的滤波器。

前边在进行滤波操作时,都只包含线性操作(算数平均、加权平均)。

另外还可以采用非线性操作,对应非线性滤波器。非线性滤波器不能表示成 kernel 矩阵卷积枝渣操作的形式。

中值滤波器是一种非线性滤波器。它把当前像素和邻域像素组成一个集合,排序之后,选择中间值(即排序中间位置猛粗悄的数值)替换当前像素值。

椒盐噪声 :像素随机替换成白色或者黑点。在通讯时,如果部分像素值丢失,就会产生这种噪声。

中值滤波器可以有效的消除椒盐噪声,因为这些噪声点在排序时很难成为中间值,因此全都被剔除了。

Sobel 也是线性滤波器,只不过采用了特殊的 kernel 矩阵:

分别针对水平方向和垂直方向的操作。

用上述 kernel 进行操作,就是计算水平或者垂直方向像素值的差分,近似反映了像素值水平和垂直变化的速度,合在一起就是图像梯度的近似。

在默认情况下,差分运算的结果很可能超过 [0,255] 这个范围,而且有正有负,应该用 CV_16S 数据类型表示。经过上述缩放和偏移之后,才勉强适合用 CV_8U 表示,但还是需要饱和截断操作。

在分别得到横向、纵向变化率之后,可以整合起来计算梯度的大小

一般如果要显示最后的 sobel 边缘检测的结果,还需要把凳颂上述模值转化到 [0,255] 范围内。

sobel 实际上包含了平滑和求导两个操作,其中邻域像素累加相当于高斯平滑,距离越近的像素权重越高。

sobel 的 kernel size 可以选择 1, 3, 5 和 7,其中 1 代表 1×3 或者 3×1,此时是没有高斯平滑的。

对于大的 size,这种平滑更明显。此时,sobel 不是高通滤波器,而是带通滤波器,既消除了部分高频,又消除了部分低频。

与 Sobel 算子类似的还有其他几个计算梯度的算子,只是采用不同的 kernel.

上述所有的滤波器都是近似计算图像函数的一阶导数,像素变化大的区域计算得到的值较大,平坦的区域计算值较小。

sobel 算子通过对图片函数求导,那些数值绝对值较高的点对应了边界区域:

如果继续求二阶导,则导数较大的点对应了过零点:

因此,也可以通过搜索二阶导的过零点来检测边界点。

Laplacian 算子的定义 :

对照 Hessian 矩阵:

Laplacian 算子实际上就是 Hessian 矩阵的 Trace。

具体到图像操作中,二阶导有如下表达式:

所以最终 Laplacian 算子表达式为:

在具体实现中,可以用以下 kernel 进行卷积操作:

Laplacian 算子具有旋转 90 度不变性,即一幅图旋转 90 度及其倍数,对应的 Laplacian 算子操作结果相同。

为了得到更好的旋转不变性,可以将 Laplacian 算子 kernel 扩展为如下形式:

这样就具有了旋转 45 度及其倍数的不变性。

Laplacian 算子对噪声比较敏感,因此一般在进行 Laplacian 之前先进行高斯平滑滤波。

两个步骤合并称为 LoG (Laplacian of Gaussian)。

在具体实现中,我们并不需要先高斯再拉普拉斯,而是两步并作一步:将拉普拉斯算子作用在高斯 kernel 上,得到新的 kernel,再与 image 做卷积:

最后作用在 位置上的卷积权重为

同样也是通过 设定滤波范围。

对高斯函数取拉普拉斯算子操作是什么样子的?

二维情况下得到的曲面很像“墨西哥草帽”。

的大小决定了检测的粗粒度:

Difference of Gaussians

为了减少 LoG 计算量,用两个不同 的高斯做差,来近似 LoG

上图中两个 的取值好像反了。。。

[img]

OpenCV Python 系列教程4 - OpenCV 图像处理(上)

学习目标:

OpenCV 中有 150 多种色彩空间转化的方法,这里只讨论两种:

HSV的色相范围为[0,179],饱和度范围为[0,255],值范围为[0,255]。不同的软件使用不同的规模。如果要比较 OpenCV 值和它们,你需要标准化这些范围。

HSV 和 HLV 解释

运行结果:该段程序的作用是检测蓝色目标,同理可以检测其他颜色的目标

结果中存在一定的噪音,之后的章节将会去掉它

这是物体跟踪中最简单的方法。一旦你学会了等高线的函数,你可以做很多事情,比如找到这个物体的质心,用它来跟踪这个物体拿拆,仅仅通过在相机前移动你的手来画图表,还有很多其他有趣的事情。

菜鸟教程 在线 HSV- BGR 转换

比如要找出绿色的 HSV 值,可以使用上面的程序,得到的值取一个上下界。如上含敏悄面的取下界 [H-10, 100, 100],上界 [H+10, 255, 255]

或者使用其他工具如 GIMP

学习目标:

对图像进行阈值处理,算是一种最简单的图像分割方法,基于图像与背景之间的灰度差异,此项分割是基于像素级的分割

threshold(src, thresh, maxval, type[, dst]) - retval, dst

计算图像小区域的阈值。所以我们对同一幅图像的不同区域得到不同的阈值,这给我们在不同光照下的图像提供了更好的结果。

三个特殊的输入参数和一个输出参数

adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst]) - dst

opencv-threshold-python

OpenCV 图片集

本节原文

学习目标:

OpenCV 提供两种变换函数: cv2.warpAffine 和 cv2.warpPerspective

cv2.resize() 完成缩放

文档说明

运行结果

说明 : cv2.INTER_LINEAR 方法比 cv2.INTER_CUBIC 还慢,好像与官方文档说的不一致? 有待验证。

速度比较: INTER_CUBIC INTER_NEAREST INTER_LINEAR INTER_AREA INTER_LANCZOS4

改变图像的位置,创建一个 np.float32 类型的变换矩阵,

warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) - dst

运行结果:

旋转角度( )是通过一个变换矩阵变换的:

OpenCV 提供的是可调旋谈渣转中心的缩放旋转,这样你可以在任何你喜欢的位置旋转。修正后的变换矩阵为

这里

OpenCV 提供了 cv2.getRotationMatrix2D 控制

cv2.getRotationMatrix2D(center, angle, scale) → retval

运行结果

cv2.getAffineTransform(src, dst) → retval

函数关系:

\begin{bmatrix} x'_i \ y'_i \end{bmatrix}\begin{bmatrix} x'_i \ y'_i \end{bmatrix} =

其中

运行结果:图上的点便于观察,两图中的红点是相互对应的

透视变换需要一个 3x3 变换矩阵。转换之后直线仍然保持笔直,要找到这个变换矩阵,需要输入图像上的 4 个点和输出图像上的对应点。在这 4 个点中,有 3 个不应该共线。通过 cv2.getPerspectiveTransform 计算得到变换矩阵,得到的矩阵 cv2.warpPerspective 变换得到最终结果。

本节原文

平滑处理(smoothing)也称模糊处理(bluring),是一种简单且使用频率很高的图像处理方法。平滑处理的用途:常见是用来 减少图像上的噪点或失真 。在涉及到降低图像分辨率时,平滑处理是很好用的方法。

图像滤波:尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。

消除图像中的噪声成分叫做图像的平滑化或滤波操作。信号或图像的能量大部分集中在幅度谱的低频和中频段,在高频段,有用的信息会被噪声淹没。因此一个能降低高频成分幅度的滤波器就能够减弱噪声的影响。

滤波的目的:抽出对象的特征作为图像识别的特征模式;为适应图像处理的要求,消除图像数字化时混入的噪声。

滤波处理的要求:不能损坏图像的轮廓及边缘等重要信息;图像清晰视觉效果好。

平滑滤波是低频增强的空间滤波技术,目的:模糊和消除噪音。

空间域的平滑滤波一般采用简单平均法,即求邻近像元点的平均亮度值。邻域的大小与平滑的效果直接相关,邻域越大平滑效果越好,但是邻域过大,平滑也会使边缘信息的损失的越大,从而使输出图像变得模糊。因此需要选择合适的邻域。

滤波器:一个包含加权系数的窗口,利用滤波器平滑处理图像时,把这个窗口放在图像上,透过这个窗口来看我们得到的图像。

线性滤波器:用于剔除输入信号中不想要的频率或者从许多频率中选择一个想要的频率。

低通滤波器、高通滤波器、带通滤波器、带阻滤波器、全通滤波器、陷波滤波器

boxFilter(src, ddepth, ksize[, dst[, anchor[, normalize[, borderType]]]]) - dst

均值滤波是方框滤波归一化后的特殊情况。归一化就是要把处理的量缩放到一个范围内如 (0,1),以便统一处理和直观量化。非归一化的方框滤波用于计算每个像素邻近内的积分特性,比如密集光流算法中用到的图像倒数的协方差矩阵。

运行结果:

均值滤波是典型的线性滤波算法,主要方法为邻域平均法,即用一片图像区域的各个像素的均值来代替原图像中的各个像素值。一般需要在图像上对目标像素给出一个模板(内核),该模板包括了其周围的临近像素(比如以目标像素为中心的周围8(3x3-1)个像素,构成一个滤波模板,即 去掉目标像素本身 )。再用模板中的全体像素的平均值来代替原来像素值。即对待处理的当前像素点(x,y),选择一个模板,该模板由其近邻的若干像素组成,求模板中所有像素的均值,再把该均值赋予当前像素点(x,y),作为处理后图像在该点上的灰度个g(x,y),即个g(x,y)=1/m ∑f(x,y) ,其中m为该模板中包含当前像素在内的像素总个数。

均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。

cv2.blur(src, ksize[, dst[, anchor[, borderType]]]) → dst

结果:

高斯滤波:线性滤波,可以消除高斯噪声,广泛应用于图像处理的减噪过程。高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过 加权平均 后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。

高斯滤波有用但是效率不高。

高斯模糊技术生成的图像,其视觉效果就像是经过一个半透明屏幕在观察图像,这与镜头焦外成像效果散景以及普通照明阴影中的效果都明显不同。高斯平滑也用于计算机视觉算法中的预先处理阶段,以增强图像在不同比例大小下的图像效果(参见尺度空间表示以及尺度空间实现)。从数学的角度来看,图像的高斯模糊过程就是图像与正态分布做卷积。由于正态分布又叫作高斯分布,所以这项技术就叫作高斯模糊。

高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器。 高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。

一维零均值高斯函数为: 高斯分布参数 决定了高斯函数的宽度。

高斯噪声的产生

GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]]) - dst

线性滤波容易构造,并且易于从频率响应的角度来进行分析。

许多情况,使用近邻像素的非线性滤波会得到更好的结果。比如在噪声是散粒噪声而不是高斯噪声,即图像偶尔会出现很大值的时候,用高斯滤波器进行图像模糊时,噪声像素不会被消除,而是转化为更为柔和但仍然可见的散粒。

中值滤波(Median filter)是一种典型的非线性滤波技术,基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,该方法在去除脉冲噪声、椒盐噪声『椒盐噪声又称脉冲噪声,它随机改变一些像素值,是由图像传感器,传输信道,解码处理等产生的黑白相间的亮暗点噪声。椒盐噪声往往由图像切割引起。』的同时又能保留图像边缘细节,

中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,其基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点,对于 斑点噪声(speckle noise)和椒盐噪声(salt-and-pepper noise) 来说尤其有用,因为它不依赖于邻域内那些与典型值差别很大的值。中值滤波器在处理连续图像窗函数时与线性滤波器的工作方式类似,但滤波过程却不再是加权运算。

中值滤波在一定的条件下可以克服常见线性滤波器如最小均方滤波、方框滤波器、均值滤波等带来的图像细节模糊,而且对滤除脉冲干扰及图像扫描噪声非常有效,也常用于保护边缘信息, 保存边缘的特性使它在不希望出现边缘模糊的场合也很有用,是非常经典的平滑噪声处理方法。

与均值滤波比较:

说明:中值滤波在一定条件下,可以克服线性滤波器(如均值滤波等)所带来的图像细节模糊,而且对滤除脉冲干扰即图像扫描噪声最为有效。在实际运算过程中并不需要图像的统计特性,也给计算带来不少方便。 但是对一些细节多,特别是线、尖顶等细节多的图像不宜采用中值滤波。

双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合 图像的空间邻近度和像素值相似度 的一种折衷处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。具有简单、非迭代、局部的特点。

双边滤波器的好处是可以做边缘保存(edge preserving),一般过去用的维纳滤波或者高斯滤波去降噪,都会较明显地模糊边缘,对于高频细节的保护效果并不明显。双边滤波器顾名思义比高斯滤波多了一个高斯方差 sigma-d ,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素值,这样就保证了边缘附近像素值的保存。 但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤波。

运行结果

学习目标:

形态变换是基于图像形状的一些简单操作。它通常在二进制图像上执行。

膨胀与腐蚀实现的功能

侵蚀的基本思想就像土壤侵蚀一样,它会侵蚀前景物体的边界(总是试图保持前景为白色)。那它是做什么的?内核在图像中滑动(如在2D卷积中)。只有当内核下的所有像素都是 1 时,原始图像中的像素( 1 或 0 )才会被视为 1 ,否则它将被侵蚀(变为零)

erode(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]) - dst

与腐蚀的操作相反。如果内核下的至少一个像素为“1”,则像素元素为“1”。因此它增加了图像中的白色区域或前景对象的大小增加。通常,在去除噪音的情况下,侵蚀之后是扩张。因为,侵蚀会消除白噪声,但它也会缩小我们的物体。所以我们扩大它。由于噪音消失了,它们不会再回来,但我们的物体区域会增加。它也可用于连接对象的破碎部分

openCV:图像的平滑去噪

低频就是颜色缓慢变化,也就是灰度缓慢地变化,就代表着那是连续渐变的一块区域。相反高频即灰度变化快,相邻区域的灰度差别大,例如边缘,噪点都是灰度变化快的区域。

图像平滑是要突出图像的低频成分、主干部分或抑制图像噪声和干扰高频成分的图像处枣哪理方法,目的是使图像亮度平缓渐变,减小突变梯度,改善图像质量。字面意思就是让图像上颜色灰度变化更光滑。我们也称图像平滑为图像模糊,因为在平滑的时候,也失去了尖锐的特点。

现实中的数字图像在数字化和传输过程中凳谨码常受到成像设备与外部环境噪声干扰等影响,称为含噪图像或噪声图像。那么除去这些噪声的过程就是图像去噪。

均值滤波也成线性滤波,其采用的主晌培要方法为邻域平均法。线性滤波的基本原理是用原图像中某个像素临近值的均值代替原图像中的像素值。即滤波器的核(kernel)中所有的系数都相等,然后用该核去对图像做卷积。

基本和均值一样,即滤波器的核(kernel)中所有的系数都相等。但是它可以选择是否归一化,如果归一化,则和均值滤波毫无差别;若不选择归一化,则会导致像素点的值超过255,发生越界。

高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。

高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的,离得越近的像素点发挥的作用越大。

高斯核主要取决于σ。如果σ越小,高斯分布中心区域更加聚集,平滑效果越差;反之,则更离散,平滑效果越明显。

中值滤波器,使用滤波器窗口包含区域的像素值的中值来得到窗口中心的像素值。是一种非线性平滑滤波器。在去噪同时,较好的保持边缘轮廓细节,适合处理椒盐噪声,但对高斯噪声效果不好。

双边滤波器是一种可以保边去噪的滤波器,也是一种加权平均滤波器,与高斯滤波不同的是,其滤波核是由两个函数构成,一个函数是由几何空间距离决定滤波器系数,另一个由像素差值决定滤波器系数。

适合处理高斯噪声,但对椒盐噪声基本不起任何作用。

【转载】opencv 频域高通、低通滤波演示

opencv 理想滤波、巴特沃兹滤波和高斯滤波的高通、低通滤波演示

    Filter Parameters 窗口: 滤波器参数窗口

        - d0: 滤波器大小 D0

        - flag: 滤波器类型

             0 - 理想滤波

             1 - 巴特沃兹滤波

             2 - 高斯滤波

        - n: 巴特沃兹滤波的阶数

        - lh: 低拍扒通滤波 or 高通滤波

    Filtered Image 窗口: 过滤后的图像和过滤器图像

#! /usr/bin/env python

#coding=utf-8

importcv2

importnumpy as np

'''

opencv 理想滤波、巴特沃兹滤波和高斯滤波的高通、低通滤波演示

    Filter Parameters 窗口: 滤波器参数窗口

        - d0: 滤波器大小 D0

        - flag: 滤波器类型

             0 - 理想滤波

             1 - 巴特沃兹滤波

             2 - 高斯滤波

        - n: 巴特沃兹滤波的阶数

        - lh: 低通滤波 or 高通滤波

    Filtered Image 窗口: 过滤后的图像和过滤器图像

'''

defcombine_images(images, axis=1):

    '''

    合并图像。

    @param images: 图像列表(图像成员的维数必须相同)

    袭拆昌@param axis: 合并方向御袜。

        axis=0时,图像垂直合并;

        axis = 1 时, 图像水平合并。

    @return 合并后的图像

    '''

    ndim =images[0].ndim

    shapes =np.array([mat.shape format inimages])

    assertnp.all(map(lambdae: len(e)==ndim, shapes)), 'all images should be same ndim.'

    ifaxis ==0:# 垂直方向合并图像

        # 合并图像的 cols

        cols =np.max(shapes[:, 1])

        # 扩展各图像 cols大小,使得 cols一致

        copy_imgs =[cv2.copyMakeBorder(img, 0, 0, 0, cols-img.shape[1],

            cv2.BORDER_CONSTANT, (0,0,0))  forimg inimages]

        # 垂直方向合并

        returnnp.vstack(copy_imgs)

    else:# 水平方向合并图像

        # 合并图像的 rows

        rows =np.max(shapes[:, 0])

        # 扩展各图像rows大小,使得 rows一致

        copy_imgs =[cv2.copyMakeBorder(img, 0, rows-img.shape[0], 0, 0,

            cv2.BORDER_CONSTANT, (0,0,0))  forimg inimages]

        # 水平方向合并

        returnnp.hstack(copy_imgs)

deffft(img):

    '''对图像进行傅立叶变换,并返回换位后的频率矩阵'''

    assertimg.ndim==2, 'img should be gray.'

    rows, cols =img.shape[:2]

    # 计算最优尺寸

    nrows =cv2.getOptimalDFTSize(rows)

    ncols =cv2.getOptimalDFTSize(cols)

    # 根据新尺寸,建立新变换图像

    nimg =np.zeros((nrows, ncols))

    nimg[:rows,:cols] =img

    # 傅立叶变换

    fft_mat =cv2.dft(np.float32(nimg), flags=cv2.DFT_COMPLEX_OUTPUT)

    # 换位,低频部分移到中间,高频部分移到四周

    returnnp.fft.fftshift(fft_mat)

deffft_image(fft_mat):

    '''将频率矩阵转换为可视图像'''

    # log函数中加1,避免log(0)出现.

    log_mat=cv2.log(1+cv2.magnitude(fft_mat[:,:,0], fft_mat[:,:,1]))

    # 标准化到0~255之间

    cv2.normalize(log_mat, log_mat, 0, 255, cv2.NORM_MINMAX)

    returnnp.uint8(np.around(log_mat))

defifft(fft_mat):

    '''傅立叶反变换,返回反变换图像'''

    # 反换位,低频部分移到四周,高频部分移到中间

    f_ishift_mat =np.fft.ifftshift(fft_mat)

    # 傅立叶反变换

    img_back =cv2.idft(f_ishift_mat)

    # 将复数转换为幅度, sqrt(re^2 + im^2)

    img_back =cv2.magnitude(*cv2.split(img_back))

    # 标准化到0~255之间

    cv2.normalize(img_back, img_back, 0, 255, cv2.NORM_MINMAX)

    returnnp.uint8(np.around(img_back))

deffft_distances(m, n):

    '''

    计算m,n矩阵每一点距离中心的距离

    见《数字图像处理MATLAB版.冈萨雷斯》93页

    '''

    u =np.array([i ifi=m/2elsem-i fori inrange(m)], dtype=np.float32)

    v =np.array([i ifi=m/2elsem-i fori inrange(m)], dtype=np.float32)

    v.shape =n, 1

    # 每点距离矩阵左上角的距离

    ret =np.sqrt(u*u +v*v)

    # 每点距离矩阵中心的距离

    returnnp.fft.fftshift(ret)

deflpfilter(flag, rows, cols, d0, n):

    '''低通滤波器

    @param flag: 滤波器类型

        0 - 理想低通滤波

        1 - 巴特沃兹低通滤波

        2 - 高斯低通滤波

    @param rows: 被滤波的矩阵高度

    @param cols: 被滤波的矩阵宽度

    @param d0: 滤波器大小 D0

    @param n: 巴特沃兹低通滤波的阶数 

    @return 滤波器矩阵

    '''

    assertd0 0, 'd0 should be more than 0.'

    filter_mat =None

    #理想低通滤波

    ifflag ==0:

        filter_mat =np.zeros((rows, cols ,2), np.float32)

        cv2.circle(filter_mat, (rows/2, cols/2) , d0, (1,1,1), thickness=-1) 

    # 巴特沃兹低通滤波

    elifflag ==1:

        duv =fft_distances(*fft_mat.shape[:2])

        filter_mat =1/(1+np.power(duv/d0, 2*n))

        # fft_mat有2个通道,实部和虚部

        # fliter_mat 也需要2个通道

        filter_mat =cv2.merge((filter_mat, filter_mat))

    #高斯低通滤波

    else:

        duv =fft_distances(*fft_mat.shape[:2])

        filter_mat =np.exp(-(duv*duv) /(2*d0*d0))

        # fft_mat有2个通道,实部和虚部

        # fliter_mat 也需要2个通道

        filter_mat =cv2.merge((filter_mat, filter_mat))                 

    returnfilter_mat

defhpfilter(flag, rows, cols, d0, n):

    '''高通滤波器

    @param flag: 滤波器类型

        0 - 理想高通滤波

        1 - 巴特沃兹高通滤波

        2 - 高斯高通滤波

    @param rows: 被滤波的矩阵高度

    @param cols: 被滤波的矩阵宽度

    @param d0: 滤波器大小 D0

    @param n: 巴特沃兹高通滤波的阶数 

    @return 滤波器矩阵

    '''

    assertd0 0, 'd0 should be more than 0.'

    filter_mat =None

    #理想高通滤波

    ifflag ==0:

        filter_mat =np.ones((rows, cols ,2), np.float32)

        cv2.circle(filter_mat, (rows/2, cols/2) , d0, (0,0,0), thickness=-1) 

    # 巴特沃兹高通滤波

    elifflag ==1:

        duv =fft_distances(rows, cols)

        # duv有 0 值(中心距离中心为0), 为避免除以0,设中心为 0.000001

        duv[rows/2, cols/2] =0.000001

        filter_mat =1/(1+np.power(d0/duv, 2*n))

        # fft_mat有2个通道,实部和虚部

        # fliter_mat 也需要2个通道

        filter_mat =cv2.merge((filter_mat, filter_mat))

    #高斯高通滤波

    else:

        duv =fft_distances(*fft_mat.shape[:2])

        filter_mat =1-np.exp(-(duv*duv) /(2*d0*d0))

        # fft_mat有2个通道,实部和虚部

        # fliter_mat 也需要2个通道

        filter_mat =cv2.merge((filter_mat, filter_mat))                 

    returnfilter_mat

defdo_filter(_=None):

    '''滤波,并显示'''

    d0 =cv2.getTrackbarPos('d0', filter_win)

    flag =cv2.getTrackbarPos('flag', filter_win)

    n =cv2.getTrackbarPos('n', filter_win)

    lh =cv2.getTrackbarPos('lh', filter_win)

    # 滤波器

    filter_mat =None

    iflh ==0:

        filter_mat =lpfilter(flag, fft_mat.shape[0], fft_mat.shape[1], d0, n)

    else:

        filter_mat =hpfilter(flag, fft_mat.shape[0], fft_mat.shape[1], d0, n)

    # 进行滤波

    filtered_mat =filter_mat *fft_mat

    # 反变换

    img_back =ifft(filtered_mat)

    # 显示滤波后的图像和滤波器图像

    cv2.imshow(image_win, combine_images([img_back, fft_image(filter_mat)]))

if__name__ =='__main__':

    img =cv2.imread('images/Fig0515.jpg',0)

    rows, cols =img.shape[:2]

    # 滤波器窗口名称

    filter_win ='Filter Parameters'

    # 图像窗口名称

    image_win ='Filtered Image'

    cv2.namedWindow(filter_win)

    cv2.namedWindow(image_win)

    # 创建d0 tracker, d0为过滤器大小

    cv2.createTrackbar('d0', filter_win, 20, min(rows, cols)/4, do_filter)

    # 创建flag tracker,

    # flag=0时,为理想滤波

    # flag=1时,为巴特沃兹滤波

    # flag=2时,为高斯滤波

    cv2.createTrackbar('flag', filter_win, 0, 2, do_filter)

    # 创建n tracker

    # n 为巴特沃兹滤波的阶数

    cv2.createTrackbar('n', filter_win, 1, 5, do_filter)

    # 创建lh tracker

    # lh: 滤波器是低通还是高通, 0 为低通, 1为高通

    cv2.createTrackbar('lh', filter_win, 0, 1, do_filter)

    fft_mat =fft(img)

    do_filter()

    cv2.resizeWindow(filter_win, 512, 20)

    cv2.waitKey(0)

    cv2.destroyAllWindows()

2.  [图片]  低通图像和滤波器.jpg

3.  [图片]  滤波器参数.jpg

OpenCV(二)掩码操作与平滑(均值,高斯模糊)

OpenCV知识总结来到了下一个难度高一点的,掩码操作和模糊效果,这是图像处理里面常见的操作。

如果遇到问题请在这里联系我:

掩码操作实际上思想上很简单:根据一个掩码矩阵(卷积核)重新计算图像中的每一个像素。掩码矩阵中的值表示近邻像素的值(包括自身像素的值)对新像素的值有多大的影响,从数学上观点看来,就是对掩码矩阵内每一个设置好权重,然后对对应的像素领域内做一个权加平均。

卷积是什么?用一个简单的公式来表示:

本质上,卷积就是这种思想。卷积把万事万物看成一个输入,当万蚂亩岁事万物的状态出现了变化,则会通过某种系统产生变化,变成另一种输出状态。而这个系统往往就在数学眼里就叫做卷积。

而在深度学习中,往往每一个卷积核是一个奇数的矩阵,做图像识别的时候会通过这个卷积核做一次过滤,筛选出必要的特征信息。

那么掩码操作在数学上是怎么回事?我们平常运用掩码做什么?在OpenCV中掩码最常见的操作就是增加图片对比度。对比度的概念是什么,在上一节聊过,通俗来讲就是能够增强像素之间的细节。我们可以对对每个像素做如下操作:

可能这幅图,理解起来比较困难。实际上流程如此:

举个例子,就以计算出掩码矩阵之后的E的位置,能看到此时是原图中所有的像素都会取出和掩码矩阵一样大小的矩阵。也就是取出原图的红色那一块的领域,分别对E周边包括自己做了一次加权处理,最后赋值回E中。

并且进行如下的权加公式:

这样就能对原来的矩阵进行掩码处理耐芹。但是这么做发现没有,如果我们要对A做掩码处理就会发现掩码矩阵对应到原图的位置不存在。现在处理有两种,一种是不对边缘的像素做掩码处理,另一种是为周边的图像做一个padding处理,这种操作在深度学习的图像处理中很常见,通常设置0像素,或者拷贝对边的边缘像素。

能看到这里处理和卷积处理不太一样,只是为了方便,把这种掩码滤波操作称为一种核,是自相关,并不是去计算卷积。

能看到此时这两张图片的对比度有很明显的区别。经过掩码矩阵之后,会发现原图会更加平滑一点,而掩码操作之后会导致整个图片最亮和最暗之间的差距拉大。

从数学公式上来看,当前像素权重为5,周边的点的权重是-1和0.能够发现会对当前的节点加深,同时把周围的像素值减掉,就增加了每一个像素点和周边像素差值,也就是对比度。

当然在OpenCV中,有这么一个函数filter2D,处理掩码操作。

这里创建一个3*3的核。这个核实际上就是上图的那个。这样传递一个掩码矩阵和图像的深度就完成了掩码操作。

平滑也称为模糊,是一项高频率使用的操作。

平滑的作用有很多,其中一项就是降噪音。平滑处理和掩码操作有点相似,也是需要一个滤波器,我们最常用的滤波器就是线性滤波器。线性滤波处理的输出像素值 是输出像素值 的权加和:

其中,h(k,l)成为核,它仅仅只是一个权加系数。图形上的操作和上面的图相似。不妨把核当成一个滑动窗口,不断的沿着闷睁原图像素的行列扫动,扫动的过程中,不断的把路过像素都平滑处理。

这里先介绍均值滤波器,它的核心如下:

这里的参数意思是,src:输入的图像,dst:经过均值模糊之后的输出图像,Size:是指这个滤波器的大小,Point是指整个图像模糊绕着哪个原点为半径的进行处理,传入(-1,-1)就是指图像中心,这样就能模糊整个图像。

其计算原理很简单就是,把核里面的所有权重设置为1,最后全部相加求平均值。最后赋值到原来的像素上。

最有用的滤波器 (尽管不是最快的)。 高斯滤波是将输入数组的每一个像素点与 高斯内核 卷积将卷积和当作输出像素值。

高斯模糊实际上是一个二维的高斯核。回顾一下一维的高斯函数:

那么二维实际上就是,就是在原来的x,y轴的情况下,增加一个z轴的纬度,实际上看起来就像一座山一样。

二维的高斯函数可以表示为:

为了达到达到

其OpenCV的调用方式:

这里的参数意思是,src:输入的图像,dst:经过高斯模糊之后的输出图像,Size:是指这个滤波器的大小。sigmaX和sigmaY分别指代的是高斯模糊x轴上和y轴上的二维高斯函数的变化幅度。

换个形象的话说,用上图举个例子,就是确定这个高斯函数这个山的x方向的陡峭程度以及y轴方向的陡峭程度。

下面就高斯模糊,均值模糊和原图的比对

能看到,高斯模糊比起均值模糊保留了图像中相关的形状信息。

为什么会这样呢?原因很简单。因为在计算高斯模糊之前,会根据当前像素区域中所有的像素点进行一次,核的计算,越往中心的权重越高,权重如同小山一下,因此中心的像素权重像素一高了,虽然模糊但是还是保留了原来的形状。

但是当高斯模糊的矩阵大小和sigmaX,sigmaY相似的时候,整个高斯函数就不像山,而是想平原一样平坦。换句话说,整个高斯核中的权重就会,偏向一,就会导致和均值模糊类似效果。

高斯模糊计算流程:

图像中某一段图形的像素是如下分布,

这个时候高斯模糊需要一个核去对每一个位置做滤波。此时不同于均值模糊,没有固定的核矩阵,而是通过上面这个矩阵,计算出高斯的核,最后再计算变化后的矩阵每一个对应的像素。

虽然原理是这样,但是实际上OpenCV为了迅速,在原生实现的时候,内部判断到核是小于7的大小,设置一套固定的高斯模糊矩阵。

这样直接就结束,不是我文章的风格,作为一个程序员,还是有必要探索一下,为什么OpenCV计算速度会比我们自己手写的快。

为了让源码看的不那么辛苦,先聊聊OpenCV底层的设计思想。首先在OpenCV中,内置了几种计算方案,按照效率高低优先度依次的向后执行。

这种设计可以看成我们的平常开发的拦截器设计。当发现优先度高的计算模式发现可以使用的时候,OpenCV将会使用这种模式下的算法进行运算。

一般来说,OpenCV内置如下四个层级计算方案,按照优先顺序依次为:

能看到按照这个优先级不断的向下查找,找到当前OpenCV最快的计算环境。除了最后一个之外,其他三个都是并发计算。

记住这个流程,我们查看OpenCV的源码就很轻松了。

先来看看filter2D的源码。

果不其然,在filter2D实现的第一步,就开始调用CV_OCL_RUN宏去调用OpenCL的显卡并发计算。

能看到,这里面发送了一个condition和一个方法到OpenCL中运行。但是如果,OpenCV在编译的时候,我们没有打开这个OpenCL的选项,没有OpenCL的环境的时候,它实际上就是一个没什么用处的宏:

当有了OpenCL的环境,这个宏就会替换成这个:

能清晰的看到,此时会判断当前的OpenCL是否还在活跃,活跃的状态,并且条件和方法符合规范,就会通过CV_IMPL_ADD,把方法添加到一个vector向量中,让OpenCL读取执行。

在这里面,OpenCV想要使用OpenCL进行计算,就需要这个Mat的类型是UMat,并且是纬度小于等于2.当不符合这两个条件将不会执行OpenCL。

UMat是专门给OpenCL规范计算而使用的矩阵。里面有很多和Mat相似的方法。

此时可能是多线程处理,因此会添加一个智能锁,去保证数据的正确性。

具体的思路,将不作为重点,这边先看看OpenCV是传入了ocl_filter2D的方法,看看这个方法在OpenCL中的执行流程。

OpenCL会把命令最后发送到显卡处理。

实际上这一步和上面的方法有点相似。本质上都是获取需要模糊的区域,如果是(-1,-1),则取中心点,接着判断当前滤波对边缘的处理(BORDER_ISOLATED 不去获取Point为圆心设置的模糊之外的区域)。

能看到这个枚举已经解释很清楚了,默认的边缘处理是复制二个和倒数第二个填充边缘。

最后进入到hal的filter2D进一步操作。

能看到这里有四种方式:

在情况1中,一般的情况replacementFilter2D返回的是一个没有实现的错误码,第二种情况是Intel的并行计算库,没有任何研究,跳过。我们来看看第三种情况和第四种情况

当然这里面判断能够使用dft的判断首先要当前必须要整张图做滤波处理,其次是不能是(0,0)的点为圆心做滤波。最后要判断当前当前的cpu指令是否支持,支持则允许核的宽 高最高为130以内使用原生实现,否则只支持核的宽 高为50以内使用原生实现。

能看到这里面的核心就是调用crossCorr,处理核以及原图的矩阵(使用了快速傅立叶处理相关性计算)。最后从同add添加到目标Mat中,由于add的delta函数为0,因此就和替代的效果一致。

能看到此时,先初始化一个FilterEngine(线性滤波引擎),接着使用apply调用滤波引擎的执行方法。

我们来看看线性引擎的创建:

实际上在这个过程中通过makePtr创建一个sharedptr的指针指向FilterEngine,其原理和Android的智能指针相似。

这个引擎不是关键关键的是getLinearFilter,这个方法创建了一个线性滤波器的实际操作对象。

我们来看看这个结构体:

能看到这里面会根据次数传进来的目标矩阵和原始矩阵的位深创建不同的滤波操作者。

假设,我们现在原图和目标图都是8位位深的矩阵,我们只需要关注下面这个构造函数。

Fliter2D结构体持有着模糊中心点,核,原/目标矩阵, 可以猜测到实际上正在做操作的就是这个结构体。

在preprocess2DKernel方法中,Fliter2D把核的相关信息存储到coords,coeffs中

可以看到此时会判断当前的核矩阵中type是什么,接着再把矩阵中每一个不为0的位置设置进coords,像素数值设置到_coeffs。此时相当于把核矩阵展开成一个向量。

能看到此时滤波引擎会先调用FilterEngine__start,再调用FilterEngine__proceed执行计算。

实际上在FilterEngine__start中计算的是本次循环,需要计算的边界。

FilterEngine__proceed中才是正式计算,做dst循环,最后把具体操作丢给线性引擎生成的Fliter2D的方法中。

了解这两个东西我们直接抽出核心看看fliter是如何运作:

OpenCV-Python系列六:图像滤波

图像滤波是一种十分常见的图像处理手段。通常,你可以认为相邻位置像素是紧密联系的,它们共同来显示对某个物体,图像滤波则通过运算来排除图像中和周围相差庆闭大的像素。当然,这并不是绝对的, 有时候你为了评估图像的质量,也会将这些“特立独行”的像素作为选取的目标 。无论你采用什么方法,记住你要的目标就行,有时候你的目标可能是别人的背景。

滤波常常会使得图像变得模糊(非绝对),那么,为什么你需要将一幅清晰的图像变得模糊呢?下面的例子应该可以解释。

高斯滤波采用满足正态分布的核模板,其参数的主要参数是标准差σ,代表核的离散程度,σ值越小,模板中心系数与边缘系数差越大,平滑的程度越小。

高斯滤波对图像采集过程中由于不良照明/高温引起的传感器噪声信号有较好的效果,消除了图像中的高频信号。

由于得到的是一维的Gaussian Kernel,你可以采用下面的方式转为二维的

为了便于直观感受高斯滤波的效果,使用Canny算子来提取轮廓对比,你可以试试在特征提取前加高斯滤波对比。

补充说明:对于均值滤波,你也可以使用cv2.boxFilter(src, ddepth, ksize[, dst[, anchor[, normalize[, borderType]]]])来实现,需要将normalize设置为True,当设置normalize为False时,实现的是将kernel内像素相加,官方文档做出的描述为:

中值滤波对图像中誉迅裂的脉冲型(椒盐等)噪声信号处理效果好,当 你的应用场景存在这种颗粒感的噪声信号时,中值滤波会昌哪是一种很好的选择 。它,选取kernel区域内像素点集的中值最为锚点的像素值,对类似投票机制中的最高分(高灰阶点)和最低分(过低灰阶点)影响有很好的抑制作用。

如果你的应用涉及到图像美化,双边滤波可以初步达到你的期望,关于双边滤波,这里不做展开,由你来探索,其函数参数信息如下。

对于opencv-python的图像滤波部分有问题欢迎留言, Have Fun With OpenCV-Python, 下期见。

关于opencv高斯滤波和opencv高斯滤波函数的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

标签列表