【问题标题】:Gimp gaussian blur - Code explanationGimp 高斯模糊 - 代码解释
【发布时间】:2018-01-11 19:25:05
【问题描述】:

我试图了解 Gimp 中的高斯模糊是如何工作的。我下载了代码,我可以几乎理解一些事情......但我对其他事情感到困惑。

代码如下:

make_rle_curve (gdouble   sigma,
            gint    **p_curve,
            gint     *p_length,
            gint    **p_sum,
            gint     *p_total)
{
  const gdouble  sigma2 = 2 * sigma * sigma;
  const gdouble  l      = sqrt (-sigma2 * log (1.0 / 255.0));
  gint           temp;
  gint           i, n;
  gint           length;
  gint          *sum;
  gint          *curve;

   n = ceil (l) * 2;
   if ((n % 2) == 0)
    n += 1;

   curve = g_new (gint, n);

  length = n / 2;
  curve += length; /* 'center' the curve[] */
  curve[0] = 255;

  for (i = 1; i <= length; i++)
  {
      temp = (gint) (exp (- (i * i) / sigma2) * 255);
      curve[-i] = temp;
      curve[i] = temp;
   }

  sum   = g_new (gint, 2 * length + 1);
  sum[0] = 0;
  for (i = 1; i <= length*2; i++)
   {
      sum[i] = curve[i-length-1] + sum[i-1];
   }

  sum += length; /* 'center' the sum[] */

  *p_total  = sum[length] - sum[-length];
  *p_curve  = curve;
  *p_sum    = sum;
  *p_length = length;

对我来说,curve 和 sum 是 2 个数组。曲线从-3到+3

和从 0 到 6。换句话说,我有

curve[-3] = ... 
curve[0] = 255
curve[3] = ...

但是curve = curve + length 到底做了什么? 同样的事情,sum = sum + length 做了什么?

非常感谢您的帮助!

ps:我不是编码天才:(

【问题讨论】:

    标签: c blur gaussian gimp


    【解决方案1】:

    流畅的代码。看来他们是在做指针运算。

    我将从顶部开始,然后使用curve 进行解释。我知道你只是在问曲线,但为了清楚起见,我也会解释其他的东西。

    gint *curve;

    这将创建一个指向内存地址的指针,该地址足够大以容纳整数(类型为 gint)。目前它还没有初始化,所以不是很有帮助

    curve = g_new (gint, n);

    现在,创建了一个整数数组 (gint),并为曲线分配了这个新数组的起始地址。

    length = n / 2;

    在这里,他们正在计算大小为n 的过滤器的中点。过滤器的大小基于l,它基于之前的 sigma 参数和对数变换数学。这里,length 指的是一维内核的 radius,而不是两倍长的数组的长度。

    curve += length; /* 'center' the curve[] */

    你的问题:这里发生了什么?

    这会更改变量curve,使其现在指向到先前初始化的数组的中间,以便程序员更容易考虑后续的for循环索引,并且编写、调试等更简洁。

    这里因为没有使用[]操作符,所以curve的引用就是它在内存中的地址。分配的内存保留在原地,不会移动(确保您可以将它从一个地方复制到另一个地方,但这不是我要说的)。可以说,指针curve 可以四处移动。 curve 的地址本身是设置的,但是,作为一个变量,它所包含的地址可以调整和更改,以便它指向不同的东西,就像任何其他非常量变量一样,可以更改其值。

    一开始,curve 指向的是curve[0]的地址。不是这样的,但是既然你说你是新人,假设curve[0]在内存地址00。所以curve的值,也等于地址00。调用curve += length可以解释为@987654337 @ 内部是将长度数据类型的大小(以字节为单位)添加到曲线的地址,然后用结果更新曲线的地址。举例来说,假设 gint 需要 4 个字节,length 为 5,curve 仍为 00。

    因此调用变成了

    1. curve += length
    2. curve = curve + length
    3. curve = curve + sizeof(length)
    4. curve =地址曲线指向+内存使用的字节数长度
    5. curve = 地址 00 + 4 字节 * 8 位/字节
    6. curve = Address 32(地址 32 将写入十六进制为 0x20)

    同样,使用g_new(gint, n) 声明的内存仍然存在,它被声明的位置(它不会移动),但是现在,由于指针已更改,它(指针)可用于索引该内存使用负索引的数组。即curve[0]实际上是现在数组中间的值,而curve[-n]是数组的第一个元素。

    在过滤器中,中点(curve[0])直接设置为最大值:

    curve[0] = 255;

    从这里 (+/- i) 开始执行后续迭代以填充内核。

    您可以在下一个 for 循环中看到曲线值再次偏移以居中(即curve[i-length-1])。现在有点令人困惑,因为看起来它们混合并匹配了这两种方法(有时使用指针算法使索引更清晰,有时则不然)。但是,嘿,他们对其进行了编程,并且可能有充分的理由根据其余代码的外观来这样做。谁知道呢,也许他们只是为了多样化而想把事情混为一谈。

    更新

    关于sum,先设置数组中的值,然后将指针改为指向这个填充数组的中心。但是,该程序可能会遵循之前在 curve 中看到的相同模式,并编写如下:

    sum += length; /* 'center' the sum[] */
    
    sum[-length] = 0;
    for (i = -length+1; i <= length; i++)
    {
       sum[i] = curve[i] + sum[i-1];
    }
    

    顺便说一句,调用*p_total = sum[length] - sum[-length]; 看起来可以简单地为p_total = sum[length];,因为sum[-length] 始终设置为0。也就是说,sum[0]=0 后跟sum += length 意味着sum[-length] 在调整与指针调整前的sum[0]相同。两个引用都指向数组中的第一个值,即 0。

    sum 指针放置到数组的中间与函数结束时将curve 设置到其数组的中间是一致的。

    然而,在使用 'sum' 的情况下,调整是在使用值初始化数组之后进行的,而在 curve 的情况下,首先进行调整,然后再初始化值。这可能只是程序员喜欢混淆事物,考虑与从 1 到 K 的索引集成可能更容易(可以这么说)。可能还有其他方法可以编写同样有效的代码,这就是它的美妙之处(或者有时可能是诅咒)。

    【讨论】:

    • 您好,非常感谢您的详细解答。我用曲线理解了这一点,但我没有用“sum”理解它。 “curve”先居中,然后设置值(curve[i] = curve[-i] = temp)。
    • "sum" 在值被定义后居中。那么我想用 sum[-1] 得到什么? (让我们假设 sum[1]= 4 )你能澄清一下吗?非常感谢!
    • 对。我会更新我的答案,因为它太长了,无法添加为评论。
    • 非常感谢!你的解释让我明白了:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-19
    • 2018-05-01
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 2016-04-30
    • 2011-12-07
    相关资源
    最近更新 更多