500 likes | 862 Views
Chapter 9 영상신호처리. 학습목표. 이번 장에서 다루게 되는 내용은 다음과 같습니다. 이번 장의 학습 목표. 영상신호처리의 개요 공간영역 해석 주파수 영역 해석. 영상신호처리의 개요. 영상 함수 f(x,y) : 공간좌표 (x,y) 에서 f 의 값은 그 점에서 영상의 밝기 혹은 빛의 세기를 의미 좌표계의 원점이 영상의 왼쪽 위에 있고 , 수평 방향으로 x 축 , 수직 아래 방향으로 y 축인 좌표계를 쓰는 함수 f(x,y). 영상신호처리의 개요.
E N D
Chapter 9 영상신호처리
학습목표 이번 장에서 다루게 되는 내용은 다음과 같습니다. 이번 장의 학습 목표 영상신호처리의 개요 공간영역 해석 주파수 영역 해석
영상신호처리의 개요 • 영상 함수 f(x,y) : 공간좌표 (x,y)에서 f의 값은 그 점에서 영상의 밝기 혹은 빛의 세기를 의미 • 좌표계의 원점이 영상의 왼쪽 위에 있고, 수평 방향으로 x축, 수직 아래 방향으로 y축인 좌표계를 쓰는 함수 f(x,y)
영상신호처리의 개요 • 영상 함수 f(x,y)는 표본화와 양자화 과정을 거쳐 수치 데이터, 또는 디지털 영상으로 바꾸어지며, 이 과정에 사용되는 장치가 아날로그 디지털 변환기(ADC)이며, 특히 디지털 영상으로 바꾸는데 사용하는 ADC를 프레임 그래버(frame grabber)라 함.
영상신호처리의 개요 • 디지털 영상신호처리 : 영상을 카메라나 스캐너 등을 통하여 디지털화 한 후, 여러 가지 목적에 따라 컴퓨터와 여러가지 알고리즘을 적용하여 처리하는 것 • 영상처리 분야 • 영상조작 • 획득 또는 전송된 영상데이터가 흐린 경우, 왜곡된 경우 등 수많은 상황에서 원하는 영상을 얻기 위해 조작을 하는 것. • 영상분석 • 영상조작에 의해 보정된 영상 내부의 특징을 찾아내는 것 • 영상인식 • 영상물을 비교하여 다른 영상과 비교, 분석하며 특징을 찾아 영상을 인식할 수 있도록 하는 분야 • 영상 통신 등 • 영상을 전송함에 있어서 어떻게 효율적으로 전송할 것인가를 연구하는 분야
공간영역 해석 • 일반적으로 영상의 공간영역 해석은 컨볼루션 연산을 통해 수행됨 • 출력 화소의 값은 이웃 화소들의 가중치의 합으로 계산, 가중치 행렬은 2차원 임펄스 응답으로 생각할 수 있음. • 가중치 행렬=“마스크”라는 용어를 사용
공간영역 해석 • 마스크는 영상 안에서 일정 부분에 위치시키기 위한 일종의 행렬 모양의 구조체 • 주로 3x3, 5x5, 16x16 등과 같은 정방 행렬을 많이 사용.
마스크를 이용한 연산 방법 • 마스크를 이용한 컨볼루션은 원 영상에 마스크를 겹쳐서 왼쪽부터 오른쪽으로 위에서 아래 방향으로 진행하면서 계산된 값을 (0,0) 자리에 다시 할당함으로서 출력 영상을 얻음.
마스크를 이용한 연산 방법 • 연산방법 • 컨볼루션 마스크의 각 원소의 합은 결과 영상, 혹은 출력 영상의 전체 밝기에 영향을 미치기 때문에 많은 컨볼루션 마스크의 원소의 합을 1이 되도록 가중치를 정하고 있다. 이 경우 출력 영상은 입력 영상과 같은 평균 밝기를 갖게 됨. • 윤곽선 검출에 사용되는 컨볼루션 마스크는 음의 계수를 포함하며, 모든 원소의 합이 0이 되는 경우가 있음. 이 경우 음의 출력 화소값이 나올 수 있다. 보통 상수값을 출력 화소값에 더하고, 더해도 음이 되는 경우에는 출력 화소값을 0으로 놓음.
마스크의 종류 • 영상을 평활화(smoothing)하거나 노이즈를 제거하거나, 윤곽 정보를 추출하는 등의 마스크가 사용 • 널리 사용되는 마스크의 형태
컨볼루션을 이용한 필터링 • 저주파 영역 : 빛의 세기가 천천히 변하는 영역 • 그림 9-6의 (a), (b)는 저주파 필터 • 고주파 영역 : 빛의 세기가 갑자기 바뀌는 물체의 경계나 무늬가 세밀한 영역 • 그림 9-6의 (a), (b)를 제외한 나머지는 고주파 필터
영상 필터링을 위한 FFT • 2차원 퓨리에 변환 • 퓨리에 변환과 역변환 • FFT의 분해 성질 + = 행FFT 열FFT 2D FFT
FFT의 기본 성질 • 스크램블링 동작(역순서 비트) N=8인 경우 입력의 순서가 0,4,2,6,1,5,3,7과 같이 순서가 바뀌어야하는데 이를 스크램블링 동작이라 한다.
FFT의 기본 성질 • 8점 FFT 를 실행 시 : 입력 수열의 순서가 데이터 수열의 순서와 다름. ∴ FFT 실행시 원래의 입력 데이터의 순서를 바꾸어 주어야 함. 즉 데이터 수열이 저장된 이진 비트 주소를 역으로 바꾸어 사용하면 됨. 역순서 비트(bit reverse)
FFT의 기본 성질 • 나비선도 나비 선도 ※ 위상인자를 의 거듭제곱으로 표시.
주파수 영역에서의 필터링 • 주파수 영역 필터링 • 영상의 푸리에 변환을 구한다. • 마스크 함수의 푸리에 변환을 구한다. • 두 변환의 원소끼리 곱한다. • 곱의 결과를 역푸리에 변환을 수행한다.
버터워스(Butterworth) 필터를 이용한 영상 필터링 • 영상에서의 고주파는 값의 변화율이 큰 부분으로 주로 윤곽선 부분이며 저주파는 값의 변화가 적은 영상의 부분을 의미한다. • 주파수 필터링 개념도 • Butterworth 저주파 필터 • Butterworth 고주파 필터 FFT 원영상 필터링 IFFT 필터링된 영상
고속 퓨리에 변환 구현 • 리소스 편집기를 이용하여 팝업 메뉴를 주파수 해석을 생성후 • 서브 메뉴에 FFT를 만듬
고속 퓨리에 변환 구현 • 만들어진 FFT 서브메뉴에 마우스 오른쪽 버튼을 눌러 클래스 마법사를 실행 • <Add Function> 버튼을 눌러 CDSPTestView 클래스에 OnFFT()함수를 추가
고속 퓨리에 변환 구현 • 생성된 OnFFT()함수를 다음과 같이 코딩 • 호출된 TwoD_FFT() 함수를 CDSPTestDoc 클래스에 생성 void CDSPTestView::OnFFT() { // TODO: Add your command handler code here CDSPTestDoc* pDoc=GetDocument(); ASSERT_VALID(pDoc); pDoc->TwoD_FFT(); Invalidate(FALSE); }
고속 퓨리에 변환 구현 • 생성된 TwoD_FFT()함수를 다음과 같이 코딩한다. void CDSPTestDoc::TwoD_FFT() { int index=0,i=0,j=0,k=0; COMPLEX col_data[256]; COMPLEX row_data[256]; for(i=0; i<256; i++){ col_data[i].re=0; col_data[i].im=0; row_data[i].re=0; row_data[i].im=0; for(j=0; j<256; j++){ complex_data[k+j].re=m_InImg[i][j]; complex_data[k+j].im=0; } k+=256; } k=0;
고속 퓨리에 변환 구현 for(int y=0; y<256; y++){ index=y*256; for(int x=0; x<256; x++) { row_data[x].re = complex_data[index].re; row_data[x].im = complex_data[index++].im; } fft(row_data,8,256,1); index=y*256; for(x=0; x<256; x++) { complex_data[index].re = row_data[x].re; complex_data[index++].im = row_data[x].im; } }
고속 퓨리에 변환 구현 for(int x=0; x<256; x++){ index=x; for(int y=0; y<256; y++) { col_data[y].re = complex_data[index].re; col_data[y].im = complex_data[index].im; index += 256; } fft(col_data,8,256,1); index=x; for(y=0; y<256; y++) { complex_data[index].re = col_data[y].re; complex_data[index].im = col_data[y].im; index += 256; } }
//result for(i=0; i<256; i++){ for(j=0; j<256; j++){ m_OutImg[i][j]=20*log(1+abs(complex_data[k+j].re)); if(m_OutImg[i][j]>=170)m_OutImg[i][j]=255; else m_OutImg[i][j]=0; } k+=256; } fftview(); } 다큐먼트 클래스의 헤더파일에 #define PI 3.141592 Typedef struct {float re, im;} COMPLEX; #include <math.h>를 추가한다. 고속 퓨리에 변환 구현 • 다큐먼트 클래스에 다음의 변수를 추가 COMPLEX complex_data[256*256]
고속 퓨리에 변환 구현 • TwoD_FFT()에서 호출한 1차원 FFT인 fft() 함수를 생성 및 코딩. void CDSPTestDoc::fft(COMPLEX *f, int logN, int numpoints, int dir) { scramble(numpoints,f); butterflies(numpoints,logN,dir,f); }
고속 퓨리에 변환 구현 • scramble(…)와 butterflies(…)를 다음과 같이 작성한다. void CTestDoc::scramble(int numpoints, COMPLEX *f) { int i,j,m; //loop variable double temp; //temporary storage during swapping j=0; for(i=0;i<numpoints;i++) //numpoint배열의 element 수 { if(i>j) { //swap real temp=f[j].re; f[j].re=f[i].re; f[i].re=(float)temp; //swap imagenary temp=f[j].im; f[j].im=f[i].im; f[i].im=(float)temp; } m=numpoints>>1; while(( j >= m ) & ( m >= 2 )) { j -=m; m = m >> 1; } j +=m; } }
고속 퓨리에 변환 구현 void CTestDoc::butterflies(int numpoints, int logN, int dir, COMPLEX *f) { double angle; //polar angle COMPLEX w,wp,temp; //intermediate complex numbers int i,j,k,offset; //loop variables int N,half_N; //storage for powers of 2 double wtemp; //temporary storage for w.re N=1; for(k=0; k<logN; k++) { half_N=N; N <<= 1; angle = -2.0 * PI / N * dir; wtemp = sin(0.5*angle); //wp.re = (float)sin(0.5*angle);//변경. wp.re = (float)(-2.0*wtemp*wtemp); wp.im = (float)sin(angle);//변경 w.re = 1.0; w.im = 0.0;
고속 퓨리에 변환 구현 for(offset=0; offset<half_N; offset++) { for(i=offset; i<numpoints; i+=N) { j=i+half_N; temp.re = (w.re*f[j].re)-(w.im*f[j].im); temp.im = (w.im*f[j].re)+(w.re*f[j].im); f[j].re = f[i].re-temp.re; f[i].re += temp.re; f[j].im = f[i].im-temp.im; f[i].im += temp.im; } wtemp = w.re; w.re = (float)(wtemp*wp.re-w.im*wp.im+w.re);//변경. w.im = (float)(w.im*wp.re+wtemp*wp.im+w.im);//변경. } } if(dir == -1) for(i=0;i<numpoints;i++) { f[i].re /= numpoints; f[i].im /= numpoints; } }
고속 퓨리에 변환 구현 • 결과 영상의 중심에 저주파 중심으로 부터 먼 부분에는 고주파를 표시하기 위한 함수 fftview()를 다음과 같이 코딩한다. void CDSPTestDoc::fftview() { unsigned char fftview[256][256]; //convert for(int i=0; i<256; i+=128){ for(int j=0; j<256; j+=128){ for(int row=0; row<128; row++){ for(int col=0; col<128; col++){ fftview[127-row+i][127-col+j]=m_OutImg[i+row][j+col]; } } } } for(int y=0; y<256; y++){ for(int x=0; x<256; x++){ m_OutImg[y][x]=fftview[y][x]; } } }
고속 퓨리에 변환 구현 • 실행결과
고속 퓨리에 역변환 구현 • 리소스 편집기를 이용하여 팝업 메뉴 주파수 해석 아래에 서브메뉴 IFFT를 생성 • 만들어진 IFFT 서브메뉴에 마우스 오른쪽 버튼을 눌러 클래스 마법사를 선택
고속 퓨리에 역변환 구현 • <Add Function> 버튼을 눌러 뷰클래스에 OnIFFT()함수를 추가 void CDSPTestView::OnIFFT() { // TODO: Add your command handler code here CDSPTestDoc* pDoc=GetDocument(); // 도큐먼트 클래스 참조 ASSERT_VALID(pDoc); pDoc->TwoD_IFFT(); Invalidate(FALSE); } • 호출된 TwoD_IFFT()함수를 CDSPTestDoc 클래스에 생성후 코딩
고속 퓨리에 역변환 구현 void CDSPTestDoc::TwoD_IFFT() { int index=0,i=0,j=0,k=0; COMPLEX col_data[256]; COMPLEX row_data[256]; for(i=0; i<256; i++){ col_data[i].re=0; col_data[i].im=0; row_data[i].re=0; row_data[i].im=0; } for(int y=0; y<256; y++) { index=y*256; for(int x=0; x<256; x++) { row_data[x].re = complex_data[index].re; row_data[x].im = complex_data[index++].im; } fft(row_data,8,256,-1); index=y*256; for(x=0; x<256; x++) { complex_data[index].re = row_data[x].re; complex_data[index++].im = row_data[x].im; } }
고속 퓨리에 역변환 구현 for(int x=0; x<256; x++) { index=x; for(int y=0; y<256; y++) { col_data[y].re = complex_data[index].re; col_data[y].im = complex_data[index].im; index += 256; } fft(col_data,8,256,-1); index=x; for(y=0; y<256; y++) { complex_data[index].re = col_data[y].re; complex_data[index].im = col_data[y].im; index += 256; } } for(i=0; i<256; i++) { for(j=0; j<256; j++) { if(complex_data[k+j].re>=255) m_OutImg[i][j]=255; else if(complex_data[k+j].re<=0) m_OutImg[i][j]=0; else m_OutImg[i][j]=complex_data[k+j].re; } k+=256; } }
고속 퓨리에 역변환 구현 • 실행 결과 : FFT를 실행하고 IFFT를 실행하면 원영상이 복원됨을 알수 있음.