Chapter 03 영역기반처리 2장의픽셀기반처리에서는각픽셀의값을처리할때주위픽셀의값은전혀고려하지않고단지현재의픽셀값만을참조하였다. 이에반해영역기반처리는입력픽셀과그주위픽셀값을고려하여출력픽셀의값을결정한다. 영역기반처리는영상을흐리게하거나, 영상을선명하게하거나, 영상의경계선을검

Similar documents
이미지 워핑과 모핑

<B9CCB5F0BEEE20C1A4BAB8C3B3B8AE2E687770>

JAVA 프로그래밍실습 실습 1) 실습목표 - 메소드개념이해하기 - 매개변수이해하기 - 새메소드만들기 - Math 클래스의기존메소드이용하기 ( ) 문제 - 직사각형모양의땅이있다. 이땅의둘레, 면적과대각

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

Microsoft PowerPoint - chap06-2pointer.ppt

목차 포인터의개요 배열과포인터 포인터의구조 실무응용예제 C 2

슬라이드 1

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

PowerPoint 프레젠테이션

Microsoft PowerPoint - ch07 - 포인터 pm0415

11장 포인터

히스토그램구하기 사전준비 : 히스토그램을저장할메모리가필요함 필요한메모리개수 à 전체영상의픽셀은그값이 0 ~ 255이므로 256 개의메모리필요함 영상을구성하는픽셀의개수는매우크므로메모리형식은 unsigned long으로해야함 ( unsigned 란 +/- 를고려하지않는다는

PowerPoint 프레젠테이션

Microsoft PowerPoint - ch10 - 이진트리, AVL 트리, 트리 응용 pm0600

Microsoft PowerPoint - chap06-1Array.ppt

중간고사

PowerPoint 프레젠테이션

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

학습목차 2.1 다차원배열이란 차원배열의주소와값의참조

Microsoft PowerPoint - 제11장 포인터

chap 5: Trees

Microsoft PowerPoint - C++ 5 .pptx

02장.배열과 클래스

금오공대 컴퓨터공학전공 강의자료

설계란 무엇인가?

Microsoft PowerPoint - 제11장 포인터(강의)

KNK_C_05_Pointers_Arrays_structures_summary_v02

<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

Microsoft PowerPoint - Java7.pptx

PowerPoint Presentation

untitled

A Hierarchical Approach to Interactive Motion Editing for Human-like Figures

PowerPoint 프레젠테이션

영상 처리 프로그래밍 By Visual C++

윤성우의 열혈 TCP/IP 소켓 프로그래밍

Microsoft PowerPoint - additional01.ppt [호환 모드]

Microsoft PowerPoint - chap11-포인터의활용.pptx

<443A5C4C C4B48555C B3E25C32C7D0B1E25CBCB3B0E8C7C1B7CEC1A7C6AE425CBED0C3E0C7C1B7CEB1D7B7A55C D616E2E637070>

OCW_C언어 기초

프로그래밍개론및실습 2015 년 2 학기프로그래밍개론및실습과목으로본내용은강의교재인생능출판사, 두근두근 C 언어수업, 천인국지음을발췌수정하였음

제 14 장포인터활용 유준범 (JUNBEOM YOO) Ver 본강의자료는생능출판사의 PPT 강의자료 를기반으로제작되었습니다.

설계란 무엇인가?

A Dynamic Grid Services Deployment Mechanism for On-Demand Resource Provisioning

Microsoft PowerPoint - chap10-함수의활용.pptx

PowerPoint 프레젠테이션

Chapter 4. LISTS

PowerPoint Presentation

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint Presentation

PowerPoint 프레젠테이션

슬라이드 1

금오공대 컴퓨터공학전공 강의자료

Microsoft PowerPoint - IP11.pptx

제 11 장포인터 유준범 (JUNBEOM YOO) Ver 본강의자료는생능출판사의 PPT 강의자료 를기반으로제작되었습니다.

Microsoft PowerPoint - chap-11.pptx

비트와바이트 비트와바이트 비트 (Bit) : 2진수값하나 (0 또는 1) 를저장할수있는최소메모리공간 1비트 2비트 3비트... n비트 2^1 = 2개 2^2 = 4개 2^3 = 8개... 2^n 개 1 바이트는 8 비트 2 2

BMP 파일 처리

Microsoft PowerPoint - chap06-5 [호환 모드]

구조체정의 자료형 (data types) 기본자료형 (primitive data types) : char, int, float 등과같이 C 언어에서제공하는자료형. 사용자정의자료형 (user-defined data types) : 다양한자료형을묶어서목적에따라새로운자료형을

임베디드시스템설계강의자료 6 system call 2/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

목차 배열의개요 배열사용하기 다차원배열 배열을이용한문자열다루기 실무응용예제 C 2

PowerPoint 프레젠테이션

PowerPoint Presentation

쉽게 풀어쓴 C 프로그래밍

1 장 C 언어복습 표준입출력배열포인터배열과포인터함수 const와포인터구조체컴파일러사용방법 C++ 프로그래밍입문

PowerPoint Template

PowerPoint 프레젠테이션

Data Structure

C 언어 프로그래밊 과제 풀이

제 3강 역함수의 미분과 로피탈의 정리

슬라이드 1

경우 1) 80GB( 원본 ) => 2TB( 복사본 ), 원본 80GB 는 MBR 로디스크초기화하고 NTFS 로포맷한경우 복사본 HDD 도 MBR 로디스크초기화되고 80GB 만큼포맷되고나머지영역 (80GB~ 나머지부분 ) 은할당되지않음 으로나온다. A. Window P

K&R2 Reference Manual 번역본

윈도우즈프로그래밍(1)

슬라이드 1

Microsoft PowerPoint - chap05-제어문.pptx

1. auto_ptr 다음프로그램의문제점은무엇인가? void func(void) int *p = new int; cout << " 양수입력 : "; cin >> *p; if (*p <= 0) cout << " 양수를입력해야합니다 " << endl; return; 동적할

PowerPoint 프레젠테이션

<B4EBC7D0BCF6C7D02DBBEFB0A2C7D4BCF62E687770>

Chapter #01 Subject

Microsoft PowerPoint - D03_SpatialDomainEnhance_note.ppt [호환 모드]

untitled

Frama-C/JESSIS 사용법 소개

1

Microsoft Word - src.doc

윈도우시스템프로그래밍

PowerPoint 프레젠테이션

Microsoft PowerPoint - C프로그래밍-chap03.ppt [호환 모드]

Microsoft Word - FunctionCall

<4D F736F F F696E74202D B3E22032C7D0B1E220C0A9B5B5BFECB0D4C0D3C7C1B7CEB1D7B7A1B9D620C1A638B0AD202D20C7C1B7B9C0D320BCD3B5B5C0C720C1B6C0FD>

(001~006)개념RPM3-2(부속)

Microsoft PowerPoint 자바-기본문법(Ch2).pptx

Microsoft PowerPoint - chap03-변수와데이터형.pptx

Infinity(∞) Strategy

쉽게 풀어쓴 C 프로그래밍

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202834C1D6C2F7207E2038C1D6C2F729>

