滤波、漫水填充、图像金字塔、图像缩放、阈值化

  imgpro 组件是 Image 和 Process 这两个单词的缩写组合,即图像处理模块,这个模块包含了如下内容:

文章目录

1.线性滤波:方框滤波、均值滤波、高斯滤波

1.1 平滑处理

  平滑处理(smoothing)也称模糊处理(bluring),是一种简单且使用频率很高的图像处理方法。最常见的用途是用来减少图像上的噪点或者失真。

1.2 图像滤波与滤波器

  图像滤波,指在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理的分析和有效性和可靠性。
  消除图像中的噪声成分叫做图像的平滑化或滤波操作。信号或图像的能量大部分集中在幅度谱的低频和中频段,而在较高频段,有用的信息经常被噪声淹没。因此一个能降低高频成分幅度的滤波器就能减弱噪声的影响。
  图像滤波的目的有两个:一个是抽出对象的特征作为图像识别的特征模式,另一个是为适应图像处理的要求,消除图像数字化时所混入的噪声。
  而对滤波处理的要求也有两条:一是不能损坏图像的轮廓及边缘等重要信息,二是使图像清晰视觉效果好。
  平滑滤波是低频增强的空间滤波技术。它的目的有两类:一类是模糊,另一类是消除噪声。
  空间域的平滑滤波一般采用简单平均法进行,就是求邻近像元点平均亮度值。邻域的大小与平滑的效果直接相关,邻域越大平滑效果越好,但邻域过大,平滑也会使边缘信息损失的越大,从而使输出的图像变得模糊,因此需合理选择邻域的大小。
  关于滤波器,一种形象的比喻是:可以把滤波器想象成一个包含加权系数的窗口,当使用这个滤波器平滑处理图像时,就可以把这个窗口放到图像之上,透过这个窗口来看我们得到的图像。
  滤波器的种类有很多,在 OpenCV 中,提供了如下 5 种常用的图像平滑处理操作方法。
  ● 方框滤波------BoxBlur 函数
  ● 均值滤波(邻域平均滤波)------ Blur 函数
  ● 高斯滤波------GaussianBlur 函数
  ● 中值滤波------medianBlur 函数
  ● 双边滤波------bilateralFilter 函数
  其中,线性滤波的有方框滤波、均值滤波和高斯滤波,非线性滤波的有中值滤波和双边滤波

1.3 线性滤波器的简介

  线性滤波器:常用于剔除输入信号中不想要的频率或者从许多频率中选择一个想要的频率。
  几种常见的线性滤波器如下:
  ● 低通滤波器:允许低频率通过。
  ● 高通滤波器:允许高频率通过。
  ● 带通滤波器:允许一定范围频率通过。
  ● 带阻滤波器:阻止一定范围频率通过并且允许其他频率通过。
  ● 全通滤波器:允许所有频率通过,仅仅改变相位关系。
  ● 陷波滤波器:阻止一个狭窄频率范围通过,是一种特殊的带阻滤波器。

1.4 滤波和模糊

  以高斯滤波为例,滤波可分为低通滤波和高通滤波两种:高斯滤波是指用高斯函数作为滤波函数的滤波操作,至于是不是模糊,要看是高斯低通还是高斯高通,低通就是模糊,高通就是锐化。
  ● 高斯滤波是指用高斯函数作为滤波函数的滤波操作。
  ● 高斯模糊就是高斯低通滤波。

1.5 邻域算子与线性邻域滤波

  邻域算子(局部算子)是利用给定像素周围的像素值的决定此像素的最终输出值的一种算子。而线性邻域滤波就是一种常用的邻域算子,像素的输出值取决于输入像素的加权和。
  邻域算子除了用于局部色调调整以外,还可以用于图像滤波,以实现图像的平滑和锐化,图像边缘增强或者图像噪声的去除。

  线性滤波处理的输出像素值 g(i,j) 是输入像素值 f(i + k , j + I)h(k, I) 的加权和,如下:
              
  其中的 h(k, l),我们称其为 “核”,是滤波器的加权系数,即滤波器的 ""滤波系数 。
  上面的式子可以简单写作:
                  
  其中 f 表示输入像素值,h 表示加权系数 “核”,g 表示输出像素值。

1.6 方框滤波(box Filter)

  方框滤波被封装在 boxblur 函数中,作用是使用方框滤波器来模糊一张图片,从 src 输入,从 dst 输出。
  函数原型如下:

void boxFilter(InputArray src, 
			OutputArray dst, 
			int ddepth, 
			Size ksize, 
			Point anchor = Point(-1, -1), 
			boolnormalize = true, 
			int borderType = BORDER_DEFAULT
		)

  ● 第一个参数:src,输入图像。该函数对通道是独立处理的,且可以处理任意通道的图片,但待处理的图片深度应该为 CV_8U、CV_16U、CV_16S、CV_32F 以及 CV_64F 之一。
  ● 第二个参数:dst,目标图像。
  ● 第三个参数:ddepth,输出图像的深度,-1 代表使用原图深度,即 src.depth()。
  ● 第四个参数:Size 类型的 ksize,内核的大小。一般采用 Size(w,h) 来表示内核的大小,Size(5,5) 就表示 5x5 的核大小。
  ● 第五个参数:Point 类型的 anchor,表示锚点(即被平滑的那个点)。它有默认值 Point(-1,-1) 。如果这个点做标是负值的话,就表示取核的中心为锚点,所以默认值 Point(-1,-1) 表示这个锚点在核的中心。
  ● 第六个参数,bool 类型的 normalize ,默认值为 true,一个标识符,表示内核是否被其区域归一化了。
  ● 第七个参数:int 类型的 borderType,用于推断图像外部像素的某种边界模式。有默认值 BORDER_DEFAULT,一般不用管它。
  BoxFilter() 函数方框滤波所用的核表示如下:
          
  其中:
          

  上式中 f 表示原图,h 表示核,g 表示目标图,当 normalize = true 时,方框滤波就变成了均值滤波,也就是说,均值滤波是方框滤波归一化后的特殊情况。其中,归一化就是把要处理的量都放缩到一个范围内,比如(0,1),以便统一处理和直观量化。而非归一化的方框滤波用于计算每个像素邻域内的积分特性,比如密集光流算法中用到的图像倒数的协方差矩阵。
  如果我们要在可变的窗口中计算像素总和,可以使用 inegral() 函数。

  下面是一个方框滤波函数的使用示例:

#include<opencv2/opencv.hpp>
#include<time.h>
#include<iostream>

using namespace std;
using namespace cv;


int main(int argc, char** argv)
{
   
	//载入原图
	Mat image = imread("8.jpg");

	//创建窗口
	namedWindow("均值滤波原图");
	namedWindow("均值滤波效果图");

	//显示窗口
	imshow("均值滤波原图", image);

	//进行滤波操作
	Mat out;
	boxFilter(image, out, -1, Size(5, 5));

	//显示效果图
	imshow("均值滤波效果图", out);

	waitKey(0);
	//system("pause");
	return 0;
}
              运行效果图(内核大小Size(5,5))

        运行效果图(内核大小Size(10,10))

1.7 均值滤波

  均值滤波,是最简单的一种滤波操作,输出图像的每一个像素是核窗口内输入图像对应像素的平均值(所有像素加权系数相等),说白了就是归一化之后的方框滤波。
  均值滤波是典型的线性滤波算法,主要方法为邻域平均法,即用一片图像区域的各个像素的均值来代替原图像中的各个像素值。
  均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。
  blur 函数的作用是:对输入的图像 src 进行均值滤波后用 dst 输出。
  其内核是这样的:
        
  blur 函数原型如下:

void blur(InputArray src, 
		OutputArrat dst, 
		Size ksize, 
		Point anchor = Point(-1, -1), 
		int borderType = BORDER_DEFAULT
	)

  ● 第一个参数:src,输入图像。该函数对通道是独立处理的,且可以处理任意通道的图片,但待处理的图片深度应该为 CV_8U、CV_16U、CV_16S、CV_32F 以及 CV_64F 之一。
  ● 第二个参数:dst,目标图像。
  ● 第三个参数:Size 类型的 ksize,内核的大小。一般采用 Size(w,h) 来表示内核的大小,Size(5,5) 就表示 5x5 的核大小。
  ● 第四个参数:Point 类型的 anchor,表示锚点(即被平滑的那个点)。它有默认值 Point(-1,-1) 。如果这个点做标是负值的话,就表示取核的中心为锚点,所以默认值 Point(-1,-1) 表示这个锚点在核的中心。
  ● 第五个参数:int 类型的 borderType,用于推断图像外部像素的某种边界模式。有默认值 BORDER_DEFAULT,一般不用管它。
  调用代码示例:

