1. 程式人生 > >影象保邊濾波演算法集錦--非區域性均值NLM濾波器

影象保邊濾波演算法集錦--非區域性均值NLM濾波器

本文介紹非區域性均值濾波,這種濾波器效果非常好,但是演算法耗時嚴重,這裡以效果為先,來給大家講解。

非區域性均值濾波(Non-Local Means,NLM)是Buades等人於2005年在論文“A non-local algorithm for image denoising”中提出的對傳統鄰域濾波方法的一種改進濾波,考慮到了影象的自相似性質,它充分利用了影象中的冗餘資訊,在去噪的同時能夠最大程度的保持影象的細節特徵。

該演算法需要計算影象中所有畫素與當前畫素之間的相似性,考慮到這個計算量與效率的問題,一般會設定兩個固定大小的視窗,一個大的搜尋視窗(D×D)和一個小的鄰域視窗(d×d),鄰域視窗在搜尋視窗中進行滑動,根據鄰域間的相似性來確定對應中心畫素對當前畫素的影響度,也就是權值。

下圖是NLM演算法執行過程,大視窗是以目標畫素為中心的搜尋視窗,兩個灰色小視窗分別是以x,y為中心的鄰域視窗。其中以y為中心的鄰域視窗在搜尋視窗中滑動,通過計算兩個鄰域視窗間的相似程度為y賦以權值w(x,y) 。

NLM的演算法流程如下:

    關於NLM的快速演算法,可以參考論文:

FromentJ. Parameter-Free Fast Pixelwise Non-Local Means Denoising[J]. Image ProcessingOn Line, 2014, 4: 300-326

本人使用C語言實現程式碼如下(沒有使用快速演算法,速度在10S以上,使用DEMO時輕耐心等待):

#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include"f_NLM.h"

#define MIN2(a, b) ((a) < (b) ? (a) : (b))
#define MAX2(a, b) ((a) > (b) ? (a) : (b))
#define CLIP3(x, a, b) MIN2(MAX2(a,x), b)


void NLM(unsigned char* srcData, int width, int height, int D, int d, float h)
{
	unsigned char* tempData = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
	memcpy(tempData, srcData, sizeof(unsigned char) * height * width);
	float sw = 0;
	float sum = 0;
	int px, py, cx, cy;
	float zx;
	float vxsy = 0;
	float DD = d * d;
	float HH = h * h;
	for(int j = 0; j < height; j++)
	{
		for(int i = 0; i < width; i++)
		{
			sw = 0;
			zx = 0; 
			sum = 0;
			for(int n = -D; n <= D; n++)
			{
				for(int m = -D; m <= D; m++)
				{			
					vxsy = 0;
					for(int kn = -d; kn <= d; kn++)
					{
						for(int km = -d; km <= d; km++)
						{
							cx = CLIP3(i - d + km, 0, width - 1);
							cy = CLIP3(j - d + kn, 0, height - 1);
							px = CLIP3(i + m + km, 0, width - 1);
							py = CLIP3(j + n + kn, 0, height - 1);
							vxsy += (tempData[px + py * width] - tempData[cx + cy * width]) * (tempData[px + py * width] - tempData[cx + cy * width]);
						}
					}
					vxsy = vxsy / DD;
					sw = exp(-vxsy / HH);
					zx += sw;
					int ox = CLIP3(i + m, 0, width - 1);
					int oy = CLIP3(j + n, 0, height - 1);
					sum += sw * tempData[ox + oy * width];
				}
			}
			srcData[i + j * width] = zx == 0 ? srcData[i + j * width] : CLIP3(sum / zx, 0, 255);
		}
	}
	free(tempData);
};

void f_NLMFilter(unsigned char* srcData, int nWidth, int nHeight, int nStride, int dRadius, int sRadius, int h)
{
	if (srcData == NULL)
	{
		return;
	}
	if(dRadius == 0 || sRadius == 0 || h == 0 || dRadius <= sRadius)
		return;
	unsigned char* rData = (unsigned char*)malloc(sizeof(unsigned char) * nWidth * nHeight);
	unsigned char* gData = (unsigned char*)malloc(sizeof(unsigned char) * nWidth * nHeight);
	unsigned char* bData = (unsigned char*)malloc(sizeof(unsigned char) * nWidth * nHeight);
	unsigned char* pSrc = srcData;
	unsigned char* pR = rData;
	unsigned char* pG = gData;
	unsigned char* pB = bData;
	for(int j = 0; j < nHeight; j++)
	{
		for(int i = 0; i < nWidth; i++)
		{
			*pR = pSrc[2];
			*pG = pSrc[1];
			*pB = pSrc[0];
			pR++;
			pG++;
			pB++;
			pSrc += 4;
		}
	}
	NLM(rData, nWidth, nHeight, dRadius, sRadius, h);
	NLM(gData, nWidth, nHeight, dRadius, sRadius, h);
	NLM(bData, nWidth, nHeight, dRadius, sRadius, h);
	pSrc = srcData;
	pR = rData;
	pG = gData;
	pB = bData;
	for(int j = 0; j < nHeight; j++)
	{
		for(int i = 0; i < nWidth; i++)
		{
            pSrc[2] = * pR;
			pSrc[1] = * pG;
			pSrc[0] = * pB;
			pR++;
			pG++;
			pB++;
			pSrc += 4;
		}
	}
	free(rData);
	free(gData);
	free(bData);
}

非區域性均值濾波的效果如下圖所示:

上面就是LNM濾波器的效果了,從效果上看,用來做美顏磨皮完全沒有問題,但是由於速度限制,基本上沒有用它來做的,當然,作為演算法學習,還是可以的。

最後給出一個原始碼+DEMO連結:NLM濾波

注意,本文演算法部分參考了網上部落格內容,測試圖片也均來自網路,若有侵權,敬請告知,謝謝。

本人QQ1358009172, 公眾號:SF影象演算法