제 5 장 기하학적 처리.

Slides:



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

재료수치해석 HW # 박재혁.
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express Slide 1 (of 27)
컴퓨터프로그래밍 1주차실습자료 Visual Studio 2005 사용법 익히기.
제 1 장 영상처리 기초.
신호처리 실험 (Signal Processing Lab)
Excel 일차 강사 : 박영민.
제 6 장 영상 워핑과 모핑.
#include <stdio.h> int main(void) { float radius; // 원의 반지름
제 9 장 구조체와 공용체.
Report #2 - Solution 문제 #1: 다음과 같이 프로그램을 작성하라.
제 7 장 동영상 처리.
11장 구조체와 열거형 구조체의 정의 구조체 변수의 선언 구조체 초기화 및 사용 구조체 재정의 포인터를 이용해서 구조체 사용
윤성우의 열혈 C 프로그래밍 윤성우 저 열혈강의 C 프로그래밍 개정판 Chapter 12. 포인터의 이해.
5장. 참조 타입.
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
컴퓨터 프로그래밍 기초 #02 : printf(), scanf()
멀티미디어 시스템 (아날로그 이미지,신호를 디지털로 변환 방법) 이름 : 김대진 학번 :
03장 영상처리를 위한 Visual C++ 디지털 영상 파일 포맷
2주차: 변수, 수식, Control Flow.
학습목표 학습목차 다른 홈페이지의 HTML 파일 코드를 보는 방법에 대해 알아봅니다.
14장. 포인터와 함수에 대한 이해.
분할 윈도, 다중 뷰… 영상 통신 연구실 권 동 진 발표 일 : 04월 27일.
11장. 1차원 배열.
제 3 장 영역 기반 처리.
13. 연산자 오버로딩.
사용자 함수 사용하기 함수 함수 정의 프로그램에서 특정한 기능을 수행하도록 만든 하나의 단위 작업
프로그래밍 개요
어서와 C언어는 처음이지 제14장.
7가지 방법 PowerPoint에서 공동 작업하는 다른 사용자와 함께 편집 작업 중인 사용자 보기
3장 상수 변수 기본 자료형 키워드와 식별자 상수와 변수 기본 자료형 형변환 자료형의 재정의.
CHAP 5. 레이아웃.
Lab 1 Guide: 교재 2장 DrawX ( 쪽)
Term Projects 다음에 주어진 2개중에서 한 개를 선택하여 문제를 해결하시오. 기한: 중간 보고서: 5/30 (5)
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
연산자 (Operator).
SEOUL NATIONAL UNIVERSITY OF SCIENCE & TECHNOLOGY
포인터 1차원 배열과 포인터 2차원 배열과 포인터 문자열 배열과 포인터 포인터 배열
3D 프린팅 프로그래밍 01 – 기본 명령어 강사: 김영준 목원대학교 겸임교수.
컴퓨터 프로그래밍 기초 - 10th : 포인터 및 구조체 -
2장. 변수와 타입.
Clipping 이진학.
1차시: 낮과 밤이 생기는 원리 지구과학
8장. spss statistics 20의 데이터 변환
SEOUL NATIONAL UNIVERSITY OF SCIENCE & TECHNOLOGY
컴퓨터 프로그래밍 기초 - 8th : 함수와 변수 / 배열 -
8주차: Strings, Arrays and Pointers
Tween Animation 천승현.
CAD 실습 2013년 2학기.
객체기반 SW설계 팀활동지 4.
디버깅 관련 옵션 실습해보기 발표 : 2008년 5월 19일 2분반 정 훈 승
1. 기하학적 변환의 개요 기하학적 변환: 영상을 구성하는 화소의 공간적 위치를 재배치하는 과정,
Window, Viewport Window, Viewport.
2장 변형률 변형률: 물체의 변형을 설명하고 나타내는 물리량 응력: 물체내의 내력을 설명하고 나타냄
4장. 데이터 표현 방식의 이해. 4장. 데이터 표현 방식의 이해 4-1 컴퓨터의 데이터 표현 진법에 대한 이해 n 진수 표현 방식 : n개의 문자를 이용해서 데이터를 표현 그림 4-1.
DA :: 퀵 정렬 Quick Sort 퀵 정렬은 비교방식의 정렬 중 가장 빠른 정렬방법이다.
가장 많이 사용 Accelerator 최상위 WM_COMMAND, OLE 메시지 관련 이벤트 처리만 가능 이 클래스를 상속받아서 다른 이벤트 처리 이벤트 처리 관련 윈도우(창) 최상위 클래스 멀티 테스킹(모듈) CFrameWnd, Cview,
7주차: Functions and Arrays
1. 정투상법 정투상법 정투상도 (1) 정투상의 원리
상관계수.
제 4 장 Record.
제 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.
Docker Study 6~7.
Report #2 (기한: 3/16) 데이터 구조 과목의 수강생이 50명이라고 가정한다. 이 학생(학번은 2016????으로 표현됨)들의 중간 시험(0~100), 기말 시험(0~100) 성적을 성적 파일에 작성하라(프로그램을 통해서 또는 수작업으로). 성적 파일을 읽어들여서.
Prof. Kyungshik Lim Kyungpook National University
2019 2학기 9장 배열과 포인터 1. 주소, 주소연산자(&) 2. 포인터, 역참조연산자(*) 3. 배열과 포인터.
Presentation transcript:

