파이썬 강의/openCV

파이썬 openCV 26. 주파수 : 푸리에 변환을 이용한 저주파 필터(LPF) / 고주파 필터(HPF)

마리사라 2020. 12. 22. 16:29
반응형

파이썬 openCV 26번째 강의는 푸리에 변환을 이용한 저주파 필터(LPF) / 고주파 필터(HPF)입니다.


0. LPF(Low Pass Filter)/HPF(High Pass Filter)?

원래 HPF와 LPF는 전기회로에서 사용하는 용어입니다. 전기신호는 0과 1로 이루어진 신호입니다. 0이면 전기가 흐르지 않고, 1이면 전기가 흐르는 방식으로 모든 전자기기가 작동합니다. 이러한 0과 1을 얼마나 빠르게 켜고 끄는지를 주파수로 표현할 수 있습니다.

하지만 전자기기라고 하더라도 100% 정확한 동작만을 하지는 않습니다. 엄청나게 빠르게 동작하는 전기신호의 특성상 채터링이라고 하는 불규칙적인 진동이 발생하게 됩니다. 또한 모든 전기신호가 한순간 생겼다가 한순간 사라지는것이 아니고, 서서히 사라집니다. 이러한 노이즈를 제거하는것 방식으로 HPF와 LPF가 있습니다.

 

2020/12/19 - [파이썬/openCV] - 파이썬 openCV 25. 주파수 : 푸리에 변환(Fourier transform)

 

파이썬 openCV 25. 주파수 : 푸리에 변환(Fourier transform)

파이썬 openCV 25번째 강의는 푸리에 변환(Fourier transform)입니다. 이번 강의부터 영상을 주파수 단위로 조작하는 방법을 알려드릴 예정입니다. 0. 푸리에 변환(Fourier transform)? 여태까지 그래 왔듯이

marisara.tistory.com

이전 강의에서 영상을 주파수로 만드는 것을 알려드렸습니다. 이전 강의에서 밝기의 값이 크게 변경되는것을 고주파, 작게 변경되는것을 저주파라고 했습니다.

 

이렇게 oepnCV에서 저주파와 고주파의 모음으로 영상을 나타낼 때, 어떤 주파수를 기준으로 고주파만 통과시키는 것을  High Pass Filter, 저주파만 통과시키는 것을 Low Pass Filter라고 합니다.


1. openCV에서의 주파수 LPF/HPF

