제 6 장 영상 워핑과 모핑.

Slides:



Advertisements
Similar presentations
1. 2 차원 배열  배열은 동일한 데이터 유형으로 여러 개의 변수를 사용할 경우 같은 이 름으로 지정하여 간편하게 사용할 수 있도록 하는 것으로서 앞에서 1 차원 배열을 공부하였습니다.  2 차원 배열은 바둑판을 생각하면 되며, 1 차원 배열에서 사용하는 첨자를 2.
Advertisements

03장 영상처리를 위한 Visual C++ 디지털 영상 파일 포맷 MFC 응용 프로그램 마법사를 이용한 MFC 프로젝트 작성
어서와 Java는 처음이지! 제20장 실전프로젝트 #2.
ㅎㅎ 구조체 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스 구조체 배열.
ㅎㅎ 구조체 C++ 프로그래밍 기초 : 객체지향의 시작 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express Slide 1 (of 27)
제 1 장 영상처리 기초.
Report #5 - due: 4/13 다음 10*5의 희소 행렬 A, B를 고려하라.
신호처리 실험 (Signal Processing Lab)
9장. C 언어의 핵심! 함수. 9장. C 언어의 핵심! 함수 9-1 함수의 정의와 선언 main 함수 다시 보기 : 함수의 기본 형태 { } 그림 9-1.
컴퓨터 프로그래밍 실습 #7 제 4 장 GUI 클래스 작성.
5.2 애니메이션 Page 283 ~ 295.
#include <stdio.h> int main(void) { float radius; // 원의 반지름
제 9 장 구조체와 공용체.
제 7 장 동영상 처리.
11장 구조체와 열거형 구조체의 정의 구조체 변수의 선언 구조체 초기화 및 사용 구조체 재정의 포인터를 이용해서 구조체 사용
자료 구조: Chapter 3 (2)구조체, 포인터
개정판 누구나 즐기는 C언어 콘서트 제9장 포인터 출처: pixabay.
제 9 장 영상압축.
Lesson 5. 레퍼런스 데이터형.
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
SqlParameter 클래스 선문 비트 18기 발표자 : 박성한.
컴퓨터 프로그래밍 기초 #02 : printf(), scanf()
제 5 장 기하학적 처리.
임베디드 실습 # LED, 7’Segment 제어
03장 영상처리를 위한 Visual C++ 디지털 영상 파일 포맷
프로그래밍 랩 – 7주 리스트.
컴퓨터 프로그래밍 실습 #6 제 4 장 클래스 작성.
14장. 포인터와 함수에 대한 이해.
분할 윈도, 다중 뷰… 영상 통신 연구실 권 동 진 발표 일 : 04월 27일.
11장. 1차원 배열.
C#.
제 3 장 영역 기반 처리.
13. 연산자 오버로딩.
사용자 함수 사용하기 함수 함수 정의 프로그램에서 특정한 기능을 수행하도록 만든 하나의 단위 작업
프로그래밍 개요
어서와 C언어는 처음이지 제14장.
3장 상수 변수 기본 자료형 키워드와 식별자 상수와 변수 기본 자료형 형변환 자료형의 재정의.
영상처리 실습 인공지능연구실.
쉽게 풀어쓴 C언어 Express 제14장 포인터 활용 C Express Slide 1 (of 22)
Lab 1 Guide: 교재 2장 DrawX ( 쪽)
지도교수 : 이광세 교수 발표자 : 권혁민 신광호
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
포인터 1차원 배열과 포인터 2차원 배열과 포인터 문자열 배열과 포인터 포인터 배열
컴퓨터 프로그래밍 기초 - 10th : 포인터 및 구조체 -
2장. 변수와 타입.
자바 5.0 프로그래밍.
컴퓨터 프로그래밍 기초 - 8th : 함수와 변수 / 배열 -
컴퓨터 계측 및 실습 디지털 출력 영남대학교 기계공학부.
CHAP 21. 전화, SMS, 주소록.
12. 상속 : 고급.
알고리즘 알고리즘이란 무엇인가?.
Chapter 1 단위, 물리량, 벡터.
영상처리 실습 (OpenCV + MFC) Chonbuk National University A.I. Lab.
원의 방정식 원의 방정식 x축, y축에 접하는 원의 방정식 두 원의 위치 관계 공통접선 원과 직선의 위치 관계
Chapter 1 단위, 물리량, 벡터.
1. 접선의 방정식 2010년 설악산.
제 8장. 클래스의 활용 학기 프로그래밍언어및실습 (C++).
컴퓨터 프로그래밍 기초 - 9th : 배열 / 포인터 -
구조체(struct)와 공용체(union)
상관계수.
컴퓨터공학과 손민정 Computer Graphics Lab 이승용 교수님
실습과제 (변수와 자료형, ) 1. 다음 작업 (가), (나), (다)를 수행하는 프로그램 작성
RPTree 코드분석 (월) Dblab 김태훈.
제 29 강 스트링(string) 다루기 s a i s . s T i h t g r i n.
29장. 템플릿과 STL 01_ 템플릿 02_ STL.
어서와 C언어는 처음이지 제21장.
영역 기반 처리.
개정판 누구나 즐기는 C언어 콘서트 제13장 동적 메모리 출처: pixabay.
2019 2학기 9장 배열과 포인터 1. 주소, 주소연산자(&) 2. 포인터, 역참조연산자(*) 3. 배열과 포인터.
Presentation transcript:

제 6 장 영상 워핑과 모핑

학습목표 다음 기하학적 처리의 개념을 설명할 수 있고 프로그램을 작성할 수 있다 영상 워핑 영상 모핑 2018-11-11 영상처리

영상 워핑(Warping) 픽셀의 위치를 이동하는 기하학적 처리 회전, 이동, 확대/축소등의 기하학적 처리와의 차이점 픽셀 별로 이동 정도가 다름 고무종이 위에 그려진 영상을 임의로 구부리는 효과를 낼 수 있음 2018-11-11 영상처리

영상 워핑(Warping) 사용 예 인공 위성이나 우주선에서 보내온 일그러진 영상을 복원하는데 처음 사용 TV나 영화에서 물체, 동물, 배우의 모습을 변형하는 데 사용 미아의 성장 모습을 생성 2018-11-11 영상처리

영상 워핑 2018-11-11 영상처리

영상 워핑 입력 영상과 출력 영상의 대응관계 기술 제어선, 제어점, 그물망, 다각형 등 다양한 방법이 있음 <제어점> <제어선> 2018-11-11 영상처리

제어선을 이용한 워핑 출력 영상의 픽셀 V에 대응되는 입력 영상의 픽셀 V’을 찾아서 픽셀값 복사 수직 교차점이 제어선 내부에 존재 V’ 변위 P’ Q’ 위치 V P Q 출력 영상 입력 영상 C’ C 2018-11-11 영상처리

제어선을 이용한 워핑 수직 교차점이 제어선 외부에 존재 Q’ Q P’ P V’ C’ V C 입력 영상 출력 영상 위치 변위 2018-11-11 영상처리

제어선을 이용한 워핑 제어선이 여러 개인 경우 각 제어선에 대한 가중치 고려 제어선은 영상 내의 모든 화소들에 영향을 미침 p 가중치 = (a+픽셀과 제어선의 거리) 제어선의 길이 p b p : 선의 길이에 대한 가중치 (0  p  1) a : 0으로 나누는 것을 방지 b : 거리의 증가에 대한 가중치의 감소율 (0.5  b  2.0) 2018-11-11 영상처리

