1  图像平滑

图像平滑,一种图像空间滤波方法 (低通滤波),可对图像进行去噪 或 模糊化 (blurring)

以 3X3 的滤波器为例 (即 a=b=1),则矩阵 Mx 和 Mf 对应的元素乘积之和,就是 g(x, y)

其中,$ M_x = \begin{bmatrix} w(-1,-1) & w(-1,0) & w(-1,1) \\ w(0,-1) & w(0,0) & w(1,1) \\ w(1,-1) & w(1,0) & w(1,1) \\ \end{bmatrix} \qquad M_f = \begin{bmatrix} f(x-1,y-1) & f(x-1,y) & f(x-1,y+1) \\ f(x,y-1) & f(x,y) & f(x+1,y+1) \\ f(x+1,y-1) & f(x+1,y) & f(x+1,y+1) \\ \end{bmatrix}$

2  OpenCV 函数

OpenCV 中主要有四个函数,分别是盒式滤波 (box),高斯滤波 (Gaussian),中值滤波 (median),双边滤波 (bilateral)

2.1  盒式滤波

 2.1.1 boxFilter

输出图像的任一像素灰度值,等于其所有邻域像素灰度值的平均值

模糊化核为,$ K = \alpha \begin{bmatrix}  1 & 1 & ... & 1 & 1 \\ 1 & 1 & ... & 1 & 1 \\ \: & \: & ... & & & \\ 1 & 1 & ... & 1 & 1 \end{bmatrix} $  其中,$\alpha = \begin{cases} \frac{1}{ksize.width * ksize.height} & \text{when normalize = true} \\  1 & \text{otherwise} \\ \end{cases} $

void cv::boxFilter (
InputArray src, // 输入图像
OutputArray dst, // 输出图像
int ddepth, // 输出图像深度,-1 表示等于 src.depth()
Size ksize, // 模糊化核 (kernel) 的大小
Point anchor = Point(-,-), // 锚点位置,缺省值表示 anchor 位于模糊核的正中心
bool normalize = true, // 是否归一化处理
int borderType = BORDER_DEFAULT // 边界模式
)

2.1.2  blur

取 ddepth = -1,normalize = true,则可由 boxFilter 得到模糊化函数 (blur)

boxFilter( src, dst, -1, ksize, anchor, true, borderType );

blur 本质上是一个输入和输出图像深度 (ddepth) 相同,并且做归一化处理的盒式滤波器

void cv::blur (
InputArray src,
OutputArray dst,
Size ksize,
Point anchor = Point(-,-),
int borderType = BORDER_DEFAULT
)

2.2  中值滤波

  中值滤波最为简单,常用来消除椒盐噪声。输出图像 g (x, y)  的像素值,等于以输入图像 f (x, y) 为中心点的邻域像素 (ksize x ksize) 平均值

void cv::medianBlur (
InputArray src,
OutputArray dst,
int ksize // 滤波器孔径大小,一般为奇数且大于 1,比如 3, 5, 7, ...
)

2.3  高斯滤波

高斯滤波最为有用,它是根据当前像素和邻域像素之间,空间距离的不同,计算得出一个高斯核 (邻域像素的加权系数),

然后,高斯核从左至右、从上到下遍历输入图像,与输入图像的像素值求卷积和,得到输出图像的各个像素值

$\quad G_{0}(x, y) = A e^{ \dfrac{ -(x - \mu_{x})^{2} }{ 2\sigma^{2}_{x} } + \dfrac{ -(y - \mu_{y})^{2} }{ 2\sigma^{2}_{y} } } $

无须理会公式的复杂,只需要记住一点即可:邻域像素距离当前像素越远 (saptial space),则其相应的加权系数越小

为了便于直观理解,可看下面这个一维高斯核,推而广之将 G(x) 曲线以 x=0 这条轴为中心线,旋转360度可想象其二维高斯核

void cv::GaussianBlur (
InputArray src,
OutputArray dst,
Size ksize, // 高斯核的大小
double sigmaX, // 高斯核在x方向的标准差
double sigmaY = , // 高斯核在y方向的标准差,缺省为 0,表示 sigmaY = sigmaX
int borderType = BORDER_DEFAULT
)  

  注意: 高斯核的大小 Size(width, height),w 和 h 二者不必相同但必须都是奇数,若都设为 0,则从 sigma 自动计算得出

2.4  双边滤波

上面三种方法都是低通滤波,因此在消除噪声的同时,也常会将边缘信息模糊化。双边滤波和高斯滤波类似,但是它将邻域像素的加权系数分为两部分,

第一部分与高斯滤波的完全相同,第二部分则考虑当前像素和邻域像素之间灰度值的差异,从而在消除噪声的基础上,也较好的保留了图像的边缘信息

void cv::bilateralFilter (
InputArray src,
OutputArray dst,
int d, // 像素邻域直径,若为非正值,则从 sigmaSpace 自动计算得出
double sigmaColor, // 颜色空间的标注方差
double sigmaSpace, // 坐标空间的标准方差
int borderType = BORDER_DEFAULT
)

注意 1)  双边滤波相比以上三种滤波方法,其处理速度很慢,因此,一般建议取 d=5 用于实时图像处理,d=9 适合于非实时的图像领域

注意 2)  sigmaColor 和 sigmaSpace 可取相同值,一般在 10 ~ 150 之间,小于 10,则没什么效果,大于 150,则效果太强烈,看起来明显“卡通化”

3  代码示例

3.1 OpenCV

  OpenCV 中的示例,通过逐渐增大像素邻域的大小 Size(w, h),将上述滤波过程动态化,非常形象的展示了邻域大小对滤波效果的影响

