【问题标题】:Gaussian blur not uniform高斯模糊不均匀
【发布时间】:2013-12-03 11:48:19
【问题描述】:

我一直在尝试为我的图像编辑程序实现一个简单的高斯模糊算法。但是,我在完成这项工作时遇到了一些麻烦,我认为问题在于以下 sn-p:

        for( int j = 0; j < pow( kernel_size, 2 ); j++ )
        {
            int idx = ( i + kx + ( ky * img.width ));

            //Try and overload this whenever possible
            valueR += ( img.p_pixelArray[ idx ].r * kernel[ j ] );
            valueG += ( img.p_pixelArray[ idx ].g * kernel[ j ] );
            valueB += ( img.p_pixelArray[ idx ].b * kernel[ j ] );

            if( kx == kernel_limit )
            {
                kx = -kernel_limit;
                ky++;
            }

            else    
            {
                kx++;
            }
       }

       kx = -kernel_limit;
       ky = -kernel_limit;

简单解释一下上面的代码:kernel size是高斯模糊公式生成的kernel(或矩阵)的大小。 kxky 是用于迭代内核的变量。 i 是父循环,它嵌套这个循环,并遍历图像中的每个像素。每个 value 变量只保存一个浮点数 R、G 或 B 值,然后用于获取最终结果。 if-else 用于增加 kxkyidx 用于找到正确的像素。 内核限制是一个变量设置为

(*kernel size* - 1) / 2

所以我可以让 kx 从 -1(使用 3x3 内核)变为 +1,使用 ky 也是如此。我认为问题出在这条线上

int idx = ( i + kx + ( ky * img.width ));

但我不确定。我得到的图像是:

可以看出,颜色在对角线方向上是模糊的,看起来更像是某种运动模糊而不是高斯模糊。如果有人能帮忙,我将不胜感激。

编辑: 我填充内核的方式如下:

for( int i = 0; i < pow( kernel_size, 2 ); i++ )
{
    // This. Is. Lisp.
    kernel[i] = (( 1 / ( 2 * pi * pow( sigma, 2 ))) * pow (e, ( -((( pow( kx, 2 ) + pow( ky, 2 )) / 2 * pow( sigma, 2 ))))));

    if(( kx + 1 ) == kernel_size )
    {
        kx = 0;
        ky++;
    }

    else
    {
        kx++;
    }
}

【问题讨论】:

  • 我认为最后两个语句应该在您的循环之外?否则,您会在每次迭代时覆盖 kxky,并且您将始终获得相同的 idx 值。另外,你能告诉你如何填写kernel,也许这就是问题所在。
  • 哦,是的,反正它们都在循环之外,我现在只是把它们放错了地方......
  • @sgvd 编辑了问题以包括内核计算。

标签: c++ image-processing gaussian


【解决方案1】:

几个问题:

您的高斯函数在2 * pow( sigma, 2 ) 周围遗漏了括号(即使您已经有很多......)。现在你乘以方差而不是除法。

但是您的问题是,您的高斯以kx = ky = 0 为中心,因为您让它从0 运行到kernel_size,而不是从-kernel_limitkernel_limit。这导致对角线模糊。像下面这样的东西应该会更好

kx = -kernel_limit;
ky = -kernel_limit;

int kernel_size_sq = kernel_size * kernel_size;

for( int i = 0; i < kernel_size_sq; i++ )
{
  double sigma_sq = sigma * sigma;
  double kx_sq = kx * kx;
  double ky_sq = ky * ky;
  kernel[i] =  1.0 / ( 2 * pi * sigma_sq) * exp(-(kx_sq + ky_sq) / (2 * sigma_sq));

  if(kx == kernel_limit )
  {
    kx = -kernel_limit;
    ky++;
  }
  else
  {
    kx++;
  }
}

还要注意我是如何摆脱你的 lisp-ness 和一些改进的:使用一些中间变量来清楚起见(如果你要求编译器会优化它们);简单的乘法比pow(x, 2) 快; pow(e, x) == exp(x).

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-25
    • 2018-05-01
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 2016-04-30
    • 2011-12-07
    • 2023-03-22
    相关资源
    最近更新 更多