/// <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; }