; struct point p[10] = {{1, 2, {5, -3, {-3, 5, {-6, -2, {2, 2, {-3, -3, {-9, 2, {7, 8, {-6, 4, {8, -5; for (i = 0; i < 10; i++){ if (p[i].x > 0 && p[i

Microsoft PowerPoint - 3ÀÏ°_º¯¼ö¿Í »ó¼ö.ppt

PowerPoint Template

Transcription:

er 03 Ch 영역 기반 처리 3.1 회선 3.2 영상 흐리게 하기 3.3 영상의 선명화 3.4 경계선 검출 3.5 잡음 제거 3.6 컬러 영상에 대한 처리 3.7 실습 t ap

Chapter 03 영역기반처리 2장의픽셀기반처리에서는각픽셀의값을처리할때주위픽셀의값은전혀고려하지않고단지현재의픽셀값만을참조하였다. 이에반해영역기반처리는입력픽셀과그주위픽셀값을고려하여출력픽셀의값을결정한다. 영역기반처리는영상을흐리게하거나, 영상을선명하게하거나, 영상의경계선을검출하거나, 잡음을제거하는등의연산을효과적으로수행할수있다. 3.1 회선 영역기반처리를효과적으로수행하기위한방법으로회선 (convolution) 기법이사용된다. 회선기법에서는입력영상의각픽셀에대한출력픽셀값을구하기위하여입력픽셀과그주위픽셀의값에회선마스크의값을곱한다음에그합을구한다. 그림 3-1에입력영상에서 3 3 크기의한부분이나타나있다. 픽셀값이 I1, I2, g, I9 이고현재처리해야할픽셀값이 I5 라하자. 회선마스크는그림 3-1에나타난것과같다고하자. 그러면 I5 에대한출력픽셀값은다음식과같이계산된다. 출력픽셀값 = I 1 M 1 + I 2 M 2 + I 3 M 3 + I 4 M 4 + I 5 M 5 + I 6 M 6 + I 7 M 7 + I 8 M 8 + I 9 M 9 76

영역기반처리 CHAPTER 03 입력영상 회선윈도우 I 1 I 2 I 3 I 4 I 5 I 6 I 7 I 8 I 9 회선마스크 출력영상 M 1 M 2 M 3 M 4 M 5 M 6 M 7 M 8 M 9 출력픽셀값 = I 1 M 1 + I 2 M 2 + I 3 M 3 + I 4 M 4 + I 5 M 5 + I 6 M 6 + I 7 M 7 + I 8 M 8 + I 9 M 9 그림 3-1 회선의개념 현재의입력픽셀에대하여주위픽셀을고려할때각방향으로대칭되도록해야하므로회선마스크의가로세로크기는홀수이어야한다. 일반적으로회선마스크의크기는 3 3을많이사용하고 5 5 또는그이상크기의마스크도사용한다. 영상을흐리게하거나, 영상을선명하게하거나, 영상의경계선을검출하거나, 잡음을제거하는영역기반처리에서회선기법을적용하는방법은모두동일하고단지마스크의값이서로다르다. 영상의경계면에서는회선기법을적용할때문제가발생한다. 예를들어회선마스크의크기가 3 3이고현재의픽셀의위치가 (0,0) 일때필요로하는 8개의주위픽셀중에서 (0,1), (1,0), (1,1) 의세위치의픽셀들만존재하고나머지픽셀은존재하지않는다. 이와같이영상의가장자리에있는모든픽셀들에는필요로하는주위픽셀들이부족하게된다. 이를해결하는방법으로는 0-삽입방법이있다. 0-삽입방법이란존재하지않는픽셀들의값은모두 0으로가정하고회선을수행하는방법이다. 다른방법으로는가장자리픽셀에대해서는회선을수행하지않고출력픽셀의값을입력픽셀의값과동일하게하는것이있다. 77

실용영상처리 3.2 영상흐리게하기 영상을흐리게하기위해서는일반적으로그림 3-2와같은회선마스크를사용한다. 5 5 크기의회선마스크의경우에는 1/9 대신에 1/25이사용된다. 이와같은회선마스크는각입력픽셀값을주위픽셀값들과의평균값으로변환한다는것을알수있다. 평균값으로대치하는것은입력영상에서두드러지게밝거나어두운값들이주위픽셀들의영향으로평준화됨으로써영상을전체적으로흐리게한다. 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 그림 3-2 흐린영상생성을위한회선마스크 그림 3-3(b) 에는 Lenna 영상에그림 3-2의회선마스크를적용한결과가나타나있다. 그리고그림 3-3(c) 에는 5 5 크기의회선마스크를적용한결과가나타나있다. 그림에서처럼마스크의크기가커질수록부드러워지는정도가더커진다. (a) 원래의 Lenna 영상 (b) 3 3 마스크적용 (c) 5 5 마스크적용 그림 3-3 흐린영상생성을위한회선마스크적용예 78

영역기반처리 CHAPTER 03 3.3 영상의선명화 영상이흐려서판독이잘안되는경우에는영상을선명하게함으로써판독력을높일수있다. 영상을선명하게해주는마스크에는그림 3-4와같은마스크들이있다. 흐린영상생성을위한회선마스크와그림 3-4의마스크들에서마스크내의값들을모두합하면 1이되는것에주목할필요가있다. 마스크내의값을합하면 1이되도록함으로써회선마스크를적용하기전과적용한후의영상에서전체적인영상의밝기가비슷하게조절된다는특성이있다. 그리고그림 3-4의회선마스크들을적용하면결과값이 0보다작거나 255보다커질수있으므로그런경우에는 0과 255의값을갖도록수정해야한다. 0-1 0-1 -1-1 -1 5-1 -1 9-1 0-1 0-1 -1-1 (a) 마스크 1 (b) 마스크 2 그림 3-4 선명한영상생성을위한회선마스크들 그림 3-5 에는 Lenna 영상에대하여그림 3-4 의회선마스크를적용한결과가 나타나있다. 마스크에따라약간씩선명해지는정도가다름을알수있다. (a) 입력영상 (b) 마스크 1 적용 (c) 마스크 2 적용 그림 3-5 선명한영상생성을위한마스크적용예 79

실용영상처리 선명한영상생성을위한회선마스크가어떻게작용하는지살펴보기위해간단한예를살펴보기로하자. 영상의일부분의픽셀값이그림 3-6 (a) 와같다고하자. 이영상의가운데 7 7 영역의픽셀들에그림 3-4 (a) 의마스크를적용하면그림 3-6(b) 와같은결과를얻게된다. 결과영상을살펴보면주위픽셀보다밝은픽셀은더밝아지고주위픽셀보다어두운픽셀은더어두워져서픽셀들사이의명암도차이가더커짐을알수있다. 0 20 40 20 30 20 0 20 50 20 0 20 30 40 30 20 0 40 50 80 50 40 0 20 30 20 0 20 50 20 0 20 40 0 (a) 입력영상 (b) 출력영상 그림 3-6 선명한영상생성회선마스크적용예 그림 3-7(a) 에는자동차의영상이나타나있다. 영상이흐리기때문에자동차의번호가잘구분이안되는데, 이러한영상에그림 3-4(a) 의회선마스크를두번적용한결과가그림 3-7(b) 에나타나있다. 입력영상에비하여결과영상이훨씬선명하고차량번호도훨씬식별하기가용이함을알수있다. (a) 입력영상 (b) 결과영상 그림 3-7 선명한영상생성을위한회선마스크적용예 80

영역기반처리 CHAPTER 03 3.4 경계선검출 경계선은상대적으로다른명암도를가진두영역간의경계이다. 경계선은물체의위치, 형태, 크기등영상에대한많은정보를제공한다. 경계선검출은영상분할을비롯하여여러가지분야에응용될수있다. 영상분할의한예로사진편집소프트웨어의마법의지팡이가있다. 마법의지팡이는영상에서한화소를선택하면그화소와유사한값을가진화소들을찾아서하나의영역으로만드는데, 이러한영역을발견할때에경계선정보를이용하게된다. 경계선을검출하는방법으로는미분개념을이용한방법이널리사용되고있다. 그림 3-8에나타나있듯이영상의경계선부분에서명암값이작은값에서큰값으로변하면미분값은 0보다큰값을갖게된다. 반대로명암값이큰값에서작은값으로변하면미분값은 0보다작은값을갖게된다. 그러나면내부에서와같이명암값의변화가없는곳에서는미분값은 0의값을갖게된다. 이와같이경계선부분에서명암값이 0보다크거나작아진다는성질을이용하여경계선을구하는방법이널리사용되고있다. 영상 명암도변화 미분값변화 그림 3-8 명암도변화와미분값의변화 81

실용영상처리 미분개념을효과적으로구현하기위한방법으로회선기법이사용되었다. Prewitt, Roberts, Sobel 등이표 3-1과같이미분을이용한경계선검출용회선마스크를개발하였다. 이들방법에서는두개의회선마스크를이용하여회선을수행한다. 한회선마스크는수평방향의경계선을구하고다른회선마스크는수직방향의경계선을구하기위해사용된다. 표 3-1 경계선검출용회선마스크 Prewitt Roberts Sobel 수평경계선 -1-1 -1 0 0 0 1 1 1-1 0 0 1-1 -2-1 0 0 0 1 2 1 수직경계선 1 0-1 1 0-1 1 0-1 0-1 1 0 1 0-1 2 0-2 1 0-1 Roberts 마스크는다른마스크보다크기가작아서연산이효율적이지만잡음 에민감하다. Prewitt 마스크는대각방향의경계선보다는수평, 수직경계선에 더민감하도록만들어졌다. Sobel 마스크는수평, 수직방향의경계선보다는대 각선방향의경계선에더민감하도록만들어졌다. Prewitt 마스크의경우에는 마스크중심에서의거리와관계없이 +1 또는 -1 의값을가지고있는데반하여, Sobel 마스크에서는마스크의중심에가까운픽셀은 +2 또는 -2 의값을가지고, 먼픽셀은 +1 또는 -1 의값을가지도록되어있어서보다정확한경계선을검출할 수있다. 이는회선연산에서는중심화소에가까운픽셀일수록영향을더많이 준다는기본특성이있기때문이다. 픽셀 Ixy (, ) 가경계선에포함될가능성의크기 Exy (, ) 는수평경계선검출용회선마스크를적용한결과값 Er ] x, yg와수직경계선검출용회선마스크를적용한결과값 Ec ] x, yg를다음식과같이합하여계산한다. 2 2 Exy (, ) = Er] xy, g+ Ec] x, yg 82

영역기반처리 CHAPTER 03 Lenna 영상에대하여세가지마스크를이용하여경계선을검출한결과가그 림 3-9 에나타나있다. (a) Prewitt 마스크 (b) Roberts 마스크 (c) Sobel 마스크 그림 3-9 Lenna 영상에대한경계선검출결과 3.5 잡음제거 아날로그영상은오래되면색이바래는등의잡음이발생할수있고디지털영상도무선이나유선으로전송되는도중에잡음이섞일수있다. 텔레비전방송에서도잡음에의하여화면이깨끗하지않은경우를흔하게경험할수있다. 잡음은임펄스 (impulse) 잡음과가우시안 (Gaussian) 잡음으로구분할수있다. 임펄스잡음은그림 3-(a) 에나타나있듯이 0 또는 255와같이영상의픽셀값과는뚜렷하게다른픽셀값에의한잡음을말하고가우시안잡음은그림 3-(b) 와같이영상의픽셀값으로부터불규칙적으로벗어나지만뚜렷하게벗어나지는않은픽셀값에의한잡음을의미한다. (a) 임펄스잡음 (b) 가우시안잡음 그림 3- 잡음이섞인 Lenna 영상 83

실용영상처리 3.5.1 평균마스크를이용한회선기법가우시안잡음은흐린영상생성을위한평균마스크를이용한회선기법을사용하여효과적으로제거할수있다. 가우시안잡음은원래의픽셀값에서크게벗어나지않기때문에주위의잡음이아닌픽셀값들과평균을구하면영상이흐려 지면서잡음이보이지않게된다. 그림 3-11(a) 에는평균마스크를이용하여가우시안잡음을제거한결과영상이나타나있다. 그러나평균에의한잡음제거는임펄스잡음제거에는효과적이지못하다. 임펄스잡음의경우에는잡음의크기가크기때문에평균을해도원래의픽셀값에서많이벗어나게된다. 그림 3-11(b) 에는평균마스크를이용하여임펄스잡음을제거한결과영상이나타나있다. (a) 가우시안잡음제거결과 (b) 임펄스잡음제거결과 그림 3-11 평균마스크를이용한잡음제거 3.5.2 중간값필터임펄스잡음을효과적으로제거할수있는방법으로중간값필터방법이있다. 이방법은회선마스크의값을영상의픽셀값과곱하여합을구하는회선기법과는다른방법이다. 중간값필터방법은그림 3-12와같이입력픽셀과주위픽셀들의값중에서중간값을찾아서이를출력픽셀값으로사용하는방법이다. 중간값을찾는영역은여러가지형태를취할수있지만회선기법과같이 3 3이나 5 5 등의정사각형모양의영역을사용하는것이일반적이다. 그림 3-12에서는 입력픽셀값 255 가필터윈도우내의중간값인 17 로대치되었다. 84

영역기반처리 CHAPTER 03 입력영상 필터윈도우 15 13 16 16 255 20 17 18 22 출력영상 픽셀값의정렬 13 15 16 16 17 18 20 22 255 그림 3-12 중간값필터적용방법 임펄스잡음은그값이영상의픽셀값으로부터크게벗어나므로대부분의경우에잡음이중간값으로선택되지않고주위의잡음이아닌픽셀값중에서중간값이선택된다. 그림 3-13 에는 3 3 크기의중간값필터를이용하여임펄스잡음과가우시안잡음을제거한결과가나타나있다. 그림 3-13에나타나있듯이중간값필터방법이평균마스크를이용한회선기법에비하여임펄스잡음을훨씬더잘제거한다. 그리고가우시안잡음도어느정도제거할수있음을알수있다. 중간값필터의또다른특성은경계선을잘보존한다는것이다. 평균마스크를이용하면영상이흐려져서경계선이모호해지는반면에중간값필터는영상을흐리게하지않는다. (a) 임펄스잡음제거결과 (b) 가우시안잡음제거결과 그림 3-13 중간값필터를이용한잡음제거 85

실용영상처리 3.6 컬러영상에대한처리 3.6.1 회선기법 보통컬러영상은 RGB 컬러로제공된다. 이러한컬러영상에대한영상처리로는 RGB 컬러모델을그대로사용하는방법과 HSI 컬러모델로변환하여처리하는방법이널리사용된다. RGB 컬러모델을사용하는경우에영상은개념적으로빨강색성분값만으로구성된영상, 초록색성분값만으로구성된영상, 파랑색성분값만으로구성된영상등세영상으로분리할수있다. 그리고회선은단순하게빨강색, 초록색, 파랑색각성분에회선마스크를독립적으로적용하여출력영상의세성분값을개별적으로구하는방법을사용할수있다. 입력컬러영상 빨강색성분 초록색 + + 성분 파랑색성분 회선수행회선수행회선수행 출력컬러영상 빨강색성분 초록색 + + 성분 파랑색성분 그림 3-14 RGB 컬러모델에서의회선 HSI 컬러모델을사용하는경우에는먼저 RGB 컬러를 HSI 컬러로변환한다. 그다음에명암값 I에대하여회선을수행하고색상 (H) 과채도 (S) 에대해서는아무런작업을수행하지않는다. 회선을수행하여명암값을변환한다음에 RGB 컬러공간으로변환하면처리된컬러영상을얻게된다. 색상 입력영상 명도 회선수행 변환된명도 결과영상 RGB 컬러 채도 RGB 컬러 HSI 컬러 86 그림 3-15 HSI 컬러모델을이용한회선수행

영역기반처리 CHAPTER 03 3.6.2 컬러영상의경계선검출컬러영상의경계선검출도회선기법과마찬가지로 RGB 컬러공간에서수행 할수도있고 HSI 컬러공간에서수행할수도있다. RGB 컬러공간에서경계선을검출하기위해서는 RGB 각성분에대하여경계선검출을위한회선마스크를수행한다음그결과값을다음과같이합하면된다. 2 2 2 Exy (, ) = E ] xy, g+ E ] x, yg+ E ] xy, g red green blue HSI 컬러공간에서의경계선검출은단지 RGB 컬러를 HSI 컬러로변환한다음 에명도 (I) 성분에회선을수행하기만하면된다. 3.7 실습 3.7.1 임의의크기영상처리를위한기억장소할당 지금까지는 256 256 크기의 RAW 형식의파일만을다루어왔다. RAW 형식을사용하면프로그램을간단하게구현할수있지만영상의크기가한가지로제한되어프로그램의유용성에많은제약이따르게된다. 따라서이절에서는임의의크기를갖는영상의처리방법을살펴보기로하자. 임의의크기를갖는영상을저장할수있는파일형식중에서가장간단한형식이 PBM, PGM, PPM 형식이다. 이중에서 256 명암도의흑백영상을저장할수있는 PGM 형식과컬러영상을저장할수있는 PPM 파일을읽어서처리하는방법을살펴보자. 이들형식에대한설명은 1.3.3 절의내용을참고하기로한다. 영상저장을위한변수선언영상의크기가정해져있는경우에는영상을저장할변수를이차원배열로선언할수있었다. 이렇게선언된이차원배열은프로그램이시작할때에기억장소를배정받게된다. 그러나임의의크기의영상을읽어들일경우에는프로그램을작성할때에영상의크기를알수없으므로크기가고정된이차원배열로 87

실용영상처리 선언할수없다. 이문제를해결하기위해서는영상을저장할변수를포인터로선언해주고, 프로그램실행중에기억장소를동적으로할당하는방법을사용해야한다. 여기에서, 영상을저장하는변수는일차원배열처럼사용하게할수도있고이차원배열처럼사용하게할수도있다. 일차원배열처럼사용하면변수를선언하고기억장소를할당하는일이단순해지지만원래이차원인영상을일차원처럼사용해야하는데따른불편이있다. 이차원배열처럼사용하기위해서는변수선언과기억장소할당이어렵지만이차원배열처럼사용할수있어서편리하다. 단일포인터를이용한방법먼저, 일차원배열처럼사용하는방법을살펴보자. 일차원배열처럼사용하기위해서는다음과같이영상을저장할기억장소의주소에대한변수 inputimg 와 resultimg를선언해야한다. 또한영상의크기를저장할변수 imagewidth, imageheight도선언해야한다. 그리고흑백영상과컬러영상을구분하기위한변수 depth도선언한다. 변수 depth 값이 1이면흑백영상을나타내고 3이면컬러영상을나타낸다고하자. 이는한픽셀에몇바이트의데이터가필요한지를의미한다. unsigned char *inputimg; unsigned char *resultimg; int imagewidth; int imageheight; int depth; // 입력영상의기억장소에대한포인터변수 // 출력영상의기억장소에대한포인터변수 // 영상의가로크기 // 영상의세로크기 // 1 = 흑백영상, 3 = 컬러영상 그리고실제로영상을저장할기억장소는다음과같이할당한다. malloc() 함수의매개변수는할당해야할기억장소가몇바이트인지를나타낸다. inputimg = (unsigned char *) malloc(imagewidth * imageheight * depth); resultimg = (unsigned char *) malloc(imagewidth * imageheight * depth); 88

영역기반처리 CHAPTER 03 앞과같이기억장소를할당하면흑백영상의경우에픽셀들은표 3-2 와같이 저장되고접근된다. 표 3-2 영상의픽셀값저장및접근방법 입력픽셀값 저장장소 I(0, 0) I(0, 1) inputimg[0] inputimg[1]...... I(0, image Width-1) I(1, 0) I(1, 1) inputimg[imagewidth-1] inputimg[imagewidth] inputimg[imagewidth+1]...... I(y, x) inputimg[y * imagewidth + x]...... I(imageHeight - 1, imagewidth - 1) inputimg[imageheight * imagewidth - 1] 임의의크기의영상에대하여각픽셀의값을 0 씩증가시키는산술덧셈연 산은다음과같이구현될수있다. for (y = 0; y < imageheight; y++) for (x = 0; x < imagewidth * depth; x++) value = inputimg[y * imagewidth + x] + 0; if (value > 255) value = 255; resultimg[y * imagewidth + x] = value; 모든픽셀의값은위와같이이중루프를사용하여접근할수도있지만다음과 같이단일루프를사용하여접근할수도있다. 89

실용영상처리 for (k = 0; k < imagewidth * imageheight * depth; k++) value = inputimg[k] + 0; if (value > 255) value = 255; resultimg[k] = value; 이중포인터를이용한방법 이차원배열처럼사용하려면다음과같이 inputimg 와 resultimg 를이중포인 터로선언해야한다. unsigned char **inputimg; unsigned char **resultimg; // 입력영상의기억장소에대한포인터변수 // 출력영상의기억장소에대한포인터변수 그리고실제로영상을저장할기억장소는다음과같이할당한다. 이와같은기억장소할당을도식적으로표현하면그림 3-16과같다. 그림과같이먼저각행이저장될기억장소를가리킬포인터의일차원배열을할당한다. 그다음에는각행이저장될기억장소를할당하고각행의포인터로하여금이기억장소를가리키게한다. inputimg = (unsigned char **) malloc(imageheight * sizeof(unsigned char *)); resultimg = (unsigned char **) malloc(imageheight * sizeof(unsigned char *)); for (i = 0; i < imageheight; i++) inputimg[i] = (unsigned char *) malloc(imagewidth * depth); resultimg[i] = (unsigned char *) malloc(imagewidth * depth); 90

영역기반처리 CHAPTER 03 inputimg inputimg[0] I(0,0) I(0,1)... I(0,iamgeWidth-1) inputimg[1] I(1,0) I(1,1)... I(1,iamgeWidth-1)... inputimg[imageheight-1] I(iamgeHeight-1,0)... I(iamgeHeight-1, imagewidth-1) 그림 3-16 이중포인터를이용한기억장소할당 위와같이기억장소를할당하면입력영상의픽셀 Iyx ], g는 inputimg[y] [x] 에저장되고접근된다. 임의의크기에영상에대하여각픽셀의값을 0 씩 증가시키는산술덧셈연산은다음과같이구현될수있다. for (y = 0; y < imageheight; y++) for (x = 0; x < imagewidth * depth; x++) value = inputimg[y][x] + 0; if (value > 255) value = 255; resultimg[y][x] = value; 3.7.2 PGM 과 PPM 형식의파일읽기 앞에서작성한프로그램 ImagePro에서는 RAW 형식의파일을읽어들이도록했는데, 이를수정하여 RAW 형식의파일뿐만아니라 PGM 형식과 PPM 형식의파일도읽어들이도록하자. 그리고기억장소할당은이중포인터를이용하도록하자. 1 앞장에서작성한프로그램의프로젝트파일 ImagePro.sln 파일을연다. 2 CImageProDoc 클래스를더블클릭하여클래스를정의하는코드로이동하 여다음과같이수정한다. 91

실용영상처리 수정전 // Attributes public: unsigned char inputimg[256][256]; unsigned char inputimg2[256][256]; unsigned char resultimg[256][256]; 수정후 // Attributes public: unsigned char **inputimg; unsigned char **inputimg2; unsigned char **resultimg; int imagewidth; int imageheight; int depth; // 입력영상의기억장소에대한포인터변수 // 입력영상의기억장소에대한포인터변수 // 출력영상의기억장소에대한포인터변수 // 영상의가로크기 // 영상의세로크기 // 1 = 흑백영상, 3 = 컬러영상 3 입력영상을저장하는변수의초기값을 NULL로설정한다. 이와같이하는이유는영상을저장할기억장소를할당했는지아닌지구분하기위해서이다. 초깃값설정을위해서작업환경의왼쪽창에서 CImageProDoc 클래스의 CImageProDoc() 함수를더블클릭하고다음과같이편집한다. CImageProDoc::CImageProDoc() // TODO: add one-time construction code here inputimg = NULL; inputimg2 = NULL; resultimg = NULL; 4 Serialize() 함수의내용을다음과같이수정한다. void CImageProDoc::Serialize(CArchive& ar) 92

영역기반처리 CHAPTER 03 if (ar.isstoring()) else LoadImageFile(ar); 5 멤버함수추가마법사를이용하여 LoadImageFile() 함수를 CImagePro Doc 클래스에추가한다. 반환형식은 void를선택하고함수이름 Load ImageFile을입력한다. 이함수는매개변수를가지고있으므로이를추가하도록한다. 매개변수를추가하기위해서는그림 3-17과같이멤버함수추가마법사대화상자에서매개변수형식상자에매개변수형식을입력하고매개변수이름상자에변수이름을입력한다음에 [ 추가 ] 버튼을선택하야한다. LoadImageFile() 함수의매개변수형식은 "CArchive &" 로입력하고변수이름은 "ar" 로입력하자. 매개변수형식상자는상자오른쪽의아래방향삼각형을선택하여미리정의된형식을선택할수도있지만, 상자안을클릭하여직접입력할수있도록되어있으므로상자를클릭한다음에선택형상자처럼 "CArchive &" 를입력하면된다. 그림 3-17 멤버함수추가마법사대화상자 93

실용영상처리 [ 추가 ] 버튼을선택하면그림 3-18 과같이매개변수목록에매개변수가추가 된다. 매개변수가여러개일때에는, 변수마다매개변수형식과이름을지정한 다음에 [ 추가 ] 버튼을누르면된다. 그림 3-18 매개변수가추가된화면 6 LoadImageFile() 함수의내용을다음과같이편집한다. void CImageProDoc::LoadImageFile(CArchive &ar) int i, maxvalue; char type[16], buf[256]; CFile *fp = ar.getfile(); CString fname = fp->getfilepath(); // 파일의헤더읽기 if (strcmp(strrchr(fname, '.'), ".ppm") == 0 strcmp(strrchr(fname, '.'), ".PPM") == 0 strcmp(strrchr(fname, '.'), ".PGM") == 0 strcmp(strrchr(fname, '.'), ".pgm") == 0 ) ar.readstring(type, 15); do // 설명문을건너뛰기위한 do-while 문 94

영역기반처리 CHAPTER 03 ar.readstring(buf, 255); while (buf[0] == '#'); sscanf_s(buf, "%d %d", &imagewidth, &imageheight); do // 설명문을건너뛰기위한 do-while문 ar.readstring(buf, 255); while (buf[0] == '#'); sscanf_s(buf, "%d", &maxvalue); if (strcmp(type, "P5") == 0) depth = 1; else depth = 3; else if (strcmp(strchr(fname, '.'), ".raw") == 0 strcmp(strchr(fname, '.'), ".RAW") == 0 ) if (fp->getlength()!= 256 * 256) AfxMessageBox("256x256 크기의파일만사용가능합니다."); return; imagewidth = 256; imageheight = 256; depth = 1; // 기억장소할당 inputimg = (unsigned char **) malloc(imageheight * sizeof(unsigned char *)); resultimg = (unsigned char **) malloc(imageheight * sizeof(unsigned char *)); for (i = 0; i < imageheight; i++) inputimg[i] = (unsigned char *) malloc(imagewidth * depth); resultimg[i] = (unsigned char *) malloc(imagewidth * depth); // 영상데이터읽기 for (i = 0; i < imageheight; i++) ar.read(inputimg[i], imagewidth*depth); 95

실용영상처리 7 OnDraw() 함수를수정하여임의의크기의영상을출력할수있도록한다. 이함수에서수정할부분은다음과같다. - inputimg 가올바른기억장소를가리키고있는지검사 기억장소가할당되지않은상태에서픽셀값을참조하면프로그램이비 정상적으로종료되어버리는현상이발생하므로반드시 inputimg 값이 NULL 이아닌지검사해야한다. - 영상의크기에대한수정 영상의크기가 256 256 에서 imagewidth imageheight 로수정되어 야한다. - 영상의출력위치수정 영상의크기가변하므로출력위치도같이변하도록해주어야한다. - 컬러영상에대한출력 PPM 형식의컬러영상에서한픽셀값은빨강색성분, 초록색성분, 파랑 색성분순서로세바이트에걸쳐서저장되므로픽셀 Iyx ], g의컬러값은다음과같다. RGB(pDoc->inputImg[y][3*x], pdoc->inputimg[y][3*x+1], pdoc->inputimg[y][3*x+2]) 위의내용들을반영하여수정된 OnDraw() 함수는다음과같다. void CImageProView::OnDraw(CDC* pdc) CImageProDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (pdoc->inputimg == NULL) return; // 입력영상이읽히지않았으면종료 if (pdoc->depth == 1) // 흑백영상출력 for(int y=0; y < pdoc->imageheight; y++) // 입력영상출력 for(int x=0; x < pdoc->imagewidth; x++) pdc->setpixel(x, y, RGB(pDoc->inputImg[y][x], pdoc->inputimg[y][x], pdoc->inputimg[y][x])); 96

영역기반처리 CHAPTER 03 if (viewmode == THREE_IMAGES) for(int y=0; y< pdoc->imageheight; y++) // 두번째입력영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth+30,y, RGB(pDoc->inputImg2[y][x], pdoc->inputimg2[y][x], pdoc->inputimg2[y][x])); for(int y=0; y< pdoc->imageheight; y++) // 결과영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth*2+60,y, RGB(pDoc->resultImg[y][x], pdoc->resultimg[y][x], pdoc->resultimg[y][x])); else for(int y=0; y< pdoc->imageheight; y++) // 결과영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth+30,y, RGB(pDoc->resultImg[y][x], pdoc->resultimg[y][x], pdoc->resultimg[y][x])); else if (pdoc->depth == 3) // 컬러영상출력 for(int y=0; y < pdoc->imageheight; y++) // 입력영상출력 for(int x=0; x < pdoc->imagewidth; x++) pdc->setpixel(x, y, RGB(pDoc->inputImg[y][3*x], pdoc->inputimg[y][3*x+1], pdoc->inputimg[y][3*x+2])); if (viewmode == THREE_IMAGES) for(int y=0; y< pdoc->imageheight; y++) // 두번째입력영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth+30,y, RGB(pDoc->inputImg2[y][3*x], pdoc->inputimg2[y][3*x+1], pdoc->inputimg2[y][3*x+2])); for(int y=0; y< pdoc->imageheight; y++) // 결과영상출력 for(int x=0; x< pdoc->imagewidth; x++) 97

실용영상처리 pdc->setpixel(x+pdoc->imagewidth*2+60,y, RGB(pDoc->resultImg[y][3*x], pdoc->resultimg[y][3*x+1], pdoc->resultimg[y][3*x+2])); else for(int y=0; y< pdoc->imageheight; y++) // 결과영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth+30,y, RGB(pDoc->resultImg[y][3*x], pdoc->resultimg[y][3*x+1], pdoc->resultimg[y][3*x+2])); 8 프로그램을컴파일하고실행한다음에 RAW 형식의파일과 PGM 형식의파일 을열어서화면에잘출력되는지확인하도록한다. 그림 3-19 에는 " 로켓발 사.pgm" 파일을불러들인화면이나타나있다. 그림 3-19 " 로켓발사.pgm" 영상 98

영역기반처리 CHAPTER 03 3.7.3 임의의크기의영상에대한픽셀기반처리 2 장에서작성하였던픽셀기반처리함수를수정하여임의의크기의영상도 처리할수있도록해보자. 또한컬러영상도처리할수있도록하자. 산술연산함수수정 1 CImageProView 클래스의 OnPixelAdd() 함수에다음과같이 inputimg 가 NULL 인지를검사하는문장을첨가한다. void CImageProView::OnPixelAdd() CImageProDoc* pdoc; // 문장 1 : pdoc 변수선언 pdoc = GetDocument(); // 문장 2 : 문서객체에대한포인터획득 ASSERT_VALID(pDoc); // 문장 3 : pdoc 변수의오류검증 if (pdoc->inputimg == NULL) return; // 추가된문장 : 입력영상이있는지검사 pdoc->pixeladd(); // 문장 4 : 문서객체의 PixelAdd() 함수호출 viewmode = TWO_IMAGES; // 문장 5 : 연산의종류설정 Invalidate(FALSE); // 문장 6 : 화면을다시그림 2 CImageProDoc 클래스의 PixelAdd() 함수내용을다음과같이수정한다. 이함수에서는변수 x 의값을 0 부터 imagewidth * depth 까지변화시킴으 로써컬러영상에대한산술덧셈도수행할수있도록하였다. void CImageProDoc::PixelAdd() int value; for(int y=0; y < imageheight; y++) for(int x=0; x < imagewidth * depth; x++) value = inputimg[y][x]+0; if(value > 255) resultimg[y][x] = 255; else resultimg[y][x]=value; 99

실용영상처리 3 컴파일하고프로그램을수행한다음에 " 로켓발사.pgm" 파일을열어서산술 덧셈연산을실행하자. 그림 3-20 과같은결과가생성되는지확인한다. 그림 3-20 임의의크기영상에대한산술덧셈연산 히스토그램평활화연산 ( 흑백영상 ) 1 CImageProView 클래스의 OnPixelHistoEq() 함수에 inputimg가 NULL인지를검사하는문장을첨가한다. 2 CImageProDoc 클래스의 PixelHistoEq() 함수내용을다음과같이수정한다. void CImageProDoc::PixelHistoEq() int i, k; int x, y; int acc_hist = 0; // 히스토그램의합을누적하는변수 float N = (float) (imagewidth * imageheight); // 영상의전체픽셀수 int hist[256], sum[256]; for(k=0; k<256; k++) hist[k]=0; 0

영역기반처리 CHAPTER 03 // 명암값의빈도수조사 for(y = 0; y < imageheight; y++) for(x = 0; x < imagewidth; x++) k = inputimg[y][x]; hist[k] = hist[k]+1; // 누적된히스토그램합계산 for(i=0; i<256; i++) acc_hist = acc_hist + hist[i]; sum[i] = acc_hist; for(y = 0; y < imageheight; y++) for(x = 0; x < imagewidth; x++) k = inputimg[y][x]; resultimg[y][x] = (unsigned char) (sum[k] / N * 255); 3 " 로켓발사.pgm" 파일을연다음에히스토그램평활화연산을실행하여그 림 3-21 과같은결과가생성되는지확인한다. 그림 3-21 임의의크기영상에대한히스토그램평활화 1

실용영상처리 두영상의산술덧셈 여기에서는두개의흑백영상또는두개의컬러영상을더하는연산을구현 해보자. 두영상의크기는동일하다고가정한다. 1 두영상을읽어들이는함수 LoadTwoImages() 함수를다음과같이수정한다. 첫번째영상은앞에서작성한 LoadImageFile() 함수를사용해서읽도록했다. 두번째영상은 LoadSecondImage() 함수를추가하여읽도록했다. void CImageProDoc::LoadTwoImages() CFile file; CFileDialog dlg(true); AfxMessageBox("Select the First Image"); if(dlg.domodal()==idok) file.open(dlg.getpathname(), CFile::modeRead); CArchive ar(&file, CArchive::load); LoadImageFile(ar); file.close(); AfxMessageBox("Select the Second Image"); if(dlg.domodal()==idok) file.open(dlg.getpathname(), CFile::modeRead); CArchive ar(&file, CArchive::load); LoadSecondImageFile(ar); file.close(); 2 CImageProDoc 클래스에 LoadSecondImageFile() 함수를추가한다. 반환 2

영역기반처리 CHAPTER 03 형식과합수이름을입력한다음, 매개변수형식과매개변수이름을입력하고추가버튼을클린한다. - 반환형식 : void - 함수이름 : LoadSecondImageFile - 매개변수형식 : CArchive& - 매개변수이름 : ar 3 LoadSecondImageFile() 함수를다음과같이편집한다. 이함수는영상을 inputimg2 변수에저장하도록하는것이외에는 LoadImageFile() 함수와 대부분동일하다. void CImageProDoc::LoadSecondImageFile(CArchive& ar) int i, maxvalue; char type[16], buf[256]; CFile *fp = ar.getfile(); CString fname = fp->getfilepath(); // 파일의헤더읽기 if (strcmp(strrchr(fname, '.'), ".ppm") == 0 strcmp(strrchr(fname, '.'), ".PPM") == 0 strcmp(strrchr(fname, '.'), ".PGM") == 0 strcmp(strrchr(fname, '.'), ".pgm") == 0 ) ar.readstring(type, 15); do ar.readstring(buf, 255); while (buf[0] == '#'); sscanf_s(buf, "%d %d", &imagewidth, &imageheight); do ar.readstring(buf, 255); while (buf[0] == '#'); 3

실용영상처리 sscanf_s(buf, "%d", &maxvalue); if (strcmp(type, "P5") == 0) depth = 1; else depth = 3; else if (strcmp(strrchr(fname, '.'), ".raw") == 0 strcmp(strrchr(fname, '.'), ".RAW") == 0 ) if (fp->getlength()!= 256 * 256) AfxMessageBox("256x256 크기의파일만사용가능합니다."); return; imagewidth = 256; imageheight = 256; depth = 1; // 기억장소할당 inputimg2 = (unsigned char **) malloc(imageheight * sizeof(unsigned char *)); for (i = 0; i < imageheight; i++) inputimg2[i] = (unsigned char *) malloc(imagewidth * depth); // 영상데이터읽기 for (i = 0; i < imageheight; i++) ar.read(inputimg2[i], imagewidth*depth); 4 PixelTwoImageAdd() 함수의내용을다음과같이수정한다. void CImageProDoc::PixelTwoImageAdd() int value; LoadTwoImages(); 4

영역기반처리 CHAPTER 03 for(int y=0; y<imageheight; y++) for(int x=0; x < imagewidth * depth; x++) value = inputimg[y][x] + inputimg2[y][x]; if (value > 255) resultimg[y][x] = 255; else resultimg[y][x] = value; 5 " 모나리자.pgm" 파일과 " 모나리자 -mask.pgm" 파일을이용하여두영상 의산술덧셈연산을수행하여그림 3-22 와같은결과가나타나는지확인 한다. 그림 3-22 두영상의산술덧셈연산 3.7.4 회선기법을이용한영상의선명화구현 이절에서는회선을이용하여선명화연산을구현해보기로하자. 여기에서는 회선마스크의크기가 3 3 이라고가정한다. 1 메뉴막대에 [ 영역처리 ] 메뉴를추가한다. 2 [ 영역처리 ] 메뉴에선명화기능을위한부메뉴를추가한다. 5

실용영상처리 - 부메뉴이름 : 선명화 - ID : ID_REGION_SHARPENING 3 이벤트처리기마법사를이용하여 OnRegionSharpening() 함수를추가하 고다음과같이편집한다. void CImageProView::OnRegionSharpening() CImageProDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (pdoc->inputimg == NULL) return; pdoc->regionsharpening(); viewmode = TWO_IMAGES; Invalidate(FALSE); 4 멤버함수추가마법사를이용하여 CImageProDoc 클래스에 Region Sharpening() 함수를추가한다. - 반환형식 : void - 함수이름 : RegionSharpening 5 RegionSharpening() 함수의내용을다음과같이편집한다. void CImageProDoc::RegionSharpening() float kernel[3][3] = 0, -1, 0, -1, 5, -1, 0, -1, 0; Convolve(inputImg, resultimg, imagewidth, imageheight, kernel, 0, depth); 6 멤버함수추가마법사를이용하여 Convolve() 함수를 CImageProDoc() 클래스에추가한다. 6

영역기반처리 CHAPTER 03 - 반환형식 : void - 함수이름 : Convolve - 매개변수 : 번호 매개변수형식 매개변수이름 1 unsigned char ** inputimg 2 unsigned char ** resultimg 3 int cols 4 int rows 5 float [][3] mask 6 int bias 7 int depth 7 Convolve() 함수를다음과같이편집한다. 이함수에서 tmpimg는영상의가장자리픽셀에서회선을적용할수있도록하기위해사용되고있다. tmpimg의크기는 (imagewidht+2) (imageheight+2) 이다. 그림 3-23과같이 tmpimg의가장자리픽셀에는 0이삽입되고중앙에 inputimg가복사된다. inputimg 복사 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 tmpimg 그림 3-23 0- 삽입 7

실용영상처리 void CImageProDoc::Convolve(unsigned char **inputimg, unsigned char **resultimg, int cols, int rows, float mask[][3], int bias, int depth) int i, j, x, y; int red, green, blue; int sum; unsigned char **tmpimg; // 기억장소할당 tmpimg = (unsigned char **) malloc((imageheight + 2)* sizeof(unsigned char *)); for (i = 0; i < imageheight + 2; i++) tmpimg[i] = (unsigned char *) malloc((imagewidth + 2) * depth); // 0-삽입을위해 0으로초기화 for (y = 0; y < imageheight + 2; y++) for (x = 0; x < (imagewidth + 2) * depth; x++) tmpimg[y][x] = 0; // 영상복사 for (y = 1; y < imageheight + 1; y++) for (x = 1; x < imagewidth + 1; x++) if (depth == 1) tmpimg[y][x] = inputimg[y-1][x-1]; else if (depth == 3) tmpimg[y][3*x] = inputimg[y-1][3*(x-1)]; tmpimg[y][3*x+1] = inputimg[y-1][3*(x-1)+1]; tmpimg[y][3*x+2] = inputimg[y-1][3*(x-1)+2]; for (y=0; y < imageheight; y++) for (x=0; x < imagewidth; x++) if (depth == 1) sum=0; for (i=0; i<3; i++) for (j=0; j<3; j++) sum += (int) (tmpimg[y+i][x+j] * mask[i][j]); if (sum > 255) sum=255; 8

영역기반처리 CHAPTER 03 if (sum < 0) sum = 0; resultimg[y][x] = (unsigned char) sum; else if (depth == 3) red = 0; green = 0; blue = 0; for (i=0; i<3; i++) for (j=0; j<3; j++) red += (int) (tmpimg[y+i][3*(x+j)] * mask[i][j]); green += (int) (tmpimg[y+i][3*(x+j)+1] * mask[i][j]); blue += (int) (tmpimg[y+i][3*(x+j)+2] * mask[i][j]); if (red > 255) red = 255; if (red < 0) red = 0; if (green > 255) green = 255; if (green < 0) green = 0; if (blue > 255) blue = 255; if (blue < 0) blue = 0; resultimg[y][3*x] = (unsigned char) red; resultimg[y][3*x+1] = (unsigned char) green; resultimg[y][3*x+2] = (unsigned char) blue; // 기억장소반환 for (i = 0; i < imageheight + 2; i++) free(tmpimg[i]); free(tmpimg); 8 프로그램을컴파일하고실행해보자. " 모나리자.pgm" 파일을연다음에 [ 선명화 ] 메뉴를선택하면그림 3-24 와같은처리결과가나타나는지확인 한다. 9

실용영상처리 그림 3-24 회선기법을이용한선명화연산 " 자동차 - 흐림.pgm" 파일을읽어들인다음에선명화연산을적용해보자. 그림 3-25 와같이자동차번호가보다선명하게보이는지확인한다. 그림 3-25 자동차번호인식을위한선명화 3.7.5 회선기법을이용한영상흐리게하기 1 [ 영역처리 ] 메뉴에흐린영상생성을위한부메뉴를추가한다. - 부메뉴이름 : 영상흐리게하기 - ID : ID_REGION_MEANING 1

영역기반처리 CHAPTER 03 2 이벤트처리기마법사를이용하여 OnRegionMeaning() 함수를추가하고다 음과같이편집한다. void CImageProView::OnRegionMeaning() CImageProDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (pdoc->inputimg == NULL) return; pdoc->regionmeaning(); viewmode = TWO_IMAGES; Invalidate(FALSE); 3 CImageProDoc 클래스에 RegionMeaning() 함수를추가한다. - 반환형식 : void - 함수이름 : RegionMeaning 4 RegionMeaning() 함수의내용을다음과같이편집한다. void CImageProDoc::RegionMeaning() float mask[3][3] = 1/9.0f, 1/9.0f, 1/9.0f, 1/9.0f, 1/9.0f, 1/9.0f, 1/9.0f, 1/9.0f, 1/9.0f; Convolve(inputImg, resultimg, imagewidth, imageheight, mask, 0, depth); 5 프로그램을컴파일하고실행해보자. " 모나리자.pgm" 파일을연다음에 [ 평균연산 ] 메뉴를선택하면그림 3-26 과같이영상이흐려지는지확인 한다. 111

실용영상처리 그림 3-26 회선기법을이용한영상흐리게하기 3.7.6 경계선검출 Sobel 마스크를이용하여경계선을검출하는기능을구현하도록하자. 1 [ 영역처리 ] 메뉴에경계선검출을위한부메뉴를추가한다. - 부메뉴이름 : 경계선검출 (Sobel) - ID : ID_REGION_SOBEL 2 이벤트처리기마법사를이용하여 OnRegionSobel() 함수를추가하고다음 과같이편집한다. void CImageProView::OnRegionSobel() CImageProDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (pdoc->inputimg == NULL) return; pdoc->regionsobel(); viewmode = TWO_IMAGES; Invalidate(FALSE); 112

영역기반처리 CHAPTER 03 3 CImageProDoc 클래스에 RegionSobel() 함수를추가한다. - 반환형식 : void - 함수이름 : RegionSobel 4 RegionSobel() 함수의내용을다음과같이편집한다. RegionSobel() 함수에서 sqrt() 함수를사용하고있는데, 이함수에대한정의가헤더파일 <math.h> 에포함되어있으므로 RegionSobel() 함수위에 include 문이추가되어야한다. 경계선검출에서는세로방향회선마스크와가로방향회선마스크두가지를적용해야하므로두회선결과를저장하기위하여 Er과 Ec를사용하였다. 그리고두값의제곱합에루트를취한값을경계선의정도로사용하였다. #include <math.h> void CImageProDoc::RegionSobel() int i, x, y, sum; float mask1[3][3] = 1, 0, -1, 2, 0, -2, 1, 0, -1; float mask2[3][3] = -1, -2, -1, 0, 0, 0, 1, 2, 1; unsigned char **Er, **Ec; // 기억장소할당 Er = (unsigned char **) malloc((imageheight)* sizeof(unsigned char *)); Ec = (unsigned char **) malloc((imageheight)* sizeof(unsigned char *)); for (i = 0; i < imageheight; i++) Er[i] = (unsigned char *) malloc(imagewidth * depth); Ec[i] = (unsigned char *) malloc(imagewidth * depth); 113

실용영상처리 Convolve(inputImg, Er, imagewidth, imageheight, mask1, 0, depth); Convolve(inputImg, Ec, imagewidth, imageheight, mask2, 0, depth); for (y = 0; y < imageheight; y++) for (x = 0; x < imagewidth * depth; x++) sum = sqrt(er[y][x]*er[y][x] + Ec[y][x]*Ec[y][x]); if (sum > 255) sum = 255; if (sum < 0) sum = 0; resultimg[y][x] = (unsigned char) sum; 5 프로그램을컴파일하고실행해보자. " 강아지.pgm" 파일을연다음에 [ 경 계선검출 (Sobel)] 메뉴를선택하면그림 3-27 과같이경계선이검출되는 지확인한다. 그림 3-27 경계선검출화면 3.7.7 중간값필터 ( 흑백영상 ) 임펄스잡음제거에효과적인중간값필터를구현해보자. 1 [ 영역처리 ] 메뉴에중간값필터를위한부메뉴를추가한다. 114

영역기반처리 CHAPTER 03 - 부메뉴이름 : 중간값필터 - ID : ID_REGION_MEDIAN 2 이벤트처리기마법사를이용하여 OnRegionMedian() 함수를추가하고다 음과같이편집한다. void CImageProView::OnRegionMedian() CImageProDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (pdoc->inputimg == NULL) return; pdoc->regionmedian(); viewmode = TWO_IMAGES; Invalidate(FALSE); 3 CImageProDoc 클래스에 RegionMedian() 함수를추가한다. - 반환형식 : void - 함수이름 : RegionMedian 4 RegionMedian() 함수를다음과같이편집한다. 이함수에서는배열 n에입력픽셀과주위의픽셀 9개를저장한다음에오름차순으로정렬하였다. 그리고중간위치인 n[4] 의값을결과영상에저장하였다. 여기에서는구현을간단하게하기위해가장자리픽셀에대해서는아무런처리도하지않았다. void CImageProDoc::RegionMedian() int i, j, temp, x, y; int n[9]; for (y = 1; y < imageheight - 1; y++) 115

실용영상처리 for (x = 1; x < imagewidth - 1; x++) n[0] = inputimg[y-1][x-1]; n[1] = inputimg[y-1][x]; n[2] = inputimg[y-1][x+1]; n[3] = inputimg[y][x-1]; n[4] = inputimg[y][x]; n[5] = inputimg[y][x+1]; n[6] = inputimg[y+1][x-1]; n[7] = inputimg[y+1][x]; n[8] = inputimg[y+1][x+1]; // 버블정렬 (bubble sorting) for (i = 8; i > 0; i--) for (j = 0; j < i; j++) if (n[j] > n[j+1]) temp = n[j+1]; n[j+1] = n[j]; n[j] = temp; resultimg[y][x] = n[4]; // 중간값을결과영상에저장 5 프로그램을컴파일하고실행해보자. "Lenna- 임펄스잡음.raw" 파일을열 은다음에 [ 중간값필터 ] 메뉴를선택하면그림 3-28 과같이잡음이제거 되는지확인한다. 116

영역기반처리 CHAPTER 03 그림 3-28 중간값필터적용화면 117

실용영상처리 연습문제 01 Prewitt 회선마스크와 Roberts 회선마스크를이용한경계선검출프로그 램을작성하시오. 02 5 5 크기의회선마스크에대한회선을수행할수있도록 Convolve() 함 수를수정하여 " 영상흐리게하기 " 기능을구현하시오. 같은입력영상에대하여 3 3 크기의회선마스크와 5 5 크기의회선마스크를각각사용하여 " 영상흐리게하기 " 기능을적용하여보고그결과를비교하시오. 03 컬러영상에대한 " 영상흐리게하기 ", " 영상의선명화 ", " 경계선검출 " 기 능을구현하는프로그램을작성하시오. 04 다음과같은마스크를적용하면그림과같은처리결과를얻을수있는데, 이와같은처리를엠보싱 (embossing) 이라한다. 엠보싱기능을구현하는 프로그램을작성하시오. -1 0 0 0 0 0 0 0 1 > H 엠보싱회선마스크 (a) 입력영상 (b) 엠보싱적용결과영상 05 경계선검출방법으로이교재에서설명한방법외에도라플라시안연산자, 가우시안-라플라시안 (LOG: Laplacian Of Gaussian) 연산자, 가우시안의차분연산자 (DOG: Difference Of Gaussian) 등이있다. 이들에대해조사하고 Sobel, Prewitt, Roberts 등의방법과비교하시오. 118

영역기반처리 CHAPTER 03 06 윈도우즈환경에서많이사용되는 BMP 파일의구조에대하여조사하시오. 07 본문에서는 PGM 과 PPM 파일읽기프로그램을구현하는방법을살펴보았다. BMP 파일을읽어들일수있도록 LoadImageFile() 함수를확장하시오. 08 3.7.2 절의 Serialize() 함수에서는파일읽기기능만구현하였고파일저 장기능은구현하지않았다. 이로인하여입력영상을처리한다음에 [ 파일 ] 메뉴에서 [ 저장 ] 부메뉴나 [ 다른이름으로저장 ] 부메뉴를선택하여파일을저장하면파일의크기가 0바이트인공백파일이생성된다. [ 저장 ] 부메뉴를선택한경우에는입력영상파일을덮어쓰게되어입력영상파일이지워지는결과를초래한다. 이문제를해결하기위하여배열 resultimg 에저장되어있는영상을 RAW, PGM, PPM 형식으로저장하도록 Serialize() 함수를확장하시오. 119

er 06 Ch 영상 워핑과 모핑 6.1 영상 워핑 6.2 모핑 6.3 실습 t ap

Chapter 06 영상 워핑과 모핑 영상 워핑(warping)과 모핑(morphing)은 TV 광고나 영화 등을 통하여 대중 화됨으로써 일반인들에게도 널리 알려진 영상 처리 기법 중의 하나가 되었다. 이 들은 앞에서 다룬 영상 처리와는 달리 영상의 형태를 크게 변화시킴으로써 아주 흥미로운 결과 영상을 만들어 낼 수 있다. 이 장에서는 영상 워핑과 모핑의 개념 을 살펴보고 구현 과정을 실습해 보도록 하자. 6.1 영상 워핑 영상 워핑은 픽셀의 위치를 이동하는 기하학적 처리 중의 한 기법이다. 영상 의 확대나 축소와 같은 기하학적 처리는 모든 픽셀에 대하여 일정한 규칙을 적용 함으로써 균일한 변환 결과를 얻는다. 반면에 영상 워핑은 픽셀별로 이동 정도를 달리할 수 있어서, 고무판 위에 그려진 영상을 임의대로 구부리는 것과 같은 효 과를 낼 수 있다. 그림 6-1에는 모나리자의 얼굴을 워핑한 예가 나타나 있다. (a) 원영상 그림 6-1 174 (b) 워핑 예 모나리자 영상 워핑 예

영상워핑과모핑 CHAPTER 06 영상워핑은인공위성이나다른우주계획의일원으로부터보내져온일그러진영상을올바르게만드는데처음사용하였다. 인공위성이나우주선으로부터전송된영상은렌즈의변형, 신호의왜곡등의이유로인해일그러지는경우가많았는데, 영상워핑은이러한일그러짐을복구하는데사용되었다. 영상워핑은 TV나영화에서물체, 동물, 배우등의모습을변환하는데사용될수있다. 예를들어, 배우의키를크게하거나, 작게하거나아니면배우의몸집을홀쭉하게하거나, 뚱뚱하게만들거나, 신체의일부만길게만들거나하는등의효과를주기위해사용된다. 또는 TV 광고에서소가노래를부른다든지냉장고의모양이변형된다든지등의특수효과를낼수있다. 그림 6-2에는영상워핑을사용하여개의표정을변화시킨예가나타나있다. (a) 입력영상 (b) 출력영상 그림 6-2 영상워핑을사용한개의표정변화 영상워핑은행방불명된아이를찾는데도사용된다. 미아와유괴된아동들을위한기구인 NCMEC(The National Center for Missing and Exploited Children) 는아이들이사라진이후에아이들의연령에맞는사진을만들어주는소프트웨어를사용한다. 행방불명된아이의사진에그아이보다나이가많은형제나친척의사진을합성하고, 현재나이에맞는머리카락과옷을입혀합성시키면아이의나이에맞는사진을만들어낼수있다. 이러한기술은유괴된후몇년이지나도그아이의현재모습을닮은사진을제공할수있게해준다. 6.1.1 입력영상과출력영상의대응관계기술 영상워핑을위해서는먼저입력영상을어떻게변형할것인지기술해야한다. 175

실용영상처리 그림 6-3 에는그림 6-1 의워핑결과를얻기위해제어선을사용하여대응되는위 치를기술한모습이나타나있다. 그림 6-3 제어선을이용한대응위치기술예 그림 6-4 에는그림 6-2 의워핑결과를얻기위하여입력영상과출력영상사 이에서로대응되어야할위치를제어점으로기술한예가나타나있다. (a) 입력영상제어점 (b) 출력영상제어점 그림 6-4 제어점을이용한대응위치기술예 제어선과제어점이외에도그물망, 다각형등여러가지방법을사용하여입력 영상과출력영상의대응관계를나타낼수있다. 6.1.2 제어선을이용한워핑기법제어선을이용하여입력영상과출력영상의대응관계를기술한경우에워핑을수행하는방법에대하여살펴보자. 이방법에서는그림 6-5와같이화소와제어선사이의수직교차점을구한다. 그리고화소와수직교차점사이의변위정 176

영상워핑과모핑 CHAPTER 06 보와제어선내에서수직교차점의위치정보두가지를활용하고역방향사상을이용하여워핑을수행한다. 그림 6-5에서는출력영상에서제어선 PQ가입력영상에서제어선 PlQl에대응되고, 출력영상의픽셀 V가입력영상의픽셀 Vl 로부터복사된다. 역방향사상에의하여픽셀 V에대응되는픽셀 Vl의위치를계산하기위해서는먼저 PQ 내에서의 C의상대적위치와동일하게 PlQl 내에서 Cl의위치를찾는다. 그다음에는 C와 V 사이의변위만큼 Cl로부터떨어진점 Vl를찾는다. Ql Q Cl 변위 Vl C 변위 V 위치 위치 Pl 입력영상 P 출력영상 그림 6-5 제어선을이용한워핑에사용되는정보 픽셀과제어선의수직교차점이그림 6-6 과같이제어선내부에존재하지않 을수있다. 이경우에도수직교차점이제어선내부에있는경우와동일한방법 에의하여원시영상의픽셀위치를찾는다. Ql Q Pl P 위치 Cl 변위 Vl 위치 C 변위 V 입력영상 출력영상 그림 6-6 수직교차점이제어선외부에존재하는경우의예 177

실용영상처리 하나의제어선에대해서는앞에서설명한바와같이단순하게픽셀의이동위치를계산할수있지만실제의워핑에서는여러개의제어선이사용된다. 제어선이여러개일때각제어선은영상의모든픽셀에영향을미치게된다. 한픽셀이여러개의제어선으로부터영향받는것을반영하기위한방법으로다음식과같은가중치를사용할수있다. 식에나타나있는바와같이제어선의길이가길수록가중치가커지고픽셀과제어선사이의거리가가까울수록가중치가커진다. 가중치 = d 제어선의길이 ] a + 픽셀과제어선의거리 g n p b 위식에서 p값은제어선의길이가가중치에영향을주는정도를결정하는값으로 0에서 1 사이의값을가진다. a는 0으로나누는것을방지하기위해사용되는값으로매우작은값을갖는다. b는제어선의길이와거리의변화에따라가중치의변화정도를조절하는값인데보통 0.5에서 2.0 사이의값을사용한다. 이값이커지면픽셀들은먼거리에있는제어선들로부터영향을적게받게된다. 픽셀과제어선의거리는그림 6-7과같이수직교차점의위치에따라다르게정의된다. 수직교차점이제어선내부에있는경우에는픽셀과수직교차점사이의거리가사용되고제어선외부에있는경우에는제어선의양끝점중에서픽셀과가까운점과픽셀사이의거리가사용된다. Q Q V d V P d Q d P V P (a) 수직교차점이제어선내부에있는경우 (b) 수직교차점이제어선외부에있는경우 그림 6-7 픽셀과제어선의거리 제어선이여러개인경우에출력영상의각픽셀에대하여입력영상의대응 픽셀을구하는 warping() 함수의알고리즘은다음과같다. 178

영상워핑과모핑 CHAPTER 06 warping() 출력영상의각픽셀 Vxy ], g에대하여 tx = 0 // x 방향변위의합을나타내는변수를초기화한다. ty = 0 // y 방향변위의합을나타내는변수를초기화한다. totalweight = 0 // 가중치의합을나타내는변수를초기화한다. 각제어선 L i 에대하여 V 와 L i 의수직교차점의위치 u 를계산한다. V 와 L i 의수직변위 h 를계산한다. u와 h를이용하여입력영상에서의대응위치 Vl] xl, ylg을구한다. V 와 L i 사이의거리를 d 를계산한다. p b weight = 제어선길이 n t = t + ] xl - xg weight x x # t = t + ] yl - yg weight y y # totalweight = totalweight + weight X = x + t x totalweight t y Y = y+ totalweight 입력영상의 Vl] X, Yg 픽셀의값을출력영상의 Vxy ], g 픽셀에복사한다. 수직교차점의위치계산 Warping() 함수에서는첫번째작업으로출력영상의각픽셀 Vxy ], g에대 하여각각의제어선 L i 와의수직교차점의위치를구한다. 픽셀 Vxy ], g가그림 6-8과같이제어선 L i 에내린수선이점 Cx ], y g에서만난다고하자. 그리고 제어선 L i 의끝점 Px ], y g에서수직교차점 Cx ], y g까지의거리를 u로나타 내기로하자. i i c c c c 179

실용영상처리 Q(x i+1, y i+1 ) C(x c, y c ) L i P(x i, y i ) u V(x, y) 그림 6-8 점과제어선사이의수직교차점 u 의값은수직교차점의위치에따라다음과같은범위의값을가지게된다. u < 0 : P 바깥에수직교차점이위치 0 # u # 1 : 제어선내부에수직교차점이위치 u > 1 : Q 바깥에수직교차점이위치 u 의값은다음식과같이제어선의양끝점 P, Q 와픽셀의위치 V 로부터구 할수있다. 이식에서 x = x i 이고 y = y i 인경우에분자가 0이되어 u의값이 0이되고 x = x i + 1 이고 y = y i + 1 인경우에분모와분자가같게되어 u의값 이 1 이된다. u = ] x-xig] xi+ 1- xig+ ] y-yig] yi+ 1- yig 2 2 ] x - xg + ] y - yg i+ 1 i i+ 1 i 제어선으로부터의수직변위계산 Warping() 함수에서는두번째작업으로출력영상의픽셀 Vxy ], g에대하여 각각의제어선 L i 으로부터의수직변위를구한다. 제어선으로부터픽셀의수직 변위는그림 6-9 와같이픽셀을지나면서제어선과수직교차하는직선상에서의 픽셀의위치를나타내는값으로, 다음과같은범위의값을갖는다. 변위 h= * <0 픽셀이제어선아래쪽에있는경우 0 픽셀이제어선에있는경우 >0 픽셀이제어선위쪽에있는경우 180

영상워핑과모핑 CHAPTER 06 그림 6-9(a) 에서는픽셀 V 가제어선위쪽에있으므로 h 값이 0 보다크고 6-9(b) 에서는픽셀 V 가제어선아래쪽에있으므로 h 값이 0 보다작게된다. 변 위의절댓값이수직교차점과픽셀사이의거리가된다. Q Q V h h P P V (a) h > 0 인경우 (b) h < 0 인경우 그림 6-9 픽셀의수직변위 변위 h 를구하는공식은다음과같다. u = ] y-yig] xi+ 1-xig-] x-xig] yi+ 1- yig 2 2 ] x - xg + ] y - yg i+ 1 i i+ 1 i 입력영상에서의대응픽셀위치계산 Warping() 함수에서는출력영상의각픽셀 Vxy ], g에대하여각각의제어 선 L i 와의수직교차점의위치 u 와수직변위 h 를구한다음, u 와 h 값을이용하 여출력영상의 Vxy ], g에대응되는입력영상의픽셀 Vl] xl, ylg을찾는다. 출 력영상의제어선 L i 에대응되는입력영상에서의제어선 L i l 의양끝점좌표를 ] xl, ylg과 ] x l, y lg이라하자. 그러면 Vl] xl, ylg은다음식과같이찾을 i i 수있다. i+ 1 i+ 1 xl = xl+ u# ] x l-x lg - i i+ 1 i yl = yl+ u# ] y l-y lg - i i+ 1 i h# ] y l i 1 - yl + ig 2 ] x l- xlg + ] y l- ylg 2 i+ 1 i i+ 1 i h# ] x l i 1 - xl + ig 2 ] x l- xlg + ] y l- ylg 2 i+ 1 i i+ 1 i 181