img = cv2.imread('lenna.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
height, width = gray.shape
dft = cv2.dft(np.float32(gray), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

우선 주파수에서의 HPF와 LPF를 하기 위해서는 당연히 영상을 주파수로 변환해 주어야 합니다. 자세한 내용은 이전 강의를 참조하시기 바랍니다.

 

row, col = int(height / 2), int(width / 2)

이제 LPF와 HPF를 하기 전에 영상의 중앙을 찾기 위해 세로와 가로의 중앙을 저장합니다.

 

LPF = np.zeros((height, width, 2), np.uint8)
LPF[row - 50:row + 50, col - 50:col + 50] = 1
LPF_shift = dft_shift * LPF
LPF_ishift = np.fft.ifftshift(LPF_shift)
LPF_img = cv2.idft(LPF_ishift)
LPF_img = cv2.magnitude(LPF_img[:, :, 0], LPF_img[:, :, 1])
out = 20*np.log(cv2.magnitude(LPF_shift[:, :, 0], LPF_shift[:, :, 1]))

이제 LPF를 먼저 알려드리겠습니다.

 

LPF를 만들기 위해 원본 영상과 같은 크기의 zeros 영상을 만듭니다. 그후 빈 영상의 중앙에서 가로 세로 각각 ±50범위는 1로 변환해 줍니다.

 

이제 주파수 변환된 영상과 위의 LPF를 곱해줍니다. 이렇게되면 중앙에서 ±50범위만 남게되고 나머지는 0이됩니다.

 

그 이후에는 이전 강의처럼 주파수로 된 영상을 만들고, 그를 역 푸리에 변환하여 이미지화된 영상을 만들어줍니다.

 

HPF = np.ones((height, width, 2), np.uint8)
HPF[row - 50:row + 50, col - 50:col + 50] = 0
HPF_shift = dft_shift * HPF
HPF_ishift = np.fft.ifftshift(HPF_shift)
HPF_img = cv2.idft(HPF_ishift)
HPF_img = cv2.magnitude(HPF_img[:, :, 0], HPF_img[:, :, 1])
out2 = 20*np.log(cv2.magnitude(HPF_shift[:, :, 0], HPF_shift[:, :, 1]))

이번에는 HPF 입니다.

 

HPF를 만들기 위해 원본 영상과 같은 크기의 ones 영상을 만듭니다. np.ones는 np.zeros와 반대로 모든 값들이 1인 행렬을 만드는 함수입니다. 이후 위 영상의 중앙에서 가로 세로 각각 ±50범위를 0으로 변환해 줍니다.

 

그 이후 LPF처럼 주파수 변환된 영상과 HPF를 곱해줍니다. 이렇게되면 중앙에서 ±50범위는 0이되고, 나머지만 남게 됩니다.

 

그 이후는 똑같이 주파수로 된 영상을 만들고, 역 푸리에 변환하여 이미지화된 영상을 만듭니다.

 

 

이제 결과입니다

out1 = LPF된 주파수 / out2 = HPF된 주파수
LPF
HPF

LPF원본 영상과 거의 비슷하지만 살짝 흐리게 나온 반면, HPF원본 영상의 에지만 나온것을 확인 할 수 있습니다.

 

이전 영상에서도 말씀드렸다시피, 영상의 대부분은 저주파가 많습니다. 그래서 LPF를 통과한 이미지는 원본과 거의 흡사한 반면, HPF는 원본에서 많이 멀어진것을 확인할 수 있습니다.


2. 마치며

이제 주파수단위의 영상조작은 끝입니다. 이 다음에는 주파수가 아닌 일반적인 LPF/HPF를 강의하도록 하겠습니다.

 

def filtering():
    img = cv2.imread('lenna.png')
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    height, width = gray.shape
    dft = cv2.dft(np.float32(gray), flags=cv2.DFT_COMPLEX_OUTPUT)
    dft_shift = np.fft.fftshift(dft)

    row, col = int(height / 2), int(width / 2)
    LPF = np.zeros((height, width, 2), np.uint8)
    LPF[row - 50:row + 50, col - 50:col + 50] = 1
    LPF_shift = dft_shift * LPF
    LPF_ishift = np.fft.ifftshift(LPF_shift)
    LPF_img = cv2.idft(LPF_ishift)
    LPF_img = cv2.magnitude(LPF_img[:, :, 0], LPF_img[:, :, 1])
    out = 20*np.log(cv2.magnitude(LPF_shift[:, :, 0], LPF_shift[:, :, 1]))

    HPF = np.ones((height, width, 2), np.uint8)
    HPF[row - 50:row + 50, col - 50:col + 50] = 0
    HPF_shift = dft_shift * HPF
    HPF_ishift = np.fft.ifftshift(HPF_shift)
    HPF_img = cv2.idft(HPF_ishift)
    HPF_img = cv2.magnitude(HPF_img[:, :, 0], HPF_img[:, :, 1])
    out2 = 20*np.log(cv2.magnitude(HPF_shift[:, :, 0], HPF_shift[:, :, 1]))

    plt.subplot(151), plt.imshow(gray, cmap='gray')
    plt.title('Input Image'), plt.xticks([]), plt.yticks([])
    plt.subplot(152), plt.imshow(LPF_img, cmap='gray')
    plt.title('LPF'), plt.xticks([]), plt.yticks([])
    plt.subplot(153), plt.imshow(out, cmap='gray')
    plt.title('out1'), plt.xticks([]), plt.yticks([])
    plt.subplot(154), plt.imshow(HPF_img, cmap='gray')
    plt.title('HPF'), plt.xticks([]), plt.yticks([])
    plt.subplot(155), plt.imshow(out2, cmap='gray')
    plt.title('out2'), plt.xticks([]), plt.yticks([])

    plt.show()
반응형