Komplex számokból álló kép kezelése OpenCV-ben
Lebegőpontos típus (CV_32F)
2 csatornából álló kép (valós és képzetes képsík)
Lebegőpontos típus (CV_32F)
2 csatornából álló kép (valós és képzetes képsík)
dft() és idft() | Diszkrét Fourier transzformáció és inverze. |
getOptimalDFTSize() | Mekkorára kell kiegészíteni a kép méretét, hogy működjön a Fourier transzformáció. |
copyMakeBorder() | Kép megadott méretre kiegészítése. |
merge() és split() | Egycsatornás képek listájából többcsatornás kép, illetve többcsatornás kép felbontása egycsatornásak listájára, ahogyan korábban is láttuk. |
magnitude() | Magnitúdó kép számítása valós és képzetes kép alapján. |
log() | Logaritmus számítása. Specktrum kép megfelelő megjelenítéséhez szükséges, általában log(1 + magnitude(DFT(I))) formában. |
normalize() | Kép értékkészlet globális átalakítása. A kép megfelelő megjelenítéséhez szükséges. |
mulSpectrums() | Spektrum képek elemenkénti szorzása. Frekvenciaszűrők alkalmazására használható. A frekvenciaszűrőt külön képként kell előzetesen előállítani. |
13_03_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
Bementi kép beolvasása, lebegőpontos típusra alakítása és megjelenítése.
img = cv2.imread('GolyoAlszik_rs.jpg', cv2.IMREAD_GRAYSCALE)
imgflt = cv2.normalize(np.float32(img), None, 0, 1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32FC1)
cv2.imshow('imgflt', img)
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 = np.fft.fftshift(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.
magnitude_spectrum = np.log(1.0 + cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))
magnitude_norm = cv2.normalize(magnitude_spectrum, None, 0, 1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32FC1)
cv2.imshow('dft log', magnitude_norm)
cv2.waitKey(0)
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] = circle_img
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.
magnitude_spectrum = np.log(1.0 + cv2.magnitude(filtered[:, :, 0], filtered[:, :, 1]))
magnitude_norm = cv2.normalize(magnitude_spectrum, None, 0, 1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32FC1)
cv2.imshow('filtered log', magnitude_norm)
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 = np.fft.ifftshift(filtered)
idft_cplx = cv2.idft(filtered_shift)
print(idft_cplx.shape)
# Taking the real part of the result
idft = idft_cplx[:, :, 0]
magnitude_norm = cv2.normalize(idft, None, 0, 1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32FC1)
cv2.imshow('idft', magnitude_norm)
cv2.waitKey(0)
Az ideális szűrő esetén a simító hatás mellett az eredeti élekkel párhuzamosan gyűrűsödést figyelhetünk meg. Ezt a hatást csökkenthetjük, ha a szűrő átmenet nem éles, hanem fokozatosan csökken a komponensek súlya. Ilyen szűrők a Gauss és a Butterworth.
Egy egyszerű kör rajzolás helyett például az alábbi függvénnyel állíthatunk elő D sugarú, n-ed rendű aluláteresztő Butterworth szűrőt.
# create a 2-channel butterworth low-pass filter with radius D, order n
# (assumes pre-allocated filter_img array)
def create_butterworth_lowpass_filter(filter_img, D, n):
center_x = filter_img.shape[1] / 2
center_y = filter_img.shape[0] / 2
for y in range(0, filter_img.shape[0]):
for x in range(0, filter_img.shape[1]):
radius = math.sqrt(math.pow(x - center_x, 2) + math.pow(y - center_y, 2))
filter_img[y, x] = 1.0 / (1 + math.pow(radius / D, (2 * n)))
A filter_img eredményt egy kétcsatornás komplex kép mindkét csatornájára másoljuk be.
A teljes példát a 13_4_dft_butterworth_lpf.py példaprogram mutat.