실용영상처리 픽셀과제어선사이의거리 픽셀과제어선사이의거리 d 는앞에서설명한방법에의하여다음과같이구 한다. 즉, u 값이 0보다작을때는픽셀 Vxy ], g와 Px ], y g 사이의거리, u 값 이 1보다큰경우에는픽셀 Vxy ], g와 Qx ], y g 사이의거리, u 값이 0에 i+ 1 i+ 1 서 1 사이인경우에는수직변위 h 의절댓값이된다. i i d = * 2 2 ] x- xig + ] y- yig 2 ] x- xi 1g + ] y- yi h g 2 + + 1 u < 0 u > 1 0 E u E 1 제어선의가중치계산 Warping() 함수에서픽셀과제어선사이의거리 d를구한다음에는제어선의가중치 weight를구한다. 여기에서 a, b, p 상수값으로는일반적으로많이사용되는값을사용하였다 (a=0.001, b=2.0, p=0.75). 입력영상의대응픽셀과의변위누적 각제어선 L i 에대하여출력영상의픽셀 Vxy ], g에대응되는입력영상 의픽셀 Vl] xl, ylg을구하고, 가중치 weight를구한다음에는다음식과같이 V 와 Vl 사이의변위와가중치의곱을계산하여 t x, t y 변수에누적한다. t = t + ] xl - xg weight x x # t = t + ] yl - yg weight y y # totalweight = totalweight + weight 입력영상에서의대응픽셀위치계산 각제어선에대해출력영상의픽셀 Vxy ], g에대응되는입력영상의픽셀 의변위값을구하여이들의합 ] t, t g를계산한다음에는다음식에의하여 Vxy ], g에대응되는입력영상의픽셀 VXY ], g의위치를계산한다. x y 182

