Gimp Gaussian Blur - объяснение кода
Я пытаюсь понять, как работает размытие по Гауссу в 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;
Для меня, кривая и сумма 2 массива. кривая идет, скажем, от -3 до +3
и сумма идет от 0 до 6. Другими словами, у меня есть
curve[-3] = ...
curve[0] = 255
curve[3] = ...
но что делает curve = curve + length
действительно ли? То же самое, что делает sum = sum + length
делает?
Большое спасибо за Вашу помощь!
PS: я не гений в кодировании:(
1 ответ
Гладкий код. Похоже, они делают арифметику указателей.
Я начну сверху и буду работать вниз, используя curve
для объяснения. Я знаю, что вы спрашиваете только о кривой, но я объясню другие вещи для ясности.
gint *curve;
Это создает указатель на адрес памяти, который является достаточно большим, чтобы содержать целое число (типа gint). На данный момент он не инициализирован и поэтому не очень полезен
curve = g_new (gint, n);
Теперь создается массив целых чисел (gint) и кривой присваивается начальный адрес этого нового массива.
length = n / 2;
Здесь они рассчитывают среднюю точку фильтра, который является размером n
, Размер фильтра был основан на l
, который основан на параметре сигма и математике преобразования журнала ранее. Вот, length
относится к радиусу 1D ядра, а не к длине массива, который в два раза длиннее.
curve += length; /* 'center' the curve[] */
Ваш вопрос: что здесь происходит?
Это меняет переменную curve
так что теперь он указывает на середину массива, который был ранее инициализирован, так что программисту, вероятно, легче следовать за индексацией цикла, и немного чище писать, отлаживать и т. д.
Здесь, потому что []
операторы не используются, ссылка на 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 бит / байтcurve = Address 32
(Адрес 32 будет записан в шестнадцатеричном виде как 0x20)
Опять же, память, которая была объявлена с g_new(gint, n)
все еще там, где он был объявлен (он не перемещается), но теперь, поскольку указатель был изменен, его (указатель) можно использовать для индексации в этом массиве с использованием отрицательных индексов. То есть, curve[0]
на самом деле это значение в середине массива сейчас, в то время как curve[-n]
это первый элемент массива.
В фильтре средняя точка (curve[0]
) устанавливается прямо на максимальное значение:
curve[0] = 255;
Далее следуют итерации (+/- i) для заполнения ядра.
В следующем цикле вы можете увидеть, что значения кривой снова смещены в центр (т.е. 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 (так сказать). Вероятно, есть другие способы написания этого кода, которые работают так же хорошо, в этом вся прелесть (или, может быть, иногда проклятие).