代码摘抄

 /**
* file Smoothing.cpp
* brief Sample code for simple filters
* author OpenCV team
*/
#include <iostream>
#include <vector> #include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/features2d/features2d.hpp" using namespace std;
using namespace cv; /// Global Variables
int DELAY_CAPTION = ;
int DELAY_BLUR = ;
int MAX_KERNEL_LENGTH = ; Mat src; Mat dst;
char window_name[] = "Smoothing Demo"; /// Function headers
int display_caption( const char* caption );
int display_dst( int delay ); /**
* function main
*/
int main( void )
{
namedWindow( window_name, WINDOW_AUTOSIZE ); /// Load the source image
src = imread( "../data/lena.jpg", ); if( display_caption( "Original Image" ) != ) { return ; } dst = src.clone();
if( display_dst( DELAY_CAPTION ) != ) { return ; } /// Applying Homogeneous blur
if( display_caption( "Homogeneous Blur" ) != ) { return ; } for ( int i = ; i < MAX_KERNEL_LENGTH; i = i + )
{ blur( src, dst, Size( i, i ), Point(-,-) );
if( display_dst( DELAY_BLUR ) != ) { return ; } } /// Applying Gaussian blur
if( display_caption( "Gaussian Blur" ) != ) { return ; } for ( int i = ; i < MAX_KERNEL_LENGTH; i = i + )
{ GaussianBlur( src, dst, Size( i, i ), , );
if( display_dst( DELAY_BLUR ) != ) { return ; } } /// Applying Median blur
if( display_caption( "Median Blur" ) != ) { return ; } for ( int i = ; i < MAX_KERNEL_LENGTH; i = i + )
{ medianBlur ( src, dst, i );
if( display_dst( DELAY_BLUR ) != ) { return ; } } /// Applying Bilateral Filter
if( display_caption( "Bilateral Blur" ) != ) { return ; } for ( int i = ; i < MAX_KERNEL_LENGTH; i = i + )
{ bilateralFilter ( src, dst, i, i*, i/ );
if( display_dst( DELAY_BLUR ) != ) { return ; } } /// Wait until user press a key
display_caption( "End: Press a key!" ); waitKey(); return ;
} /**
* @function display_caption
*/
int display_caption( const char* caption )
{
dst = Mat::zeros( src.size(), src.type() );
putText( dst, caption,
Point( src.cols/, src.rows/),
FONT_HERSHEY_COMPLEX, , Scalar(, , ) ); imshow( window_name, dst );
int c = waitKey( DELAY_CAPTION );
if( c >= ) { return -; }
return ;
} /**
* @function display_dst
*/
int display_dst( int delay )
{
imshow( window_name, dst );
int c = waitKey ( delay );
if( c >= ) { return -; }
return ;
}

3.2  滤波对比

实际中,可直接调用以上四个滤波函数,代码如下:

 #include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp" using namespace cv; int main()
{
Mat src = imread("E:/smooth/bird.jpg");
if(src.empty()) {
return -;
}
imshow("original", src); Mat dst; blur(src, dst, Size(,));
imshow("blur", dst); medianBlur(src,dst,);
imshow("medianBlur",dst); GaussianBlur(src,dst,Size(,),);
imshow("GaussianBlur",dst); bilateralFilter(src,dst,,,);
imshow("bilateralFilter",dst); waitKey();
}

四种滤波方法的效果图,如下所示:

参考资料

<Digital Image Processing> 3rd, chapter 3

<Learning OpenCV3>

OpenCV Tutorials \ Image Processing (imgproc module) \ Smoothing Images

 图像卷积与滤波的一些知识点,zouxy09

最新文章

  1. 通过squid 禁止访问/只允许访问指定 网址
  2. Linux线程基础
  3. php中计算二维数组中某一元素之和
  4. mysql学习(3)-linux下mysql主从复制
  5. [ruby on rails] 跟我学之(4)路由映射
  6. codeforces C. Arithmetic Progression 解题报告
  7. python--切片--6
  8. PrintWriter 和 BufferedWriter 写入文件.
  9. LeetCode_Reverse Integer
  10. MVC-03 控制器(3)
  11. 《Algorithms Unlocked》读书笔记2——二分查找和排序算法
  12. redhat初始化yum源,使用阿里云yum源
  13. 使用Iterator的方式也可以顺利删除和遍历
  14. 175. Combine Two Tables【LeetCode】-LEFT JON 和RIGHT JOIN,两张表关联查询-java -sql入门
  15. RAPIDIO高速串行协议
  16. 使用GDB调试将符号表与程序分离后的可执行文件
  17. [原][openstack-pike][controller node][issue-3][horizon] dashboard show internal error 500 Cannot serve directory /var/www/html
  18. p2042 维修数列(SPLAY)
  19. (笔记)Linux下检测网卡与网线连接状态
  20. linux查看是否有某个运行的进程命令

热门文章

  1. 太可爱了!CSS3 &amp; SVG 制作的米老鼠钟表
  2. 你应该知道的10个奇特的 HTML5 单页网站
  3. css中white-space的值pre-wrap
  4. 【zepto学习笔记01】核心方法$()(补)
  5. Delphi 获取系统时间后格式化输出
  6. 为Sharepoint 2010 批量创建SharePoint测试用户
  7. [javascript svg fill stroke stroke-width x y rect rx ry 属性讲解] svg fill stroke stroke-width rect 绘制具有圆角矩形属性讲解
  8. Android压力测试工具——Monkey
  9. JavaSE 和 JavaEE 的关系
  10. 自定义圆形控件 RoundImageView