Click here to Skip to main content
15,886,137 members
Articles / Programming Languages / Visual Basic
Tip/Trick

Perform a 2D Fourier Transform with the Package mathnet.numerics

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
9 Mar 2021CPOL2 min read 10.9K   173   10   13
How to compute a 2D Fourier Transform using the nuget package "mathnet.numerics"
In this tip, you will see how to use the mathnet.numerics library to compute a 2D FFT. You will also learn how to use a mathnet complex32 array to return amplitude and phase of the complex numbers and aggregate functions.

Introduction

This tip shows how to perform a 2D FFT in VB.NET for arbitrary image sizes using the freely available mathnet.numerics library.

Background

The nuget package "mathnet.numerics" for VB.NET provides a 1D Fourier Transform, but no multidimensional FFT. However, the 1D transform can be used to compute a 2D Fourier transform for processing image data by transforming first the rows and then the columns using the 1D FFT (or the other way round). I have shown how to read/write the image data of a bitmap in a separate article.

Using the Code

  • Import the nuget package mathnet.numerics
  • Define a complex32 array from the mathnet numerics library
  • Fill the array with image data,
  • For all rows: read out the ith row using "in_row = arr.Row(i).ToArray"
  • Perform the 1D FFT for the ith row
  • Write the result back into the row using "arr.SetRow(in_row)"
  • For all columns: read out the jth column using "in_col = arr.Column(i).ToArray"
  • Perform the 1D FFT for the jth column
  • Write the result back into the column using "arr.SetColumn(in_col)"
VB.NET
Imports mnum = MathNet.Numerics

Dim arr As New mnum.LinearAlgebra.Complex32.DenseMatrix(Height, Width)

'Fill arr with data....
For i = 0 To Height - 1
    For j = 0 To Width - 1
    'read out value from bitmap...
    arr(i, j) = New mnum.Complex32(value, 0.0)
    next 'j
next 'i

'then transform arr, first the rows
For i = 0 To Height - 1
              
    in_row = arr.Row(i).ToArray
    mnum.IntegralTransforms.Fourier.Forward(in_row)
    arr.SetRow(i, in_row)

Next 'loop over the rows

'now loop over the columns to transform the columns
For j = 0 To Width - 1
    in_col = arr.Column(j).ToArray
    mnum.IntegralTransforms.Fourier.Forward(in_col)
    arr.SetColumn(j, in_col)
Next 'loop over columns

'the 2D Fourier transform is now stored in the array "arr"
'do some evaluation with amplitudes and phases, for example

'read out the amplitude
Dim magnitude as double 
magnitude = arr(i, j).Magnitude
'determine the maximum amplitude
maxval = arr.Enumerate().Max(Function(x) mnum.Complex32.Abs(x))

'read out the phase
Dim phase as double
phase = arr(i, j).Phase
'determine the maximum phase
maxval = arr.Enumerate().Max(Function(x As mnum.Complex32) Math.Abs(x.Phase))

When it comes to displaying the 2D FFT data (amplitude and phase) there are two things to note: 
- the amplitudes should be scaled with a dynamic range compression or otherwise the image will appear completely black. In my case I used the function f(x) = log(1+x)/log(1+max(x))*255, where 255 is the intensity range of a color channel for one pixel. You could also use other concave functions, such as sqrt(x), sqrt(1+x) or log(1+log(1+x)) for dynamic range compression. 
- the quadrants should be swapped so that zero frequency is at the center of the image. I used the following vb.net function: 
 

VB.NET
Function FFTShift(FFTmat As mnum.LinearAlgebra.Matrix(Of mnum.Complex32)) As mnum.LinearAlgebra.Matrix(Of mnum.Complex32)

        Dim i, j As Integer
        Dim i_shift, j_shift As Integer
        Dim i_max, j_max As Integer
        
        i_shift = FFTmat.RowCount
        If isEven(i_shift) Then
            i_shift = i_shift / 2
        Else
             i_shift = i_shift \ 2 + 1
        End If
        i_max = FFTmat.RowCount \ 2

        j_shift = FFTmat.ColumnCount

        If isEven(j_shift) Then
             j_shift = j_shift / 2
        Else
            j_shift = j_shift \ 2 + 1
        End If
        j_max = FFTmat.ColumnCount \ 2

        Dim FFTShifted As New mnum.LinearAlgebra.Complex32.DenseMatrix(FFTmat.RowCount, FFTmat.ColumnCount)

        For i = 0 To i_max - 1
             For j = 0 To j_max - 1
                FFTShifted(i + i_shift, j + j_shift) = FFTmat(i, j)
                FFTShifted(i, j) = FFTmat(i + i_shift, j + j_shift)
                FFTShifted(i + i_shift, j) = FFTmat(i, j + j_shift)
                FFTShifted(i, j + j_shift) = FFTmat(i + i_shift, j)
             Next
        Next

        Return FFTShifted
End Function

For the well known "cameraman" picture, the ampitude and phase of the 2D FFT would look like this:

Image 1

Points of Interest

The FFT from mathnet numerics is not limited to data with a height and width equal to a power of two. Rather, it can be used to process images of arbitrary sizes (up to a maximum size). The possibility to slice the data by accessing the rows and columns of a mathnet array is useful in this context. Even though the image data are usually real numbers, the data must be supplied as complex numbers to the FFT function. Another interesting point to note is that a mathnet.numerics array can return an enumerator which can be used to calculate an aggregate function, such as max, min, median, average, etc. The aggregate is supplied as a lambda function. In VB.NET, the lambda function takes the syntax "Function(x As Datatype) function body".

History

  • 1st March, 2021: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
jasin kuiken12-Mar-21 0:47
jasin kuiken12-Mar-21 0:47 
GeneralMy vote of 5 Pin
jasin kuiken12-Mar-21 0:47
jasin kuiken12-Mar-21 0:47 
QuestionCode Fragment Pin
Member 66623714-Mar-21 12:26
Member 66623714-Mar-21 12:26 
AnswerRe: Code Fragment Pin
jkluge7-Mar-21 9:16
jkluge7-Mar-21 9:16 
GeneralRe: Code Fragment Pin
Member 66623717-Mar-21 10:10
Member 66623717-Mar-21 10:10 
GeneralRe: Code Fragment Pin
jkluge7-Mar-21 18:40
jkluge7-Mar-21 18:40 
GeneralRe: Code Fragment Pin
Member 66623718-Mar-21 9:06
Member 66623718-Mar-21 9:06 
GeneralRe: Code Fragment Pin
jkluge8-Mar-21 10:08
jkluge8-Mar-21 10:08 
GeneralRe: Code Fragment Pin
Member 66623718-Mar-21 11:07
Member 66623718-Mar-21 11:07 
Questiondoes this make sense ? Pin
Member 117206812-Mar-21 11:02
Member 117206812-Mar-21 11:02 
AnswerRe: does this make sense ? YES Pin
jkluge3-Mar-21 5:14
jkluge3-Mar-21 5:14 
GeneralRe: does this make sense ? YES Pin
Member 117206813-Mar-21 6:20
Member 117206813-Mar-21 6:20 
GeneralRe: does this make sense ? YES Pin
jkluge3-Mar-21 8:14
jkluge3-Mar-21 8:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.