Take FFT of an Image in Google Go

fft, go, signal-processing

Solution

You have two options, both involve copying the pixels. You can either use the methods provided by the `Image` interface, namely `At(x,y)` or you can assert the image to one of the image types provided by the `image` packet and access the `Pix` attribute directly.

Since you will most likely be using a Gray image, you could easily assert your image to type `*image.Gray` and access the pixels directly but for the sake of abstraction I did not in my example:

inImage, _, err := image.Decode(inFile)

// error checking

bounds := inImage.Bounds()

realPixels := make([][]float64, bounds.Dy())

for y := 0; y < bounds.Dy(); y++ {
    realPixels[y] = make([]float64, bounds.Dx())
    for x := 0; x < bounds.Dx(); x++ {
        r, _, _, _ := inImage.At(x, y).RGBA()
        realPixels[y][x] = float64(r)
    }
}

This way you read all the pixels of your image `inImage` and store them as `float64` values in a two-dimensional slice, ready to be processed by `fft.FFT2Real`:

// apply discrete fourier transform on realPixels.
coeffs := fft.FFT2Real(realPixels)

// use inverse fourier transform to transform fft 
// values back to the original image.
coeffs = fft.IFFT2(coeffs)

// write everything to a new image
outImage := image.NewGray(bounds)

for y := 0; y < bounds.Dy(); y++ {
    for x := 0; x < bounds.Dx(); x++ {
        px := uint8(cmplx.Abs(coeffs[y][x]))
        outImage.SetGray(x, y, color.Gray{px})
    }
}

err = png.Encode(outFile, outImage)

In the code above I applied FFT on the pixels stored in `realPixels` and then, to see whether it worked, used inverse FFT on the result. The expected result is the original image.

A full example can be found here.

Problem

How do you take the FFT of an image in Google Go? The Go DSP library (github.com/mjibson/go-dsp/fft) has a function for a 2D FFT with the following signature: ``` func FFT2Real(x [][]float64) [][]complex128 ``` How do I convert an image from the standard go image types to float64? Is this the right approach? Here is a link to the documentation.

Original source