제 5 장 기하학적 처리

학습목표 다음 기하학적 처리의 개념을 설명할 수 있고 프로그램을 작성할 수 있다 역방향 사상과 보간법에 대해 설명할 수 있다 확대 축소 회전 대칭 역방향 사상과 보간법에 대해 설명할 수 있다 2018-12-31

개 요 기하학적 처리란? 임의의 기하학적 변환에 의하여 화소들의 위치를 변경하는 처리 확대/축소 회전 이동 2018-12-31

확대(픽셀 복제 방법) 배율만큼 픽셀을 반복적으로 복사 확대 배율이 정수일 경우에 사용가능 100 110 120 130 100 110 120 130 <가로 세로 방향으로 두 배씩 확대> 2018-12-31

확대(픽셀 복제 방법) 픽셀 단위의 세밀한 편집에 활용 <원래 영상> <영상을 8배 확대하여 편집하는 화면> 2018-12-31

확대(픽셀 복제 방법) - 단점 확대된 영상에 계단 현상 발생 영상이 매끄럽지 못함 확대 배율이 실수인 경우 처리 어려움 2018-12-31

역방향 사상과 양선형 보간법 확대 결과 영상에서 계단 현상을 줄일 수 있음 확대 비율이 실수이어도 처리 가능 2018-12-31

역방향 사상 역방향 사상 역방향 사상 가로 세로 방향으로 2배씩 확대하는 경우의 역방향 사상 입력 영상 출력 영상 2018-12-31

보간법 (Interpolation) 역방향 사상의 결과가 정수가 아닐 수 있음 목적 영상 화소 (1,1)은 원시 영상의 (0.5, 0.5)로 사상됨  (0.5, 0.5)는 원시 영상에 존재하지 않음  (0,0), (0,1), (1,0), (1,1) 화소들을 보간함으로써 해결 2018-12-31

