算法部分,我参考了这篇博客 http://blog.csdn.net/maozefa/article/details/5576499
namespace GaussianBlur{ #define PI 3.14156 double * dArray = NULL; double dQ = 0; int iRadius = 0; void InitGaussianBlur(double Q , int R) { dQ = Q; iRadius = R; dArray = new double[2*iRadius + 1]; double x; for (int i = -iRadius ; i <= iRadius ; ++i) { assert(dQ!=0); x = i/dQ; dArray[i+iRadius] = exp((double)(-x*x/2)); } double dUniform = 0; for (int i = -iRadius ; i <= iRadius ; ++i) { dUniform += dArray[i+iRadius]; } if (dUniform != 1) { for (int i = -iRadius ; i <= iRadius ; ++i) { dArray[i+iRadius] /= dUniform; } } } double GetFactor(int i) { if (dArray) { if (i>=0 && i<2*iRadius+1) { return dArray[i]; } } return 0; } void UnInitGaussianBlur() { if (dArray) { delete []dArray; dArray = NULL; } } }
上面这段代码是用于生成一个向量的函数。高斯模糊有两种方法,一种是用二元函数,就是在空间上正态分布的二元函数,或者使用一元函数,此时只能在图像的每一行上进行使用。高斯模糊的两个函数 http://www.cnblogs.com/hoodlum1980/articles/1088567.html
HBITMAP GaussianBlurFunc(HDC hDC, int x, int y, int iWidth, int iHeight ) { //定义图形大小 int iPixel = 24; int iBytesPerPixel = iPixel/8; //图形格式参数 LPBITMAPINFO lpbmih = new BITMAPINFO; lpbmih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); lpbmih->bmiHeader.biWidth = iWidth; lpbmih->bmiHeader.biHeight = iHeight; lpbmih->bmiHeader.biPlanes = 1; lpbmih->bmiHeader.biBitCount = iPixel; lpbmih->bmiHeader.biCompression = BI_RGB; lpbmih->bmiHeader.biSizeImage = 0; lpbmih->bmiHeader.biXPelsPerMeter = 0; lpbmih->bmiHeader.biYPelsPerMeter = 0; lpbmih->bmiHeader.biClrUsed = 0; lpbmih->bmiHeader.biClrImportant = 0; //创建位图数据 BYTE *pBits; HDC hdcMem = CreateCompatibleDC(hDC); HBITMAP hBitMap = CreateDIBSection(hdcMem,lpbmih,DIB_RGB_COLORS,(void **)&pBits,NULL,0); HGDIOBJ hOld = SelectObject( hdcMem, hBitMap); ::BitBlt( hdcMem, 0, 0, iWidth, iHeight, hDC, x, y, SRCCOPY); BYTE * pBitsCurrent; BYTE * newBitmap; BYTE r,g,b; BYTE newR,newG,newB; int iBytesScanLine; iBytesScanLine = ((iBytesPerPixel * iWidth + 3)>>2)<<2; newBitmap = new BYTE[iBytesScanLine*iHeight]; memset(newBitmap , 0 , iBytesScanLine*iHeight); BYTE * newBitmapCurrentPointer = newBitmap; double Q = 3; int R = 5; GaussianBlur::InitGaussianBlur(Q , R); BYTE * processBegin , * processEnd , * processCurrent; int indexBegin , indexEnd , indexCurrent; for (int j=0;j<iHeight;++j) { for (int i=0;i<iWidth;++i) { pBitsCurrent = pBits + j * iBytesScanLine + i * 3; newBitmapCurrentPointer = newBitmap + j * iBytesScanLine + i * 3; b = pBitsCurrent[0]; g = pBitsCurrent[1]; r = pBitsCurrent[2]; if (i < R) { processBegin = pBits + j * iBytesScanLine; indexBegin = R - i; } else { processBegin = pBitsCurrent - iBytesPerPixel * R; indexBegin = 0; } if (i > iWidth - R - 1) { processEnd = pBitsCurrent + j * iBytesScanLine + iWidth * 3; indexEnd = R - i + iWidth - 1; } else { processEnd = pBitsCurrent + R * iBytesPerPixel; indexEnd = 2 * R; } processCurrent = processBegin,indexCurrent = indexBegin ; newB = 0 , newG = 0 , newR = 0; for (; processCurrent <= processEnd && indexCurrent <= indexEnd ; processCurrent += iBytesPerPixel , indexCurrent += 1) { newB += processCurrent[0] * GaussianBlur::GetFactor(indexCurrent); newG += processCurrent[1] * GaussianBlur::GetFactor(indexCurrent); newR += processCurrent[2] * GaussianBlur::GetFactor(indexCurrent); } newBitmapCurrentPointer[0] = newB; newBitmapCurrentPointer[1] = newG; newBitmapCurrentPointer[2] = newR; } } #ifndef USE_TWO_GAUSSIANBLUR memcpy(pBits , newBitmap , iBytesScanLine*iHeight); delete [] newBitmap; #else for (int j=0;j<iHeight;++j) { for (int i=0;i<iWidth;++i) { pBitsCurrent = pBits + j * iBytesScanLine + i * 3; newBitmapCurrentPointer = newBitmap + j * iBytesScanLine + i * 3; b = newBitmapCurrentPointer[0]; g = newBitmapCurrentPointer[1]; r = newBitmapCurrentPointer[2]; if (j < R) { processBegin = pBits + i * 3; indexBegin = R - j; } else { processBegin = pBitsCurrent - iBytesScanLine * R; indexBegin = 0; } if (j > iWidth - R - 1) { processEnd = pBitsCurrent + iHeight * iBytesScanLine + i * 3; indexEnd = R - j + iHeight - 1; } else { processEnd = pBitsCurrent + R * iBytesScanLine; indexEnd = 2 * R; } processCurrent = processBegin,indexCurrent = indexBegin ; newB = 0 , newG = 0 , newR = 0; for (; processCurrent <= processEnd && indexCurrent <= indexEnd ; processCurrent += iBytesScanLine , indexCurrent += 1) { newB += newBitmapCurrentPointer[0] * GaussianBlur::GetFactor(indexCurrent); newG += newBitmapCurrentPointer[1] * GaussianBlur::GetFactor(indexCurrent); newR += newBitmapCurrentPointer[2] * GaussianBlur::GetFactor(indexCurrent); } pBitsCurrent[0] = newB; pBitsCurrent[1] = newG; pBitsCurrent[2] = newR; } } delete []newBitmap; #endif SelectObject(hdcMem, hOld); DeleteObject(hdcMem); GaussianBlur::UnInitGaussianBlur(); return hBitMap; }如果没有定义USE_TWO_GAUSSIANBLUR宏,那么图像处理一次,否则处理两次,也就是在行上处理一次,列上处理一次。
高斯模糊本质上是利用周边的点对中心的点进行模糊,比如有一个点,这个点受到周围像素值的混合,使这个点受到影响,而且越远的点对该点的影响会较小,之所以选择正态分布的函数,原因很简单,就是权值之和为1,并且中间位置占的比重最大,越往边上,值会越小。
举个例子。
这一行有一系列的点,A0,A1,A2,A3,A4。A2点受到周围两个点的影响,A2 = 较大权值*A2 + 较小权值*(A1 + A3) + 最小权值 *(A0+A4),这个权值可以怎么来呢, 就用一元的正态分布的函数,这几个权值肯定达不到1,因为正态分布的积分值才是1,所以要对其进行放大为1。
下面是Q=3,R=5处理后的效果图