1. 程式人生 > >VC++高斯濾波\中值濾波實現影象模糊處理

VC++高斯濾波\中值濾波實現影象模糊處理

一、演算法

高斯模糊演算法 詳見:高斯模糊,基本思想就是利用高斯函式,將一個座標點的所有鄰域的加權平均值設定為這些點的顏色值。

中值濾波演算法就更簡單了:將一個座標點的所有鄰域的平均值設定為這些點的畫素值。

二、演算法的程式碼實現

高斯函式:

使用巨集定義來替換:

#define PI<span style="white-space:pre">	</span>3.1415926
//高斯模糊函式
#define GAUSS_FUN(x, y) (exp(-(x*x)/(double)(2*y*y)))/(sqrt(2.0*PI)*y)
#define SQUARE(x)<span style="white-space:pre">	</span>((x)*(x))

//暫且定義sigma為10
const double sigma=10;

高斯模糊演算法處理畫素

//高斯模糊,nRadius為平均取值的半徑,半徑越大,影象越模糊,處理時間也越長
bool GaussFilter( DWORD* pData, DWORD* pCopy, const int nWidth, const int nHeight, const int nRadius/*=1*/ )
{
	if ( nWidth<=0 || nHeight<=0 || nRadius<=0 )
		return false;
	for ( int ny=0; ny<nHeight; ++ny )
	{
		for ( int nx=0; nx<nWidth; ++nx )
		{
			vector<COLOR_DATA> cdList;
			cdList.reserve(200);
			COLOR_DATA cd;
			double dTotal=0;
			for ( int m=nx-nRadius; m<=nx+nRadius; ++m )
			{
				if ( m<0 || m>=nWidth ) continue;
				for ( int n=ny-nRadius; n<=ny+nRadius; ++n )
				{
					if ( n<0 || n>=nHeight ) continue;
					cd.dDistance=GAUSS_FUN(sqrt((double)(SQUARE(m-nx)+SQUARE(n-ny))), sigma);
					dTotal+=cd.dDistance;
					cd.dwColor=*(pData+n*nWidth+m);
					cdList.push_back(cd);
				}
			}
			if ( cdList.size()>0 )
			{//這裡來計算整個鄰域內所有畫素點的加權平均值
				std::vector<COLOR_DATA>::const_iterator itor=cdList.begin();
				double r=0, g=0, b=0;
				for ( ; itor!=cdList.end(); ++itor ) 
				{
					double dRate=itor->dDistance/dTotal;//距離中心點越遠,權值越小
					r+=GetRValue(itor->dwColor)*dRate;
					g+=GetGValue(itor->dwColor)*dRate;
					b+=GetBValue(itor->dwColor)*dRate;
				}
				*(pCopy+ny*nWidth+nx)=RGB((int)r, (int)g, (int)b);
			}
		}
	}
	return true;
}
中值濾波函式就很簡單了,不細說
//中值濾波
bool MedianFilter( DWORD* pData, DWORD* pCopy, const int nWidth, const int nHeight, const int nRadius )
{
	if ( nWidth<=0 || nHeight<=0 || nRadius<=0 )
		return false;
	for ( int ny=0; ny<nHeight; ++ny )
	{
		for ( int nx=0; nx<nWidth; ++nx )
		{//掃描每一個點的鄰域,把他們的畫素值儲存起來。
			vector<DWORD> data;
			for ( int m=nx-nRadius; m<=nx+nRadius; ++m )
			{
				if ( m<0 || m>=nWidth || (m==nx) ) continue;
				for ( int n=ny-nRadius; n<=ny+nRadius; ++n )
				{
					if ( n<0 || n>=nHeight || (n==ny) ) continue;
					data.push_back(*(pData+n*nWidth+m));
				}
			}
			if ( data.size()>0 )
			{
				std::sort(data.begin(), data.end());//排序
				*(pCopy+ny*nWidth+nx)=data[data.size()/2];//取所有畫素值的中值作為整個區域的畫素值
			}
		}
	}
	return true;
}

執行緒函式中處理影象的畫素,完成後發訊息通知介面更新
DWORD __stdcall GaussThread(LPVOID lpParam)
{
	HLOCAL hMem=LocalAlloc(LHND, g_lBmpSize);
	DWORD* pBuffer=(DWORD*)LocalLock(hMem);
	LONG lCopySize=::GetBitmapBits(g_hBitmap1, g_lBmpSize, pBuffer);
	HLOCAL hMemCopy=LocalAlloc(LHND, g_lBmpSize);
	DWORD* pBufferCopy=(DWORD*)LocalLock(hMemCopy);
	//MedianFilter(pBuffer, bmMetric.bmWidth, bmMetric.bmHeight, 1);
	//MedianFilter(pBuffer, pBufferCopy, g_nBmpWidth, g_nBmpHeight, 3);
	//MedianFilterRGB(pBuffer, pBufferCopy, g_nBmpWidth, g_nBmpHeight, 10);
	GaussFilter(pBuffer, pBufferCopy, g_nBmpWidth, g_nBmpHeight, 6);
	::SetBitmapBits(g_hBitmap1, g_lBmpSize, pBufferCopy);
	LocalUnlock(hMem);
	LocalFree(hMem);
	LocalUnlock(hMemCopy);
	LocalFree(hMemCopy);
	::PostMessage(g_hMainWnd, WM_GAUSS_MSG, 0, 0);
	return 0;
}

三、程式執行效果圖:

鄰域距離為6時的高斯模糊處理效果:



鄰域距離為12時的高斯模糊處理效果:


鄰域距離為24時的高斯模糊處理效果:


這時候,執行緒處理得花好幾十秒時間了。

接著,對比中值濾波處理效果,鄰域距離為6、12、24時的三張效果圖分別為:




四、後記

對比效果圖可以看出,高斯濾波模糊效果比較平滑,中值濾波則比較粗糙。當然了,高斯演算法相對複雜,其處理時也很花費的時間。