雙邊濾波原理與C++實現

一、原理

     雙邊濾波(Bilateral filter)是一種可以去噪保邊的濾波器。之所以可以達到此效果,是因爲濾波器是由兩個函數構成:一個函數是由幾何空間距離決定濾波器係數,另一個由像素差值決定濾波器係數。
 原理示意圖如下:

     雙邊濾波器中,輸出像素的值依賴於鄰域像素的值的加權組合,
          
     權重係數w(i,j,k,l)取決於定義域核
          
     和值域核
          
     的乘積
          

二、C++實現
     2.1 OpenCV調用方法:
cvSmooth(m_iplImg, dstImg, CV_BILATERAL, 2 * r + 1, 0, sigma_r, sigma_d);


     2.2 MATLAB版代碼:
調用方法參見資料[1]     

     2.3 C++代碼
     
void CImageObj::Bilateral_Filter(int r, double sigma_d, double sigma_r)
{
	int i, j, m, n, k;
	int nx = m_width, ny = m_height;
	int w_filter = 2 * r + 1; // 濾波器邊長

	double gaussian_d_coeff = -0.5 / (sigma_d * sigma_d);
	double gaussian_r_coeff = -0.5 / (sigma_r * sigma_r);

	double** d_metrix = NewDoubleMatrix(w_filter, w_filter);  // spatial weight
	double r_metrix[256];  // similarity weight

	// copy the original image
	double* img_tmp = new double[m_nChannels * nx * ny];
	for (i = 0; i < ny; i++)
		for (j = 0; j < nx; j++)
			for (k = 0; k < m_nChannels; k++)
			{
				img_tmp[i * m_nChannels * nx + m_nChannels * j + k] = m_imgData[i * m_nChannels * nx + m_nChannels * j + k];
			}

	// compute spatial weight
	for (i = -r; i <= r; i++)
		for (j = -r; j <= r; j++)
		{
			int x = j + r;
			int y = i + r;

			d_metrix[y][x] = exp((i * i + j * j) * gaussian_d_coeff);
		}

	// compute similarity weight
	for (i = 0; i < 256; i++)
	{
		r_metrix[i] = exp(i * i * gaussian_r_coeff);
	}

	// bilateral filter
	for (i = 0; i < ny; i++)
		for (j = 0; j < nx; j++)
		{
			for (k = 0; k < m_nChannels; k++)
			{
				double weight_sum, pixcel_sum;
				weight_sum = pixcel_sum = 0.0;

				for (m = -r; m <= r; m++)
					for (n = -r; n <= r; n++)
					{
						if (m*m + n*n > r*r) continue;

						int x_tmp = j + n;
						int y_tmp = i + m;

						x_tmp = x_tmp < 0 ? 0 : x_tmp;
						x_tmp = x_tmp > nx - 1 ? nx - 1 : x_tmp;   // 邊界處理,replicate
						y_tmp = y_tmp < 0 ? 0 : y_tmp;
						y_tmp = y_tmp > ny - 1 ? ny - 1 : y_tmp;

						int pixcel_dif = (int)abs(img_tmp[y_tmp * m_nChannels * nx + m_nChannels * x_tmp + k] - img_tmp[i * m_nChannels * nx + m_nChannels * j + k]);
						double weight_tmp = d_metrix[m + r][n + r] * r_metrix[pixcel_dif];  // 複合權重

						pixcel_sum += img_tmp[y_tmp * m_nChannels * nx + m_nChannels * x_tmp + k] * weight_tmp;
						weight_sum += weight_tmp;
					}

				pixcel_sum = pixcel_sum / weight_sum;
				m_imgData[i * m_nChannels * nx + m_nChannels * j + k] = (uchar)pixcel_sum;
				
			} // 一個通道

		} // END ALL LOOP

	UpdateImage();
	DeleteDoubleMatrix(d_metrix, w_filter, w_filter);
	delete[] img_tmp;
}
性能方面,跟OpenCV處理速度有差距,有興趣的,可以自己研究OpenCV版本的源代碼

三、效果圖




四、參考資料
     資料[4]是MIT的學習資料,最全面,包括課件、論文、代碼等,涵蓋原理、改進、應用、與PDE的聯繫等等,最值得一看。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章