영상워핑과모핑 CHAPTER 06 X = x + Y = y+ t x totalweight t y totalweight 이와같이최종적으로 Vxy ], g에대응되는픽셀 VXY ], g을구한다음에는 입력영상의 VXY ], g 픽셀의값을출력영상의 Vxy ], g 픽셀에복사한다. 6.2 모핑 워핑은하나의입력영상에대하여영상의형태만변환하는데, 모핑은두개의서로다른입력영상에대하여한영상을다른영상으로변환하는것을말한다. 그림 6-에는사람을침팬지로변화시키기위해사용된두입력영상예가나타나있다. 그림 6- 사람을침팬지로모핑시키기위해사용된두입력영상 그림 6-의두입력영상을이용하여모핑한예가그림 6-11에나타나있다. 그림과같이영상이다른영상으로자연스럽게변화되도록하기위해서는중간에많은영상들이생성되어야한다. 이렇게연속된영상들의각각을프레임이라부르기로하자. 183

실용영상처리 그림 6-11 사람이침팬지로변하는모핑예 그림 6-11 의모핑을위해서는먼저두입력영상사이의대응관계를기술해야 한다. 그림 6-12 에는제어선을이용하여사람과침팬지사이의대응관계를표시 한예가나타나있다. 그림 6-12 모핑을위한두입력영상사이의대응관계기술 모핑은워핑과합병두단계로구성된다. 워핑단계에서는두입력영상을같은형태가되도록변환한다. 그리고합병단계에서는변환된두영상을더하여출력영상을생성한다. 그림 6-13에는그림 6-11의중간프레임중에서 4번째프레임을얻기위해수행한워핑과정과합병과정이나타나있다. 184

