Aluláteresztő ideális szűrő a frekvenciatérben
13_03_a_dft_ideal_lpf.py példaprogram
Az aluláteresztő szűrés azt jelenti, hogy a képet frekvenciatérbe alakítva, ott az alacsony frekvenciákért felelős komponenseket tartjuk meg, a magasakat kinullázzuk. Visszatérve a képtérbe egy simító hatást láthatunk. Az ideális szó jelentése arra vonatkozik, hogy egy komponenst vagy teljesen megtartunk, vagy kinullázuk, a kettő határán az átmenet éles.
Importálás.
import cv2
import numpy as np
Kör alakú szűrő sugara.
filter_radius = 40
Frekvenciakép megjelenítése.
def display_freq_log_magnitude(dft_in, wnd_title='Frequency magnitude'):
# Displaying log normalized magnitude of the frequency spectrum
spectrum_magnitude = np.log(1.0 + cv2.magnitude(dft_in[:, :, 0], dft_in[:, :, 1]))
magnitude_norm = cv2.normalize(spectrum_magnitude, None, 0, 1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32FC1)
cv2.imshow(wnd_title, magnitude_norm)
Segédfüggvények a DFT síknegyedek cseréjére.
def do_fft_shift(dft_in):
dft_np_shift = np.fft.fftshift(dft_in)
return cv2.merge([dft_np_shift[:, :, 1], dft_np_shift[:, :, 0]])
def do_ifft_shift(dft_in):
dft_np_shift = np.fft.ifftshift(dft_in)
return cv2.merge([dft_np_shift[:, :, 1], dft_np_shift[:, :, 0]])
Bementi kép beolvasása és méretének feljegyzése.
img = cv2.imread('GolyoAlszik_rs.jpg', cv2.IMREAD_GRAYSCALE)
orig_width = img_in.shape[1]
orig_height = img_in.shape[0]
Az optimális képméret számítása és alkalmazása, lebegőpontos képre áttérés.
print('Proposed padding of the original image sizes:')
padded_width = cv2.getOptimalDFTSize(img_in.shape[1])
padded_height = cv2.getOptimalDFTSize(img_in.shape[0])
print('Width:', img_in.shape[1], '->', cv2.getOptimalDFTSize(img_in.shape[1]))
print('Height:', img_in.shape[0], '->', cv2.getOptimalDFTSize(img_in.shape[0]))
img = np.zeros((padded_height, padded_width), np.uint8)
img[:img_in.shape[0], :img_in.shape[1]] = img_in
img_float = np.float32(img) / 255
cv2.imshow('img_float', img_float)
Diszkrét Fourier transzformáció végrehajtása. Az eredmény komplex számokból álló (kétcsatornás) kép lesz! A képnegyedeket átrendezzük, hogy a bal felső sarok a kép középpontjába kerüljön.
dft = cv2.dft(imgflt, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = do_fft_shift(dft)
Megjelenítjük a Fourier eredményt. Komplex számokból kiszámítjuk a magnitúdójukat. Mivel a magnitúdókban nagyon nagy eltérések mutatkoznak, a jobb megjelenítés miatt célszerű logaritmikus skálán tenni ezt.
display_freq_log_magnitude(dft_shift, 'dft log magnitude')
Az ideális aluláteresztő szűrő egy kör a kép középpontjában, 1.0 értékekkel a valós és képzetes síkon egyaránt. Először a kört rajzoljuk meg, majd ebből állítjuk elő a szűrőt.
circle_img = np.ndarray(img.shape, np.float32)
circle_img[:, :] = 0
cv2.circle(circle_img, (int(circle_img.shape[1] / 2), int(circle_img.shape[0] / 2)), filter_radius, 1, -1)
# Ideal filter should be complex
ideal_filter = np.ndarray(dft.shape, np.float32)
ideal_filter[:, :, 0] = circle_img
ideal_filter[:, :, 1] = 0
cv2.imshow('circle', circle_img)
A szűrés végrehajtását a Fourier transzformált kép és a szűrő elemenkénti szorzásával állíthatjuk elő. Ezt végzi el az OpenCV mulSpectrums() függvénye.
filtered = cv2.mulSpectrums(dft_shift, ideal_filter, 0)
A megjelenítést az előzővel megegyezően a logaritmikus normalizált magnitúdóval végezzük.
display_freq_log_magnitude(filtered, 'filtered log magnitude')
cv2.waitKey(0)
Frekvenciatérből az inverz Fourier transzformációval térünk vissza a képtérbe. Előzetesen szükséges a képnegyedek visszarendezése, hogy az origó a bal felső sarokban legyen újra. Ennek az eredménye is komplex lesz! Ebből a valós rész jelenti a szűrt eredmény képet, ennek a normalizált változatát jelenítjük meg
filtered_shift = do_ifft_shift(filtered)
idft_cplx = cv2.idft(filtered_shift, flags=cv2.DFT_SCALE)
print(idft_cplx.shape)
# Take the real part of the result
idft = idft_cplx[:, :, 0]
filtered_img = np.uint8(np.clip(idft, 0, 1) * 255)[:orig_height, :orig_width]
cv2.imshow('idft', magnitude_norm)
cv2.waitKey(0)