pythonfftpython-2.xphasemagnitude

Magnitude only reconstruction doesn't look correct, am I interpreting this correctly?


I have implemented a method from "Phase retrieval from the magnitude of the Fourier transforms of nonperiodic objects" paper available at: https://pdfs.semanticscholar.org/4796/592751aaa5b316aaefbd5eab09ca51fad580.pdf

in which the authors reconstruct an object by oversampling and then using the magnitude following an HIO iterative process.

Reading the paper the figure section states: "Examples of image reconstruction from the magnitude of the Fourier transforms of complex-valued objects by oversampling;"

When I reconstruct only using the magnitude I get what looks like a blank image. Am I doing this correctly? Did I misinterpret the meaning of the paper?

import matplotlib.pyplot as plt
import numpy as np
import scipy.ndimage as nd

img = nd.imread("einstein.bmp", flatten=True)

numIters = 500

# Pad image to simulate oversampling
initSize = img.shape
pad_len = 64
padded = np.pad(img, ((pad_len, pad_len), (pad_len, pad_len)), 'constant')

# Get initial magnitude
targetImg = np.fft.fftshift(np.fft.fft2(padded))
F_mag = np.abs(targetImg)
# Save for plotting later
startMag = np.abs(np.fft.ifft2(np.fft.ifftshift(F_mag)))
startPhase = np.angle(targetImg)

# keep track of where the image is vs the padding
mask = np.ones((initSize[0], initSize[1]))
mask = np.pad(mask, ((pad_len, pad_len), (pad_len, pad_len)), 'constant')

# Paper uses random phase for phase, adding noise here
noise = np.random.normal(0,1.5,(initSize[0], initSize[1]))
noise = np.pad(noise, ((pad_len, pad_len), (pad_len, pad_len)), 'constant')
source = F_mag * np.exp(1j * (startPhase + noise))

# Shift first then transform for inverse
imgWithNoise = np.abs(np.fft.ifft2(np.fft.ifftshift(source))) * mask
sourceImg = np.abs(np.fft.ifft2(np.fft.ifftshift(source))) * mask

# Test for proper image
# imgplot = plt.imshow(sourceImg)
# plt.show()

beta=0.8
for i in range(numIters):
    print "Progress on: " + str(i) + " Of " + str(numIters)
    G_k = np.fft.fftshift(np.fft.fft2(sourceImg))
    G_k_phase = np.angle(G_k)
    G_k_prime = F_mag * np.exp(1j*G_k_phase)
    g_k_prime = np.fft.ifft2(np.fft.ifftshift(G_k_prime))

    # In support i.e non negative real and imaginary
    real_g_k = np.real(g_k_prime)
    imag_g_k = np.imag(g_k_prime)
    # x_e_S = np.where(((real_g_k > 0) & (imag_g_k > 0)))
    x_e_notS = np.where(((real_g_k <= 0) & (imag_g_k <= 0) & (mask == 1)) | (mask == 0))

    tmp = g_k_prime
    beta_g_k_prime = beta * g_k_prime[x_e_notS]
    tmp[x_e_notS] = sourceImg[x_e_notS] - beta_g_k_prime
    sourceImg = tmp

G_k = np.fft.fftshift(np.fft.fft2(sourceImg))
finalMag = np.abs(G_k)
finalMagImg = np.abs(np.fft.ifft2(np.fft.ifftshift(finalMag)))

# Show magnitude plot
plt.subplot(231),plt.imshow(padded)
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(232),plt.imshow(np.abs(imgWithNoise))
plt.title('Image with Noise'), plt.xticks([]), plt.yticks([])
plt.subplot(233),plt.imshow(np.abs(sourceImg))
plt.title('Image after HIO'), plt.xticks([]), plt.yticks([])
plt.subplot(234),plt.imshow(startMag)
plt.title('Start Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.subplot(235),plt.imshow(finalMagImg)
plt.title('End Magnitude Spectrum Img'), plt.xticks([]), plt.yticks([])
plt.subplot(236),plt.imshow(finalMag)
plt.title('End Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

enter image description here


Solution

  • You did misunderstand the paper. They retrieve the phase using only magnitude information, which is different from applying the IDFT using only magnitude information.

    Your FinalMagImg is not empty, it has a peak at the top-left corner. Apply fftshift to move it to the center, and apply logarithmic mapping to see the rest of the data. This is what an inverse DFT looks like if the phase is all zero.