VC++高斯濾波\中值濾波實現影象模糊處理
阿新 • • 發佈:2019-02-18
一、演算法
高斯模糊演算法 詳見:高斯模糊,基本思想就是利用高斯函式,將一個座標點的所有鄰域的加權平均值設定為這些點的顏色值。
中值濾波演算法就更簡單了:將一個座標點的所有鄰域的平均值設定為這些點的畫素值。
二、演算法的程式碼實現
高斯函式:
使用巨集定義來替換:
#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時的高斯模糊處理效果:鄰域距離為24時的高斯模糊處理效果:
這時候,執行緒處理得花好幾十秒時間了。
接著,對比中值濾波處理效果,鄰域距離為6、12、24時的三張效果圖分別為:
四、後記
對比效果圖可以看出,高斯濾波模糊效果比較平滑,中值濾波則比較粗糙。當然了,高斯演算法相對複雜,其處理時也很花費的時間。