/// <summary>
        /// Voer een voorwaards Fourier analyse uit
        /// </summary>
        /// <param name="greyArray"></param>
        /// <returns>Object met: [0] Fourier resultset, [1] Bitmap Modulus plot, [2] Bitmap Argument plot</returns>
        public static Object[] forwardFFT(int[,] greyArray, bool shift, int scale1, int scale2)
        {
            // Ons return object
            Object[] ret = new Object[3];

            // Maak een container object aan voor de complexe getallen
            // Nu hebben we nog reële getallen maar na da Fourier analyse
            // Bekomen we imaginaire getallen
            ComplexGetal[,] complexeArray = new ComplexGetal[greyArray.GetLength(0), greyArray.GetLength(1)];

            // Vul de complexe array op
            for (int i = 0; i < greyArray.GetLength(0); i++) {
                for (int j = 0; j < greyArray.GetLength(1); j++) {
                    complexeArray[i, j] = new ComplexGetal(greyArray[i, j], 0);
                }
            }

            // Voer de Fourier analyse uit
            complexeArray = FFT2D(complexeArray, FourierDirection.Forward);
            ret[0] = complexeArray;

            // Moeten de plot grafieken genormaliseerd worden?
            if (shift) complexeArray = shiftFFTResult(complexeArray);

            // Maak een plot a.d.h.v. de modulus (Magnitude)
            ret[1] = plotMod(complexeArray, scale1);

            // Maak een plot a.d.h.v. het argument (Phase)
            ret[2] = plotArg(complexeArray, scale2);

            // Geef de waarden terug
            return ret;
        }
        /// <summary>
        /// Maak van een Fourier resultset opnieuw een afbeelding
        /// </summary>
        /// <param name="fourier">De Fourier set</param>
        /// <returns>De geproduceerde grijs-waarden afbeelding</returns>
        public static Bitmap backwardFFT(ComplexGetal[,] fourier)
        {
            float[,] greyscale = new float[fourier.GetLength(0),fourier.GetLength(1)];

            fourier = FFT2D(fourier, FourierDirection.Backward);

            for (int i = 0; i < fourier.GetLength(0); i++) {
                for (int j = 0; j < fourier.GetLength(1); j++) {
                    greyscale[i, j] = fourier[i, j].Modulus;
                }
            }

            return createImage(greyscale, 1);
        }
        /// <summary>
        /// Hersorteer de meegegeven Fourier resultatenset van een indeling met de oorsprong in 0,0
        /// O -   -  --->
        /// |1,1 1,2 ..
        /// |2,1 2,2 ..
        /// |..  ..
        /// V
        ///
        /// Naar een met de oorsprong in het midden
        ///
        ///             ^
        ///  1,-2  1,-1 |  1,1  1,2
        ///   -     -   O   -    -   --->
        /// -1,-2 -1,-1 | -1,1 -1,2
        ///             V
        ///
        /// Referentie https://www.youtube.com/watch?v=X53SrMnu91A
        /// </summary>
        /// <param name="result">Te herindelen set</param>
        /// <returns>aangepaste set</returns>
        private static ComplexGetal[,] shiftFFTResult(ComplexGetal[,] result)
        {
            int a = result.GetLength(0);
            int b = result.GetLength(1);

            ComplexGetal[,] shiftResult = new ComplexGetal[a, b];

            for (int i = 0; i < (a / 2); i++)
            {
                for (int j = 0; j < (b / 2); j++)
                {
                    shiftResult[i + (a / 2), j + (b / 2)] = result[i, j];
                    shiftResult[i + (a / 2), j]           = result[i, j + (b / 2)];
                    shiftResult[i, j + (b / 2)]           = result[i + (a / 2), j];
                    shiftResult[i, j] = result[i + (a / 2), j + (b / 2)];
                }
            }

            return(shiftResult);
        }
        /// <summary>
        /// Voer een voorwaards Fourier analyse uit
        /// </summary>
        /// <param name="greyArray"></param>
        /// <returns>Object met: [0] Fourier resultset, [1] Bitmap Modulus plot, [2] Bitmap Argument plot</returns>
        public static Object[] forwardFFT(int[,] greyArray, bool shift, int scale1, int scale2)
        {
            // Ons return object
            Object[] ret = new Object[3];

            // Maak een container object aan voor de complexe getallen
            // Nu hebben we nog reële getallen maar na da Fourier analyse
            // Bekomen we imaginaire getallen
            ComplexGetal[,] complexeArray = new ComplexGetal[greyArray.GetLength(0), greyArray.GetLength(1)];

            // Vul de complexe array op
            for (int i = 0; i < greyArray.GetLength(0); i++)
            {
                for (int j = 0; j < greyArray.GetLength(1); j++)
                {
                    complexeArray[i, j] = new ComplexGetal(greyArray[i, j], 0);
                }
            }

            // Voer de Fourier analyse uit
            complexeArray = FFT2D(complexeArray, FourierDirection.Forward);
            ret[0]        = complexeArray;

            // Moeten de plot grafieken genormaliseerd worden?
            if (shift)
            {
                complexeArray = shiftFFTResult(complexeArray);
            }

            // Maak een plot a.d.h.v. de modulus (Magnitude)
            ret[1] = plotMod(complexeArray, scale1);

            // Maak een plot a.d.h.v. het argument (Phase)
            ret[2] = plotArg(complexeArray, scale2);

            // Geef de waarden terug
            return(ret);
        }
        /// <summary>
        /// Hersorteer de meegegeven Fourier resultatenset van een indeling met de oorsprong in 0,0
        /// O -   -  --->
        /// |1,1 1,2 ..
        /// |2,1 2,2 ..
        /// |..  .. 
        /// V
        /// 
        /// Naar een met de oorsprong in het midden
        /// 
        ///             ^
        ///  1,-2  1,-1 |  1,1  1,2
        ///   -     -   O   -    -   --->
        /// -1,-2 -1,-1 | -1,1 -1,2
        ///             V
        /// 
        /// Referentie https://www.youtube.com/watch?v=X53SrMnu91A
        /// </summary>
        /// <param name="result">Te herindelen set</param>
        /// <returns>aangepaste set</returns>
        private static ComplexGetal[,] shiftFFTResult(ComplexGetal[,] result)
        {
            int a = result.GetLength(0);
            int b = result.GetLength(1);
            ComplexGetal[,] shiftResult = new ComplexGetal[a, b];

            for (int i = 0; i < (a / 2); i++) {
                for (int j = 0; j < (b / 2); j++) {
                    shiftResult[i + (a / 2), j + (b / 2)] = result[i, j];
                    shiftResult[i + (a / 2), j] = result[i, j + (b / 2)];
                    shiftResult[i, j + (b / 2)] = result[i + (a / 2), j];
                    shiftResult[i, j] = result[i + (a / 2), j + (b / 2)];
                }
            }

            return shiftResult;
        }
        /// <summary>
        /// Maak een amplitude plot aan de hand van de modulus van de imaginaire getallen
        /// </summary>
        /// <param name="array">Fourier resultset</param>
        /// <param name="scale">Herschaling van de amplitude plot</param>
        /// <returns>Bitmap</returns>
        private static Bitmap plotMod(ComplexGetal[,] array, int scale)
        {
            float[,] modulusPlot = new float[array.GetLength(0),array.GetLength(1)];
            float max = 0;

            // Plaats de Modulus van ieder complex getal in een multidimensionale float array
            // De Modulus wordt berekend door de ComplexGetal klasse.
            for (int i = 0; i < array.GetLength(0); i++) {
                for (int j = 0; j < array.GetLength(1); j++) {
                    modulusPlot[i, j] = (float)Math.Log(1 + array[i, j].Modulus);

                    // Bepaal de hoogste waarde
                    if (modulusPlot[i, j] > max) max = modulusPlot[i, j];
                }
            }

            // Herschaal alle waarden met als referentie de hoogste waarde (100%)
            for (int i = 0; i < modulusPlot.GetLength(0); i++) {
                for (int j = 0; j < modulusPlot.GetLength(1); j++) {
                    modulusPlot[i, j] /= max;
                }
            }

            return createImage(modulusPlot, scale);
        }
        /// <summary>
        /// Maak een fase plot aan de hand van het Imaginair argument
        /// </summary>
        /// <param name="array">Fourier resultset</param>
        /// <param name="scale">Herschaling van de fase plot</param>
        /// <returns>Bitmap</returns>
        private static Bitmap plotArg(ComplexGetal[,] array, int scale)
        {
            float[,] argumentPlot = new float[array.GetLength(0), array.GetLength(1)];
            float max = 0;

            // Plaats het argument van ieder complex getal in een multidimensionale float array
            // Het argument wordt berekend door de ComplexGetal klasse.
            for (int i = 0; i < array.GetLength(0); i++) {
                for (int j = 0; j < array.GetLength(1); j++) {
                    argumentPlot[i, j] = (float)Math.Log(1 + Math.Abs(array[i, j].Argument));

                    // Bepaal de hoogste waarde
                    if (argumentPlot[i, j] > max) max = argumentPlot[i, j];
                }
            }

            // Herschaal alle waarden met als referentie de hoogste waarde (100%)
            for (int i = 0; i < argumentPlot.GetLength(0); i++) {
                for (int j = 0; j < argumentPlot.GetLength(1); j++) {
                    argumentPlot[i, j] = argumentPlot[i, j] / max;
                }
            }

            return createImage(argumentPlot, scale);
        }
        /// <summary>
        /// Voert een 2 dimensionale Fourier analyse uit op een afbeelding
        /// </summary>
        /// <param name="invoer">De complexe waarden van de afbeelding</param>
        /// <param name="dir">FourierDirection.Forward or FourierDirection.Backward</param>
        /// <returns>Fourier resultset</returns>
        private static ComplexGetal[,] FFT2D(ComplexGetal[,] invoer, FourierDirection dir)
        {
            float[] reëel = new float[invoer.GetLength(1)];
            float[] imaginair = new float[invoer.GetLength(1)];
            ComplexGetal[,] resultaat = invoer;

            //rijen
            for (int i = 0; i < invoer.GetLength(0); i++) {
                // Plaats de waarden in een 1 dimensionale array
                for (int j = 0; j < invoer.GetLength(1); j++) {
                    reëel[j] = invoer[i, j].Reëel;
                    imaginair[j] = invoer[i, j].Imaginair;
                }

                // Voer een 1 dimensionale fourier analyse uit op de huidige rij
                FFT1D(dir, reëel, imaginair);

                // Plaats de waarden in het resultaat object
                for (int j = 0; j < resultaat.GetLength(1); j++) {
                    resultaat[i, j].Reëel = reëel[j];
                    resultaat[i, j].Imaginair = imaginair[j];
                }
            }

            //kolommen - gebruik nu het resultaat object, anders gaan de berekeningen van de rijen verloren
            for (int i = 0; i < resultaat.GetLength(1); i++) {
                // Plaats de waarden in een 1 dimensionale array
                for (int j = 0; j < resultaat.GetLength(0); j++) {
                    reëel[j] = resultaat[j, i].Reëel;
                    imaginair[j] = resultaat[j, i].Imaginair;
                }

                // Voer een 1 dimensionale fourier analyse uit op de huidige kolom
                FFT1D(dir, reëel, imaginair);

                // Plaats de waarden in het resultaat object
                for (int j = 0; j < resultaat.GetLength(0); j++) {
                    resultaat[j, i].Reëel = reëel[j];
                    resultaat[j, i].Imaginair = imaginair[j];
                }
            }

            return resultaat;
        }