/** This demonstrates using Fourier transforms to process an image, obtain its
Fourier transform, display the Fourier transform in a logarithmic scale,
and then invert the transform to produce the original image. */
// Image available at https://frinklang.org/frinksamp/AudreyHepburnMoire.jpg
// It has a noisy Moire pattern
img = new image["file:AudreyHepburnMoire.jpg"]
// Comment in the resize below to test different image sizes.
//img = img.resize[undef, 1024]
[origWidth, origHeight] = img.getSize[]
println["image size is [$origWidth, $origHeight]"]
// Make the image into an efficient data structure (ComplexArray) and then
// take its two-dimensional Fourier transform.
array = img.toComplexArray[]
ff = FFT[array]
// Encode the image into an image that contains magnitude-phase components.
// The magnitude is encoded into the green channel on a logarithmic scale,
// and the phase is encoded into the red channel.
// If the flag below is true, this assumes the DC component is in the
// center of the image. This needs to match the value in the
// .toComplexArrayFromLog call below.
img2f = ff.toLogImage[true]
println["Resultant image size from FFT is " + img2f.getSize[]]
img2f.show["FFT Magnitude-Phase"]
img2f.write["fft.png"]
// Reverse the FFT of the image and display it. This is all done in memory
// and should preserve the original image very closely.
inverseF = inverseFFT[ff]
inverseImgF = inverseF.toImage[origWidth, origHeight]
inverseImgF.show["Inverse FFT"]
inverseImgF.write["reconstructed.png"]
// Reverse the magnitude-phase encoded image into the original image. This
// has gone through a few levels of re-encoding, but the result should look
// like the original image.
// If the flag below is true, this assumes the DC component is in the
// center of the image. This needs to match the value in the .toLogImage call
// above.
a2 = img2f.toComplexArrayFromLog[true]
ia = inverseFFT[a2]
back = ia.toImage[origWidth, origHeight]
back.show["Inverse from FFT Magnitude-Phase image"]