原文:http://simplesource.blog.163.com/blog/static/1034140620113284223430/
高斯模糊就是把一个点与其周围的点进行相加然后平均,但是图像中的每个点都需要进行计算,所以计算量比较大,而且取像素设置像素的代码写起来也比较繁琐。今天我突然想到AlphaBlend其实就是整幅图像的像素与像素的相加操作,那么是不是可以用若干次AlphaBlend来实现高斯模糊呢?于是尝试了一下,果然可以。
代码如下:
bool Blur(HBITMAP hBmp, double a = 1, double b = 0.08) { static int modles[][3] = { {1, 0, 0}, {0, 1, 0}, {-1, 0, 0}, {0, -1, 0}, {1, 1, 0}, {1, -1, 0}, {-1, 1, 0}, {-1, -1, 0} }; int i; for(i = 7; i >= 0; i--) { modles[i][2] = (int)(255 * b); b = b / (1 - b); if(i == 4) { b *= 1.4142135623; } } CWindowDC wdc(NULL); CDC dc; dc.CreateCompatibleDC(&wdc); CImage imgSrc; imgSrc.Attach(hBmp); CBitmap bmp; if(bmp.CreateCompatibleBitmap(&wdc, imgSrc.GetWidth(), imgSrc.GetHeight())) { dc.SelectObject(&bmp); int alpha = (int)(a * 255); if(alpha > 254) { imgSrc.BitBlt(dc, 0, 0); } else if(alpha > 1) { imgSrc.AlphaBlend(dc, 0, 0, alpha); } for(i = 0; i < 8; i++) { imgSrc.AlphaBlend(dc, modles[i][0], modles[i][1], modles[i][2]); } imgSrc.Detach(); dc.SelectObject(hBmp); imgSrc.Attach(bmp); imgSrc.BitBlt(dc, 0, 0); imgSrc.Detach(); return true; } imgSrc.Detach(); return false; } |
至于标红色的那段,其实是因为每次AlphaBlend都是一次像素叠加运算,如果每次都是用相同的半透明度那么会导致最后一次的叠加占的比重最大,这样模糊就会发生偏移,而与正常的高斯模糊出现出入。
实际上每次AlphaBlend的像素叠加中每个像素的公式可以用下面的公式表示:
c = c0 * a + c1 * (1 - a) a表示半透明度,c0表示原始像素0,c1表示原始像素1,c表示叠加后的新像素 |
c = (1 - a8)(1 - a7)...(1 - a1) * c0 + (1 - a8)(1 - a7)...(1 - a2)* a1* c1 + (1 - a8)(1 - a7)...(1 - a3) * a2 * c2 + ... + a8 * c8 注意:这里有9个项 |
a8 = a; (1 - a8) * a7 = a; (1 - a8) * (1 - a7) * a6 = a; ... (1 - a8)(1 - a7)...(1 - a2)*a1 = a; 注意:我们只要8个方程。这里的a表示每个像素的目标占比,a1到a8表示每次AlphaBlend的透明度 |
a8 = a; a7 = a / (1 - a8) = a8 / (1 - a8); a6 = a / (1 - a8) / (1 - a7) = a7 / (1 - a7); ... a1 = a2 / (1 - a2); |
程序截图:
源代码下载:
HaloApp.rar |