Вот посмотрел я сегодня еще раз те жалкие картинки, которые мне сделал hugin вместо HDR, и подумал, что надо бы все-таки реализовать свою HDR-собиралку (теоретически, т.к. hugin — всего лишь обертка, запускающая консольные утилиты, можно ей вместо hugin_hdrmerge свое подсунуть).
Теорию я уже приводил на ЛОРе, да и частично реализовывал при анализе камеры Apogee. Т.к. здесь работа ведется с png-файлами, все сильно упрощается (правда, надо где-то сохранять сведения об экспозиции каждого кадра, иначе ничего не получится): открываем одновременно все файлы, затем построчно считываем их, строка за строкой заполняя результирующее HDR-изображение. Обработка элементарная: отбрасываем значения ЧБ-интенсивности, близкие к 0 или 255; далее делим оставшиеся интенсивности на экспозиции; вычисляем медиану; сохраняем логарифм полученного значения во временный файл (лучше, пожалуй, double использовать), параллельно вычисляя максимальную и минимальную величину логарифма. В другой или этот же файл сохраняем данные о цвете, которые берем из того изображения, где уровень серого в данном пикселе лежит где-нибудь так в диапазоне 176..230 (надо экспериментально подобрать).
По окончании обработки всего изображения преобразуем наш бинарник в нормальный png-файл.
Такой способ обработки все шумы максимально уменьшит, кроме шумов на уж очень темных местах (т.е. на темных участках изображения с максимальной экспозицией). Их придется восстанавливать, предварительно пройдясь медианным фильтром.
В общем, если не забуду об этой идее, как-нибудь от скуки реализую.
Для демонстрации я набросал простенький код. Функция proc_images(im) открывает изображение im, генерирует на его основе "кадры с разными экспозициями", а затем получает нечто, вроде HDR (еще допиливать надо):
function [II, BIN] = proc_images(Imname)
II = imread(Imname);
I0 = 64; I1 = 192;
W = size(II, 2);
H = size(II, 1);
I = []; G = [];
N = [1:7];
T = 2.^(N-N(ceil(size(N,2)/2)));
for n = N
[I_t G_t] = mk_im(II, T(n));
I_t(:,:,1) = medfilt2(I_t(:,:,1), "replicate");
I_t(:,:,2) = medfilt2(I_t(:,:,2), "replicate");
I_t(:,:,3) = medfilt2(I_t(:,:,3), "replicate");
G_t(find(G_t < I0)) = 0;
G_t(find(G_t > I1)) = 255;
I(:,:,:,n) = I_t;
G(:,:,n) = G_t;
clear I_t G_t
endfor
clear II;
BIN = [];
Imax = 0;
Imin = 1e10;
for y = 1:H
fprintf(1, "Y = %d\n", y);
fflush(1);
for x = 1:W
PT = [];
nn = [];
for n = N
g = G(y,x,n);
if(g >= I0 && g <= I1)
PT = [PT g];
nn = [nn n];
endif
endfor
if(size(PT) == 0)
if(g < I0)
%colr = [0 0 0];
colr = I(y,x,:,end) / T(end);
else
%i = 255 / T(1);
%colr = [i i i];
colr = I(y,x,:,1) / T(1);
endif
else
%i = median(PT./T(nn));
PT = PT./T(nn);
[ii s] = sort(PT./T(nn));
S = ceil(size(s,2)/2);
i = PT(S); S = nn(S);
colr = I(y,x,:,S) / T(S);
endif
BIN(y,x,:) = colr;
im = max(colr);
if(Imax < im) Imax = im; endif
im = min(colr);
if(Imin > im) Imin = im; endif
endfor
endfor
II1 = uint8((BIN - Imin) / (Imax - Imin) * 255);
Imin = log(Imin + 1); Imax = log(Imax + 1);
II = uint8((log(BIN + 1) - Imin) / (Imax - Imin) * 255);
imwrite(II, "result_log.png");
imwrite(II1, "result_lin.png");
endfunction
Вспомогательная фукнция mk_im(i, t) из изображения i (экспозиция которого считается равной 1с) получает изображение с экспозицией t:
function [I, G] = mk_im(I0, T)
I = uint8(I0 * T);
name = sprintf("exp_%.3f.png", T);
imwrite(I, name);
G = rgb2gray(I);
name = sprintf("exp_%.3f_gray.png", T);
imwrite(G, name);
endfunction
И вот что получается:
Оригинал — кусок фотографии для тренировок.
Кадры с разной "экспозицией".
Соответствующие уровни серого.
Результат.
Из-за медианного усреднения результат несколько размыт, но это не беда.
С логарифмом у меня вышел "косячок": т.к. после логарифмирования "внизу" получается очень мало значений, итоговая гистограмма съезжает в яркую область. Надо подумать, как покрасивше делать.
Естественно, с настоящими фото интересней поработать, но это надо на сях писать обработчик, т.к. октава уж очень тормозит...
делаем N кадров с экспозициями от T₀ до T₁ секунд (T₀ < T₁);
определяем пороги (нижний, I₀, и верхний, I₁), в пределах которых считаем уровень серого приемлемым;
открываем все изображения и построчно считываем;
для каждой строки вычисляем уровень серого (по какой-нибудь из формул вроде 0.3R+0.5G+0.2B);
каждому пикселю считанной строки делаем подборку изображений, у которых I₀ <= I <= I₁; если таких нет (т.е. везде передержано, или везде черно), берем значение I, равное медиане в квадрате 3x3 (или больше, смотря какого размера картинка) соответствующего "крайнего" изображения (для I < I₀ берем изображение с T₀, а для I > I₁ — с T₁); если же такие значения есть, вычисляем I как медиану интенсивностей в данном кадре;
значение цвета берем из медианы 3x3 изображения, у которого уровень серого наиболее близок к 127; если же у нас крайние варианты (пересвет/чернота), берем R=G=B=255 для белого, R=G=B=0 для черного;
полученное новое значение I для каждого оставшегося на шаге 4 изображения делим на экспозицию (приводя таким образом к единой системе); лучше всего было бы дальше сделать линейную интерполяцию, но можно и просто опять взять медиану из полученных значений; это число, Inorm, мы умножаем на полученные на предыдущем шаге значения R,G,B, и сохраняем в бинарный файл (как тройку float или даже double); параллельно вычисляя экстремальные значения Inorm;
по окончанию преобразований, опять откатываемся к началу полученного бинарника, и, считывая из него тройки чисел, приводим их логарифмы к шкале 0..255 (используя вычисленные на предыдущем шаге экстремальные значения Inorm);
получаем красивое изображение.
Сами картинки и графики могу подготовить в octave.
Это из-за того, что я поленился взять реальные фото (как я уже выше говорил, октава очень сильно тормозит на циклах, поэтому для реальных фото ее применять — это значит запустить, и пару суток ждать результат). А в данном случае простейшей "модельки" результирующее фото содержит меньше информации, чем исходное (в отличие от настоящего процесса сборки HDR).
no subject
Date: 2013-05-13 02:48 am (UTC)no subject
Date: 2013-05-13 03:18 am (UTC)no subject
Date: 2013-05-13 03:45 am (UTC)no subject
Date: 2013-05-13 04:17 am (UTC)Принцип такой:
Сами картинки и графики могу подготовить в octave.
no subject
Date: 2013-05-13 04:52 am (UTC)no subject
Date: 2013-05-13 06:37 am (UTC)no subject
Date: 2013-05-13 08:10 am (UTC)no subject
Date: 2013-05-13 08:12 am (UTC)no subject
Date: 2013-05-13 11:00 am (UTC)