OpenCV 之 图像平滑
2016-05-07 06:50
459 查看
1 图像平滑
图像平滑,可用来对图像进行去噪 (noise reduction) 或 模糊化处理 (blurring),实际上图像平滑仍然属于图像空间滤波的一种 (低通滤波)
既然是滤波,则图像中任一点 (x, y),经过平滑滤波后的输出 g(x, y) 如下:
$\quad g(x, y) = \sum \limits_{s=-a}^a \: \sum \limits_{t=-b}^b {w(s, t)\:f(x+s, y+t)} $
以 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 盒式滤波
输出图像的任一像素灰度值,等于其所有邻域像素灰度值的平均值
模糊化核为,$ K = \alpha \begin{bmatrix} 1 & 1 & ... & 1 & 1 \\ 1 & 1 & ... & 1 & 1 \\ \: & \: & ... & & & \\ 1 & 1 & ... & 1 & 1 \end{bmatrix} $ 其中,$\alpha = \begin{cases} \frac{1}{ksize.weidth * ksize.height} & \text{when normalize = true} \\ 1 & \text{otherwise} \\ \end{cases} $
取 ddepth = 1,normalize = true,则可以得到模糊化函数 (blur)
模糊化函数 (blur),本质上是一个输入和输出图像深度 (ddepth) 相同,并且做归一化处理的盒式滤波器
2.2 中值滤波
中值滤波最为简单,常用来消除椒盐噪声
输出图像中 (x, y) 点处的像素值,等于输入图像以 (x, y) 为中心点的邻域像素 (ksize x ksize) 平均值
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度可想象其二维高斯核
View Code
3.2 滤波对比
实际中,可直接调用以上四个滤波函数,代码如下:
四种滤波方法的效果图,如下所示:
![](http://images2015.cnblogs.com/blog/890227/201605/890227-20160507064014326-73580735.jpg)
参考资料
<Digital Image Processing_3rd> chapter 3
<Learning OpenCV_2nd>
<OpenCV Tutorials> imgproc module - Smoothing Images
图像平滑,可用来对图像进行去噪 (noise reduction) 或 模糊化处理 (blurring),实际上图像平滑仍然属于图像空间滤波的一种 (低通滤波)
既然是滤波,则图像中任一点 (x, y),经过平滑滤波后的输出 g(x, y) 如下:
$\quad g(x, y) = \sum \limits_{s=-a}^a \: \sum \limits_{t=-b}^b {w(s, t)\:f(x+s, y+t)} $
以 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 盒式滤波
输出图像的任一像素灰度值,等于其所有邻域像素灰度值的平均值
模糊化核为,$ K = \alpha \begin{bmatrix} 1 & 1 & ... & 1 & 1 \\ 1 & 1 & ... & 1 & 1 \\ \: & \: & ... & & & \\ 1 & 1 & ... & 1 & 1 \end{bmatrix} $ 其中,$\alpha = \begin{cases} \frac{1}{ksize.weidth * 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(-1,-1), // 锚点位置,缺省值表示 anchor 位于模糊核的正中心 bool normalize = true, // 是否归一化处理 int borderType = BORDER_DEFAULT // 边界模式 )
取 ddepth = 1,normalize = true,则可以得到模糊化函数 (blur)
boxFilter( src, dst, -1, ksize, anchor, true, borderType );
模糊化函数 (blur),本质上是一个输入和输出图像深度 (ddepth) 相同,并且做归一化处理的盒式滤波器
void cv::blur ( InputArray src, OutputArray dst, Size ksize, Point anchor = Point(-1,-1), int borderType = BORDER_DEFAULT )
2.2 中值滤波
中值滤波最为简单,常用来消除椒盐噪声
输出图像中 (x, y) 点处的像素值,等于输入图像以 (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度可想象其二维高斯核
/** * 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 = 1500; int DELAY_BLUR = 100; int MAX_KERNEL_LENGTH = 31; 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", 1 ); if( display_caption( "Original Image" ) != 0 ) { return 0; } dst = src.clone(); if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; } /// Applying Homogeneous blur 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; } } /// Applying Gaussian blur 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; } } /// Applying Median blur 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; } } /// Applying Bilateral Filter 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; } } /// Wait until user press a key display_caption( "End: Press a key!" ); waitKey(0); return 0; } /** * @function display_caption */ 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) ); imshow( window_name, dst ); int c = waitKey( DELAY_CAPTION ); if( c >= 0 ) { return -1; } return 0; } /** * @function display_dst */ int display_dst( int delay ) { imshow( window_name, dst ); int c = waitKey ( delay ); if( c >= 0 ) { return -1; } return 0; }
View Code
3.2 滤波对比
实际中,可直接调用以上四个滤波函数,代码如下:
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" using namespace std; using namespace cv; int main() { Mat src = imread("E:/smooth/bird.jpg"); if(src.empty()) return -1; namedWindow("original", CV_WINDOW_AUTOSIZE); namedWindow("blur", CV_WINDOW_AUTOSIZE); namedWindow("GaussianBlur", CV_WINDOW_AUTOSIZE); namedWindow("medianBlur", CV_WINDOW_AUTOSIZE); namedWindow("bilateralFilter", CV_WINDOW_AUTOSIZE); imshow("original", src); Mat dst; blur(src, dst, Size(3,3)); imshow("blur", dst); medianBlur(src,dst,3); imshow("medianBlur",dst); GaussianBlur(src,dst,Size(3,3),0); imshow("GaussianBlur",dst); bilateralFilter(src,dst,9,50,50); imshow("bilateralFilter",dst); waitKey(0); return 0; }
四种滤波方法的效果图,如下所示:
![](http://images2015.cnblogs.com/blog/890227/201605/890227-20160507064014326-73580735.jpg)
参考资料
<Digital Image Processing_3rd> chapter 3
<Learning OpenCV_2nd>
<OpenCV Tutorials> imgproc module - Smoothing Images
相关文章推荐
- -bash: ./****.py: /usr/bin/python^M: bad interpreter: No such file or directory
- SGU 199 Beautiful People 二维最长递增子序列
- Android视图控件架构分析之View、ViewGroup
- [Architecture] 系统架构正交分解法
- 【译】Android系统架构
- CentOS7上安装Pycharm
- OpenGLES:: GLKView是如何工作的
- 解决linux不能解压rar格式压缩包
- popupWindow (弹出窗口)点击某个按钮时,在旁边显示其他按钮。
- org.apache.commons.lang3.xwork.StringUtils找不到的问题
- linux平台使用gnu工具链来开发stm32单片机 环境搭建,备忘录
- CProperySheet使用
- if top实时监控参考
- 2016学习Linux决心书
- 一个可以查看 Linux 当前缓存了哪些大文件的小工具
- CentOS下搭建PHP环境与WordPress博客程序的全流程总结
- linux安装jdk详细步骤(rpm方式)
- how to custom bash prompt
- 开启Nginx的目录文件列表功能
- linux rsync+inotify 文件自动同步