해당 포스트는 "OpenCV로 배우는 영상 처리 및 응용", "C++ API OpenCV 프로그래밍" 책의 내용을 요약한 것이다.



※ OpenCV DFT 함수

- void dft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0)

: 1차원 또는 2차원 영상의 정방향 푸리에 변환(DFT) 및 역방향 푸리에 변환(IDFT)를 수행한다. src는 1채널로 표현되는 실수 또는 2채널로 u,v로 표현되는 복소수가 있다. 출력 dst의 크기와 자료형은 flags에 의해서 의존된다. flags은 다음과 같다.

1. flags = 0(Default) 라면 DFT를 수행한다.

2. flags = DFT_INVERSE 라면 IDFT를 수행하는 데 마지막에 1/MN을 곱하지 않는다.

3. flags = DFT_SCALE 라면 결과를 1/MN로 스케일링하여 반환한다. 일반적으로 역방향 푸리에 변환과 같이 DFT_INVERSE | DFT_SCALE로 사용한다.

4. flags = DFT_ROWS 라면 각 행 단위로 정방향 푸리에 변환과 역방향 푸리에 변환을 사용한다.

5. flags = DFT_COMPLEX_OUTPUT 이면 결과는 2채널의 복소수 행렬이 된다.

6. flags = DFT_REAL_OUTPUT 이면 출력 행렬이 1채널의 실수 행렬이 되고 복소수가 있을 시 실수-허수 순서로 행렬 요소들이 배치된다.

만약 src가 1채널 실수이고 DFT_INVERSE가 설정되지 않으면, dft 함수는 DFT를 수행한다. 이 때 DFT_COMPLEX_OUTPUT이 설정되면, 출력 dst는 입력과 같은 크기의 복소수 행렬이 된다. DFT_COMPLEX_OUTPUT이 설정되지 않으면 출력 dst는 입력과 같은 크기의 1채널 실수 행렬이 되며 실수-허수 순서로 행렬 요소들이 배치된다. 


- void idft(InputArray src, OutputArray dst, int flags=0, int nonzeroRows=0)

: idft 함수는 역방향 푸리에 변환을 한다. dt(src, dst, flags } DFT_INVERSE)와 같다.


- int getOptimalDFTSize(int vecsize)

: vecsize와 같거나 큰 정수 중에 DFT를 계산하기에 최적의 크기인 N을 계산하여 반환한다. N은 vecsize와 같거나 큰 2^p*3^q*5^r이다. DFT에서 최적의 크기는 getOptimalDFTSize((vecsize+1)/2)*2)이다.


- void mulSpectrums(InputArray a, InputArray b, OutputArray c, int flags, bool conjB=false)

: conjB가 false이면 행렬 a와 b를 회선(convolution) 계산한다. conjB가 true이면 행렬 a와 b의 상관관계(correlation)을 계산한다. 


- 푸리에 변환의 이동 특성을 이용한 함수 

: 입력 영상 f(x,y)에 (-1)^(x+y)를 곱해준 후 DFT를 수행하면 주파수 영역의 원점이 (M/2, N/2)로 이동한다. 즉 F(u-M/2, v-N/2)가 된다. 그러면 주파수 중앙이 저주파가 되고, 중앙에서 거리가 멀어지면 고주파가 된다. 우리는 주파수 스펙트럼을 만들 때 저주파를 중앙으로, 고주파를 테두리로 만들기 위해 주파수 영상의 정중앙을 원점으로 했을 때 2사분면과 4사분면, 1사분면과 3사분면을 바꿔줘야 한다. 이 때 Mat.copyTo 또는 memcpy 함수를 이용해서 픽셀들의 값을 Swap을 한다. 하지만 푸리에 변환의 이동 특성을 활용하면 더 쉽게 영역 이동이 가능하다. 입력 영상에 (-1)^(x+y)를 곱해주면 주파수 영역의 원점이 정중앙으로 이동해 저주파가 중앙에 오기 때문에 이를 구현하면 된다. 다음 코드는 이를 구현한 함수이다. 아래의 메서드의 매개변수로 입력영상을 준 후 결과 영상에 푸리에 변환을 수행하면 저주파가 정중앙에 온다.

void ChangeSignOddPositionInXY(Mat &m)
{
	int x, y;
	float fValue;
	for (y = 0; y<m.rows; y++)
	for (x = 0; x<m.cols; x++)
	{
		fValue = m.at<float>(y, x);
		//		if((x+y)%2==1 && fValue != 0)
		if ((x + y) % 2 == 1) // odd number
			m.at<float>(y, x) = -fValue;
	}
}


※ 저주파/고주파 통과 필터(저주파/고주파 통과필터에 대한 기본적인 내용이 궁금하면 여기를 클릭하세요)

저주파 통과 필터는 저주파 영역은 통과시키고 고주파 영역은 0으로 만들어 통과시키지 않은 필터를 말한다. 고주파는 영상의 화소값이 급격하게 변하는 부분이기에 저주파 통과 필터를 통해 잡음 제거/약화 효과가 낼 수 있고 에 지 등의 세밀한 부분을 부드럽게 만든다. 보통의 저주파 통과 필터는 특정 임계값 D0을 기준으로 저주파는 1, 고주파는 0인 값을 생성해 화소값에 곱하여 구현한다. 하지만 급격하게 화소값이 변경되 자연스러운 영상을 얻지 못하게 된다. 그래서 다음의 저주파 통과 필터가 있다.


- 버터워스 저주파 통과 필터 


- 가우시안 저주파 통과 필터



※ 고주파 통과 필터

고주파 통과 필터는 고주파 영역은 통과시키고 저주파 영역은 0으로 만든다. 영상을 날카롭게 강조하는 샤프닝 효과를 일으킨다. 단순히 고주파 통과 필터는 저주파 통과 필터에서 1을 빼면 된다.


- 버터워스 고주파 통과 필터 


- 가우시안 고주파 통과 필터


+ Recent posts