보간법 입력 영상의 화소 값 계산 방법 역방향 사상에 의해 계산된 점 주위의 네 개의 화소들의 값에 가중치를 곱하여 합함 원시 화소 E A B X축 보간 화소 최종 보간 화소 X 역방향 사상의 결과가 정수가 아니어서 입력 영상에서 픽셀값을 곧바로 구할 수 없을때에 픽셀값을 계산하는 방법을 살펴 보겠습니다. 역방향 사상에 의해 계산된 주소가 정수가 아닐 때의 상황을 그림으로 도식화하면 아래 그림과 같습니다. 그림에서 보라색 마름모꼴로 표시된 위치는 역방향 사상에 의해 계산된 위치를 나타냅니다. 역방향 사상의 값이 어떻게 되든지 그 주위에는 그림과 같이 청록색으로 표시되어 있는 4개의 픽셀이 위치하게 됩니다. 역방향 사상된 위치의 픽셀 값을 X라고 하고 주위의 4개의 픽셀 값을 A, B, C, D라 할때에 X값을 계산하는 식이 그림 오른쪽에 나타나 있습니다. 식에서 알파와 베타는 역방향 사상된 위치가 좌측 상단 픽셀로부터 얼마 만큼 떨어져 있는지의 비율을 나타내는 값으로써 0에서 1까지의 값을 가집니다. 식에서는 A, B 값과 알파 값을 이용하여 E 값과 F 값을 먼저 구하고 있습니다. E 값과 F 값은 좌측 픽셀로부터 떨어져있는 거리에 비례하여 값이 변하게 됩니다. 예를 들어 A의 값의 0이고 B위 값이 100일 경우에 알파가 0.5이면 E의 값은 50이되고 알파가 0.1이면 E의 값은 10이 되며 알파가 0.7이면 E의 값은 70이 됩니다. 즉 좌측 픽셀이 0이고 우측 픽셀이 100이므로 좌측에서 우측으로 이동할 수록 값이 커지는 것을 알 수 있습니다. E와 F값을 구한 다음에는 E와 F 그리고 베타 값을 이용하여 X값을 구합니다. 즉, 세로 방향으로 어느 위치에 있는지에 비례하여 X값이 결정됩니다. 예를 들어 E가 50이고 F가 100이고 베타가 0.5라면 X위 값은 50과 100의 중간 값인 75가 될 것입니다. 이상에서 살펴보았듯이 자로 방향으로 보간을 수행한 다음에 세로 방향으로 보간을 한번더 수행하므로 이를 양선형 보간법이라고 합니다 가로 방향과 세로 방향 각각은 값이 알파와 베타의 1차식에 따라 변화하므로 선형보간이라하고 가로 방향의 선형 보간을 수행 한 다음에 세로 방향의 선형 보간을 수행하므로 양선형 보간이라 하는 것입니다. C D F 2018-12-31 2018-12-31 10 10

보간법 적용 예 (1,1) 100 110 120 130 I(0.5, 0.5)의 주위 네 픽셀 : I(0,0)=100, I(0,1)=110, I(1,0)=120, I(1,1)=130 가로 방향 보간 : E(0, 0.5) = I(0,0)*0.5 + I(0,1)*0.5 = 100*0.5 +110*0.5 = 105 F(1, 0.5) = I(1,0)*0.5 + I(1,1)*0.5 = 120*0.5 +130*0.5 = 125 세로 방향 보간 : O(0.5, 0.5) = E(0, 0.5)*0.5 + F(1, 0.5)*0.5 = 105 * 0.5 + 125 * 0.5 = 115 2018-12-31 2018-12-31 11

축소(서브샘플링 방법 이용) 서브샘플링 축소 배율만큼 건너뛰면서 픽셀 값을 취하는 방법 예) x, y 방향으로 2배씩 축소 모든 짝수 행과 열의 화소를 출력 영상에 복사 문제점 영상의 상세한 세부 항목을 상실 해결책 서브샘플링 전에 영상을 흐리게 하여 어느 정도 해결 가능 2018-12-31

축소(서브샘플링 방법 이용) 서브샘플링에 의한 축소 2018-12-31

축소(서브샘플링 방법 이용) 서브샘플링에 의한 축소의 문제점 영상의 세밀한 정보를 잃어버릴 수 있음 2018-12-31

축소(서브샘플링 방법 이용) 영상을 흐리게 한 다음 서브샘플링 적용 2018-12-31

축소(평균값 필터링 방법 이용) 블록을 평균값으로 대치 평균값 입력 영상 출력 영상 13 4 8 2 9 6 7 25 16 10 2018-12-31

축소(평균값 필터링 방법 이용) 예) <출력 영상> <입력 영상> 2018-12-31

축소(평균값 필터링 방법 이용) 2018-12-31

회전 원점을 중심으로 점 (xsource,ysource)를 반시계 방향으로 θ만큼 회전한 점 (xdest, ydest) 2018-12-31

회전의 고려 사항 - 1 전방향 사상을 이용한 회전 <전방향 사상 이용> 출력 영상에서 픽셀 값을 할당 받지 못한 빈 곳이 발생 <전방향 사상 이용> 2018-12-31

회전의 고려 사항 - 1 역방향 사상을 이용하여 문제 해결 <시계방향으로 회전> 원점을 중심으로 점 (xdest, ydest) 를 시계 방향으로 θ만큼 회전한 점이 (xsource,ysource)가 됨 θ ( x source ,y ) dest , y <시계방향으로 회전> 2018-12-31

