Skip navigation

OpenCV DFT

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)

Kapcsolódó OpenCV függvények

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.

Aluláteresztő ideális szűrő a frekvenciatérben

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)

Aluláteresztő Butterworth szűrő

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.