高斯模糊算法

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

 

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

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

112 140 168 1/9 1/9 1/9
196 224 252 => 1/9 1/9 1/9
28 56 84 1/9 1/9 1/9

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


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

高斯模糊权重计算公式

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

0.0453542 0.0566406 0.0453542
0.0566406 0.0707355 0.0566406
0.0453542 0.0566406 0.0453542

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

0.094741 0.118318 0.094741
0.118318 0.147761 0.118318
0.094741 0.118318 0.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次

原文链接:https://94wz.top/3388.html,转载请注明出处。
赏 0

评论0

显示验证码
没有账号?注册  忘记密码?