算法部分,我参考了这篇博客 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处理后的效果图