图像降噪算法——小波硬阈值滤波(下)

图像降噪算法——小波硬阈值滤波(下)

  • 图像降噪算法——小波硬阈值滤波(下)
    • 1. 基本原理
    • 2. C++代码实现
    • 3. 结论

图像降噪算法——小波硬阈值滤波(下)

1. 基本原理

关于离散小波变换的原理在

图像降噪算法——小波硬阈值滤波(上)

中已经有了非常详细的总结,这里介绍下本博客利用离散小波变换进行降噪的原理(其实不能算是降噪,应该算是图像压缩),就是在小波变换之后,将输出系数进行由大到小的排序,然后将前10%大的通过小波反变换成图像,因为噪声不属于图像的主要信息,因此通过这种方法会有降噪的效果,这种算法又称为小波硬阈值滤波。

2. C++代码实现

这里是基于OpenCV、FFTW以及C++ Wavelet Libraries,这其中
(1)FFTW是一个基于C写的实现傅里叶变换和小波变换的基础库,链接戳这里,源码安装后用CmakeList链接到静态库文件即可。
(2)C++ Wavelet Libraries是利用FFTW封装的一个小波变换处理图像的库,下载链接戳这里,这里主要是用到了它的wavelet2d.cpp和wavelet2d.h两个文件。
我封装的小波变换的降噪算法如下:

Mat Denoise::WaveletFilter(const Mat &src, int num, int percentage)
{
    //需要讲Mat数据结构转换为vector数据结构
    vector<vector<double>> dwtInput(src.rows, vector<double>(src.cols));
    for(int i = 0; i<src.rows; i++)
    {
        for(int j = 0; j<src.cols; j++)
        {
            dwtInput[i][j] = (double)src.at<uchar>(i,j);
        }
    }

    //计算小波变换,输出结果是output
    vector<int> dwtLength;
    vector<double> dwtOutput, dwtFlag;
    dwt_2d(dwtInput, num, "db2", dwtOutput, dwtFlag, dwtLength);

    //******************************显示相关******************************
//    //通过dwtLength计算dim
//    vector dwtDim;
//    dwt_output_dim_sym(dwtLength, dwtDim, num);
//
//    //dim的后两位是显示尺寸,并将dwtOutput构造成display
//    int dwtRow = dwtDim[dwtDim.size()-2], dwtCol = dwtDim[dwtDim.size()-1];
//    vector> dwtDisplay(dwtRow, vector(dwtCol));
//    dispDWT(dwtOutput, dwtDisplay, dwtLength, dwtDim, num);
//
//    //获取display中的最大值
      double m = 0;
//    for(int i = 0; i < dwtRow; i++)
//    {
//        for(int j = 0; j < dwtCol; j++)
//        {
//            if(m < dwtDisplay[i][j])
//                m = dwtDisplay[i][j];
//        }
//    }
//
//    //dst是用于显示的图像
//    Mat dst = Mat::zeros(dwtRow,dwtCol,CV_8UC1);
//    for(int i = 0; i < dwtRow; i++)
//    {
//        for(int j = 0; j < dwtCol; j++)
//        {
//            if(dwtDisplay[i][j] <= 0.0)
//                dwtDisplay[i][j] = 0.0;
//            if(i<=dwtDim[0] && j<=dwtDim[1])
//                dst.at(i,j) = (uchar)(dwtDisplay[i][j]/m*255);
//            else
//                dst.at(i,j) = (uchar)(dwtDisplay[i][j]);
//        }
//    }
//    imshow("dst", dst);
    //******************************************************************


    //******************************滤波相关******************************
    //开始滤波
    int filterSize = int(dwtOutput.size() / percentage);
    vector<double> filter;
    for(auto it : dwtOutput)
    {
        filter.push_back(abs(it));
    }
    sort(filter.begin(), filter.end(), greater<double>());
    double threshold = filter.at(filterSize-1);
    for(int i = 0; i<dwtOutput.size(); i++)
    {
        double tmp = abs(dwtOutput[i]);
        if(tmp < threshold)
            dwtOutput.at(i) = 0.0;
    }
    //******************************************************************


    //******************************显示相关******************************
//    dispDWT(dwtOutput, dwtDisplay, dwtLength, dwtDim, num);
//
//    //获取display中的最大值
//    m = 0;
//    for(int i = 0; i < dwtRow; i++)
//    {
//        for(int j = 0; j < dwtCol; j++)
//        {
//            if(m < dwtDisplay[i][j])
//                m = dwtDisplay[i][j];
//        }
//    }
//
//    //dst是用于显示的图像
//    Mat dst2 = Mat::zeros(dwtRow,dwtCol,CV_8UC1);
//    for(int i = 0; i < dwtRow; i++)
//    {
//        for(int j = 0; j < dwtCol; j++)
//        {
//            if(dwtDisplay[i][j] <= 0.0)
//                dwtDisplay[i][j] = 0.0;
//            if(i<=dwtDim[0] && j<=dwtDim[1])
//                dst2.at(i,j) = (uchar)(dwtDisplay[i][j]/m*255);
//            else
//                dst2.at(i,j) = (uchar)(dwtDisplay[i][j]);
//        }
//    }
//    imshow("dst2", dst2);
    //******************************************************************

    //下面是进行小波反变换过程
    vector<vector<double>> idwtOutput(src.rows, vector<double>(src.cols));
    idwt_2d(dwtOutput, dwtFlag, "db2", idwtOutput, dwtLength);

    int idwtRow = idwtOutput.size();
    int idwtCol = idwtOutput[0].size();

    //获取idwtOutput中的最大值
    m = 0;
    for(int i = 0; i < idwtRow; i++)
    {
        for(int j = 0; j < idwtCol; j++)
        {
            if(m < idwtOutput[i][j])
                m = idwtOutput[i][j];
        }
    }

    //显示降噪后的图像
    Mat img = Mat::zeros(idwtRow, idwtCol, CV_8UC1);
    for(int i = 0; i<idwtRow; i++)
    {
        for(int j = 0; j<idwtCol; j++)
        {
            if(idwtOutput[i][j] <= 0.0)
            {
                idwtOutput[i][j] = 0.0;
            }
            img.at<uchar>(i,j) = (uchar)(idwtOutput[i][j]/m*255);
        }
    }
    return img;
}

原图如下:
图像降噪算法——小波硬阈值滤波(下)_第1张图片
加入高斯噪声:图像降噪算法——小波硬阈值滤波(下)_第2张图片
进行图像小波变换:图像降噪算法——小波硬阈值滤波(下)_第3张图片
按照上述方法进行滤波:
图像降噪算法——小波硬阈值滤波(下)_第4张图片
进行图像小波反变换:
图像降噪算法——小波硬阈值滤波(下)_第5张图片

3. 结论

  1. 可以看到通过图像小波变换进行降噪的效果看上去还可以,起码比傅里叶变换的效果要好,但是呢,感觉小波变换的速度还是比较慢,实时运行应该比较困难;
  2. 本文采用的降噪算法其实比较简单,在这篇文献中《Image Denoising Review From Classical to State-of-the-art Approaches,2020》提到,对于转换域的降噪算法主要有两个关键点:1.转换到什么变换域(傅里叶?小波?脊波?);2.采用什么类型的阈值进行滤波,这篇文献中提到了六种设计阈值的方法,需要了解的同学可以参考下;
  3. 小波变化提取信息主要是在水平、垂直和对角线三个方向,在小波的基础上,还有curvelet、contourlet等一些更加高级的变化,之后有需要再进一步了解。

你可能感兴趣的:(图像降噪,计算机视觉)