영상워핑과모핑 CHAPTER 06 워핑 워핑 합병 그림 6-13 모핑의한영상을얻기위한과정 모핑에서는여러개의중간프레임을생성해야하는데, 각프레임에대한제어선들은주어지지않고모핑의처음과끝에해당하는두입력영상에대한제어선들이주어진다. 중간프레임에대한제어선은두입력영상에대한제어선을보간하여얻을수있다. 그림 6-14에는그림 6-11의 4번째프레임의워핑을위해보간법으로생성한제어선의예가나타나있다. 영상 1 의제어선 중간프레임의제어선 그림 6-14 중간프레임에대한제어선생성예 영상 2 의제어선 보간법을이용하여중간프레임에대한제어선을생성하는방법을살펴보자. 입력영상 1의제어선과이에대응되는입력영상 2의제어선좌표가그림 6-15 와같다고하자. 그리고생성하고자하는전체프레임의개수가 N이라하고현재얻고자하는프레임이 k 번째프레임이라하자. 그러면 k 번째중간프레임의대 응되는제어선의양끝점좌표 ] x, y g와 ] x, y g는다음과같이구할수있다. p p q q 185

실용영상처리 u = k/ N x = x + ux ] - x g p 1 3 1 y = y + uy ] - y g p 1 3 1 x = x + ux ] - x g q 2 4 2 y = y + uy ] - y g q 2 4 2 (x 2, y 2 ) (x q, y q ) (x 4, y 4 )...... (x 1, y 1 ) (x p, y p ) (x 3, y 3 ) 입력영상 1 K 번째중간프레임입력영상 2 그림 6-15 제어선의좌표 중간프레임에대한제어선을구한다음에는 6.1절에서설명한워핑방법을이용하여입력영상 1과입력영상 2를각각중간프레임으로워핑한다. 워핑된두영상은가중치를이용한픽셀덧셈연산을이용하여합병할수있다. 생성할전체프레임수가 N 개이고 k번째중간프레임의영상을합병한다고하자. 그리고워핑된두영상에서픽셀 (x, y) 의값이각각 I ] 1 x, y g와 I x, y 2 ] g라하자. 합병된영상의픽셀 (x, y) 의값 O(x, y) 는다음과같이계산될수있다. u = k/ N Oxy ], g = ] - ugi ] x, yg+ ui ] x, yg 1 1 2 6.3 실습 6.3.1 영상워핑 1 [ 기하학적처리 ] 메뉴아래에워핑연산을위한부메뉴를추가한다. - 부메뉴이름 : 워핑 186

