繁体   English   中英

FFT 图像的 IFFT 导致原始图像奇怪的倒置重叠

[英]IFFT of FFT-image results in weird upside-down overlap of original image

在下面的代码中,我有一个函数,它返回裁剪到某个半径的中心圆的图像。 然后我对图像进行傅立叶变换,再次逆傅立叶变换,以恢复图像,效果很好。

然后我计算出,半径为 43 的能量谱(此处不包括)的中心圆将产生原始图像能量的 99%。 但是当我尝试将我的函数“imgRadius”应用于幅度谱(傅立叶变换图像),然后对该图像执行傅立叶逆变换时,我得到了原始图像的这种奇怪的倒置重叠。

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()

在此处查看生成的子图

它与我使用绝对值的事实有什么关系吗? 我不明白我应该如何在不去除图像的虚部的情况下绘制图像,但我可以看到一些信息如何在逆 fft 中丢失。

我只是不明白为什么在原始幅度谱上执行 IFFT 时我没有遇到问题。

丢弃 FFT 的虚部(以及实部的符号)正是导致倒置图像“回折”到自身的问题所在。 一个关于其原点对称的函数的 FFT 是实数(即虚部 0)。 通过丢弃虚部,图像因此以某种方式“对称化”。

在傅里叶空间对复数FFT结果进行运算后,可以进行逆FFT,然后只绘制它的实部np.fft.ifft2((imgRadius(amp,43))).real

以下在 Python/OpenCV/Numpy 中对我有用,并显示了使用尖锐边界圆和通过高斯模糊平滑以减轻振铃伪影的区别

输入:

在此处输入图片说明

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)


锋利的面具:

在此处输入图片说明

模糊蒙版:

在此处输入图片说明

简单往返:

在此处输入图片说明

来自锐利掩模的低通滤波结果(振铃明显):

在此处输入图片说明

模糊蒙版的低通滤波结果(减轻了振铃):

在此处输入图片说明

问题发生在这里:

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

您正在创建一个实数值数组,并复制复数值。 可能将实数分量或幅度写入数组。 在任何情况下,复值频域数据都变为实值。 逆变换是一个对称矩阵。

为了解决这个问题,将result初始化为复数值数组。

在此之后,确保使用逆变换的实部分量,而不是幅度,正如Gianluca 在他们的回答中已经建议的那样

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM