大家好,又见面了,我是你们的朋友全栈君。
文章目录
- 一. 线性滤波
- 1.1. 方框滤波
- demo
- 1.2. 均值滤波
- demo
- 1.3. 高斯滤波
- demo
- 1.1. 方框滤波
- 二. 非线性滤波
- 2.1. 中值滤波
- demo
- 2.2. 双边滤波
- demo
- 2.1. 中值滤波
- 结构体参考
一. 线性滤波
1.1. 方框滤波
方框滤波是所有滤波器中最简单的一种滤波方式。每一个输出像素的是内核邻域像素值的平均值得到。 通用的滤波kernel如下:
这里是一个长宽分别为Kwidth和Kheight的窗口函数,在此区域内邻域中像素值叠加求平均即可求出位于kernel中心点像素的像素值。
代码语言:javascript复制/ ** @brief使用框过滤器模糊图像。
该函数使用内核对图像进行平滑处理:
未归一化的框式滤波器可用于计算每个像素邻域的各种积分特征,
例如图像导数的协方差矩阵(用于密集光流算法等)。
如果需要在可变大小的窗口上计算像素总和,请使用#integral。
@param src输入图像。
@param dst输出图像的大小和类型与src相同。
@param ddepth输出图像深度(使用src.depth()时为-1)。
@param ksize模糊内核的大小。一般Size(w,h)来表示内核的大小。
@param 锚点(即被平滑的那个点);默认值Point(-1,-1)表示锚点位于内核中心。
@param normalize标志,指定是否通过内核区域对其进行规范化。
@param borderType用于推断图像外部像素的边框模式,请参阅#BorderTypes
* /
CV_EXPORTS_W void boxFilter( InputArray src, OutputArray dst, int ddepth,
Size ksize, Point anchor = Point(-1,-1),
bool normalize = true,
int borderType = BORDER_DEFAULT );
boxFilter()函数方框滤波所用的核为:
其中:
当normalize=true的时候,方框滤波就变成了下面要说的的均值滤波。
demo
代码语言:javascript复制int MPT_test_boxFilter()
{
cv::Mat dst1, dst2, dst3, dst4;
cv::Mat src = cv::imread("../image/beauty.jpg", cv::IMREAD_COLOR);
cv::boxFilter(src, dst1, -1, cv::Size(5, 5), cv::Point(-1, -1), true);
cv::namedWindow("src", 0);
cv::imshow("src", src);
cv::namedWindow("方框滤波", 0);
cv::imshow("方框滤波", dst1);
cv::waitKey(0);
return 0;
}
1.2. 均值滤波
均值滤波的原理非常简单,就是输出图像的每一个像素是核窗口内输入图像对应像素的像素的平均值( 所有像素加权系数相等),其实说白了它就是归一化后的方框滤波。
但是均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。
代码语言:javascript复制/ ** @brief使用标准化框过滤器模糊图像。
该函数使用内核对图像进行平滑处理:
@param src输入图像; 它可以具有任意数量的通道,这些通道是独立处理的,但是深度应为CV_8U,CV_16U,CV_16S,CV_32F或CV_64F。
@param dst输出图像的大小和类型与src相同。
@param ksize模糊内核大小。
@param锚点; 默认值Point(-1,-1)表示锚点位于内核中央。
@param borderType用于推断图像外部像素的边框模式,请参阅#BorderTypes
*/
CV_EXPORTS_W void blur( InputArray src, OutputArray dst,
Size ksize, Point anchor = Point(-1,-1),
int borderType = BORDER_DEFAULT );
demo
代码语言:javascript复制//均值滤波
int MPT_test_blur() {
cv::Mat dst;
cv::Mat src = cv::imread("../image/beauty.jpg", cv::IMREAD_COLOR);
cv::blur(src, dst, cv::Size(5, 5));
cv::namedWindow("src", 0);
cv::imshow("src", src);
cv::namedWindow("均值滤波", 0);
cv::imshow("均值滤波", dst);
cv::waitKey(0);
return 0;
}
1.3. 高斯滤波
图像的高斯模糊过程就是图像与服从二维正态分布的卷积核做卷积。由于正态分布又叫作高斯分布,所以这项技术就叫作高斯模糊。 图像与圆形卷积核做卷积将会生成更加精确的焦外成像效果。由于高斯函数的傅立叶变换是另外一个高斯函数,所以高斯模糊对于图像来说就是一个低通滤波操作。 高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。
一维零均值高斯函数为:
其中,高斯分布参数σ决定了高斯函数的宽度。
对于二维图像来说,常用二维零均值离散高斯函数作平滑滤波器。 二维高斯函数为:
代码语言:javascript复制/ ** @brief使用高斯滤镜模糊图像。
该函数将源图像与指定的高斯内核进行卷积。就地过滤是
支持的。
@param src输入图像;图像可以具有任意数量的经过处理的通道
但深度应为CV_8U,CV_16U,CV_16S,CV_32F或CV_64F。
@param dst输出图像的大小和类型与src相同。
@param ksize高斯内核大小。 ksize.width和ksize.height可以不同,但它们都必须为正数和奇数。或者,它们可以为零,然后根据sigma计算得出。
@param sigmaX X方向上的高斯核标准偏差。
@param sigmaY Y方向上的高斯核标准差;如果sigmaY为零,则将其设置为等于sigmaX;如果两个sigmas为零,则分别从ksize.width和ksize.height计算得出(有关详细信息,请参见#getGaussianKernel);为了完全控制结果,而不考虑将来可能对所有这些语义的修改,建议指定所有ksize,sigmaX和sigmaY。
@param borderType像素外推方法,请参见#BorderTypes
*/
代码语言:javascript复制CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
double sigmaX, double sigmaY = 0,
int borderType = BORDER_DEFAULT );
demo
代码语言:javascript复制//高斯滤波
int MPT_test_GaussianBlur() {
cv::Mat dst;
cv::Mat src = cv::imread("../image/beauty.jpg", cv::IMREAD_COLOR);
cv::GaussianBlur(src, dst, cv::Size(5, 5), 0, 0);
cv::namedWindow("src", 0);
cv::imshow("src", src);
cv::namedWindow("高斯滤波", 0);
cv::imshow("高斯滤波", dst);
cv::waitKey(0);
return 0;
}
二. 非线性滤波
非线性滤波器的原始数据与滤波结果是一种逻辑关系,即通过比较一定邻域内的灰度值大小来实现的。
2.1. 中值滤波
中值滤波原理:
简言之中值滤波就是把函数框(如图中的3 X 3)内的灰度值按顺序排列,然后中值取代函数框中心的灰度值。所以一般采用奇数点的邻域来计算中值,但如果像素点数为偶数,中值就取排序像素中间两点的平均值。
中值滤波在一定的条件下可以克服常见线性滤波器如方框滤波器、均值滤波等带来的图像细节模糊,而且对滤除脉冲干扰及图像扫描噪声非常有效,也常用于保护边缘信息, 保存边缘的特性使它在不希望出现边缘模糊的场合也很有用,是非常经典的平滑噪声处理方法。
但是中值滤波的缺点也很明显,因为要进行排序操作,所以处理的时间长,是均值滤波的5倍以上。
代码语言:javascript复制/ ** @brief使用中值滤镜模糊图像。
@note中值过滤器内部使用#BORDER_REPLICATE来处理边框像素,请参阅#BorderTypes
@param src输入1、3或4通道图像;当ksize为3或5时,
图像深度应为CV_8U,CV_16U或CV_32F,对于较大的光圈,只能为CV_8U。
@param dst目标数组,其大小和类型与src相同。
@param ksize孔径线性大小; 它必须是奇数且大于1,例如:3、5、7 ...
*/
CV_EXPORTS_W void medianBlur( InputArray src, OutputArray dst, int ksize );
demo
代码语言:javascript复制//中值滤波
int MPT_test_medianBlur() {
cv::Mat dst;
cv::Mat src = cv::imread("../image/beauty.jpg", cv::IMREAD_COLOR);
cv::medianBlur(src, dst, 9);
cv::namedWindow("src", 0);
cv::imshow("src", src);
cv::namedWindow("中值滤波", 0);
cv::imshow("中值滤波", dst);
cv::waitKey(0);
return 0;
}
2.2. 双边滤波
双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。具有简单、非迭代、局部的特点。
双边滤波器的好处是可以做边缘保存(edge preserving),一般用高斯滤波去降噪,会较明显地模糊边缘,对于高频细节的保护效果并不明显。双边滤波器顾名思义比高斯滤波多了一个高斯方差sigma-d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素值,这样就保证了边缘附近像素值的保存。但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤波。
下图是双边滤波的原理示意图:
在双边滤波器中,输出像素的值依赖于邻域像素值的加权值组合:
而加权系数w(i,j,k,l)取决于空域核和值域核的乘积。 (i,j),(k,l)分别指两个像素点的坐标。 其中空域核表示如下(如图):
值域核表示为:
两者相乘后,就会产生依赖于数据的双边滤波权重函数:
d函数是根据像素距离选择权重,距离越近权重越大,这一点和方框滤波,高斯滤波方式相同。而r函数则是根据像素的差异来分配权值。如果两个像素值越接近,即使相距较远,也比差异大而距离近的像素点权重大。正是r函数的作用,使得边缘,即相距近但差异大的像素点的特性得以保留。
代码语言:javascript复制/ ** @brief将双边过滤器应用于图像。
可以在保持边缘相当清晰的同时很好地减少不必要的噪音。但是,与大多数过滤器相比,它非常慢。
_Sigma values_:为简单起见,您可以将2个sigma值设置为相同。如果它们很小(<10),则滤镜效果不大;
而如果它们很大(> 150),它们将具有非常大的效果。效果强,使图像看起来“卡通化”。
_Filter size_:大型滤镜(d > 5)非常慢,因此建议实时使用d = 5
应用程序,对于需要重噪声过滤的脱机应用程序,d = 9。
@param src 源8位或浮点,1通道或3通道图像。
@param dst 与src大小和类型相同的目标映像。
@param d 滤波期间使用的每个像素邻域的直径。如果它不是正值,
则从sigmaSpace计算得出。
@param sigmaColor 在色彩空间中过滤sigma。
这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域
@param sigmaSpace 在坐标空间中过滤sigma。
该参数的值越大,表示越远的像素就会相互影响,
只要它们的颜色足够接近即可(请参见sigmaColor)。
当d > 0时,它指定邻域大小,而不考虑sigmaSpace。
否则,d为与sigmaSpace成比例。
@param borderType 用于推断图像外部像素的边框模式,请参阅#BorderTypes
*/
CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d,
double sigmaColor, double sigmaSpace,
int borderType = BORDER_DEFAULT );
demo
代码语言:javascript复制//双边滤波
int MPT_test_bilateralFilter() {
cv::Mat dst;
cv::Mat src = cv::imread("../image/beauty.jpg", cv::IMREAD_COLOR);
cv::bilateralFilter(src, dst, 25, 10.0, 25);
cv::namedWindow("src", 0);
cv::imshow("src", src);
cv::namedWindow("双边滤波", 0);
cv::imshow("双边滤波", dst);
cv::waitKey(0);
return 0;
}
结构体参考
代码语言:javascript复制enum BorderTypes {
BORDER_CONSTANT = 0, //!< `iiiiii|abcdefgh|iiiiiii` with some specified `i`
BORDER_REPLICATE = 1, //!< `aaaaaa|abcdefgh|hhhhhhh`
BORDER_REFLECT = 2, //!< `fedcba|abcdefgh|hgfedcb`
BORDER_WRAP = 3, //!< `cdefgh|abcdefgh|abcdefg`
BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba`
BORDER_TRANSPARENT = 5, //!< `uvwxyz|abcdefgh|ijklmno`
BORDER_REFLECT101 = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_DEFAULT = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_ISOLATED = 16 //!< do not look outside of ROI
};
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/127113.html原文链接:https://javaforall.cn