영상워핑과모핑 CHAPTER 06 - ID : ID_GEOMETRY_WARPING 2 이벤트처리기마법사를이용하여 CImageProView 클래스에 OnGeometry Warping() 함수를추가하고다음과같이편집한다. void CImageProView::OnGeometryWarping() CImageProDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (pdoc->inputimg == NULL) return; pdoc->geometrywarping(); viewmode = TWO_IMAGES; Invalidate(FALSE); 3 CImageProDoc 클래스에 GeometryWarping() 함수를추가한다. - 반환형식 : void - 함수이름 : GeometryWarping 4 GeometryWarping() 함수를다음과같이편집한다. 함수위에는제어선에대한구조체 control_line에대한정의가나타나있다. 함수의첫부분에서는제어선에대한변수를선언하였고미리계산된제어선의좌표를초깃값으로지정하였다. typedef struct int Px; int Py; int Qx; int Qy; control_line; void CImageProDoc::GeometryWarping() 187

실용영상처리 control_line source_lines[23] = 116,7,207,5,34,9,90,21,55,249,30,128,118,320,65,261, 123,321,171,321,179,319,240,264,247,251,282,135,281,114,228,8, 78,6,123,9,187,115,235,114,72,142,99,128,74,150,122,154, 8,127,123,146,182,152,213,132,183,159,229,157,219,131,240,154, 80,246,117,212,127,222,146,223,154,227,174,221,228,252,183,213, 114,255,186,257,9,258,143,277,152,278,190,262; control_line dest_lines[23] = 120,8,200,6,12,93,96,16,74,271,16,1,126,336,96,290, 142,337,181,335,192,335,232,280,244,259,288,8,285,92,212,13, 96,135,136,118,194,119,223,125,5,145,124,134,1,146,138,151, 131,133,139,146,188,146,198,134,189,153,218,146,204,133,221,140, 91,268,122,202,149,206,159,209,170,209,181,204,235,265,208,199, 121,280,205,284,112,286,160,301,166,301,214,287; double u; double h; double d; double tx, ty; double xp, yp; // 수직교차점의위치 // 제어선으로부터픽셀의수직변위 // 제어선과픽셀사이의거리 // 결과영상픽셀에대응되는입력영상픽셀사이의변위의합 // 각제어선에대해계산된입력영상의대응되는픽셀위치 double weight; double totalweight; double a=0.001; double b=2.0; double p=0.75; // 각제어선의가중치 // 가중치의합 int x1, x2, y1, y2; int src_x1, src_y1, src_x2, src_y2; double src_line_length, dest_line_length; int num_lines = 23; int line; int x, y; int source_x, source_y; int last_row, last_col; // 제어선의수 188