#include<opencv2/opencv.hpp>
#include<time.h>
#include<iostream>

using namespace std;
using namespace cv;


int main(int argc, char** argv)
{
   
	//载入原图
	Mat image = imread("8.jpg");

	//创建窗口
	namedWindow("均值滤波原图");
	namedWindow("均值滤波效果图");

	//显示窗口
	imshow("均值滤波原图", image);

	//进行滤波操作
	Mat out;
	blur(image, out, Size(5, 5));

	//显示效果图
	imshow("均值滤波效果图", out);

	waitKey(0);
	//system("pause");
	return 0;
}
              运行效果图(内核大小Size(5,5))

1.8 高斯滤波

  高斯滤波是一种线性平滑的滤波,可以消除高斯噪声,广泛运用于图像处理的减噪过程。通俗的将,高斯滤波就是对整幅图像进行加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩膜)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。
  图像与圆形方框模糊做卷积会生成更加精确的焦外成像效果。由于高斯函数的傅里叶变换是另外一个高斯函数,所以高斯模糊对于图像来说就是一个低通滤波操作。
  高斯滤波器是一类根据高斯函数的形状来选择权值的线性平均滤波器。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。一维零均值高斯函数如下:
            
  其中,高斯分布参数 Sigma 决定了高斯函数的宽度。对于图像处理来说,常用二维零均值离散高斯函数作为平滑滤波器。
  二维高斯函数如下:
            
  高斯滤波函数 GaussianBlur 函数的作用是用高斯滤波器来模糊一张图片,对输入的图像 src 进行高斯滤波后用 dst 输出。它将源图像和指定的高斯核函数做卷积运算,并且支持就地过滤。

void GaussianBlur(InputArray src,
 			OutputArray dst, 
 			Size ksize, 
 			double sigmaX, 
			double sigmaY = 0, 
			int borderType = BORDER_DEFAULT
		)

  ● 第一个参数:src ,输入图像,它可以是单独的任意通道的图片,但需要注意的是,其图片深度应该为 CV_8U、CV_16U、CV_16S、CV_32F 以及 CV_64F 之一。
  ● 第二个参数:dst,即目标图像。
  ● 第三个参数:Size 类型的 ksize ,高斯内核的大小,其中 ksize.width 和 ksize.height 可以不同,但它们必须为正数和奇数,或者是零,这都由 sigma 计算而来。
  ● 第四个参数:double 类型的 sigmaX,表示高斯核函数在 X 方向的标准偏差。
  ● 第五个参数:double 类型的 sigmaY ,表示高斯核函数在 Y 方向的标准偏差。若 sigmaY 为零,就将它设为 sigmaX,如果 sigmaX 和 sigmaY 都是零,那么就由 ksize.width 和 ksize.height 计算出来。
  ● 第五个参数:int 类型的 borderType,用于推断图像外部像素的某种边界模式。有默认值 BORDER_DEFAULT,一般不用管它。
  调用代码示例:

#include<opencv2/opencv.hpp>
#include<time.h>
#include<iostream>

using namespace std;
using namespace cv;


int main(int argc, char** argv)
{
   
	//载入原图
	Mat image = imread("8.jpg");

	//创建窗口
	namedWindow("高斯滤波原图");
	namedWindow("高斯滤波效果图");

	//显示窗口
	imshow("高斯滤波原图", image);

	//进行滤波操作
	Mat out;
	GaussianBlur(image, out, Size(5, 5), 0, 0);

	//显示效果图
	imshow("高斯滤波效果图", out);

	waitKey(0);
	//system("pause");
	return 0;
}
              运行效果图(内核大小Size(5,5))

1.9 图像线性滤波综合示例

#include<opencv2/opencv.hpp>
#include<time.h>
#include<iostream>

using namespace std;
using namespace cv;

Mat g_srcImage, g_dstImage1, g_dstImage2, g_dstImage3;
int g_nBoxFilterValue = 3;	//方框滤波参数值
int g_nMeanBlurValue = 3;	//均值滤波参数值
int g_nGaussianBlurValue = 3;	//高斯滤波参数值

//方框滤波操作的回调函数
void on_BoxFilter(int, void *)
{
   
	//方框滤波操作
	boxFilter(g_srcImage, g_dstImage1, -1, Size(g_nBoxFilterValue + 1, g_nBoxFilterValue + 1));

	//显示窗口
	imshow("方框滤波", g_dstImage1);
}

