这一节,谈一谈如何对图像进行平滑,也可以叫做模糊。平滑图像的主要目的是减少噪声,这样采用平滑图像来降低噪声是是非常常见的预处理方法。
1.归一化滤波平滑-Homogeneous Smoothing
2.高斯滤波平滑-Gaussian Smoothing
3.中值滤波平滑-Median Smoothing
4.双边滤波平滑-Bilateral Smoothing
平滑是通过滑动窗口(内核或过滤器)扫描整个图像窗口,计算每个像素的基于核的值的和重叠的原始图像的像素的值的值来完成。这个过程在数学上称为具有一些内核卷积的图像。上述4种不同平滑方法唯一的区别就是内核。
例如, 5 x 5的核用来平滑(模糊)下面图片, 归一化块滤波器"Normalized box filter".
而高斯平滑(模糊)采用5x5的内核是如下。这个内核被称为“高斯核” "Gaussian kernel"
下面是关于平滑核(滤波器)比较重要的几个方面。
- 平滑核的行像素数及列像素数必须是奇数(e.g. - 3x3, 11x5, 7x7, etc)
- 平滑核的size越大,计算时间越长。
归一化滤波平衡 Homogeneous Smoothing
简单的滤波器, 输出像素值是核窗口内像素值的 均值 (
所有像素加权系数相等)
选择核的大小是很关键,如果选择太大,比较细微的图像特征可能被平滑掉,图像看起来很模糊。如果核选择太小,就可能无法完全删除噪声。
核定义如下:
OpenCV 代码
下面的OpenCV 的代码中,核大小从1x1增加到29x29.可以观察到图像平滑程度随着核增大的变化程度。平滑图像的核的大小显示在被平滑图像上。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" using namespace cv; int main( int argc, char** argv ) { //create 2 empty windows namedWindow( "Original Image" , CV_WINDOW_AUTOSIZE ); namedWindow( "Smoothed Image" , CV_WINDOW_AUTOSIZE ); // Load an image from file Mat src = imread( "MyPic.JPG", 1 ); //show the loaded image imshow( "Original Image", src ); Mat dst; char zBuffer[35]; for ( int i = 1; i < 31; i = i + 2 ) { //copy the text to the "zBuffer" _snprintf_s(zBuffer, 35,"Kernel Size : %d x %d", i, i); //smooth the image in the "src" and save it to "dst" blur( src, dst, Size( i, i ) ); //put the text in the "zBuffer" to the "dst" image putText( dst, zBuffer, Point( src.cols/4, src.rows/8), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) ); //show the blurred image with the text imshow( "Smoothed Image", dst ); //wait for 2 seconds int c = waitKey(2000); //if the "esc" key is pressed during the wait, return if (c == 27) { return 0; } } //make the "dst" image, black dst = Mat::zeros( src.size(), src.type() ); //copy the text to the "zBuffer" _snprintf_s(zBuffer, 35,"Press Any Key to Exit"); //put the text in the "zBuffer" to the "dst" image putText( dst, zBuffer, Point( src.cols/4, src.rows / 2), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) ); //show the black image with the text imshow( "Smoothed Image", dst ); //wait for a key press infinitely waitKey(0); return 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
平滑图像 -可以看到随着平滑核增大,图像逐渐变得模糊 |
新OpenCV函数详解
- src - 源图像. (图像位深必须是; CV_8U, CV_16S, CV_16U, CV_32F or CV_64F)
- dst - 输出图像 (必须与源图像大小及位深一致)
- ksize - 核大小
- anchor - 点(-1,-1)的值意味着anchor是核中心的值。如果愿意可以自己定义自己的点。
- borderType - Y可以定义不同的边界插入方法,这个值仅仅影响边缘的像素。 (可选参数: BORDER_DEFAULT, BORDER_REFLECT, BORDER_REPLICATE, BORDER_TRANSPARENT, BORDER_REFLECT_101 )
- void putText( Mat& img, const string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness=1, int lineType=8, bool bottomLeftOrigin=false )
这个OpenCV 函数在图像上显示文字
- img - 欲显示文字的图片
- text - 欲在图片显示的文字
- org - 文本字符串在图像的左下角
- fontFace - 字体类型 (可选字体有: FONT_HERSHEY_SIMPLEX, FONT_HERSHEY_PLAIN, FONT_HERSHEY_DUPLEX, FONT_HERSHEY_COMPLEX, FONT_HERSHEY_TRIPLEX, FONT_HERSHEY_COMPLEX_SMALL, FONT_HERSHEY_SCRIPT_SIMPLEX
or FONT_HERSHEY_SCRIPT_COMPLEX. 上面任何一个字体可以与FONT_ITALIC"按位与"(bitwise or)可以得到斜体字) - fontScale - 缩放因子(如果设为1,默认大小)
- color - 文本以BGR颜色定义
- thickness - 字粗
- lineType - 线类型
- bottomLeftOrigin - 如果为true,原点设置在左下角。否则原点设定在左上角
- static MatExpr zeros(Size size, int type)
这个OpenCV的函数将返回指定的大小和类型的数组与零值
- size - 数组大小( e.g - Size(no. of columns, no. of rows) )
- type -数组元素类型
Gaussian Smoothing
"高斯平滑" 也叫 "高斯模糊" 或 "高斯过滤".是比较常用的一个平滑方法。是比较常见的平滑方法。也用于去除图像噪声。高斯核滑动扫描图像来对图像进行平滑。
内核的大小和在X和Y方向上的高斯分布的标准偏差应慎重选择。
OpenCV 代码
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" using namespace cv; int main( int argc, char** argv ) { //create 2 empty windows namedWindow( "Original Image" , CV_WINDOW_AUTOSIZE ); namedWindow( "Smoothed Image" , CV_WINDOW_AUTOSIZE ); // Load an image from file Mat src = imread( "MyPic.JPG", CV_LOAD_IMAGE_UNCHANGED ); //show the loaded image imshow( "Original Image", src ); Mat dst; char zBuffer[35]; for ( int i = 1; i < 31; i = i + 2 ) { //copy the text to the "zBuffer" _snprintf_s(zBuffer, 35,"Kernel Size : %d x %d", i, i); //smooth the image using Gaussian kernel in the "src" and save it to "dst" GaussianBlur( src, dst, Size( i, i ), 0, 0 ); //put the text in the "zBuffer" to the "dst" image putText( dst, zBuffer, Point( src.cols/4, src.rows/8), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255), 2 ); //show the blurred image with the text imshow( "Smoothed Image", dst ); //wait for 2 seconds int c = waitKey(2000); //if the "esc" key is pressed during the wait, return if (c == 27) { return 0; } } //make the "dst" image, black dst = Mat::zeros( src.size(), src.type() ); //copy the text to the "zBuffer" _snprintf_s(zBuffer, 35,"Press Any Key to Exit"); //put the text in the "zBuffer" to the "dst" image putText( dst, zBuffer, Point( src.cols/4, src.rows / 2), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) ); //show the black image with the text imshow( "Smoothed Image", dst ); //wait for a key press infinitely waitKey(0); return 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
采用高斯模糊后得到的图像 |
新出现的OpenCV函数
上面例子中OpenCV几乎都在之前例子中见到过。
- void GaussianBlur( InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT )
这个OpenCV函数中高斯模糊的核的定义,图像的所有通道都独立的进行处理。
- src - 源图像 (图像位深定义CV_8U, CV_16S, CV_16U, CV_32F or CV_64F)
- dst - 输出图像 (与输入图像位深及大小必须一致)
- ksize - 高斯平滑核大小 (核大小必须为正奇数)
- sigmaX - 在X方向的标准偏差。如果使用0,它会自动从内核尺寸计算
- sigmaY - 在Y方向的标准偏差。如果使用0,它会取和sigmaX一样的值.
- borderType - 可以定义各种边界插值方法。该值只影响在边界的像素。 ( k; BORDER_DEFAULT,可选参数 BORDER_REFLECT, BORDER_REPLICATE, BORDER_TRANSPARENT, BORDER_REFLECT_101 )
Median Smoothing
“平均平滑处理”也被称为“中间模糊处理”或“值滤波”。这也是一种常见的平滑技术。输入图像进行卷积用中值的内核。中值滤波是广泛用于边缘检测算法,因为在某些情况下,它保留边缘的同时去除噪声。
OpenCV Code
代码和上面的代码只有一行不一样。
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" using namespace cv; int main( int argc, char** argv ) { //create 2 empty windows namedWindow( "Original Image" , CV_WINDOW_AUTOSIZE ); namedWindow( "Smoothed Image" , CV_WINDOW_AUTOSIZE ); // Load an image from file Mat src = imread( "MyPic.JPG", CV_LOAD_IMAGE_UNCHANGED ); //show the loaded image imshow( "Original Image", src ); Mat dst; char zBuffer[35]; for ( int i = 1; i < 31; i = i + 2 ) { //copy the text to the "zBuffer" _snprintf_s(zBuffer, 35,"Kernel Size : %d x %d", i, i); //smooth the image using Median kernel in the "src" and save it to "dst" medianBlur( src, dst, i ); //put the text in the "zBuffer" to the "dst" image putText( dst, zBuffer, Point( src.cols/4, src.rows/8), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255), 2 ); //show the blurred image with the text imshow( "Smoothed Image", dst ); //wait for 2 seconds int c = waitKey(2000); //if the "esc" key is pressed during the wait, return if (c == 27) { return 0; } } //make the "dst" image, black dst = Mat::zeros( src.size(), src.type() ); //copy the text to the "zBuffer" _snprintf_s(zBuffer, 35,"Press Any Key to Exit"); //put the text in the "zBuffer" to the "dst" image putText( dst, zBuffer, Point( src.cols/4, src.rows / 2), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) ); //show the black image with the text imshow( "Smoothed Image", dst ); //wait for a key press infinitely waitKey(0); return 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
New OpenCV Functions
- void medianBlur( InputArray src, OutputArray dst, int ksize )
所有的通道图像平滑都是独立的
- src - 输入源图像 ( images with 1, 3 or 4 channels / Image depth should be CV_8U for any value of "ksize". If "ksize" equals 3 or 5, image
depths of CV_16U and CV_32F are also supported. - dst - 输出图像 (需与源图像大小和位深一致)
- ksize - 滤波器的大小 ( 必须是奇数且大于1 ) (注意 - 滤波器的尺寸大小为ksize x ksize)
双边平滑 Bilateral Smoothing
“双边平滑处理”也被称为“双边模糊处理”或“双边滤波”。这是最先进的过滤器,以平滑图像和减少噪音。同时去除噪声上述所有过滤器会抚平的边缘。但该过滤器能够减少图像的噪声,同时保留边缘。这种类型的过滤器的缺点是,它需要较长的时间来处理。
OpenCV 代码
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" using namespace cv; int main( int argc, char** argv ) { //create 2 empty windows namedWindow( "Original Image" , CV_WINDOW_AUTOSIZE ); namedWindow( "Smoothed Image" , CV_WINDOW_AUTOSIZE ); // Load an image from file Mat src = imread( "MyPic.JPG", CV_LOAD_IMAGE_UNCHANGED ); //show the loaded image imshow( "Original Image", src ); Mat dst; char zBuffer[35]; for ( int i = 1; i < 31; i = i + 2 ) { //copy the text to the "zBuffer" _snprintf_s(zBuffer, 35,"Kernel Size : %d x %d", i, i); //smooth the image using Bilateral filter in the "src" and save it to "dst" bilateralFilter( src, dst, i, i, i); //put the text in the "zBuffer" to the "dst" image putText( dst, zBuffer, Point( src.cols/4, src.rows/8), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255), 2 ); //show the blurred image with the text imshow( "Smoothed Image", dst ); //wait for 2 seconds int c = waitKey(2000); //if the "esc" key is pressed during the wait, return if (c == 27) { return 0; } } //make the "dst" image, black dst = Mat::zeros( src.size(), src.type() ); //copy the text to the "zBuffer" _snprintf_s(zBuffer, 35,"Press Any Key to Exit"); //put the text in the "zBuffer" to the "dst" image putText( dst, zBuffer, Point( src.cols/4, src.rows / 2), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) ); //show the black image with the text imshow( "Smoothed Image", dst ); //wait for a key press infinitely waitKey(0); return 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
新出现的OpenCV 函数
- void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT )
此OpenCV的功能筛选使用双边内核的图像。每个通道独立进行处理。此方法不到位工作。实时应用,“d”的值建议使用一个小于5值。
- src - 输入图像 (单通道或者三通道图像)
- dst - 输出图像(与输入图像属性一致)
- d - 像素领域直径
- sigmaColor - 在颜色空间的sigma
- sigmaSpace - 在坐标空间的sigma
- borderType - 可以定义各种边界插值方法。该值只影响在边界的像素。(可选参数如下:
BORDER_DEFAULT, BORDER_REFLECT, BORDER_REPLICATE, BORDER_TRANSPARENT, BORDER_REFLECT_101 )