영상워핑과모핑 CHAPTER 06 last_row = imageheight-1; last_col = imagewidth-1; // 출력영상의각픽셀에대하여 for(y=0; y<imageheight; y++) for(x=0; x<imagewidth; x++) totalweight = 0.0; tx = 0.0; ty = 0.0; // 각제어선에대하여 for (line = 0; line < num_lines; line++) x1 = dest_lines[line].px; y1 = dest_lines[line].py; x2 = dest_lines[line].qx; y2 = dest_lines[line].qy; dest_line_length = sqrt((double)((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))); // 수직교차점의위치및픽셀의수직변위계산 u = (double) ((x-x1)*(x2-x1)+(y-y1)*(y2-y1)) / (double) ((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); h = (double) ((y-y1)*(x2-x1)-(x-x1)*(y2-y1)) / dest_line_length; // 제어선과픽셀사이의거리계산 if (u < 0 ) d = sqrt((double) ((x-x1) * (x-x1) + (y-y1) * (y-y1))); else if (u > 1) d = sqrt((double) ((x-x2) * (x-x2) + (y-y2) * (y-y2))); else d = fabs(h); src_x1 = source_lines[line].px; src_y1 = source_lines[line].py; src_x2 = source_lines[line].qx; src_y2 = source_lines[line].qy; src_line_length=sqrt((double) ((src_x2-src_x1)*(src_x2-src_x1)+ (src_y2-src_y1)*(src_y2-src_y1))); 189

실용영상처리 // 입력영상에서의대응픽셀위치계산 xp = src_x1+u*(src_x2 - src_x1) - h * (src_y2 - src_y1) / src_line_length; yp = src_y1+u*(src_y2 - src_y1) + h * (src_x2 - src_x1) / src_line_length; // 제어선에대한가중치계산 weight = pow((pow((double)(dest_line_length),p) / (a + d)), b); // 대응픽셀과의변위계산 tx += (xp - x) * weight; ty += (yp - y) * weight; totalweight += weight; source_x = x + (int) (tx / totalweight + 0.5); source_y = y + (int) (ty / totalweight + 0.5); // 영상의경계를벗어나는지검사 if (source_x < 0) source_x = 0; if (source_x > last_col) source_x = last_col; if (source_y < 0) source_y = 0; if (source_y > last_row) source_y = last_row; resultimg[y][x] = inputimg[source_y][source_x]; 5 프로그램을컴파일하고실행시킨다음에 "warp.pgm" 영상을열자. 그다음 에워핑메뉴를선택하면그림 6-16 과같은결과를얻게된다. 190

영상워핑과모핑 CHAPTER 06 그림 6-16 모핑연산실행화면 6.3.2 모핑 1 [ 기하학적처리 ] 메뉴아래에모핑연산을위한부메뉴를추가한다. - 부메뉴이름 : 모핑 - ID : ID_GEOMETRY_MORPHING 2 이벤트처리기마법사를이용하여 CImageProView 클래스에 OnGeometry Morphing() 함수를추가하고다음과같이편집한다. 여기에서 viewmode 값을 MORPHING으로설정하였음에유의하자. 모핑결과는하나의영상이아니라여러개의중간프레임들로생성된다. 따라서모핑결과를출력하는부분이기존의연산과는다르므로모핑을위한 viewmode를설정하였다. 이값은 OnDraw() 함수에서사용된다. void CImageProView::OnGeometryMorphing() CImageProDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); pdoc->geometrymorphing(); viewmode = MORPHING; Invalidate(FALSE); 191

실용영상처리 3 CImageProView.cpp 파일의위부분에 MORPHING 상수에대한정의를추가 한다. -- 추가하기전 #define TWO_IMAGES 1 #define THREE_IMAGES 2 #define TWO_IMAGES_SCALED 4 -- 추가한다음 #define TWO_IMAGES 1 #define THREE_IMAGES 2 #define TWO_IMAGES_SCALED 4 #define MORPHING 8 4 CImageProDoc 클래스의정의에다음과같이모핑과정에서생성되는중간프레임을저장하기위한변수 morphedimg를선언한다. 여기에서는 개의중간프레임을저장할수있도록배열의크기를 으로설정하였다. 프레임의수를변경하려면이값을변경하여야한다. CImageProDoc 클래스를더블클릭한다음클래스의정의부분에다음과같이변수를추가한다. // Attributes public: unsigned char **inputimg; unsigned char **inputimg2; unsigned char **resultimg; int imagewidth; int imageheight; int depth; int gimagewidth; int gimageheight; unsigned char **gresultimg; // 입력영상의기억장소에대한포인터변수 // 입력영상의기억장소에대한포인터변수 // 출력영상의기억장소에대한포인터변수 // 영상의가로크기 // 영상의세로크기 // 1 = 흑백영상, 3 = 컬러영상 // 크기가변한결과영상의가로크기 // 크기가변한결과영상의세로크기 // 크기가변한결과영상에대한포인터변수 // 모핑결과저장을위해새로이추가되는코드 unsigned char **morphedimg[]; 192

영상워핑과모핑 CHAPTER 06 5 CImageProDoc 클래스에 GeometryMorphing() 함수를추가한다. - 반환형식 : void - 함수이름 : GeometryMorphing 6 GeometryMorphing() 함수를다음과같이편집한다. #define NUM_FRAMES void CImageProDoc::GeometryMorphing() control_line source_lines[23] = 116,7,207,5,34,9,90,21,55,249,30,128,118,320,65,261, 123,321,171,321,179,319,240,264,247,251,282,135,281,114,228,8, 78,6,123,9,187,115,235,114,72,142,99,128,74,150,122,154, 8,127,123,146,182,152,213,132,183,159,229,157,219,131,240,154, 80,246,117,212,127,222,146,223,154,227,174,221,228,252,183,213, 114,255,186,257,9,258,143,277,152,278,190,262; control_line dest_lines[23] = 120,8,200,6,12,93,96,16,74,271,16,1,126,336,96,290, 142,337,181,335,192,335,232,280,244,259,288,8,285,92,212,13, 96,135,136,118,194,119,223,125,5,145,124,134,1,146,138,151, 131,133,139,146,188,146,198,134,189,153,218,146,204,133,221,140, 91,268,122,202,149,206,159,209,170,209,181,204,235,265,208,199, 121,280,205,284,112,286,160,301,166,301,214,287; double u; double h; double d; double tx, ty; double xp, yp; // 수직교차점의위치 // 제어선으로부터픽셀의수직변위 // 제어선과픽셀사이의거리 // 결과영상픽셀에대응되는입력영상픽셀사이의변위의합 // 각제어선에대해계산된입력영상의대응되는픽셀위치 double weight; double totalweight; double a=0.001; double b=2.0; double p=0.75; // 각제어선의가중치 // 가중치의합 193