회전의 고려 사항 - 2 회전의 중심 앞에서 사용한 식은 원점을 기준으로 한 회전임 결과 영상에서 잘리는 부분이 많이 발생  영상의 중심점을 기준으로 한 회전으로 문제 해결 <입력 영상> <원점 기준 회전> <영상 중심점 기준 회전> 2018-12-31

회전의 고려 사항 - 2 영상의 중심점 (Cx, Cy)를 기준으로 하는 회전 2018-12-31

회전의 고려 사항 - 3 화면 좌표계와 수학적 좌표계 화면 좌표계 : 좌측 상단이 원점 수학적 좌표계 : 좌측 하단이 원점 두 좌표계의 차이로 인하여 영상이 반시계 방향으로 회전되지 않고 시계 방향으로 회전됨 화면 좌표를 수학적 좌표로 변환한 다음에 회전시키고 다시 화면 좌표로 변환함으로써 문제 해결 2018-12-31

회전의 고려 사항 - 3 좌표계 변환 후 회전 2018-12-31

회전의 고려 사항 - 3 좌표계 변환과 회전 결과 반시계 방향으로 30도 회전 입력 영상 좌표계 변환을 하지 않은 경우 한 경우 2018-12-31

회전의 고려사항 - 4 출력 영상의 크기 고려 입력 영상과 출력 영상의 크기를 같게 하면 출력 영상에서 잘려나가는 부분이 발생 출력 영상의 크기를 미리 계산하여 역방향 사상을 적용해야 함 출력 영상의 크기 회전 각도에 따라 달라짐 2018-12-31

회전의 고려 사항 - 4 출력 영상의 크기 계산 방법 W H’ H a b c W’ W’ H’ W’ H’ W : 입력 영상의 너비 y H : 입력 영상의 높이 W’ : 출력 영상의 너비 H’ : 출력 영상의 높이 W 90 - θ W cos (90 - θ ) H’ H a b θ H cos θ θ 90 - θ c x H cos (90 - θ ) W cos θ W’ 2018-12-31 W’ = H cos (90 - θ ) + W cos θ H’ = H cos θ + W cos (90 – θ )

회전의 고려 사항 - 4 출력 영상의 크기를 고려한 회전 입력 영상 출력 영상 2018-12-31

대칭 입력 영상 좌우 대칭 상하 대칭 2018-12-31

대칭 변환의 구현 (흑백 영상) 좌우 대칭 상하 대칭 for (y = 0; y < imageHeight; y++) for (x = 0; x < imageWidth; x++) resultImg[y][x] = inputImg[y][imageWidth - 1 - x]; for (y = 0; y < imageHeight; y++) for (x = 0; x < imageWidth; x++) resultImg[imageHeight - 1 - y][x] = inputImg[y][x]; 2018-12-31

실습

픽셀 복제 방법을 이용한 확대 메뉴막대에 [기하학적처리] 메뉴 추가 부메뉴 추가 메뉴 이름 : 기하학적 처리 이름 : 확대(픽셀 복제) ID : ID_GEOMETRY_ZOOMIN_PIXEL_COPY 2018-12-31

픽셀 복제 방법을 이용한 확대 CImageProView 클래스에 OnGeometryZoominPixelCopy() 함수를 추가하고 다음과 같이 편집 void CImageProView::OnGeometryZoominPixelCopy() { CImageProDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (pDoc->inputImg == NULL) return; pDoc->GeometryZoominPixelCopy(); viewMode = TWO_IMAGES_SCALED; Invalidate(FALSE); } 2018-12-31

픽셀 복제 방법을 이용한 확대 ImageProView.cpp 파일의 앞부분에 상수 정의 추가 // 추가한 후 #define TWO_IMAGES 1 #define THREE_IMAGES 2 #define TWO_IMAGES_SCALED 4 2018-12-31

