Симулация на фотографски филм

Задачата ви е да промените линейните RGB стойности, излизащи от рейтрейсъра, така че изхода да заприлича на снимка, заснета на фотографски филм.

Филмите има нелинейна трансферна функция, което ще рече, че потъмняването на филма при облъчване със светлината не е пропорционално на броя получени фотони. По-точно, получават се следните три области при увеличаване на входната яркост:

- недоосветена (до 1) - фотоните не са достатъчно за да предизвикат реакция и тя е много вяла;
- линеен регион (2 до 3) - степента на потъмняването е приблизително пропорционална на логаритъма на броя фотони;
- насищане (над 4) - увеличаване на яркостта над този праг почти не указва влияние на потъмняването.

Разбира се, тези области и гладките преходи между тях допринасят за "филмовото усещане" и характерния рисунък при/около ярките отблясъци.

Задачата ви е да измерите таква конкретна крива на подходящ фотоапарат (ваш или назаем от приятел - необходимо е само да има ръчен контрол, с който да може да му се задава фиксирани параметри за ISO, апертура, и скоростта на затвора), след което да накарате рейтрейсъра да я имитира.

Работата трябва да протече в три фази:

1. Заснемане
Тук взимате фотоапарата и му изключвате beautification опциите - без увеличаване на контраста и резкоста, без допълнително ошареняване. Избирате ръчния режим, и си харесвате някакво фиксирано ISO и f-число (например 100 и f/4). Заснемате нещо скучно и равномерно осветено - парче таван, стена без шарки или празен лист хартия (възможно е да се наложи да изключите автофокуса). Настройвате скоростта на затвора така, че снимката да не е нито ярка, нито тъмна. Снимате на JPEG. Осветлението ви трябва да е непроменливо - индиректно осветление от слънцето в стая при безоблачен ден, или пак в стая, но осветена от нощна лампа. Направете 8-12 снимки с все по-висока яркост (т.е. по-ниска скорост на затвора). Например, ако първоначалната снимка с нормална ярост е била при 1/100s, направете снимки при 1/80, 1/60, 1/50, 1/40, ... 1/5s. Целта е най-ярката снимка да е с 20 пъти повече входна яркост от "нормалната". Направете още 10-15 снимки при по-ниска яркост - в горния пример би било 1/125, 1/160, 1/200, ..., 1/4000 - целта е най-тъмната снимка да е 40 пъти по-тъмна.

2. Анализиране на яркостта на снимките
Напишете си програмка, на какъвто език ви е удобно, не ви задължавам да е C++. Ако решите да ползвате познатата среда, вижте SDL_image за четене на снимките. Имайте предвид, че почти всички библиотеки (SDL_image не прави изключение) ви връщат суровите пикселни стойности, както са си гама компресирани. Програмката ви трябва да прави sRGB декомпресия, след което пикселите в центъра трябва да се сумират и усреднят (в краищата може да има vignetting, затова анализирайте например централната 1/9, след като сте махнали 1/3 отляво, отдясно, отгоре и отдолу). Разбира се, картинките ще са цветни, така че смятайте яркостите като (R + G + B)/3.

За всяка картинка, вашата анализираща програмка трябва да изведе число - средна пикселна яркост в линейното RGB пространство между 0 и 1, т.е. средната яркост на гама-декомпресираните пиксели в централната 1/9.

3. Прилагане на събраните данни в рейтрейсъра
От предходната стъпка имате един списък от data points - за всеки файл е известна (записвали сте си докато сте снимали, или просто може да се консултирате с Exif данните във файловете) каква е релативната входяща яркост, в логаритмично пространство (вижте примера долу). Това са x-координатите на данните. y координатите са яркостите на файловете от стъпка 2. Данните може да изглеждат така:

# x         y   # comments
...
-0.66   0.415   # ISO 100, f/4, shutter 1/160
-0.33   0.455   # ISO 100, f/4, shutter 1/125
 0      0.500   # ISO 100, f/4, shutter 1/100
 0.33   0.587   # ISO 100, f/4, shutter 1/80 
...

Ако изчертаете получените точки на графика, ще получите подобие на кривата от картинката по-горе - това е трансферната функция на избрания фотоапарат.

На базата на тези data points си създайте fitting крива (или интерполирайте чрез сплайни между точките). По тази крива трябва да ремапнете яркостите, излизащи от рейтрейсъра (т.е. резутлата във vfb[][] масива). За всеки пиксел, за всеки канал, ако стойността не е 0, намерете двоичния логаритъм на линейната R, G или B стойност, и на базата на така получения x се ориентирайте в кривата, и намерете съответното y - това записвате в този канал на пиксела. Така яркостите в картинката придобиват чара на фотофилм (или поне на апроксимацията, която са написали производителите на апарата). Пискелите все още имат нужда от гама-компресия, преди да се покажат на екрана.

Почти е сигурно, че някъде в GlobalSettings ще трябва да сложите настройка exposure - по колко да се умножат входните пиксели, преди да се подложат на трансферната функция.

На практика, курсовата работа се свежда до малко снимки (5-10 минути работа), писане на тривиална програмка за анализ, и смилане на получените данни след това. Смилането може да направите и на ръка, и с помощта на Mathematica/matlab, за да получите необходимите сплайни или fitting крива на трансферната функция. Самата трансферна функция спокойно можете да хардкоднете в рейтрейсъра, веднъж, след като сте я сметнали.