//均值滤波操作的回调函数
void on_MeanFilter(int, void *)
{
   
	//均值滤波操作
	blur(g_srcImage, g_dstImage2, Size(g_nMeanBlurValue + 1, g_nMeanBlurValue + 1), Point(-1, -1));

	//显示窗口
	imshow("均值滤波", g_dstImage2);
}

//高斯滤波操作的回调函数
void on_GaussianBlur(int, void *)
{
   
	//高斯滤波操作
	GaussianBlur(g_srcImage, g_dstImage3, Size(g_nGaussianBlurValue * 2 + 1, g_nGaussianBlurValue * 2 + 1), 0, 0);

	//显示窗口
	imshow("高斯滤波", g_dstImage3);
}


int main(int argc, char** argv)
{
   
	//改变 console 字体颜色
	system("color 5E");

	//载入原图
	g_srcImage = imread("6.jpg", 1);
	if (!g_srcImage.data)
	{
   
		printf("图像读取失败!");
		return 0;
	}

	//复制原图到三个目标图中
	g_dstImage1 = g_srcImage.clone();
	g_dstImage2 = g_srcImage.clone();
	g_dstImage3 = g_srcImage.clone();

	//显示原图
	namedWindow("原始图", 1);
	imshow("原始图", g_srcImage);

	//-------------方框滤波-------------
	//创建窗口
	namedWindow("方框滤波", 1);
	//创建轨迹条
	createTrackbar("内核值:", "方框滤波", &g_nBoxFilterValue, 40, on_BoxFilter);
	on_BoxFilter(g_nBoxFilterValue, 0);

	//-------------均值滤波-------------
	//创建窗口
	namedWindow("均值滤波", 1);
	//创建轨迹条
	createTrackbar("内核值:", "均值滤波", &g_nMeanBlurValue, 40, on_MeanFilter);
	on_MeanFilter(g_nMeanBlurValue, 0);


	//-------------高斯滤波-------------
	//创建窗口
	namedWindow("高斯滤波", 1);
	//创建轨迹条
	createTrackbar("内核值:", "高斯滤波", &g_nGaussianBlurValue, 40, on_GaussianBlur);
	on_GaussianBlur(g_nGaussianBlurValue, 0);

	waitKey(0);
	//system("pause");
	return 0;
}

2. 非线性滤波:中值滤波、双边滤波

2.1 非线性滤波概述

  上面所讲的滤波器都是线性的,即两个信号之和的响应和它们各自响应之和相等。换句话说,每个像素的输出值是一些输入像素的加权和。
  在很多情况下,使用邻域像素的非线性滤波会得到更好的效果。比如在噪声是散粒噪声而不是高斯噪声,即图像偶尔会出现很大的值的时候,用高斯滤波器对图像进行模糊的话,噪声像素是不会被去除的,只是转换为更为柔和但仍然可见的散粒。

2.2 中值滤波

  中值滤波(Median filter)是一种典型的非线性滤波技术,基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,该方法在去除脉冲噪声、椒盐噪声的同时又能保留图像的边缘细节。
  中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,其基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替。让周围的像素值接近真实值,从而消除孤立的噪声点。这对于斑点噪声和椒盐噪声来说尤其有用,因为它不依赖于邻域内那些与典型值差别很大的值。中值滤波器在处理连续图像函数时与线性滤波器的工作方式类似,但滤波过程不再是加权运算。
  中值滤波在一定的条件下可以克服常见的线性滤波器,如最小均方滤波、方框滤波器、均值滤波器等带来的图像细节模糊,而且对滤除脉冲干扰及图像扫描噪声非常有效,也常用于保护边缘信息。保存边缘的特性使它在不希望出现边缘模糊的场合也很有用,是非常经典的平滑噪声处理方法。
  ● 中值滤波与均值滤波的比较
  优势:在均值滤波器中,由于噪声成分被放入平均计算中,所以输出受到了噪声的影响。但是在中值滤波器中,由于噪声成分很难选上,所以几乎不会影响到输出。因此同样用 3x3 区域进行处理,中值滤波消除噪声的能力更胜一筹。中值滤波无论是在消除噪声还是保存边缘方面都是一个不错的方法。
  劣势:中值滤波花费的时间是均值滤波的 5 倍以上。
  中值滤波对于一些细节(特别是细、尖顶等)多的图像不太适合。

