IFFT FFT-изображения приводит к странному переворачиванию исходного изображения вверх дном - PullRequest
2 голосов
/ 01 марта 2020

В следующем коде у меня есть функция, которая возвращает изображение, обрезанное по центру круга определенного радиуса. Затем я выполняю преобразование Фурье изображения и снова обращаюсь к преобразованию Фурье, чтобы восстановить изображение, которое работает нормально.

Затем я рассчитал, что центрированный круг с радиусом 43 энергетического спектра ( исключено здесь) даст 99% энергии исходного изображения. Но когда я пытаюсь применить свою функцию «imgRadius» к амплитудному спектру (изображение, преобразованное Фурье), а затем выполнить обратное преобразование Фурье для этого изображения, я получаю это странное переворачивание исходного изображения вверх ногами *. 1003 *

def imgRadius(img, radius):
    result = np.zeros(img.shape,np.float64)
    centerX = (img.shape[0])/2
    centerY = (img.shape[1])/2
    for m in range(img.shape[0]):
        for n in range(img.shape[1]):
            if math.sqrt((m-centerX)**2+(n-centerY)**2) < radius:
                result[m,n] = img[m,n]
    return result

imgpath = directory+"NorbertWiener.JPG"
img = cv.imread(imgpath, cv.IMREAD_GRAYSCALE)
norm_image = cv.normalize(img, None, alpha=0, beta=1, norm_type=cv.NORM_MINMAX, dtype=cv.CV_32F)
amp = (np.fft.fftshift(np.fft.fft2(norm_image)))
amp_log = np.log(np.abs(amp))
norm_amp = cv.normalize(amp_log, None, alpha=0, beta=1, norm_type=cv.NORM_MINMAX, dtype=cv.CV_32F)
restoredAMP = np.abs(np.fft.ifft2(np.fft.ifftshift(amp)))
radamp = imgRadius(norm_amp,43)
rest99 = np.abs(np.fft.ifft2((imgRadius(amp,43))))

plt.subplot(231),plt.imshow(norm_image, "gray", vmin=0, vmax=1),plt.title('Image')
plt.xticks([]), plt.yticks([])
plt.subplot(232),plt.imshow(norm_amp, "gray", vmin=0, vmax=1),plt.title('Amplitude')
plt.xticks([]), plt.yticks([])
plt.subplot(233),plt.imshow(restoredAMP, "gray", vmin=0, vmax=1),plt.title('Restored from amplitude')
plt.xticks([]), plt.yticks([])
plt.subplot(235),plt.imshow(rest99, "gray", vmin=0, vmax=1),plt.title('Restored from r=43')
plt.xticks([]), plt.yticks([])
plt.subplot(234),plt.imshow(radamp, "gray", vmin=0, vmax=1),plt.title('Amplitude r=43')
plt.xticks([]), plt.yticks([])
plt.show()

See the resulting subplots here

Это как-то связано с тем, что я использую абсолютные значения? Я не понимаю, как мне удастся построить изображение, не избавляясь от мнимых частей изображений, но я вижу, как, возможно, некоторая информация теряется в обратном FFT.

Я просто не Не понимаю, почему у меня не возникает проблем при выполнении IFFT для исходного спектра амплитуд.

Ответы [ 3 ]

3 голосов
/ 02 марта 2020

Проблема возникает здесь:

def imgRadius(img, radius):
    result = np.zeros(img.shape,np.float64)

Вы создаете массив с действительными значениями и копируете сложные значения. Вероятно, либо реальный компонент, либо величина записывается в массив. В любом случае комплексные данные в частотной области становятся реальными. Обратное преобразование - это симметричная матрица c.

Чтобы решить эту проблему, инициализируйте result как комплексный массив.

После этого убедитесь, что используется действительный компонент обратное преобразование, а не величина, как Джанлука уже предложил в своем ответе .

3 голосов
/ 01 марта 2020

Отказ от мнимой части БПФ (а также знака действительной части) - это как раз то, что приводит к «сворачиванию» перевернутого изображения в себя. БПФ функции, симметрично c относительно ее происхождения, является действительным (т. Е. Мнимой частью 0). Отбрасывая мнимую часть, изображение, таким образом, было как-то «симметризовано».

После выполнения операций со сложным результатом БПФ в пространстве Фурье можно взять обратное БПФ, а затем построить только действительную часть np.fft.ifft2((imgRadius(amp,43))).real этого.

2 голосов
/ 02 марта 2020

Следующее работает для меня в Python / OpenCV / Numpy и показывает разницу между использованием острого граничного круга и сглаженного гауссовым размытием для смягчения звонких артефактов

Ввод:

enter image description here

import numpy as np
import cv2

# read input and convert to grayscale
img = cv2.imread('lena_gray.png', cv2.IMREAD_GRAYSCALE)

# do dft saving as complex output
dft = np.fft.fft2(img)

# apply shift of origin to center of image
dft_shift = np.fft.fftshift(dft)

# generate spectrum from magnitude image (for viewing only)
mag = np.abs(dft_shift)
spec = np.log(mag) / 20

# create circle mask
radius = 32
mask = np.zeros_like(img)
cy = mask.shape[0] // 2
cx = mask.shape[1] // 2
cv2.circle(mask, (cx,cy), radius, (255,255,255), -1)[0]

# blur the mask
mask2 = cv2.GaussianBlur(mask, (19,19), 0)

# apply mask to dft_shift
dft_shift_masked = np.multiply(dft_shift,mask) / 255
dft_shift_masked2 = np.multiply(dft_shift,mask2) / 255


# shift origin from center to upper left corner
back_ishift = np.fft.ifftshift(dft_shift)
back_ishift_masked = np.fft.ifftshift(dft_shift_masked)
back_ishift_masked2 = np.fft.ifftshift(dft_shift_masked2)


# do idft saving as complex output
img_back = np.fft.ifft2(back_ishift)
img_filtered = np.fft.ifft2(back_ishift_masked)
img_filtered2 = np.fft.ifft2(back_ishift_masked2)

# combine complex components to form original image again
img_back = np.abs(img_back).clip(0,255).astype(np.uint8)
img_filtered = np.abs(img_filtered).clip(0,255).astype(np.uint8)
img_filtered2 = np.abs(img_filtered2).clip(0,255).astype(np.uint8)


cv2.imshow("ORIGINAL", img)
cv2.imshow("SPECTRUM", spec)
cv2.imshow("MASK", mask)
cv2.imshow("MASK2", mask2)
cv2.imshow("ORIGINAL DFT/IFT ROUND TRIP", img_back)
cv2.imshow("FILTERED DFT/IFT ROUND TRIP", img_filtered)
cv2.imshow("FILTERED2 DFT/IFT ROUND TRIP", img_filtered2)
cv2.waitKey(0)
cv2.destroyAllWindows()

# write result to disk
cv2.imwrite("lena_dft_numpy_mask.png", mask)
cv2.imwrite("lena_dft_numpy_mask_blurred.png", mask2)
cv2.imwrite("lena_dft_numpy_roundtrip.png", img_back)
cv2.imwrite("lena_dft_numpy_lowpass_filtered1.png", img_filtered)
cv2.imwrite("lena_dft_numpy_lowpass_filtered2.png", img_filtered2)


Sharp Mask:

enter image description here

Размытая маска:

enter image description here

Простое круговое путешествие:

enter image description here

Низкий Проходной отфильтрованный результат по резкой маске (очевидный звонок):

enter image description here

Низкочастотный отфильтрованный результат по размытой маске (обзвон ослаблен):

enter image description here

...