제어선을 이용한 영상 워핑 알고리즘 warping() { 출력 영상의 각 픽셀 V(x,y) 에 대하여 tx = 0 // 방향 변위의 합을 나타내는 변수를 초기화한다 ty = 0 // 방향 변위의 합을 나타내는 변수를 초기화한다 totalWeight = 0 // 가중치의 합을 나타내는 변수를 초기화한다 각 제어선 Li 에 대하여 V와 Li 의 수직교차점의 위치 u 를 계산한다. V와 Li 의 수직 변위 h 를 계산한다 u 와 h 를 이용하여 입력 영상에서의 대응 위치 V’(x’, y’)을 구한다. V와 Li 사이의 거리를 d 를 계산한다. weight = ((제어선의 길이p)/(a+d))b tx = tx + (x’-x) * weight ty = ty + (y’-y) * weight totalWeight = totalWeight + weight } X = x + tx / totalWeight Y = y + ty / totalWeight 입력 영상의 V’(X,Y) 픽셀의 값을 출력 영상의 V(x,y)픽셀에 복사한다. 2018-11-11 영상처리

제어선을 이용한 워핑 수직 교차점의 위치 계산 2018-11-11 영상처리

제어선을 이용한 워핑 수직 교차점의 위치 계산 u < 0 : P 바깥에 위치 u > 1 : Q 외부에 위치 2018-11-11 영상처리

(a) h > 0인 경우 (b) h < 0인 경우 제어선을 이용한 워핑 제어선으로부터의 변위 계산 픽셀을 지나면서 제어선과 수직으로 교차하는 점과 픽셀 사이의 변위 변위(h)의 값 변위 < 0 : 픽셀이 제어선 아래쪽에 있음 변위 = 0 : 픽셀이 제어선에 있음 변위 > 0 : 픽셀이 제어선 위쪽에 있음 (a) h > 0인 경우 (b) h < 0인 경우 2018-11-11 영상처리

제어선을 이용한 워핑 제어선으로부터의 변위 계산 2018-11-11 영상처리

제어선을 이용한 워핑 입력 영상에서 대응 픽셀 위치 계산 : 제어선 Li의 양 끝점 좌표 2018-11-11 영상처리

제어선을 이용한 워핑 픽셀과 제어선의 거리 계산 Q Q V P Q V P P V (b) 수직 교차점이 제어선 외부에 있는 경우 d Q d d V P P V 수직 교차점이 제어선 내부에 있는 경우 (b) 수직 교차점이 제어선 외부에 있는 경우 2018-11-11 영상처리

제어선을 이용한 워핑 픽셀과 제어선 사이의 거리 계산 P Q V d 2018-11-11 영상처리

제어선을 이용한 워핑 제어선의 가중치 계산 2018-11-11 영상처리

제어선을 이용한 워핑 입력 영상 대응 픽셀의 변위 누적 2018-11-11 영상처리

제어선을 이용한 워핑 입력 영상의 대응 픽셀 위치 계산 2018-11-11 영상처리

모핑(Morphing) 두 개의 서로 다른 입력 영상에 대하여 한 영상을 다른 영상으로 변환 2018-11-11 영상처리

모핑의 단계 모핑은 워핑과 합병의 두 단계로 구성 2018-11-11 영상처리

두 영상 사이의 대응 관계 기술 모핑을 위해서는 두 영상 사이의 대응 위치를 기술해야 함 2018-11-11 영상처리

워핑 중간 프레임에 대한 제어선 생성 두 입력 영상의 제어선으로부터 보간법을 사용하여 생성 2018-11-11 영상처리

워핑 K번째 중간 프레임에 대한 제어선 계산 식 N : 전체 프레임 수 2018-11-11 영상처리

합병 영상 합병 I1(x,y) : 입력 영상 1로부터 복사되는 픽셀 값 I2(x,y) : 입력 영상 2로부터 복사되는 픽셀 값 2018-11-11 영상처리

실습

워핑 기하학적 처리 메뉴에 워핑 연산 부메뉴 추가 이름 : 워핑 ID : ID_GEOMETRY_WARPING

워핑 CImageProView 클래스에 OnGeometryWarping() 함수를 추가하고 편집한다. void CImageProView::OnGeometryWarping() { CImageProDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (pDoc->inputImg == NULL) return; pDoc->GeometryWarping(); viewMode = TWO_IMAGES; Invalidate(FALSE); }

워핑 CImageProDoc 클래스에 GeometryWarping() 함수를 추가 반환 형식: void

워핑 typedef struct { int Px; int Py; int Qx; int Qy; } control_line; #include <math.h> void CImageProDoc::GeometryWarping() control_line source_lines[23] = {{116,7,207,5},{34,109,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,106,123,109},{187,115,235,114},{72,142,99,128},{74,150,122,154}, {108,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},{109,258,143,277},{152,278,190,262}};

워핑 control_line dest_lines[23] = {{120,8,200,6},{12,93,96,16},{74,271,16,110},{126,336,96,290}, {142,337,181,335},{192,335,232,280},{244,259,288,108},{285,92,212,13}, {96,135,136,118},{194,119,223,125},{105,145,124,134},{110,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; 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));

워핑 // 입력 영상에서의 대응 픽셀 위치 계산 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]; }

워핑 Warp.pgm 파일을 열어서 워핑을 적용

모핑 기하학적 처리 메뉴에 모핑 부메뉴 추가 Caption : 모핑 ID : ID_GEOMETRY_MORPHING

모핑 CImageProView 클래스에 OnGeometryMorphing() 함수 추가 void CImageProView::OnGeometryMorphing() { CImageProDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDoc->GeometryMorphing(); viewMode = MORPHING; Invalidate(FALSE); }

모핑 CImageProView.cpp 파일의 위부분에 MORPHING 상수에 대한 정의를 추가 -- 추가하기전 #define TWO_IMAGES 1 #define THREE_IMAGES 2 #define TWO_IMAGES_SCALED 4 -- 추가한 다음 #define MORPHING 8

모핑 CImageProDoc 클래스의 정의에 모핑 과정에서 생성되는 중간 프레임을 저장하기 위한 변수 morphedImg를 선언 // Attributes public: unsigned char **inputImg; // 입력 영상의 기억 장소에 대한 포인터 변수 unsigned char **inputImg2; // 입력 영상의 기억 장소에 대한 포인터 변수 unsigned char **resultImg; // 출력 영상의 기억 장소에 대한 포인터 변수 int imageWidth; // 영상의 가로 크기 int imageHeight; // 영상의 세로 크기 int depth; // 1 = 흑백 영상, 3 = 컬러 영상 int gImageWidth; // 크기가 변한 결과 영상의 가로 크기 int gImageHeight; // 크기가 변한 결과 영상의 세로 크기 unsigned char **gResultImg; // 크기가 변한 결과 영상에 대한 포인터 변수 // 모핑 결과 저장을 위해 새로이 추가되는 코드 unsigned char **morphedImg[10];

모핑 CImageProDoc 클래스에 GeometryMorphing() 함수를 추가 반환 형식: void

모핑 #define NUM_FRAMES 10 void CImageProDoc::GeometryMorphing() { control_line source_lines[23] = {{116,7,207,5},{34,109,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,106,123,109},{187,115,235,114},{72,142,99,128},{74,150,122,154}, {108,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},{109,258,143,277},{152,278,190,262}}; control_line dest_lines[23] = {{120,8,200,6},{12,93,96,16},{74,271,16,110},{126,336,96,290}, {142,337,181,335},{192,335,232,280},{244,259,288,108},{285,92,212,13}, {96,135,136,118},{194,119,223,125},{105,145,124,134},{110,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, b=2.0, p=0.75; unsigned char **warpedImg; unsigned char **warpedImg2; int frame; double fweight; control_line warp_lines[23]; double tx2, ty2, xp2, yp2; int dest_x1, dest_y1, dest_x2, dest_y2, source_x2, source_y2; int x1, x2, y1, y2, src_x1, src_y1, src_x2, src_y2; double src_line_length, dest_line_length; int i, j; int num_lines = 23; // 제어선의 수 int line, x, y, source_x, source_y, 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 *)); warpedImg2[i] = (unsigned char *) malloc(imageWidth * depth);

모핑 for (i = 0; i < NUM_FRAMES; i++) { morphedImg[i]=(unsigned char **) malloc(imageHeight*sizeof(unsigned char *)); 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 = (int) (source_lines[line].Px + (dest_lines[line].Px - source_lines[line].Px)*fweight); warp_lines[line].Py =(int) (source_lines[line].Py + (dest_lines[line].Py - source_lines[line].Py)*fweight); warp_lines[line].Qx = (int) (source_lines[line].Qx + (dest_lines[line].Qx - source_lines[line].Qx)*fweight); warp_lines[line].Qy = (int) (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; // 각 제어선에 대하여 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) + 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; if (source_y2 < 0) source_y2 = 0; if (source_y2 > last_row) source_y2 = last_row;

모핑 // 워핑 결과 저장 warpedImg[y][x] = inputImg[source_y][source_x]; } // 모핑 결과 합병 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;

모핑 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]));

모핑 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++) // 결과 영상 출력 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 < 10; i++) for(int y=0; y< pDoc->imageHeight; y++) // 모핑 결과 출력 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 { 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++) // 결과 영상 출력 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 { for(int y=0; y< pDoc->imageHeight; y++) // 결과 영상 출력 for(int x=0; x< pDoc->imageWidth; x++) RGB(pDoc->resultImg[y][3*x], pDoc->resultImg[y][3*x+1], pDoc->resultImg[y][3*x+2]));

모핑 프로그램을 컴파일하고 모핑 실행 두 입력 영상 선택 첫번째 : "morph_src.pgm“, 두번째 : “morph_dest.pgm"