픽셀 복제 방법을 이용한 확대 CImageProDoc 클래스에 GeometryZoominPixelCopy() 함수 추가하고 편집 void CImageProDoc::GeometryZoominPixelCopy() { int i, y, x; gImageWidth = imageWidth * 3; gImageHeight = imageHeight * 3; gResultImg = (unsigned char **) malloc(gImageHeight * sizeof(unsigned char *)); for (i = 0; i < gImageHeight; i++) { gResultImg[i] = (unsigned char *) malloc(gImageWidth * depth); } for (y = 0; y < gImageHeight; y++) for (x = 0; x < gImageWidth; x++) gResultImg[y][x] = inputImg[y/3][x/3]; 2018-12-31

픽셀 복제 방법을 이용한 확대 확대 결과 영상 저장을 위한 변수 선언 // 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; // 크기가 변한 결과 영상에 대한 포인터 변수 2018-12-31

픽셀 복제 방법을 이용한 확대 gResultImg 변수값 초기화 CImageProDoc::CImageProDoc() { // TODO: add one-time construction code here inputImg = NULL; inputImg2 = NULL; resultImg = NULL; gResultImg = NULL; // 추가되는 코드 } 2018-12-31

픽셀 복제 방법을 이용한 확대 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])); 2018-12-31

픽셀 복제 방법을 이용한 확대 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])); } 2018-12-31

픽셀 복제 방법을 이용한 확대 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 { for(int y=0; y< pDoc->imageHeight; y++) // 결과 영상 출력 for(int x=0; x< pDoc->imageWidth; x++) RGB(pDoc->resultImg[y][x], pDoc->resultImg[y][x], pDoc->resultImg[y][x])); 2018-12-31

픽셀 복제 방법을 이용한 확대 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])); 2018-12-31

