1. 程式人生 > >影象處理基礎及OpenCV實現(四)

影象處理基礎及OpenCV實現(四)

四、 影象去噪

1、 影象的卷積核心

影象的空域處理一般利用卷積實現,影象二維卷積方式如下:
選定一種卷積模板,下圖是典型的矩形模板和十字形模板,
在這裡插入圖片描述在這裡插入圖片描述
然後遍歷整幅影象,假設影象在i、j處的灰度值為I_ij,那麼按矩形模板卷積後的值為
在這裡插入圖片描述
即根據模板的係數對原灰度值進行操作,根據模板的形狀和引數的不同而獲得不同的結果。這種模板也稱為影象的卷積核(kernel)。模板大小一般為奇數如33、55、7*7等,對於影象邊界一般不操作或者複製邊界擴大影象來處理。

2、 影象濾波

影象濾波是為了減小或消除影象中的噪聲,opencv中提供如下幾種濾波方式:
1) 均值濾波
在這裡插入圖片描述
將目標點和周圍的點的灰度值相加取平均,即模板的係數全部相同。使得影象更加平滑,但會減少影象邊緣高頻部分,使影象變模糊。
根據距離中心的距離設定權重,稱為加權中值濾波如下
在這裡插入圖片描述


後面高斯濾波就是一種加權濾波。
2) 中值濾波
選取模板中位於中間的灰度值作為濾波後的值,可以很好的抑制脈衝椒鹽噪聲,但同樣會弱化影象邊緣高頻部分。
3) 高斯濾波
模板是一個高斯二維影象的形狀,加重中心畫素的比例,即距離目標畫素越近,我們認為它對合成的新的灰度值貢獻越大,可以一定程度上保留影象細節和高頻部分。
在這裡插入圖片描述
上圖是19*19大小的高斯模板。
4) 雙邊濾波
雙邊濾波類似高斯濾波,但除了像高斯濾波那樣考慮位置對權重的影響,還考慮了模板畫素中顏色強度,即包含了空間域和顏色域的加權,詳細可參考這篇文章 https://blog.csdn.net/piaoxuezhong/article/details/78302920

OpenCV 提供了濾波函式:

    CVAPI(void) cvSmooth( const CvArr* src, CvArr* dst,
                      int smoothtype CV_DEFAULT(CV_GAUSSIAN),
                      int size1 CV_DEFAULT(3),
                      int size2 CV_DEFAULT(0),
                      double sigma1 CV_DEFAULT(0),
                      double
sigma2 CV_DEFAULT(0));

引數src:輸入影象
引數dst:輸出影象(注:opencv不支援原影象和輸出影象相同地址)
引數smoothtype:平滑方式

enum SmoothMethod_c
{
    CV_BLUR_NO_SCALE =0, /* 對模板下的每個畫素求和*/
    CV_BLUR  =1,/* 均值濾波 */
    CV_GAUSSIAN  =2,/* 高斯平滑*/
    CV_MEDIAN =3,/* 中值濾波 */
    CV_BILATERAL =4/** 雙向濾波 */
};

引數size1:模板大小,預設為3
引數size2:模板大小,為0時模板大小就為size1* size1
引數sigma1:高斯引數的標準差,為0時sigma=(size/2-1)*0.3+0.8
引數sigma2:雙向濾波時色域的標準差

IplImage* addNoise(IplImage* src, int noise_type, uint noise_count)
{
	IplImage *dst = cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
	IplImage *noise = cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
	CvRNG rng = cvRNG(-1);
	switch (noise_type)
	{
	case 1: //高斯噪聲
		cvRandArr(&rng, noise, CV_RAND_NORMAL, cvScalarAll(0), cvScalarAll(25));
		cvAdd(src, noise, dst);
		break;
	case 0: //椒鹽噪聲
		cvCopy(src, dst);
		for (int k = 0; k<noise_count; k++)
		{
			//CvRNG rng = cvRNG(-1);
			int i = cvRandInt(&rng) % src->height;
			int j = cvRandInt(&rng) % src->width;
			int m = cvRandInt(&rng) % 2;
			CvScalar s = cvGet2D(src, i, j);
			if (src->nChannels == 1)
			{
				if (m == 0)
				{
					s.val[0] = 255;
				}
				else
				{
					s.val[0] = 0;
				}
			}
			else if (src->nChannels == 3)
			{
				if (m == 0)
				{
					s.val[0] = 255;
					s.val[1] = 255;
					s.val[2] = 255;
				}
				else
				{
					s.val[0] = 0;
					s.val[1] = 0;
					s.val[2] = 0;
				}
			}
			cvSet2D(dst, i, j, s);
		}
		break;
	default:
		break;
	}
	cvReleaseImage(&noise);
	return dst;
}
void COpenPictureDlg::OnBnClickedMedian()
{
	// TODO: Add your control notification handler code here
	IplImage *src = cvCreateImage(cvGetSize(m_ipl), IPL_DEPTH_8U, 3);
	IplImage *src2 = cvCreateImage(cvGetSize(m_ipl), IPL_DEPTH_8U, 3);
	IplImage *dst = cvCreateImage(cvGetSize(m_ipl), IPL_DEPTH_8U, 3);
	cvCopy(m_ipl, src);
	UpdateData(TRUE);
	src2 = addNoise(src, m_nNoiseType,m_ipl->height*m_ipl->width/25);
	cvSmooth(src2, dst, CV_MEDIAN, 3, 3);
	// cvSmooth(src2, dst, CV_BLUR, 3, 3);
	// cvSmooth(src2, dst, CV_GAUSSIAN, 5, 5);
	// cvSmooth(src2, dst, CV_BILATERAL, 7, 0, 50, 10);
	cvNamedWindow(_T("濾波前的影象"));
	cvShowImage(_T("濾波前的影象"), src2);
	cvNamedWindow(_T("濾波後的影象"));
	cvShowImage(_T("濾波後的影象"), dst);
	cvReleaseImage(&src);
	cvReleaseImage(&src2);
	cvReleaseImage(&dst);
}

程式結果:(分別在椒鹽噪聲和高斯噪聲下的表現)
1) 均值濾波
在這裡插入圖片描述在這裡插入圖片描述
在這裡插入圖片描述在這裡插入圖片描述
2) 中值濾波
在這裡插入圖片描述在這裡插入圖片描述
在這裡插入圖片描述在這裡插入圖片描述
3) 高斯濾波
在這裡插入圖片描述在這裡插入圖片描述
在這裡插入圖片描述在這裡插入圖片描述
4) 雙邊濾波
在這裡插入圖片描述在這裡插入圖片描述
在這裡插入圖片描述在這裡插入圖片描述