실용영상처리 unsigned char **warpedimg; unsigned char **warpedimg2; int frame; double fweight; control_line warp_lines[23]; double tx2, ty2; double xp2, yp2; int dest_x1, dest_y1, dest_x2, dest_y2; int source_x2, source_y2; int x1, x2, y1, y2; int src_x1, src_y1, src_x2, src_y2; double src_line_length, dest_line_length; int i, j; int num_lines = 23; int line; int x, y; int source_x, source_y; int last_row, last_col; // 제어선의수 // 두입력영상을읽어들임 LoadTwoImages(); // 중간프레임의워핑결과를저장을위한기억장소할당 warpedimg = (unsigned char **) malloc(imageheight * sizeof(unsigned char *)); for (i = 0; i < imageheight; i++) warpedimg[i] = (unsigned char *) malloc(imagewidth * depth); warpedimg2 = (unsigned char **) malloc(imageheight * sizeof(unsigned char *)); for (i = 0; i < imageheight; i++) warpedimg2[i] = (unsigned char *) malloc(imagewidth * depth); for (i = 0; i < NUM_FRAMES; i++) morphedimg[i]=(unsigned char **) malloc(imageheight* sizeof(unsigned char *)); 194

영상워핑과모핑 CHAPTER 06 for (j = 0; j < imageheight; j++) morphedimg[i][j] = (unsigned char *) malloc(imagewidth * depth); last_row = imageheight-1; last_col = imagewidth-1; // 각중간프레임에대하여 for(frame=1; frame <= NUM_FRAMES; frame++) // 중간프레임에대한가중치계산 fweight = (double)(frame) / NUM_FRAMES; // 중간프레임에대한제어선계산 for(line=0; line<num_lines; line++) warp_lines[line].px = source_lines[line].px + (dest_lines[line].px - source_lines[line].px)*fweight; warp_lines[line].py = source_lines[line].py + (dest_lines[line].py - source_lines[line].py)*fweight; warp_lines[line].qx = source_lines[line].qx + (dest_lines[line].qx - source_lines[line].qx)*fweight; warp_lines[line].qy = source_lines[line].qy + (dest_lines[line].qy - source_lines[line].qy)*fweight; // 출력영상의각픽셀에대하여 for(y=0; y<imageheight; y++) for(x=0; x<imagewidth; x++) totalweight = 0.0; tx = 0.0; ty = 0.0; tx2 = 0.0; ty2 = 0.0; 195

실용영상처리 // 각제어선에대하여 for (line = 0; line < num_lines; line++) x1 = warp_lines[line].px; y1 = warp_lines[line].py; x2 = warp_lines[line].qx; y2 = warp_lines[line].qy; dest_line_length = sqrt((double) ((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))); // 수직교차점의위치및픽셀의수직변위계산 u = (double) ((x-x1)*(x2-x1)+(y-y1)*(y2-y1))/ (double) ((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); h = (double) ((y-y1)*(x2-x1)-(x-x1)*(y2-y1))/ dest_line_length; // 제어선과픽셀사이의거리계산 if (u < 0 ) d = sqrt((double) ((x-x1) * (x-x1) + (y-y1) * (y-y1))); else if (u > 1) d = sqrt((double) ((x-x2) * (x-x2) + (y-y2) * (y-y2))); else d = fabs(h); src_x1 = source_lines[line].px; src_y1 = source_lines[line].py; src_x2 = source_lines[line].qx; src_y2 = source_lines[line].qy; src_line_length = sqrt((double) ((src_x2-src_x1)*(src_x2-src_x1) + (src_y2-src_y1)*(src_y2-src_y1))); dest_x1 = dest_lines[line].px; dest_y1 = dest_lines[line].py; dest_x2 = dest_lines[line].qx; dest_y2 = dest_lines[line].qy; dest_line_length = sqrt((double) ((dest_x2-dest_x1)* (dest_x2-dest_x1)+(dest_y2-dest_y1)*(dest_y2-dest_y1))); // 입력영상 1에서의대응픽셀위치계산 xp = src_x1 + u * (src_x2 - src_x1) - h * (src_y2 - src_y1) / src_line_length; yp = src_y1 + u * (src_y2 - src_y1) + 196

영상워핑과모핑 CHAPTER 06 h * (src_x2 - src_x1) / src_line_length; // 입력영상 2에서의대응픽셀위치계산 xp2 = dest_x1 + u * (dest_x2 - dest_x1) - h * (dest_y2 - dest_y1) / dest_line_length; yp2 = dest_y1 + u * (dest_y2 - dest_y1) + h * (dest_x2 - dest_x1) / dest_line_length; // 제어선에대한가중치계산 weight = pow((pow((double)(dest_line_length),p) / (a + d)), b); // 입력영상 1의대응픽셀과의변위계산 tx += (xp - x) * weight; ty += (yp - y) * weight; // 입력영상 2의대응픽셀과의변위계산 tx2 += (xp2 - x) * weight; ty2 += (yp2 - y) * weight; totalweight += weight; // 입력영상 1의대응픽셀위치계산 source_x = x + (int) (tx / totalweight + 0.5); source_y = y + (int) (ty / totalweight + 0.5); // 입력영상 2의대응픽셀위치계산 source_x2 = x + (int) (tx2 / totalweight + 0.5); source_y2 = y + (int) (ty2 / totalweight + 0.5); // 영상의경계를벗어나는지검사 if (source_x < 0) source_x = 0; if (source_x > last_col) source_x = last_col; if (source_y < 0) source_y = 0; if (source_y > last_row) source_y = last_row; if (source_x2 < 0) source_x2 = 0; if (source_x2 > last_col) source_x2 = last_col; 197

실용영상처리 if (source_y2 < 0) source_y2 = 0; if (source_y2 > last_row) source_y2 = last_row; // 워핑결과저장 warpedimg[y][x] = inputimg[source_y][source_x]; warpedimg2[y][x] = inputimg2[source_y2][source_x2]; // 모핑결과합병 for(y=0; y<imageheight; y++) for(x=0; x<imagewidth; x++) int val = (int) ((1.0 - fweight) * warpedimg[y][x] + fweight * warpedimg2[y][x]); if (val < 0) val = 0; if (val > 255) val = 255; morphedimg[frame-1][y][x] = val; 7 모핑결과를출력할수있도록 CImageProView 클래스의 OnDraw() 함수를 수정한다. void CImageProView::OnDraw(CDC* pdc) CImageProDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); if (pdoc->inputimg == NULL) return; if (pdoc->depth == 1) for(int y=0; y < pdoc->imageheight; y++) // 입력영상출력 for(int x=0; x < pdoc->imagewidth; x++) pdc->setpixel(x, y, RGB(pDoc->inputImg[y][x], pdoc->inputimg[y][x], pdoc->inputimg[y][x])); 198

영상워핑과모핑 CHAPTER 06 if (viewmode == THREE_IMAGES) for(int y=0; y< pdoc->imageheight; y++) // 두번째입력영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth+30, y, RGB(pDoc->inputImg2[y][x], pdoc->inputimg2[y][x], pdoc->inputimg2[y][x])); for(int y=0; y< pdoc->imageheight; y++) // 결과영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth*2+60, y, RGB(pDoc->resultImg[y][x], pdoc->resultimg[y][x], pdoc->resultimg[y][x])); else if (viewmode == TWO_IMAGES_SCALED) for(int y=0; y< pdoc->gimageheight; y++) // 크기가변한결과영상출력 for(int x=0; x< pdoc->gimagewidth; x++) pdc->setpixel(x+pdoc->imagewidth+30, y, RGB(pDoc->gResultImg[y][x], pdoc->gresultimg[y][x], pdoc->gresultimg[y][x])); else if (viewmode == MORPHING) for(int y=0; y< pdoc->imageheight; y++) // 두번째입력영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth+30, y, RGB(pDoc->inputImg2[y][x], pdoc->inputimg2[y][x], pdoc->inputimg2[y][x])); for (int i = 0; i < ; i++) for(int y=0; y< pdoc->imageheight; y++) // 모핑결과출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth*2+60,y, RGB(pDoc->morphedImg[i][y][x], pdoc->morphedimg[i][y][x], pdoc->morphedimg[i][y][x])); else 199

실용영상처리 for(int y=0; y< pdoc->imageheight; y++) // 결과영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth+30, y, RGB(pDoc->resultImg[y][x], pdoc->resultimg[y][x], pdoc->resultimg[y][x])); else if (pdoc->depth == 3) for(int y=0; y < pdoc->imageheight; y++) // 입력영상출력 for(int x=0; x < pdoc->imagewidth; x++) pdc->setpixel(x, y, RGB(pDoc->inputImg[y][3*x], pdoc->inputimg[y][3*x+1], pdoc->inputimg[y][3*x+2])); if (viewmode == THREE_IMAGES) for(int y=0; y< pdoc->imageheight; y++) // 두번째입력영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth+30, y, RGB(pDoc->inputImg2[y][3*x], pdoc->inputimg2[y][3*x+1], pdoc->inputimg2[y][3*x+2])); for(int y=0; y< pdoc->imageheight; y++) // 결과영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth*2+60, y, RGB(pDoc->resultImg[y][3*x], pdoc->resultimg[y][3*x+1], pdoc->resultimg[y][3*x+2])); else if (viewmode == TWO_IMAGES_SCALED) for(int y=0; y< pdoc->gimageheight; y++) // 크기가변한결과영상출력 for(int x=0; x< pdoc->gimagewidth; x++) pdc->setpixel(x+pdoc->imagewidth+30, y, RGB(pDoc->gResultImg[y][3*x], pdoc->gresultimg[y][3*x+1], pdoc->gresultimg[y][3*x+2])); else 200

영상워핑과모핑 CHAPTER 06 for(int y=0; y< pdoc->imageheight; y++) // 결과영상출력 for(int x=0; x< pdoc->imagewidth; x++) pdc->setpixel(x+pdoc->imagewidth+30, y, RGB(pDoc->resultImg[y][3*x], pdoc->resultimg[y][3*x+1], pdoc->resultimg[y][3*x+2])); 8 프로그램을컴파일하고실행시킨다음에기하학적메뉴에서 [ 모핑 ] 부메뉴 를선택한다. 그러면그림 6-17 과같이첫번째입력영상을선택하라는메 시지상자가나타난다. 그림 6-17 파일을선택하라는메시지상자 [ 확인 ] 을클릭하면파일선택대화상자가나타나는데, "morph_src.pgm" 파일을선택한다. 그다음에는두번째파일을선택하라는메시지상자가나타난다. 두번째영상으로는 "morph_dest.pgm" 파일을선택한다. 파일을선택하면모핑이수행되고그결과가동영상으로나타난다. 그림 6-18에는모핑결과가출력되는장면중의하나가나타나있다. 201

실용영상처리 그림 6-18 모핑수행화면 202

영상워핑과모핑 CHAPTER 06 연습문제 01 영상워핑과영상모핑의개념을설명하시오. 02 영상워핑과영상모핑의실질적인사용예를조사하여요약하시오. 03 실습에서구현한영상워핑과영상모핑프로그램에서는다음그림과같이사람과침팬지사이에대응되는제어선을사용하였다. 주의할점은제어선의순서가맞아야하고제어선의시작점과끝점의순서도맞아야한다는것이다. 그림에서처음세개의제어선에대하여시작점은 's' 로끝점은 'e' 로표시하였다. 자신의얼굴사진을사용하여침팬지와워핑과모핑을수행해보시오. 사진은되도록얼굴이전체영역에다차도록하는것이좋다. 본인의사진을이용한워핑과모핑을수행하기위해서는먼저사진의크기를침팬지영상과동일한크기인 300 340으로변환한다음에포토샵이나페인트샵과같은프로그램을이용하여침팬지의제어선에대응되는제어선의위치를파악하여프로그램의좌표를수정하면된다. 영상의좌측상단의좌표가 (0,0) 이고우측하단의좌표가 (299,339) 이다. 04 사람과침팬지가아닌새로운두영상을선정하여영상워핑과모핑을수행하도록제어선을설정하고프로그램을수정하시오. 203