图像去噪之非局部均值算法-原理和实现

1、基本原理

是一种空间域滤波,和高斯模糊、均值滤波类似,当前像素点的值时通过周围像素的加权平均得到。不同之处在于权值计算策略不同,也就是下面公式中w计算方式不同;
这里写图片描述

2、权重策略

这里写图片描述

以上图为例,对其去噪;对于帽子边缘的一个像素点,相比于高斯模糊或者均值模糊,用附近帽子边缘的像素点求均值更能好。那么计算机如何知道哪些像素也同样的是帽子边缘的像素?帽子边缘具有相似的结构,如果我们在每个像素周围画一个方框,方框内像素的欧式距离越小,说明结构越相似,中间的像素越是处于相同的结构位置,对应权重要更大,这个框的大小称kernel size。对多大范围内(B(p,r))的像素求加权平均,在这个算法中成为search size;

距离计算公式:
这里写图片描述

距离越小,越相似,权重越大
这里写图片描述

3、实现代码

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/photo.hpp>

using namespace std;
using namespace cv;




int distance2(Mat m1, Mat m2)
{
    Mat dst;
    absdiff(m1, m2, dst);
    int sum = 0;
    for (int j = 0; j < dst.rows; j++) {
        for (int i = 0; i < dst.cols; i++) {
            sum += dst.at<uchar>(j,i) *  dst.at<uchar>(j, i);
        }
    }
    return sum;
}

void nlmean(Mat src, Mat &dst, double h, double sigma, int halfKernelSize, int halfSearchSize)
{
    Mat boardSrc;
    dst.create(src.rows, src.cols, CV_8UC1);
    int boardSize = halfKernelSize + halfSearchSize;
    copyMakeBorder(src, boardSrc, boardSize, boardSize, boardSize, boardSize, BORDER_REFLECT);
    double h2 = h*h;
    double sigma2 = 2 * sigma*sigma;

    int rows = src.rows;
    int cols = src.cols;

    int lookupTableSize = 256 * 256 *(2* halfKernelSize +1)*(2* halfKernelSize+1);
    double *lookupTable = new double[lookupTableSize];

    for (int i = 0; i < lookupTableSize; i++) {
        if(i<sigma2)
            lookupTable[i] =1;
        else
            lookupTable[i] = exp(-i/ h2/(2* halfKernelSize+1) /(2* halfKernelSize+1));
    }

    for (int j = boardSize; j < boardSize+ rows; j++) {
        for (int i = boardSize; i < boardSize+cols; i++) {
            Mat patchA=boardSrc( Range(j - halfKernelSize, j + halfKernelSize), Range (i - halfKernelSize, i + halfKernelSize));
            double w = 0;
            double p = 0;
            double sumw = 0;

            for (int sr = -halfSearchSize; sr <= halfSearchSize; sr++) {
                for (int sc = -halfSearchSize; sc <= halfSearchSize; sc++) {

                    Mat patchB = boardSrc(Range(j+sr - halfKernelSize, j+sr + halfKernelSize), Range(i +sc- halfKernelSize, i+sc + halfKernelSize));
                    int d2 = distance2(patchA, patchB);

                    w = lookupTable[d2];
                    p += boardSrc.at<uchar>(j+sr, i+sc)*w;

                    sumw += w;
                }
            }

            dst.at<uchar>(j - boardSize, i - boardSize) = saturate_cast<uchar>(p / sumw);

        }
    }
    delete[]lookupTable;

}

int main()
{
    Mat src = imread("lena.png", IMREAD_GRAYSCALE);
    Mat dst;
    Mat cvdst;

    fastNlMeansDenoising(src, cvdst, 3, 7, 10);


    namedWindow("src");
    imshow("src", src);
    imshow("cvdst", cvdst);
    nlmean(src, dst, 3, 5, 3, 10);
    imshow("mydst", dst);

    Mat diff;
    absdiff(src, dst, diff);
    imshow("diff", diff);
    waitKey(0);
}

4、效果:

原图
这里写图片描述

opencv自带函数实现效果
这里写图片描述

我的实现效果
这里写图片描述

4、论文链接
http://www.ipol.im/pub/art/2011/bcm_nlm/?utm_source=doi

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值