본문 바로가기

물리 낙서장/전산물리

Python으로 Fourier filter씌워 이미지 재구성해보기

반응형

 지난 나의 글 - https://physikk.tistory.com/35 에서 Fouirer filter를 소개하면서 "이미지에서 명암의 변화를 기준으로 Fourier transform을 수행하여 다시 이미지를 재구성 할 수 있는데, 이 때 고주파 성분을 저주파수 성분 대비 상대적으로 증폭시키면 원래 이미지의 가장자리를 보다 선명하게 만들 수 있다. 반대로 고주파 성분을 제거하면 그림이 뿌옇게 되며 blur 효과를 얻을 수 있다." 고 설명했다. 

 이번 게시글에서는 Google colab. 환경에서 python을 이용해 iu사진을 직접 푸리에 변환한 뒤, 필터링해서 이미지를 재구성 해 보겠다. 

 컴퓨터 비전 처리에서는 다음 사진의 주인공 - 레나가 많이 쓰인다. 

컴퓨터 비전처리에 예시로 많이 쓰이는 잡지모델 레나

위키피디아에 따르면, 세밀함, 평면, 그림자, 질감이 적절하게 조화되어 아주 적합한 테스트용 샘플이라고 하는데, 나는 그냥 아이유 사진을 가지고 할 예정이다. 

우리의 샘플 이미지이다. 

먼저 다음의 모듈을 import 해주자

import glob
from skimage import io
import matplotlib.pyplot as plt
import numpy as np

우리는 Numpy module에 있는 FFT2를 이용해서 Fourier transformation 할 것이다. 이에 관련된 기술적이고 상세한 설명은 다른 블로그에도 잘 작성되어있으니, 우리는 우선 써보겠다. 먼저 이미지를 불러와준다. 

#image import  
our_file=glob.glob('/content/drive/MyDrive/iu.png')[0]
#showing original image
io.imshow(our_file)
plt.show()
img = io.imread(our_file, as_gray=True)

여기서 포인트가 두 가지 정도 있다.

1. 이미지를 흑백으로 전처리하는 이유는, 이미지의 Noise를 감소하기 위함이다. 노이즈가 심하다고 판단되는 경우에는 가우시안 블러처리까지 해주는 경우도 있다. 

2. 그럼 왜 흑백처리하기 전에 사진을 불러왔나? - 앞으로 계속 흑백으로 볼꺼라서, 마지막으로 컬러로 한 번 감상하기 위함이다. 

 

이제 Fourier Transformation해주자.

fig=plt.figure(figsize=(12,8))
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
phase = np.angle(fshift)

plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('Input Image',fontsize = 14, fontweight='bold'), plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum',fontsize = 14, fontweight='bold'), plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(phase, cmap = 'gray')
plt.title('Phase Spectrum',fontsize = 14, fontweight='bold'), plt.xticks([]), plt.yticks([])
plt.savefig('iu',dpi=300,bbox_inches='tight')

plt.show()

numpy모듈의 fft2를 이용해서 푸리에 변환해주고, 같은 모듈의 fftshift를 이용해서 원점을 왼쪽 위에서 센터로 가져왔다. 그리고 magnitude spectrum, phase spectrum, original을 subplot으로 한 눈에 비교할 수 있게 그려보았다. Phase spectrum은 별 의미가 없고, Magnitude spectrum을 이용해서 filtering을 해보자. 

 

원점을 센터로 가져왔으니, 가운데로 갈 수록 저주파수이고, 가장자리로 갈 수록 고주파수이다. 먼저 다음과 같이 가운데 (저주파수)를 가려보자. 

 

fig=plt.figure(figsize=(8,8))
(w, h) = fshift.shape
half_w, half_h = int(w/2), int(h/2)
# high pass filter
n = 15
fshift[half_w-n:half_w+n+1,half_h-n:half_h+n+1] = 0 # select first 30x30 (low) frequencies
plt.imshow( (20*np.log10( 0.1 + fshift)).astype(int),cmap='gray')
plt.axis('off')
plt.savefig('highfrequencyfilter',dpi=300,bbox_inches='tight')
plt.show()

 w by h  의  matrix shape에서 w/2, h/2로 원점을 찾아주고,  거기서부터 -15, +15하여 첫 30번째까지의 주파수들을 0으로 세팅해준다. 그러면 이렇게 된다. 

이를 이제 이미지로 재조합(?)할 차례이다. inverse Fourier transformation해주면 된다. 고주파수만 남았으니까, hiu라고 칭하겠다. imaginary part는 쓸데없으니 버려준다. 

hiu = np.fft.ifft2(fshift).real
plt.figure(figsize=(10,10))
plt.subplot(111),plt.imshow(hiu, cmap = 'gray')
plt.title('Blocked low frequency image',fontsize = 14, fontweight='bold'), plt.xticks([]), plt.yticks([])
plt.axis('off')
plt.savefig('hiu',dpi=300,bbox_inches='tight')
plt.show()

보다싶이 테두리가 진한(?) 부분들만 남았다! 원래사진과 비교하면 다음과 같다. 

이번에는 고주파수를 없에보자. 아까 했던 방식대로인데, 이번에는 뒤에서부터 30번째 주파수를 없엘것이다. 

f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
phase = np.angle(fshift)
fig=plt.figure(figsize=(8,8))
(w, h) = fshift.shape
# high pass filter
n = 30
fshift[0:n,:] = 0 
fshift[:,0:n] = 0 
fshift[w-n:w,:] = 0 
fshift[:,h-n:h] = 0 

plt.imshow( (20*np.log10( 0.1 + fshift)).astype(int),cmap='gray')
plt.axis('off')
plt.savefig('lowfrequencyfilter',dpi=300,bbox_inches='tight')
plt.show()

이를 이미지로 재조합하자. 저주파수만 남겼으니까, liu라고 하겠다. 

liu = np.fft.ifft2(fshift).real
plt.figure(figsize=(10,10))
plt.subplot(111),plt.imshow(liu, cmap = 'gray')
plt.title('Blocked high frequency image',fontsize = 14, fontweight='bold'), plt.xticks([]), plt.yticks([])
plt.axis('off')
plt.savefig('liu',dpi=300,bbox_inches='tight')
plt.show()

hiu와 달리 고주파수가 날아간 liu는 테두리부분이 날아간 것을 확인할 수 있다. 그런데 위에서 블러처리가 되어야 한다고 했는데, 그림이 그렇게 블러가 들어간거같지는 않다고 생각할 수 있다. 화끈하게(?) (500x500)에서 440x440을 0으로 처리해보면 다음과 같은 결과가 나온다.

 

화끈하게 날려버린(?) 고주파수
위 필터를 재구성한 이미지

확실히 블러된 것이 느껴진다. 

 

여기서 이런 의문을 가질 수 있다. 저번 예시에서도 2D 이미지였지만, 1D Power spectrum을 가지고 컨트롤을 했는데,  우리도 그럴 수는 없을까? 

 

1D Spectrum은 다음과 같이 magnitude specturm에서 Azimuthal angle에 대해 평균을 내어 구해줄 수 있다. 1D Spectrum 구하기는 다음 게시물에서 다루어본다. 

 

(방금 마지막에 화끈하게(?)날려버린 1D Power spectrum은 아래와 같은 모양이다)