2.3 双边滤波

  双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空域信息和灰度相识性,达到保边去噪的目的,具有简单、非迭代、局部的特点。
  双边滤波的好处是可以做边缘保存。双边滤波器比高斯滤波多了一个高斯方差 sigma - d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离得较远的像素不会对边缘上的像素值影响太多,这样就保证了边缘附近像素值的保存。但是,由于保存了太多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净地滤掉,只能对于低频信息进行较好的滤波。
  在双边滤波器中,输出的像素值依赖于临域像素值的加权组合,公式如下:
            
  而加权系数 w(i,j,k,l) 取决于定义域核和值域核的乘积。
  其中定义域核表示如下:
            
  值域核如下:
           
  定义域滤波和值域滤波如图:
      
  两者相乘后,就会产生依赖与数据的双边滤波权重函数:
        

2.4 非线性滤波相关核心 API 函数

2.4.1 中值滤波:medianBlur 函数

  medianBlur 函数使用中值滤波器来平滑(模糊)处理一张图片,从 src 输入,结果从 dst 输出。对于多通道图片,它对每一个通道都单独进行处理,并且支持就地操作。

void medianBlur(InputArray src, OutputArray dst, int ksize)

  ● 第一个参数:InputArray 类型的 src,函数的输入参数,填 1、3 或者 4 通道的 Mat 类型的图像。当 ksize 为 3 或 5 的时候,图像深度需 为 CV_8U、CV_16U、CV_32F 其中之一,而对于较大孔尺寸的图片时,它只能是 CV_8U。
  ● 第二个参数:OutputArray 类型的 dst,即目标图像,需与源图一样的尺寸和类型,可用 Mat::Clone() ,以源码为模板,来得到目标图。
  ● 第三个参数:int 类型的 ksize,孔径的线性尺寸,注意这个参数必须是大于 1 的奇数,比如:3、5、7、9······
  调用示例如下:

#include<opencv2/opencv.hpp>
#include<time.h>
#include<iostream>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
   
	//改变 console 字体颜色
	system("color 5E");

	Mat image = imread("2.jpg");
	imshow("中值滤波原图", image);

	Mat out;
	medianBlur(image, out, 7);

	imshow("中值滤波效果图", out);

	waitKey(0);
	//system("pause");
	return 0;
}

2.4.2 双边滤波:bilateralFilter 函数

  medianBlur 函数使用中值滤波器来模糊处理一张图片,从 src 输入,结果从 dst 输出。

void bilateralFilter(InputArray src, 
				OutputArray dst, 
				int d, 
				double sigmaColor, 
				double sigmaSpace, 
				int borderType = BORDER_DEFAULT
			)

  ● 第一个参数:InputArray 类型的 src,函数的输入参数,需为 8 位或者浮点型单通道、三通道的图像。
  ● 第二个参数:OutputArray 类型的 dst,即目标图像,需与源图一样的尺寸和类型,可用 Mat::Clone() ,以源码为模板,来得到目标图。
  ● 第三个参数:int 类型的 d,表示在过滤过程中每个像素邻域的直径。如果这个值被设为非正数,那么 OpenCV 会从第五个参数 sigmaSpace 来计算出它。
  ● 第四个参数:double 类型的 sigmaColor,颜色空间中滤波器的 sigma 值。它的数值越大,就表明该像素邻域内有越宽广的颜色会被混合到一起,产生较大的半径相等的颜色区域。
  ● 第五个参数:double 类型的 sigmaSpace,坐标空间中滤波器的 sigma 值,坐标空间的标注方差。它的数值越大,意味着越远的像素会互相影响,从而使更大区域中足够相似的颜色获取相同的颜色。当 d > 0 时, d 指定了邻域大小且与 sigmaSpace 无关,否则, d 正比于 sigmaSpace。
  ● 第六个参数:int 类型的 borderType,用于推断图像外部像素的某种边界模式,有默认值 BORDER_DEFAULT。
  调用示例如下:

#include<opencv2/opencv.hpp>
#include<time.h>
#include<iostream>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
   
	//改变 console 字体颜色
	system("color 5E");

	Mat image = imread("2.jpg");
	imshow("双边滤波原图", image);

	Mat out;
	bilateralFilter(image, out, 25,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值