Gimp高斯模糊——代码解释
Gimp gaussian blur - Code explanation
我想了解 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:我不是编码天才:(
流畅的代码。看来他们在做指针运算。
我将从顶部开始,然后使用 curve
进行解释。我知道你只是问曲线,但为了清楚起见,我也会解释其他的东西。
gint *curve;
这将创建一个指向内存地址的指针,该地址大到足以容纳一个整数(gint 类型)。目前它还没有初始化,所以不是很有帮助
curve = g_new (gint, n);
现在,创建了一个整数数组 (gint),并为曲线分配了这个新数组的起始地址。
length = n / 2;
这里他们正在计算大小为 n
的过滤器的中点。过滤器的大小基于 l
,它基于之前的 sigma 参数和对数变换数学。这里,length
指的是一维核的半径,而不是数组的长度,是数组的两倍长。
curve += length; /* 'center' the curve[] */
你的问题:这是怎么回事?
这会更改变量 curve
,因此它现在 指向 到先前初始化的数组的中间,以便后续的 for 循环索引很可能程序员更容易思考,编写、调试等更简洁
这里因为没有使用[]
运算符,所以对curve
的引用就是它在内存中的地址。分配的内存保留在原处,不会移动(当然你可以将它从一个地方复制到另一个地方,但这不是我在说的)。可以说,指针 curve
可以四处移动。 curve
本身的地址是设置的,但是,作为一个变量,它包含的地址可以调整和更改,以便它指向不同的东西,就像其他任何东西一样,非常量变量可以改变它的值。
起初,curve
指向曲线[0]的地址。事实并非如此,但既然你说你是新手,假设曲线 [0] 位于内存地址 00。所以 curve
的值也等于地址 00。调用 curve += length
可以是解释为 curve = curve + length
其内部是 将长度数据类型的大小(以字节为单位)添加到曲线的地址,然后用结果更新曲线的地址。为了举例,假设 gint 需要 4 个字节,length
是 5,curve
仍然是 00。
这样调用就变成了
curve += length
curve = curve + length
curve = curve + sizeof(length)
curve =
地址曲线指向+
字节长度使用内存
curve =
地址 00 +
4 字节 * 8 bits/byte
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(可以这么说)的索引集成。可能还有其他方法可以编写同样有效的代码,这就是它的美妙之处(或者,有时,也许是诅咒)。
我想了解 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:我不是编码天才:(
流畅的代码。看来他们在做指针运算。
我将从顶部开始,然后使用 curve
进行解释。我知道你只是问曲线,但为了清楚起见,我也会解释其他的东西。
gint *curve;
这将创建一个指向内存地址的指针,该地址大到足以容纳一个整数(gint 类型)。目前它还没有初始化,所以不是很有帮助
curve = g_new (gint, n);
现在,创建了一个整数数组 (gint),并为曲线分配了这个新数组的起始地址。
length = n / 2;
这里他们正在计算大小为 n
的过滤器的中点。过滤器的大小基于 l
,它基于之前的 sigma 参数和对数变换数学。这里,length
指的是一维核的半径,而不是数组的长度,是数组的两倍长。
curve += length; /* 'center' the curve[] */
你的问题:这是怎么回事?
这会更改变量 curve
,因此它现在 指向 到先前初始化的数组的中间,以便后续的 for 循环索引很可能程序员更容易思考,编写、调试等更简洁
这里因为没有使用[]
运算符,所以对curve
的引用就是它在内存中的地址。分配的内存保留在原处,不会移动(当然你可以将它从一个地方复制到另一个地方,但这不是我在说的)。可以说,指针 curve
可以四处移动。 curve
本身的地址是设置的,但是,作为一个变量,它包含的地址可以调整和更改,以便它指向不同的东西,就像其他任何东西一样,非常量变量可以改变它的值。
起初,curve
指向曲线[0]的地址。事实并非如此,但既然你说你是新手,假设曲线 [0] 位于内存地址 00。所以 curve
的值也等于地址 00。调用 curve += length
可以是解释为 curve = curve + length
其内部是 将长度数据类型的大小(以字节为单位)添加到曲线的地址,然后用结果更新曲线的地址。为了举例,假设 gint 需要 4 个字节,length
是 5,curve
仍然是 00。
这样调用就变成了
curve += length
curve = curve + length
curve = curve + sizeof(length)
curve =
地址曲线指向+
字节长度使用内存curve =
地址 00+
4 字节 * 8 bits/bytecurve = 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(可以这么说)的索引集成。可能还有其他方法可以编写同样有效的代码,这就是它的美妙之处(或者,有时,也许是诅咒)。