Я следовал руководству на этом веб-сайте, чтобы создать фильтр нижних частот с использованием NumPy и OpenCV в python. Вместо отображения преобразованного изображения с помощью pyplot, как показано в руководстве, я попытался использовать функцию imshow OpenCV, но не получил желаемого результата.
img = cv2.imread('./lenna.jpg', 0)
img = np.array(img)
dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
rows, cols = img.shape
crow,ccol = int(rows/2) , int(cols/2)
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 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])
cv2.imshow('before', img)
cv2.imshow('after', img_back)
cv2.waitKey(0)
Может ли кто-нибудь помочь мне понять, что я делаю неправильно? Является ли выходное изображение неправильным типом данных?






Если вы хотите отображать данные в типе np.float32, вы должны нормализовать его до 1.0.
img_back = cv2.normalize(img_back, None, alpha=0, beta=1.0, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)
imshow ожидает, что числа с плавающей запятой в диапазоне 0..1 будут отображаться правильно (или uint8 в диапазоне 0..255).
сделайте это для чтения изображения:
img = cv2.imread('./lenna.jpg')
img = img / np.float32(255)
Я бы не советовал cv2.normalize с NORM_MINMAX, потому что это меняет глобальный контраст изображения, а это не то, что вам нужно (или не нужно).
далее я бы советовал получить реальную составляющую комплексного результата. не берите масштаб.
вы передаете чисто действительные комплексные числа в БПФ, так что это компонент, который вы должны убрать из него. представьте, что вы даете ему отрицательные реалы или ожидаете, что отрицательные реалы вернутся? когда вы берете их величину, вы получаете абсолютное значение, которое является положительным, и это было бы ошибкой, когда значение на самом деле отрицательное.
Это имеет смысл, спасибо! Но решение, которое вы предоставили, похоже, не дает правильного результата в моем примере.
ах вижу проблему. БПФ и коэффициенты масштабирования... Я добавлю еще один ответ.
Функции OpenCV FFT требуют, чтобы флаг масштабирования DFT_SCALE был задан ровно одному из dft,idft. см. примечание на https://docs.opencv.org/3.4/d2/de8/group__core__array.html#gaa708aa2d2e57a508f968eb0f69aa5ff1
Я решил передать его в первой функции, потому что она уже принимает другой флаг.
функциям fft2 numpy это не нужно. они работают как есть.
вот обе версии, отличающиеся только dft/idft и fft2/ifft2.
import os
import sys
import numpy as np
import cv2 as cv
def prepare_spectrum(spectrum):
mag = np.linalg.norm(spectrum, axis=2)
mag /= mag.max()
mag **= 1/4
return mag
img = cv.imread(cv.samples.findFile("lena.jpg"), cv.IMREAD_GRAYSCALE)
img = img / np.float32(255)
dft = cv.dft(img, flags=cv.DFT_COMPLEX_OUTPUT | cv.DFT_SCALE)
cv.imshow("1 dft", prepare_spectrum(dft))
dft_shift = np.fft.fftshift(dft)
cv.imshow("2 dft_shift", prepare_spectrum(dft_shift))
rows, cols = img.shape
crow,ccol = (rows // 2), (cols // 2)
mask = np.zeros((rows,cols,2), dtype=np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
dft_shift *= mask
cv.imshow("3 dft_shift masked", prepare_spectrum(dft_shift))
dft = np.fft.ifftshift(dft_shift)
cv.imshow("4 dft masked", prepare_spectrum(dft))
img_back = cv.idft(dft)
img_back = img_back[:,:,0] # real part
cv.imshow('before', img)
cv.imshow('after', img_back)
cv.waitKey()
cv.destroyAllWindows()
Нампи:
import os
import sys
import numpy as np
import cv2 as cv
def prepare_spectrum(spectrum):
mag = np.abs(spectrum)
mag /= mag.max()
mag **= 1/4
return mag
img = cv.imread(cv.samples.findFile("lena.jpg"), cv.IMREAD_GRAYSCALE)
img = img / np.float32(255)
dft = np.fft.fft2(img)
cv.imshow("1 dft", prepare_spectrum(dft))
dft_shift = np.fft.fftshift(dft)
cv.imshow("2 dft_shift", prepare_spectrum(dft_shift))
rows, cols = img.shape
crow,ccol = (rows // 2), (cols // 2)
mask = np.zeros((rows,cols), dtype=np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
dft_shift *= mask
cv.imshow("3 dft_shift masked", prepare_spectrum(dft_shift))
dft = np.fft.ifftshift(dft_shift)
cv.imshow("4 dft masked", prepare_spectrum(dft))
img_back = np.fft.ifft2(dft)
img_back = np.real(img_back)
cv.imshow('before', img)
cv.imshow('after', img_back)
cv.waitKey()
cv.destroyAllWindows()
Почему брать действительную составляющую предпочтительнее, чем брать величину?