openCV:图像的平滑去噪

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了openCV:图像的平滑去噪相关的知识,希望对你有一定的参考价值。

参考技术A 低频就是颜色缓慢变化,也就是灰度缓慢地变化,就代表着那是连续渐变的一块区域。相反高频即灰度变化快,相邻区域的灰度差别大,例如边缘,噪点都是灰度变化快的区域。

图像平滑是要突出图像的低频成分、主干部分或抑制图像噪声和干扰高频成分的图像处理方法,目的是使图像亮度平缓渐变,减小突变梯度,改善图像质量。字面意思就是让图像上颜色灰度变化更光滑。我们也称图像平滑为图像模糊,因为在平滑的时候,也失去了尖锐的特点。

现实中的数字图像在数字化和传输过程中常受到成像设备与外部环境噪声干扰等影响,称为含噪图像或噪声图像。那么除去这些噪声的过程就是图像去噪。

均值滤波也成线性滤波,其采用的主要方法为邻域平均法。线性滤波的基本原理是用原图像中某个像素临近值的均值代替原图像中的像素值。即滤波器的核(kernel)中所有的系数都相等,然后用该核去对图像做卷积。

基本和均值一样,即滤波器的核(kernel)中所有的系数都相等。但是它可以选择是否归一化,如果归一化,则和均值滤波毫无差别;若不选择归一化,则会导致像素点的值超过255,发生越界。

高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。

高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的,离得越近的像素点发挥的作用越大。

高斯核主要取决于σ。如果σ越小,高斯分布中心区域更加聚集,平滑效果越差;反之,则更离散,平滑效果越明显。

中值滤波器,使用滤波器窗口包含区域的像素值的中值来得到窗口中心的像素值。是一种非线性平滑滤波器。在去噪同时,较好的保持边缘轮廓细节,适合处理椒盐噪声,但对高斯噪声效果不好。

双边滤波器是一种可以保边去噪的滤波器,也是一种加权平均滤波器,与高斯滤波不同的是,其滤波核是由两个函数构成,一个函数是由几何空间距离决定滤波器系数,另一个由像素差值决定滤波器系数。
适合处理高斯噪声,但对椒盐噪声基本不起任何作用。

OpenCV图像处理篇之图像平滑

图像平滑算法

图像平滑与图像模糊是同一概念,主要用于图像的去噪。平滑要使用滤波器。为不改变图像的相位信息,一般使用线性滤波器,其统一形式例如以下:

技术分享

当中h称为滤波器的核函数。说白了就是权值。不同的核函数代表不同的滤波器,有不同的用途。

在图像处理中。常见的滤波器包含:

  1. 归一化滤波器(Homogeneous blur)

    也是均值滤波器,用输出像素点核窗体内的像素均值取代输出点像素值。

  2. 高斯滤波器(Guassian blur)

    是实际中最经常使用的滤波器。高斯滤波是将输入数组的每个像素点与 高斯内核 卷积将卷积和当作输出像素值。高斯核相当于对输出像素的邻域赋予不同的权值,输出像素点所在位置的权值最大(相应高斯函数的均值位置)。二维高斯函数为,

    技术分享

  1. 中值滤波器(median blur)

    中值滤波将图像的每个像素用邻域(以当前像素为中心的正方形区域)像素的中值取代。

    对椒盐噪声最有效的滤波器,去除跳变点很有效。

  2. 双边滤波器(Bilatrial blur)

    为避免滤波器平滑图像去噪的同一时候使边缘也模糊,这样的情况下使用双边滤波器。关于双边滤波器的解释參见http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html

以下的程序将先给标准Lena图像加入椒盐噪声。分别使用4种不同的滤波器进行平滑操作,请注意观察不同滤波器对椒盐噪声的去噪效果。

程序分析及结果

/*
 * FileName : image_smoothing.cpp
 * Author   : xiahouzuoxin @163.com
 * Version  : v1.0
 * Date     : Wed 17 Sep 2014 08:30:25 PM CST
 * Brief    : 
 * 
 * Copyright (C) MICL,USTB
 */
#include "cv.h"
#include "imgproc/imgproc.hpp"
#include "highgui/highgui.hpp"

using namespace std;
using namespace cv;

const int MAX_KERNEL_LENGTH = 10;

const char *wn_name = "Smoothing";

static void salt(Mat &I, int n);
static void disp_caption(const char *wn_name, Mat src, const char *caption);
static void disp_image(const char *wn_name, Mat I);

/*
 * @brief   
 * @inputs  
 * @outputs 
 * @retval  
 */
