pythonで一から画像処理 (5)フーリエ変換

基本となる画像処理を一から勉強していくシリーズ (5)。

OpenCV-Pythonチュートリアルを参考に、
画像認識本　https://www.amazon.co.jp/dp/4061529129/
でやっている処理の理解を進める方針です。

# 目次

1.環境
2.フーリエ変換
3.ハイパスフィルタ
4.ローパスフィルタ

# 環境

Python 3.7.0
OpenCV 4.1.0
Jupyter Notebook

# フーリエ変換
グレイスケールのガイコツ画像に対して、2次元離散フーリエ変換 (DFT) を適用。
中心に白い領域が集中していて、低周波成分を多く含んでいる。

```python:fourier.py

import cv2
import numpy as np
from matplotlib import pyplot as plt
from pylab import rcParams
%matplotlib inline
rcParams['figure.figsize'] = 25, 20

#grayscaleで読み込み
img = cv2.imread('/brabra/1.jpg',0)

#フーリエ変換
f = np.fft.fft2(img)
#画像中心を原点に変更
fshift = np.fft.fftshift(f)
#フーリエ変換結果は複素数なので絶対値にし、logにしている
magnitude_spectrum = 20*np.log(np.abs(fshift))

plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
```
<img width="596" alt="fourier.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480516/39aad174-cea6-64cc-8bc9-9fb2434c4d72.png">



# ハイパスフィルタ
ハイパスフィルタ（高周波成分のみ残す）を行った。フーリエ変換後、矩形のウィンドウで原点付近の成分をフィルタし、画像に戻している。

```python:highpass.py

rows, cols = img.shape
#画像の中心
crow,ccol = int(rows/2) , int(cols/2)
#フィルタする原点付近の幅
reg = 50

#フーリエ変換像からフィルタ
fshift[crow-reg:crow+reg, ccol-reg:ccol+reg] = 0
#逆フーリエ変換で画像に戻す
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.abs(img_back)

plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(img_back, cmap = 'gray')
plt.title('Image after HPF'), plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])

plt.show()
```
![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480516/ac8a30b0-430c-b7e0-1a74-2cc8997e06d2.png)

ガイコツのエッジが残っていることが分かった。
# ローパスフィルタ
ローパスフィルタ（低周波成分のみ残す）を行った。フーリエ変換後、原点付近のみ残すように処理し、画像に戻している。

```python:lowpass.py

#opencvでフーリエ変換
dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)
#原点シフト
dft_shift = np.fft.fftshift(dft)
#絶対値,log
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))

rows, cols = img.shape
crow,ccol = int(rows/2) , int(cols/2)
#残す原点付近の幅
fil2 = 20

# マスク作成
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-fil2:crow+fil2, ccol-fil2:ccol+fil2] = 1

# フーリエ変換象にマスク適用
fshift = dft_shift*mask
#逆フーリエ変換で画像に戻す
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

```

![low.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480516/534a12e6-1201-1dc6-5c1e-9c68540fcd6a.png)

今度はエッジが薄くなった。エッジ付近で波のように見えるのはリンギング効果という矩形ウィンドウでフィルタした際に出てくるものとの事。
# まとめ

画像に対するフーリエ変換とハイパスフィルタ、ローパスフィルタについて実行し、理解を深めた。

# 参考文献
- OpenCVを使った画像処理（OpenCV-Pythonチュートリアル）
http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_table_of_contents_imgproc/py_table_of_contents_imgproc.html#py-table-of-content-imgproc

- 画像認識（機械学習プロフェッショナルシリーズ）
https://www.amazon.co.jp/dp/4061529129/