Міністерство освіти та науки України
Національний університет «Львівська політехніка»
Кафедра автоматизованих систем управління
Розрахунково – графічна робота
з дисципліни
«Комп’ютерна графіка»
на тему:
“Морфінг”
Львів – 2009
Зміст
Огляд літературних джерел.
Теоретичні відомості (можливі методи та алгоритми вирішення даної проблеми).
Область застосування алгоритму.
Текст програми.
Інструкція користувачу.
Результат виконання програми.
Висновки.
Теоретичні відомості
Морфінг – це метод, в якому використовується злиття двох зображень, внаслідок чого ми можемо отримати різні відтінки цих зображень. Морфінг в основі базується на згладжуванні або усуненні ступінчастості.
Згладжування - це метод поліпшення візуального дозволу з використанням декількох рівнів інтенсивності. Апроксимація півтонами, з іншого боку, - це метод, в якому використовується мінімальне число рівнів інтенсивності, звичайно чорний і білий, для поліпшення візуального дозволу, тобто отримання декількох півтонів сірого або рівнів інтенсивності. Метод півтонів відомий досить давно. Спочатку він використовувався при виготовленні шовкових картин і інших текстильних виробів. У 1880 р. Стефаном Хагеном був винайдений сучасний півтоновий друк. У цьому методі можна одержати велику кількість фотографічних півтонів сірого, використовуючи чисто дворівневе середовище: чорну фарбу на білому папері. Півтоновий друк - це гратчастий або клітинний процес. Розмір клітки варіюється залежно від дрібнозернистості грат і тривалості експозиції. Для газетних фотографій із-за низької якості паперу застосовуються грати від 50 до 90 крапок на дюйм. Папір вищої якості, призначений для книг і журналів, дозволяє використовувати грати з кількістю крапок від 100 до 300 на дюйм. Успіх методу півтонів залежить від властивості зорової системи людини бути інтегратором, тобто об'єднувати або згладжувати дискретну інформацію.
Візуальний дозвіл машино - згенерованого зображення, можна поліпшити за допомогою методу, що називається конфігурацією. У протилежність півтоновому друку, в якому використовуються змінні розміри кліток, в даному методі звичайно розміри кліток фіксовані. Для зображення з фіксованим дозволом декілька пікселів об'єднуються в конфігурації. Тут погіршення просторового дозволу обмінюється на поліпшення візуального. На мал. 17.1a показана одна з можливих груп конфігурацій для дворівневого чорно-білого дисплея. Для кожної клітки використовується чотири пікселя. При такій організації виходить п'ять можливих рівнів або тонів сірого (0-4).
У загальному випадку для дворівневого дисплея число можливих інтенсивностей на одиницю більше числа пікселів в клітці. При виборі конфігурацій слід проявляти обережність, оскільки інакше можуть виникнути небажані дрібномасштабні структури. Наприклад, не слід застосовувати жодну з конфігурацій, зображених на мал. 17.1b або мал. 17.1c, інакше це приведе до того, що для великої області з постійною інтенсивністю на зображенні з'являться небажані горизонтальні або вертикальні лінії. Число доступних рівнів інтенсивності можна збільшити за допомогою збільшення розміру клітки. Конфігурації для клітки 3 * 3 пікселів приведені на мал. 17.2. Вони дають десять рівнів (з 0 по 9) інтенсивності.
Клітки конфігурацій не обов'язково повинні бути квадратними; на мал. 17.3 зображена клітка 3 * 2 пікселов, що дає сім (0-6) рівнів інтенсивності.
Якщо крапки можуть бути різного розміру, то можна одержати додаткову кількість рівнів інтенсивності. На мал. 17.4 представлені конфігурації для клітки 2 * 2 пікселя з двома розмірами крапок. В результаті виходить 9 рівнів інтенсивності. Подібна клітка розміру 3 * 3 з точками двох розмірів дозволяє мати 27 рівнів інтенсивності. Якщо на піксель доводиться більше одного біта, то також можна одержати додаткові рівні інтенсивності.
Для конфігурації 2 * 2 з 2 бітами на піксель вийде 13 рівнів інтенсивності, показані на мал. 17.5. Більша кількість біт на піксель або більший розмір клітки дадуть відповідне збільшення числа рівнів інтенсивності.
Використання конфігурацій веде до втрати просторового дозволу, що прийнятно у разі, коли дозвіл зображення менше дозволу дисплея. Розроблені також методи поліпшення візуального дозволу при збереженні просторового. Простий з них полягає в застосуванні порогового значення для кожного піксела. Якщо інтенсивність зображення перевищує деяку порогову величину, то піксель вважається білим, інакше він чорний: if I(x, у)> Т then Білий else Чорний, де I(x, у) означає інтенсивність пікселя (x, у) зображення. Білий відповідає максимальній інтенсивності для дисплея, а чорний - мінімальній. Порогову величину звичайно встановлюють приблизно рівну половині максимальної інтенсивності.
На малюнку представлений результат для фотографії, над якою здійснено приклад морфізму.
Область застосування вибраного алгоритму
Даний алгоритм широко застосовується у облаті кіноматографії та анімації. Це є зручний метод якісної зміни об’єктів, навіть у тих випадках, де людина не в силі саморуч це зробити (кіноматографія). Так як у наш час досить широко розвинена анімація, то приклад морфізму є значно актуальним, що досить полегшує обробку зображень. Цей алгоритм використовується при змішуванні кольорів, при роботі з фотографічними об’єктами.
Текст програми
/****************************************************************************
* Func: fields_warp *
* Desc: warps an image base on the fields warping algorithm presented in *
* Siggraph 1992 proceedings *
* Params: source- pointer to source image *
* ptr- pointer to destination image buffer *
* source_lines- array of source image control lines *
* dest_lines- array of destination image control lines *
* num_lines- number of control lines *
* num_frames- number of frames in warp sequence *
* outfile- base name of output file *
* rows- number of rows in image *
* cols- number of cols in image *
* type- image type *
****************************************************************************/
void fields_warp(void *source_ptr, void *dest_ptr, LINE *source_lines, LINE *dest_lines,
int num_lines, int num_frames, char *outfile, int rows, int cols,
int type)
{
int frame; /* current frame number */
int line; /* current line number */
int x, y; /* destination coordinate indices */
int source_x, source_y; /* source coordinate indices */
float u, v; /* intermediate source coordinate indices */
char suffix[3]; /* terminating output filename string */
char file_name[100]; /* name of output file */
unsigned long source_index; /* index into linear addressed source image */
unsigned long dest_index; /* index into linear addressed destination */
LINE warp_lines[100]; /* array of intermediate control lines */
float fweight; /* frame weight used to interpolate lines */
int last_row, last_col; /* last valid row and column */
float fraction, distance; /* fraction along and distance from control line */
float fdist; /* intermediate variable used to compute distance */
int dx, dy; /* delta X and delta Y */
float weight_sum; /* accumulated weight */
double numerator; /* numerator used to compute line weight */
double denominator; /* denominator used to compute line weight */
float sum_x, sum_y; /* delta sum X and Y */
float weight; /* line weight */
float a=0.001; /* small number used to avoid divide by 0 */
float b=2.0; /* exponent used in line weight calculation */
float p=0.75; /* exponent used in line weight calculation */
image_ptr sourcei; /* source pointer for gray-scale image */
pixel_ptr sourcep; /* source pointer for color image */
pixel_ptr destp; /* destination pointer for color image */
image_ptr desti; /* destination pointer for gray-scale */
last_row = rows-1; /* initialize last row */
last_col = cols-1; /* initialize last column */
/* setup for a color or gray scale image */
if(type == 5)
{
sourcei = (image_ptr) source_ptr;
desti = (image_ptr) dest_ptr;
}
else
{
sourcep = (pixel_ptr) source_ptr;
destp = (pixel_ptr) dest_ptr;
}
for(frame=1; frame<=num_frames; frame++)
{
fweight = (float)(frame) / num_frames;
/* interpolate intermediate control lines */
for(line=0; line<num_lines; line++)
{
warp_lines[line].P.x=source_lines[line].P.x +
((dest_lines[line].P.x - source_lines[line].P.x)*fweight);
warp_lines[line].P.y=source_lines[line].P.y +
((dest_lines[line].P.y - source_lines[line].P.y)*fweight);
warp_lines[line].Q.x=source_lines[line].Q.x +
((dest_lines[line].Q.x - source_lines[line].Q.x)*fweight);
warp_lines[line].Q.y=source_lines[line].Q.y +
((dest_lines[line].Q.y - source_lines[line].Q.y)*fweight);
warp_lines[line].dx = warp_lines[line].Q.x - warp_lines[line].P.x;
warp_lines[line].dy = warp_lines[line].Q.y - warp_lines[line].P.y;
warp_lines[line].length_squared =
(long) (warp_lines[line].dx) * warp_lines[line].dx +
(long) (warp_lines[line].dy) * warp_lines[line].dy;
warp_lines[line].length = sqrt(warp_lines[line].length_squared);
}
for(y=0; y<rows; y++)
{
printf("processing frame %d: line %d of %d\n", frame, y, rows);
for(x=0; x<cols; x++)
{
weight_sum = 0.0;
sum_x = 0.0;
sum_y = 0.0;
for (line = 0; line < num_lines; line++)
{
dx = x - warp_lines[line].P.x;
dy = y - warp_lines[line].P.y;
fraction = (dx * (long) warp_lines[line].dx +
dy * (long) warp_lines[line].dy) /
(float) warp_lines[line].length_squared;
fdist = (dy * (long) warp_lines[line].dx -
dx * (long) warp_lines[line].dy) /
warp_lines[line].length;
if (fraction <= 0 )
distance = sqrt(dx * (long) dx + dy * (long) dy);
else if (fraction >= 1)
{
dx = x - warp_lines[line].Q.x;
dy = y - warp_lines[line].Q.y;
distance = sqrt(dx * (long) dx + dy * (long) dy);
}
else if (fdist >= 0)
distance = fdist;
else
distance = -1.0 * fdist;
u = source_lines[line].P.x +
fraction * source_lines[line].dx -
fdist * source_lines[line].dy /
source_lines[line].length;
v = source_lines[line].P.y +
fraction * source_lines[line].dy +
fdist * source_lines[line].dx /
source_lines[line].length;
/* calculate line weight */
numerator = pow((double)(warp_lines[line].length),p);
denominator = a + distance;
weight = pow((numerator / denominator) , b);
sum_x += (u - x) * weight;
sum_y += (v - y) * weight;
weight_sum += weight;
}
source_x = x + sum_x / weight_sum + 0.5;
source_y = y + sum_y / weight_sum + 0.5;
CLIP(source_x, 0, last_col);
CLIP(source_y, 0, last_row);
source_index = source_x + (unsigned long) cols * source_y;
dest_index = x + (unsigned long) cols * y;
if(type == 5)
desti[dest_index] = sourcei[source_index];
else
{
destp[dest_index].r = sourcep[source_index].r;
destp[dest_index].g = sourcep[source_index].g;
destp[dest_index].b = sourcep[source_index].b;
}
}
}
suffix[0]='.';
itoa(frame, &suffix[1], 10);
suffix[2]=0;
strcpy(file_name, outfile);
strcat(file_name, suffix);
printf("Writing out frame %d\n",frame);
if(type == 5)
write_pnm(desti, file_name, rows, cols, type);
else
write_pnm((image_ptr) destp, file_name, rows, cols, type);
}
}
Інструкція користувачеві
Робота з програмою складається знаступних кроків:
по-перше, користувач запускаєдану програму
по-друге, вибирає зображення для морфізму
по-третє, запускає на виконання сам алгоритм
по-п’яте, насолоджується виконанням програми
Результат виконання програми
а б
а зображення до виконання морфізму
б зображення отримане після виконання морфізму
Проміжні етапи виконання програми
Висновок: під час виконання даної розрахункової роботи я ознайомився з поняттям морфізму. Провів потрібний по даній тематиці огляд літератури. Розробив алгоритм роботи методу морфізму, по якому написав текст програми реалізації алгоритму. Дана робота дає змогу систематизувати, закріпити і розширити теоретичні і практичні знання з програмування в області комп’ютерної графіки.