前两年我发过一文:Win32下的C++高斯模糊算法实例,里面给出了一个高斯模糊的实现,并写了粗略的简介。
不过当时内容讲得非常简单,而且附带的例子算法是有缺陷的:
- 一是对图片的边角采用“跳过”的方式处理,导致模糊后的图片有黑边;
- 二是算法本身采用的是二维矩阵,效率上不如一维高斯模糊好。
鉴于此,这里重新整理并试图完整的讲述一下高斯模糊。
一、高斯模糊是什么
模糊算法,不论是使用哪种算法,目的都是为了让图片看起来不如原来那么清晰。
清晰的图片,像素间的过渡会较为干脆利落,简而言之,就是像素之间的差距比较大。
而模糊的本质,其实就是使用某种算法把图像像素和像素之间的差距缩小,让中间点和周围点变得差不多;即,让中间点取一个范围内的平均值。
模糊到了极致,比如用于计算模糊的取值区域为整张图片,就会得到一张全图所有像素颜色都差不多的图片:
左边是原图,右边是彻底模糊之后的对比图
计算模糊的取值区域就是滤镜区域,那么关键就是,我们采用什么曲线函数来生成平均值了。
假设滤镜区域为正方形,且半径为r,我们可以用如下曲线函数来计算图片上某一个点的值:
这是一个非常简单的直线函数,求得的点值即为算术平均值,图片上某个点的值仅和模糊半径r有关,与坐标的位置无关。
由此我们可以得到用于模糊图像的滤镜算法:
void Average(filter_t& kernel, long radius)
{
long diamet = Diamet(radius); // (r * 2) + 1
kernel.set(radius, diamet * diamet); // kernel size is d * d
double average = 1.0 / (double)kernel.size();
for(long n = 0, i = 0; i < diamet; ++i)
for(long j = 0; j < diamet; ++j, ++n)
kernel[n] = average;
}
然后使用如下算法遍历整张图片,并使用滤镜处理像素:
void Blur2D(bitmap_t& bitmap, filter_t& kernel)
{
for(long inx = 0, y = 0; y < bitmap.h(); ++y)
{
for(long x = 0; x < bitmap.w(); ++x, ++inx)
{
double r = 0.0, g = 0.0, b = 0.0;
for (long n = 0, j = -kernel.radius(); j <= kernel.radius(); ++j)
{
long j_k = Edge(j, y, bitmap.h());
for (long i = -kernel.radius