픽셀 복제 방법을 이용한 확대 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 { pDC->SetPixel(x+pDoc->imageWidth+30, y, 2018-12-31

컴파일 및 실행 프로그램을 컴파일하고 실행시킨 다음에 “Lenna-64x64.pgm" 파일을 열어서 [확대 (픽셀 복제)] 연산을 적용 2018-12-31 2018-12-31 44

양선형 보간법을 이용한 확대 [기하학적처리] 메뉴에 부메뉴 추가 이름 : 확대 (양선형보간법) ID : ID_GEOMETRY_ZOOMIN_INTERPOLATION 2018-12-31

양선형 보간법을 이용한 확대 CImageProView 클래스에 OnGeometryZoominInterpolation() 함수 추가 void CImageProView::OnGeometryZoominInterpolation() { CImageProDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (pDoc->inputImg == NULL) return; pDoc->GeometryZoominInterpolation(); viewMode = TWO_IMAGES_SCALED; Invalidate(FALSE); } 2018-12-31

양선형 보간법을 이용한 확대 CImageProDoc 클래스에 GeometryZoominInterpolation() 함수 추가 void CImageProDoc::GeometryZoominInterpolation() { int i, y, x; float src_x, src_y; // 원시 화소 위치 float alpha, beta; int scale_x, scale_y; // x 방향과 y 방향으로의 확대 비율 int E, F; // x 방향으로 보간된 결과 값 int Ax, Ay, Bx, By, Cx, Cy, Dx, Dy; // 보간에 사용될 4개 픽셀의 좌표 scale_x = 3; scale_y = 3; 2018-12-31

양선형 보간법을 이용한 확대 // 결과 영상의 크기 설정 gImageWidth = imageWidth * scale_x; gImageHeight = imageHeight * scale_y; // 결과 영상을 저장할 기억장소 공간 할당 gResultImg = (unsigned char **) malloc(gImageHeight * sizeof(unsigned char *)); for (i = 0; i < gImageHeight; i++) { gResultImg[i] = (unsigned char *) malloc(gImageWidth * depth); } 2018-12-31

양선형 보간법을 이용한 확대 for (y = 0; y < gImageHeight; y++) for (x = 0; x < gImageWidth; x++) { // 원시 영상에서의 픽셀 좌표 계산 src_x = x / (float) scale_x; src_y = y / (float) scale_y; alpha = src_x - x / scale_x; beta = src_y - y / scale_y; // 보간에 사용된 4 픽셀의 좌표 계산 Ax = x / scale_x; Ay = y / scale_y; Bx = Ax + 1; By = Ay; Cx = Ax; Cy = Ay + 1; Dx = Ax + 1; Dy = Ay + 1; 2018-12-31

양선형 보간법을 이용한 확대 // 픽셀 위치가 영상의 경계를 벗어나는지 검사 if (Bx > imageWidth - 1) Bx = imageWidth - 1; if (Dx > imageWidth - 1) Dx = imageWidth - 1; if (Cy > imageHeight - 1) Cy = imageHeight - 1; if (Dy > imageHeight - 1) Dy = imageHeight - 1; // x 방향으로 보간 E = (int) (inputImg[Ay][Ax] * (1-alpha) + inputImg[By][Bx] * alpha); F = (int) (inputImg[Cy][Cx] * (1-alpha) + inputImg[Dy][Dx] * alpha); // y 방향으로 보간 gResultImg[y][x] = (unsigned char) (E * (1-beta) + F * beta); } 2018-12-31

컴파일 및 실행 프로그램을 컴파일하고 실행시킨 다음에 “Lenna-64x64.pgm" 파일을 열어서 [확대 (양선형보간법)] 연산을 적용 2018-12-31 2018-12-31 51

서브샘플링을 이용한 축소 [기하학적처리] 메뉴에 부메뉴 추가 이름 : 축소 (서브샘플링) ID : ID_GEOMETRY_ZOOMOUT_SUBSAMPLING 2018-12-31

서브샘플링을 이용한 축소 CImageProView 클래스에 OnGeometryZoomoutSubsampling() 함수 추가 void CImageProView::OnGeometryZoomoutSubsampling() { CImageProDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (pDoc->inputImg == NULL) return; pDoc->GeometryZoomoutSubsampling(); viewMode = TWO_IMAGES_SCALED; Invalidate(FALSE); } 2018-12-31

서브샘플링을 이용한 축소 CImageProDoc 클래스에 GeometryZoomoutSubsampling() 함수 추가 void CImageProDoc::GeometryZoomoutSubsampling() { int i, y, x; int src_x, src_y; int scale_x = 3, scale_y = 3; // 결과 영상의 크기 계산 gImageWidth = imageWidth / scale_x; gImageHeight = imageHeight / scale_y; // 결과 영상 저장을 위한 기억장소 할당 gResultImg = (unsigned char **) malloc(gImageHeight * sizeof(unsigned char *)); for (i = 0; i < gImageHeight; i++) { gResultImg[i] = (unsigned char *) malloc(gImageWidth * depth); } 2018-12-31

서브샘플링을 이용한 축소 for (y = 0; y < gImageHeight; y++) for (x = 0; x < gImageWidth; x++) { src_y = y*scale_y; src_x = x*scale_x; if (src_x > imageWidth - 1) src_x = imageWidth - 1; if (src_y > imageHeight - 1) src_y = imageHeight - 1; gResultImg[y][x] = inputImg[src_y][src_x]; } 2018-12-31

서브샘플링을 이용한 축소 프로그램을 컴파일하고 실행 “lines.pgm" 파일은 다음 [축소(서브샘플링)] 연산 적용 2018-12-31

평균값 필터링을 이용한 축소 [기하학적 처리] 메뉴에 항목 추가 이름 : 축소 (평균값필터링) ID : ID_GEOMETRY_ZOOMOUT_AVG 2018-12-31

평균값 필터링을 이용한 축소 CImageProView 클래스에 OnGeometryZoomoutAvg() 함수 추가 void CImageProView::OnGeometryZoomoutAvg() { CImageProDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (pDoc->inputImg == NULL) return; pDoc->GeometryZoomoutAvg(); viewMode = TWO_IMAGES_SCALED; Invalidate(FALSE); } 2018-12-31

평균값 필터링을 이용한 축소 CImageProDoc 클래스에 GeometryZoomoutAvg() 함수 추가 void CImageProDoc::GeometryZoomoutAvg() { int i, j, x, y; int sum; int src_x, src_y; int scale_x = 3, scale_y = 3; // 결과 영상의 크기 계산 gImageWidth = imageWidth / scale_x + 1; gImageHeight = imageHeight / scale_y + 1; // 결과 영상을 저장할 기억장소 할당 gResultImg = (unsigned char **) malloc(gImageHeight * sizeof(unsigned char *)); for (i = 0; i < gImageHeight; i++) { gResultImg[i] = (unsigned char *) malloc(gImageWidth * depth); } 2018-12-31

평균값 필터링을 이용한 축소 for (y=0; y < imageHeight; y = y + scale_y) for (x=0; x < imageWidth; x = x + scale_x) { // 필터 윈도우 내의 픽셀값 합계 계산 sum=0; for (i=0; i<scale_y; i++) for (j=0; j<scale_x; j++) { src_x = x + j; src_y = y + i; if (src_x > imageWidth - 1) src_x = imageWidth - 1; // 영상의 경계 검사 if (src_y > imageHeight - 1) src_y = imageHeight - 1; sum += inputImg[src_y][src_x]; } sum = sum / (scale_x * scale_y); // 평균값 계산 if (sum > 255) sum=255; if (sum < 0) sum = 0; gResultImg[y/scale_y][x/scale_x] = (unsigned char) sum; // 결과 값 저장 2018-12-31

평균값 필터링을 이용한 축소 프로그램을 컴파일하고 실행 “lines.pgm" 파일은 다음 [축소(평균값필터링)] 연산 적용 2018-12-31

회전 [기하학적 처리] 메뉴에 회전 연산을 위한 부메뉴 추가 이름 : 회전 ID : ID_GEOMETRY_ROTATE 2018-12-31

회전 CImageProView 클래스에 OnGeometryRotate() 함수 추가 void CImageProView::OnGeometryRotate() { CImageProDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (pDoc->inputImg == NULL) return; pDoc->GeometryRotate(); viewMode = TWO_IMAGES_SCALED; Invalidate(FALSE); } 2018-12-31

회전 CImageProDoc 클래스에 GeometryRotate() 함수 추가 #define PI 3.14159 void CImageProDoc::GeometryRotate() { int y, x, x_source, y_source, Cx, Cy; float angle; int Oy; int i, xdiff, ydiff; Oy = imageHeight - 1; angle = PI / 180.0 * 30.0; // 30도를 라디안 값의 각도로 변환 Cx = imageWidth / 2; // 회전 중심의 x좌표 Cy = imageHeight / 2; // 회전 중심의 y좌표 2018-12-31

회전 // 결과 영상 크기 계산 gImageWidth =(int)(imageHeight * cos(PI / 2.0 - angle) + imageWidth * cos(angle)); gImageHeight =(int)(imageHeight * cos(angle) + imageWidth * cos(PI / 2.0 - angle)); // 결과 영상을 저장할 기억장소 할당 gResultImg = (unsigned char **) malloc(gImageHeight * sizeof(unsigned char *)); for (i = 0; i < gImageHeight; i++) { gResultImg[i] = (unsigned char *) malloc(gImageWidth * depth); } // 결과 영상의 x 좌표 범위 : -xdiff ~ gImageWidth - xdiff - 1 // 결과 영상의 y 좌표 범위 : -ydiff ~ gImageHeight - ydiff - 1 xdiff = (gImageWidth - imageWidth) / 2; ydiff = (gImageHeight - imageHeight) / 2; 2018-12-31

회전 for (y = -ydiff; y < gImageHeight - ydiff; y++) for (x = -xdiff; x < gImageWidth - xdiff; x++) { // 변환 단계 // 1 단계 : 원점이 영상의 좌측 하단에 오도록 y 좌표 변환 // 2 단계 : 회전 중심이 원점에 오도록 이동 // 3 단계 : 각도 angle 만큼 회전 // 4 단계 : 회전 중심이 원래 위치로 돌아가도록 이동 x_source =(int) (((Oy - y) - Cy) * sin(angle) + (x - Cx) * cos(angle) + Cx); y_source =(int) (((Oy - y) - Cy) * cos(angle) - (x - Cx) * sin(angle) + Cy); // 5 단계 : 원점이 영상의 좌측 상단에 오도록 y 좌표 변환 y_source = Oy - y_source; if (x_source < 0 || x_source > imageWidth - 1 || y_source < 0 || y_source > imageHeight - 1) gResultImg[y+ydiff][x+xdiff] = 255; else gResultImg[y+ydiff][x+xdiff] = inputImg[y_source][x_source]; } 2018-12-31

회전 프로그램을 컴파일하고 실행 “화성탐사선.pgm" 파일을 열고 [회전] 연산 적용 2018-12-31