주파수 영역 처리

Seungpil Choi·2022년 8월 16일
1

주파수 영역 처리

공간 주파수(spatial frequency)

푸리에 변환(Fourier Transform)은 전기 신호를 사인파들의 합으로 분해하는 수학적 기법을 말한다. 푸리에에 의하면 영상도 사인파들의 합으로 변환할 수 있다. 영상에서 화소값의 변화를 파형의 형태로 그린 것을 공간 주파수(spatial frequency)라고 한다.

공간 주파수는 영상에서 "화소값들의 변화율"이다. 고주파와 저주파로 나눌수있다. 저주파는 주로 화소값이 거의 변화가 없는 영역에서 발견된다. 배경 하늘이나 바다가 여기에 해당한다. 고주파는 화소값이 급격하게 변화하는 부분이다. 영상에서 고주파 성분을 제거한다면 흐릿한 영상을 만들 수 있다. 반대로 영상에서 저주파 성분을 제거한다면 영상을 보다 날카롭게 만들 수 있다. 이것을 주파수 필터링(frequency domain filtering)이라고 한다.

푸리에 변환

푸리에 변환(Fourier Transform)은 신호처리에서 유래한 방법이다. 푸리에 변환은 시간에 따라 변화하는 함수를 분해하여 그 안에 들어 있는 주파수 성분을 끄집어내는 변환이다. 비사인파(non-sinusoidal signal)를 사인파(sinusoidal signals)들로 분해할 수 있고 또 반대로 사인파들을 합하여 비사인파를 합성할 수 있다는 것이 핵심 개념이다.

이산 푸리에 변환

푸리에 변환은 영상을 사인 및 코사인 요소로 분해한다. 즉 영상을 공간 영역에서 주파수 영역으로 변환한다. 중심 아이디어는 어떤 함수라도 여러 개의 사인과 코사인 함수의 중첩으로 근사될 수 있다는 것이다. 우리가 다루는 영상은 0에서 255 사이의 이산적인 값만을 가지는 2차원 영상이므로 DFT(Discrete Fourier Transform)을 사용하여 푸리에 변환을 하게 된다.

푸리에 변환의 결과는 복소수가 된다. 복소수를 표시하려면 실수부 영상과 허수부 영상으로 나누어 표시하든지, 아니면 복소수의 절대값과 위상으로 나누어서 표시하여야 한다. 그러나 영상 처리 알고리즘에서는 일반적으로 복소수의 절대값만 있으면 된다. 복소수의 절대값에는 영상에 대한 거의 모든 정보가 포함되어있다.

  • dft() 매개변수
    • src : 입력 행렬(실수이거나 복소수)
    • flags : 변환 플래그
      • DFT_INVERSE : 역변환
      • DFT_SCALE : 결과값을 스케일 한다. 결과를 행렬요수의 수로 나눈다(역변환에서만 사용된다.)
      • DFT_COMPLEX_OUTPUT : 수행결과가 복소수가 된다.
      • DFT_REAL_OUTPUT : 수행결과가 실수가 된다.
# 그레이스케일 영상을 실수로 변환
img = cv2.imread("../Downloads/lena.png", 0)
img = img.astype(np.float32) / 255.0

# dft연산후 쉬프트
dft_img = cv2.dft(img, flags=cv2.DFT_COMPLEX_OUTPUT)
dft_img = np.fft.fftshift(dft_img)

# dft 결과 영상을 2개의 영상으로 분리하고
# 푸리에 변환 계수들의 절댓값을 계산
image_array = cv2.split(dft_img)
mag_image = cv2.magnitude(image_array[0], image_array[1])

# 로그 값이 0이 안나오도록 1을 더함
mag_image += 1
mag_image = cv2.log(mag_image)

# 0에서 255로 범위로 정규화함
mag_image = cv2.normalize(mag_image, None, 0, 1, cv2.NORM_MINMAX)

