OpenCV 2.4.3 C++ 平滑处理分析
原理
平滑也称模糊, 是一项简单且使用频率很高的图像处理方法。
平滑处理时需要用到一个滤波器。 最常用的滤波器是线性滤波器,线性滤波处理的输出像素值(例如:)是输入像素值(例如:)的加权平均:
称为核, 它仅仅是一个加权系数。
均值平滑
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <stdio.h>
using namespace cv;
int main( int argc, char** argv ){
Mat image;
image = imread( argv[1]);
if( argc != 2 || !image.data ){
printf("没有图片\n");
return -1;
}
namedWindow( "平滑处理-输入" );
namedWindow( "平滑处理-输出" );
imshow( "平滑处理-输入", image );
Mat out;
blur( image, out, Size(3, 3));
imshow( "平滑处理-输出", out );
waitKey( 0 );
}
blur函数API资料:
使用归一化块滤波器进行模糊图片操作。
C++: void blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT )
该函数对图片进行平滑处理利用了下面的内核:
调用blur(src, dst, ksize, anchor, borderType)相当于调用boxFilter(src, dst, src.type(), anchor, true, borderType)。
blur使用的是归一化块滤波器,输出像素值是核窗口内像素值的均值( 所有像素加权系数相等)。
高斯平滑
下面代码使用了GaussianBlur来实现平滑:
代码如下:
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <stdio.h>
using namespace std;
using namespace cv;int main( int argc, char** argv ){
Mat image;
image = imread( argv[1]);
if( argc != 2 || !image.data ){
printf("没有图片\n");
return -1;
}
namedWindow( "平滑处理-输入" );
namedWindow( "平滑处理-输出" );
imshow( "平滑处理-输入", image );
Mat out;
GaussianBlur( image, out, Size( 3, 3 ), 0, 0 );
imshow( "平滑处理-输出", out );
waitKey( 0 );
}
GaussianBlur函数API资料:
使用高斯滤波器进行模糊操作
C++: void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT)
最有用的滤波器 (尽管不是最快的)。 高斯滤波是将输入数组的每一个像素点与高斯内核卷积将卷积和当作输出像素值。
参考一维高斯函数,我们可以看见,他是个中间大两边小的函数。
所以高斯滤波器其加权数是中间大,四周小的。
其二维高斯函数为:
其中 为均值 (峰值对应位置), 代表标准差 (变量 和 变量 各有一个均值,也各有一个标准差)。
中值平滑
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <stdio.h>
using namespace std;
using namespace cv;int main( int argc, char** argv ){
Mat image;
image = imread( argv[1]);
if( argc != 2 || !image.data ){
printf("没有图片\n");
return -1;
}
namedWindow( "平滑处理-输入" );
namedWindow( "平滑处理-输出" );
imshow( "平滑处理-输入", image );
Mat out;
medianBlur( image, out, 3);
imshow( "平滑处理-输出", out );
waitKey( 0 );
}
medianBlur函数API资料:
使用中值滤波器进行模糊操作
C++: void medianBlur(InputArray src, OutputArray dst, int ksize)
中值滤波将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的中值代替 。
双边平滑
使用bilateralFilter执行双边平滑:
代码如下:
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <stdio.h>
using namespace std;
using namespace cv;int main( int argc, char** argv ){
Mat image;
image = imread( argv[1]);
if( argc != 2 || !image.data ){
printf("没有图片\n");
return -1;
}
namedWindow( "平滑处理-输入" );
namedWindow( "平滑处理-输出" );
imshow( "平滑处理-输入", image );
Mat out;
bilateralFilter ( image, out, 3, 3*2, 3/2 );
imshow( "平滑处理-输出", out );
waitKey( 0 );
}
bilateralFilter的API资料:
对一个图片应用双边滤波器。
C++: void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, intborderType=BORDER_DEFAULT )
原理可参考:
http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html
目前我们了解的滤波器都是为了平滑图像, 问题是有些时候这些滤波器不仅仅削弱了噪声, 连带着把边缘也给磨掉了。 为避免这样的情形 (至少在一定程度上 ), 我们可以使用双边滤波。
类似于高斯滤波器,双边滤波器也给每一个邻域像素分配一个加权系数。 这些加权系数包含两个部分, 第一部分加权方式与高斯滤波一样,第二部分的权重则取决于该邻域像素与当前像素的灰度差值。