高斯模糊算法

图像处理软件中通常都会有个高斯模糊的选项,能够将一张清晰的图片变得模糊。

模糊的实现很简单,就是将像素点周围格子按照指定的权重分配,求和后取平均值,即为该像素点最终的值。

假设某个像素点与周围格子的颜色值如下,按照右边的权重分配:

1121401681/91/91/9
196224252=>1/91/91/9
28 56841/91/91/9

那么该像素点的取值为:
112 * 1/9 + 140 * 1/9 + … + 84 * 1/9 = 140
这是一个简单的模糊例子,周围权重按等比例分配的模糊,叫均值模糊。


而高斯模糊与均值模糊的区别仅仅是在权重的分配上,高斯模糊是越靠近中心点的格子权值越高,计算公式:

高斯模糊权重计算公式

模糊半径为 1 的权重分配:

0.04535420.05664060.0453542
0.05664060.07073550.0566406
0.04535420.05664060.0453542

权重之和需要等于 1 ,最终的权重为:

0.0947410.1183180.094741
0.1183180.1477610.118318
0.0947410.1183180.094741

代码实现:

$step = 1;
$sigma = 1.5;
$weights = [];
$weightSum = 0;

// 通过公式计算权重分配
for ($y = -$step; $y <= $step; $y ++) {
  $weights[$y] = [];
  for ($x = -$step; $x <= $step; $x ++) {
    $weights[$y][$x] = 1 / (2 * pi() * $sigma ** 2) * exp(- ($x ** 2 + $y ** 2) / (2 * $sigma ** 2));
    $weightSum += $weights[$y][$x];
  }
}

// 计算最终权重
for ($y = -$step; $y <= $step; $y ++) {
  for ($x = -$step; $x <= $step; $x ++) {
    $weights[$y][$x] /= $weightSum;
  }
}

完整代码:

$img = imagecreatefromstring(file_get_contents('lenna.jpg'));
$width = imagesx($img);
$height = imagesy($img);
$output = imagecreatetruecolor($width, $height);
$maxX = $width - 1;
$maxY = $height - 1;

// 获取图像所有像素点的颜色值
for ($y = 0; $y < $height; $y ++) {
  for ($x = 0; $x < $width; $x ++) {
    $hex = imagecolorat($img, $x, $y);
    $colors[$y][$x] = [
      $hex >> 16 & 0xff,
      $hex >> 8 & 0xff,
      $hex & 0xff
    ];
  }
}

// 遍历每个像素点
for ($y = 0; $y < $height; $y ++) {
  for ($x = 0; $x < $width; $x ++) {
    // 将r、g、b分别抽离出来计算
    $r = 0;
    $g = 0;
    $b = 0;
    // 遍历周围像素点
    for ($y2 = -$step; $y2 <= $step; $y2 ++) {
      for ($x2 = -$step; $x2 <= $step; $x2 ++) {
        $px = max(min($x + $x2, $maxX), 0);
        $py = max(min($y + $y2, $maxY), 0);
        $rgb = $colors[$py][$px];
        $weight = $weights[$y2][$x2];
        $r += $rgb[0] * $weight;
        $g += $rgb[1] * $weight;
        $b += $rgb[2] * $weight;
      }
    }
    // 绘制最终像素点
    imagesetpixel($output, $x, $y, ($r << 16) + ($g << 8) + $b);
  }
}

// 输出
header('Content-Type:image/png');
imagepng($output);

效果:

Lenna高斯模糊

可以看出半径为 1 的模糊效果不是十分明显,如果需要更模糊,可以尝试将半径的值调大(但按照这种写法性能极差),或是半径为 1 多模糊几次。

原图、半径5、半径1执行5次

留下评论

邮箱地址不会被公开。 必填项已用*标注

给博主打赏

2元 5元 10元