cv2.imshow("dft", mag_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

역변환

위의 DFT영상으로부터 원래의 그레이스케일 영상을 복원한다.

# 위의 코드에서

dft_img = np.fft.ifftshift(dft_img) * 255.0

inversedft = cv2.idft(dft_img, flags=cv2.DFT_SCALE|cv2.DFT_REAL_OUTPUT)
inversedft = inversedft.astype(np.uint8)

cv2.imshow("inversedft", inversedft)
cv2.waitKey(0)
cv2.destroyAllWindows()

주파수 필터링

영상을 푸리에 변환을 사용하여 주파수 영역으로 변환하면 우리는 쉽게 저주파 부분과 고주파 부분을 분리할 수 있다. 따라서 이들 계수들을 변경하면 손쉽게 각 주파수 영역을 강화하거나 약화시킬 수 있다. 예를 들어 고주파 부분을 제거하면 영상은 부드러워질 것이다. 반대로 고주파 부분을 강화한다면 더 날카로운 영상이 될 것이다.

# 그레이스케일 영상을 실수로 변환
img = cv2.imread("../Downloads/lena.png", 0)
img = img.astype(np.float32) / 255.0

# dft연산후 쉬프트
dft_img = cv2.dft(img, flags=cv2.DFT_COMPLEX_OUTPUT)
dft_img = np.fft.fftshift(dft_img)

mask = np.zeros((dft_img.shape[0],dft_img.shape[1],dft_img.shape[2]), dtype=np.float32)
circle = cv2.circle(mask, (dft_img.shape[0]//2,dft_img.shape[1]//2), radius=50, color=(1,1,1), thickness=-1)

result = cv2.multiply(dft_img, mask)

result = np.fft.ifftshift(result) * 255.0

inversedft = cv2.idft(result, flags=cv2.DFT_SCALE|cv2.DFT_REAL_OUTPUT)
inversedft = inversedft.astype(np.uint8)

cv2.imshow("inversedft", inversedft)
cv2.waitKey(0)
cv2.destroyAllWindows()

고주파만 통과하도록 하는 필터

mask = np.ones((dft_img.shape[0],dft_img.shape[1],dft_img.shape[2]), dtype=np.float32)
circle = cv2.circle(mask, (dft_img.shape[0]//2,dft_img.shape[1]//2), radius=10, color=(0,0,0), thickness=-1)

주기적인 패턴 제거

푸리에 변환을 사용하면 영상에 존재하는 주기적인 패턴을 제거할 수 있다. 통신 장비의 잡음과 같은 주기적인 패턴이 발생할 수 있는데 이러한 주기적인 패턴도 주파수라고 볼 수 있다.

img = cv2.imread("../Downloads/Noisy_Smithsonian_Castle.jpg",0)
img = img.astype(np.float32) / 255.0

# dft연산후 쉬프트
dft_img = cv2.dft(img, flags=cv2.DFT_COMPLEX_OUTPUT)
dft_img = np.fft.fftshift(dft_img)

# dft 결과 영상을 2개의 영상으로 분리하고
# 푸리에 변환 계수들의 절댓값을 계산
image_array = cv2.split(dft_img)
mag_image = cv2.magnitude(image_array[0], image_array[1])

# 로그 값이 0이 안나오도록 1을 더함
mag_image += 1
mag_image = cv2.log(mag_image)

# 0에서 255로 범위로 정규화함
mag_image = cv2.normalize(mag_image, None, 0, 1, cv2.NORM_MINMAX)

# 주기적인 패턴 제거
mask = np.ones((dft_img.shape[0],dft_img.shape[1],dft_img.shape[2]), dtype=np.float32)
mask[0:113,160:170,:] = 0
mask[133:245,160:170,:] = 0
mask[:,260:270,:] = 0

result = cv2.multiply(dft_img, mask)
result = np.fft.ifftshift(result) * 255.0

inversedft = cv2.idft(result, flags=cv2.DFT_SCALE|cv2.DFT_REAL_OUTPUT)
inversedft = inversedft.astype(np.uint8)

cv2.imshow("src", img)
cv2.imshow("frequency",mag_image)
cv2.imshow("inversedft", inversedft)
cv2.waitKey(0)
cv2.destroyAllWindows()
  • 패턴 제거 전

  • 패턴 제거 후

0개의 댓글