1. 目标
在本文中,将学习如何使用 OpenCV 函数应用各种线性滤波器来平滑图像,例如:
2. 理论
笔记
下面的解释来自Richard Szeliski的Computer Vision: Algorithms and Applications 一书和LearningOpenCV
-
平滑,也称为模糊,是一种简单且经常使用的图像处理操作。
-
平滑的原因有很多。在本文中,将专注于平滑以减少噪声(其他用途将在以后文章中看到)。
-
为了执行平滑操作,将对图像应用过滤器。最常见的过滤器类型是线性的,其中输出像素的值(即)被确定为输入像素值的加权和(即 ) :
称为核,其实就是滤波器的系数。
可以将滤波器可视化为在图像上滑动的系数窗口。
- 过滤器有很多种,这里将提到最常用的:
2.1 Normalized Box Filter
-
这个过滤器是最简单的!每个输出像素是其邻居像素的平均值(它们都具有相同的权重)
-
内核如下:
2.2 Gaussian Filter
-
可能是最有用的过滤器(虽然不是最快的)。高斯滤波是通过将输入图像与高斯核进行卷积,然后将它们全部相加。
-
只是为了让图片更清晰,还记得一维高斯核的样子吗?
假设图像是一维的,注意到位于中间的像素的权重最大。其邻居的权重随着它们与中心像素之间的空间距离的增加而减小。
-
笔记
请记住,二维高斯可以表示为:
是均值(峰值)和表示方差(对于变量x和y)
2.3 Median Filter
中值滤波器遍历信号的每个元素(在本例中为图像),并将每个像素替换为其相邻像素的中值(位于被评估像素周围的正方形邻域中)。
2.4 Bilateral Filter
- 到目前为止,已经解释了一些主要目标是平滑输入图像的过滤器。但是,有时过滤器不仅可以消除噪声,还把边缘平滑了,导致图像模糊。为了避免平滑边缘(至少在一定程度上避免),可以使用双边滤波器。双边滤波是一种非线性滤波器,它可以达到保持边缘、降噪平滑的效果。
- 与高斯滤波器类似,双边滤波器也考虑相邻像素,并为每个像素分配权重。这些权重有两个分量,第一个分量与高斯滤波器使用的权重相同。第二个组件考虑了相邻像素和评估像素之间的强度差异。
- 有关更详细的说明,您可以查看此链接
3. 代码
-
这个程序有什么作用?
- 加载图像
- 应用 4 种不同类型的过滤器(在理论中解释)并按顺序显示过滤后的图像
-
点击这里下载代码
-
代码一览:
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;
Mat src; Mat dst;
char window_name[] = "Smoothing Demo";
int display_caption( const char* caption );
int display_dst( int delay );
int main( int argc, char ** argv )
{
namedWindow( window_name, WINDOW_AUTOSIZE );
const char* filename = argc >=2 ? argv[1] : "lena.jpg";
src = imread( samples::findFile( filename ), IMREAD_COLOR );
if (src.empty())
{
printf(" Error opening image\n");
printf(" Usage:\n %s [image_name-- default lena.jpg] \n", argv[0]);
return EXIT_FAILURE;
}
if( display_caption( "Original Image" ) != 0 )
{
return 0;
}
dst = src.clone();
if( display_dst( DELAY_CAPTION ) != 0 )
{
return 0;
}
if( display_caption( "Homogeneous Blur" ) != 0 )
{
return 0;
}
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
blur( src, dst, Size( i, i ), Point(-1,-1) );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
if( display_caption( "Gaussian Blur" ) != 0 )
{
return 0;
}
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
GaussianBlur( src, dst, Size( i, i ), 0, 0 );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
if( display_caption( "Median Blur" ) != 0 )
{
return 0;
}
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
medianBlur ( src, dst, i );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
if( display_caption( "Bilateral Blur" ) != 0 )
{
return 0;
}
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
bilateralFilter ( src, dst, i, i*2, i/2 );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
display_caption( "Done!" );
return 0;
}
int display_caption( const char* caption )
{
dst = Mat::zeros( src.size(), src.type() );
putText( dst, caption,
Point( src.cols/4, src.rows/2),
FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );
return display_dst(DELAY_CAPTION);
}
int display_dst( int delay )
{
imshow( window_name, dst );
int c = waitKey ( delay );
if( c >= 0 ) { return -1; }
return 0;
}
4. 代码解释
下边讨论一下只涉及平滑过程的 OpenCV 函数,因为其余的现在已经知道了。
4.1 Normalized Block Filter:
-
OpenCV 提供了blur()函数来使用这个过滤器进行平滑处理。指定了 4 个参数(更多详细信息,请查看参考资料):
- src:源图像
- dst:目标图像
- Size( w, h ) :定义要使用的内核的大小(宽度为w像素,高度为h像素)
- Point(-1, -1) :指示锚点(评估的像素)相对于邻域的位置。如果有负值,则内核的中心被认为是锚点。
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
blur( src, dst, Size( i, i ), Point(-1,-1) );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
4.2 Gaussian Filter:
-
它由函数GaussianBlur()执行:这里使用 4 个参数(更多详细信息,请查看 OpenCV 参考):
- src:源图像
- dst:目标图像
- Size(w, h) :要使用的内核的大小(要考虑的邻居)。在和H必须是奇数和正数,否则大小将使用pX和p是论据。
- : x 的标准差。参数值0意味是使用内核大小计算的。
- : y 的标准差。参数值0意味是使用内核大小计算的。
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
GaussianBlur( src, dst, Size( i, i ), 0, 0 );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
4.3 Median Filter:
-
该过滤器由medianBlur()函数提供:使用三个参数:
- src:源图像
- dst:目标图像,必须与src类型相同
- i:内核的大小(只有一个,因为我们使用方形窗口)。大小必须为奇数。
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
medianBlur ( src, dst, i );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
4.4 Bilateral Filter
-
由 OpenCV 函数提供的**双边过滤器()** 我们使用 5 个参数:
- src:源图像
- dst:目标图像
- d:每个像素邻域的直径。
- :色彩空间的标准差。
- :坐标空间标准偏差(以像素为单位)
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
bilateralFilter ( src, dst, i, i*2, i/2 );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
5.结果
-
打开一个图像(在本例中为 lena.jpg)并展示了在 4 个过滤器下处理效果。
-
图像的快照:
原 图
Median Filter效果
Gaussian Filter效果
Bilateral Filter 效果