int main(int argc, char *argv[])
{
    if (argc<2) {
        cout<<"Usage: ./image_smoothing [file name]"<<endl;
        return -1;
    }

    Mat I = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
    salt(I, 6000);
    imshow(wn_name, I);
    waitKey(0);

    Mat dst;  // Result

    /* Homogeneous blur */
    disp_caption(wn_name, I, "Homogeneous blur");
    for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
        blur(I, dst, Size(i, i), Point(-1,-1));
        disp_image(wn_name, dst);
    }

    /* Guassian blur */
    disp_caption(wn_name, I, "Gaussian blur");
    for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
        GaussianBlur(I, dst, Size(i, i), 0, 0);
        disp_image(wn_name, dst);
    }

    /* Median blur */
    disp_caption(wn_name, I, "Median blur");
    for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
        medianBlur(I, dst, i);
        disp_image(wn_name, dst);
    }

    /* Bilatrial blur */
    disp_caption(wn_name, I, "Bilatrial blur");
    for (int i=1; i<MAX_KERNEL_LENGTH; i+=2) {
        bilateralFilter(I, dst, i, i*2, i/2);
        disp_image(wn_name, dst);
    }
    waitKey(0);

    return 0;
}


/*
 * @brief   显示提示文字(滤波方法)
 * @inputs  
 * @outputs 
 * @retval  
 */
static void disp_caption(const char *wn_name, Mat src, const char *caption)
{
    Mat dst = Mat::zeros(src.size(), src.type());

    putText(dst, caption, Point(src.cols/4, src.rows/2), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255,255,255));

    imshow(wn_name, dst);
    waitKey(0);
}



/*
 * @brief   显示图像
 * @inputs  
 * @outputs 
 * @retval  
 */
static void disp_image(const char *wn_name, Mat I)
{
    imshow(wn_name, I);
    waitKey(1000);
}


/*
 * @brief   加入椒盐噪声
 * @inputs  
 * @outputs 
 * @retval  
 */
static void salt(Mat &I, int n=3000)
{
    for (int k=0; k<n; k++) {
        int i = rand() % I.cols;
        int j = rand() % I.rows;

        if (I.channels()) {
            I.at<uchar>(j,i) = 255;
        } else {
            I.at<Vec3b>(j,i)[0] = 255;
            I.at<Vec3b>(j,i)[1] = 255;
            I.at<Vec3b>(j,i)[2] = 255;
        }
    }
}

上面程序的逻辑很清晰:

  1. 读入灰度图,并加入椒盐噪声(6000个噪声点):

    Mat I = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
    salt(I, 6000);

    技术分享

  2. disp_captiondisp_image函数各自是用于显示提示文字和平滑过程中的变化图像的,平滑过程中图像的变化例如以下图:

    技术分享

    注意观察上面的图。中值滤波(Median Blur)对椒盐噪声的效果最好!

  3. 四种滤波方法分别使用到4个OpenCV函数,这些函数的声明都在imgproc.hpp中。这些函数的前2个參数都是原图像和滤波后图像。

    归一化滤波器blur的第3个參数为滤波核窗体的大小。Size(i,i)表示ixi大小的窗体。

    高斯滤波器GaussianBlur第3个參数也是滤波核窗体的大小,第4、第5个參数分辨表示x方向和y方向的δ。

    中值滤波器medianBlur第3个參数是滤波器的长度,该滤波器的窗体为正方形。

    双边滤波器的函数原型例如以下:

    //! smooths the image using bilateral filter
    CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d,
                                 double sigmaColor, double sigmaSpace,
                                 int borderType=BORDER_DEFAULT );
  4. 本程序使用的Makefile文件为:

     TARG=image_smoothing
     SRC=image_smoothing.cpp
     LIB=-L/usr/local/lib/
     INC=-I/usr/local/include/opencv/ -I/usr/local/include/opencv2
     CFLAGS=
    
     $(TARG):$(SRC)
         g++ -g -o [email protected] ${CFLAGS} $(LIB) $(INC)          -lopencv_core -lopencv_highgui -lopencv_imgproc          $^
    
     .PHONY:clean
    
     clean:
         -rm $(TARG) tags -f

以上是关于openCV:图像的平滑去噪的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV图像处理篇之图像平滑

[OpenCV-Python] OpenCV 中计算摄影学 部分 IX 对象检测 部分 X

opencv1

opencv1

OpenCv 025---图像去噪

使用Opencv去噪多个灰度文本图像[重复]