Почему 2d FFT дает абсолютно черный вывод? - PullRequest
0 голосов
/ 26 сентября 2018

Примечание: Я решил проблему.

Я взял FourierTransform - класс из AForge.net и изменил его так, чтобы он мог работать с System.Numerics.Complex.

Я попытался показать, может ли он показать спектр значений Фурье.Но моя тестовая программа выдает пустой вывод следующим образом:

enter image description here

Я попытался изменить масштабирование следующим образом:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        Bitmap bmp = Bitmap.FromFile("lenagr.png") as Bitmap;
        pictureBox1.Image = bmp;

        Complex[,] cImage = ToComplex(bmp);

        FourierTransform.FFT2(cImage, FourierTransform.Direction.Forward);

        int[,] intImage = ToInteger(cImage);

        intImage = Rescale(intImage);

        Bitmap bmpMagImg = ToBitmap(intImage, PixelFormat.Format24bppRgb);
        pictureBox2.Image = bmpMagImg;
    }

    public static int[,] Rescale(int[,]image)
    {
        int[,] imageCopy = (int[,])image.Clone();

        int Width = imageCopy.GetLength(0);
        int Height = imageCopy.GetLength(1);

        int minVal = 0;
        int maxVal = 0;

        for (int j = 0; j < Height; j++)
        {
            for (int i = 0; i < Width; i++)
            {
                int conv = imageCopy[i, j];

                minVal = Math.Min(minVal, conv);
                maxVal = Math.Max(maxVal, conv);
            }
        }

        int minRange = 0;
        int maxRange = 255;

        int[,] array2d = new int[Width, Height];

        for (int j = 0; j < Height; j++)
        {
            for (int i = 0; i < Width; i++)
            {
                array2d[i, j] = ConstraintInt(imageCopy[i, j], minVal, maxVal, minRange, maxRange);
            }
        }

        return array2d;
    }

    private static int ConstraintInt(int value, int minVal, int maxVal, int minRange, int maxRange)
    {
        return (maxRange - minRange) * (value - minVal) / (maxVal - minVal) + minRange;
    }
.... ....
}

снова, это никогда не работало.

Затем я попытался изменить масштабирование как двойное:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        Bitmap bmp = Bitmap.FromFile("lenagr.png") as Bitmap;
        pictureBox1.Image = bmp;

        Complex[,] cImage = ToComplex(bmp);

        FourierTransform.FFT2(cImage, FourierTransform.Direction.Forward);

        double[,] intImage = ToDouble(cImage);

        intImage = Rescale(intImage);

        Bitmap bmpMagImg = ToBitmap(intImage, PixelFormat.Format24bppRgb);
        pictureBox2.Image = bmpMagImg;
    }

    public double[,] ToDouble(Complex[,] image)
    {
        int Width = image.GetLength(0);
        int Height = image.GetLength(1);

        double[,] array2d = new double[Width, Height];

        for (int j = 0; j < Height; j++)
        {
            for (int i = 0; i < Width; i++)
            {
                array2d[i, j] = (double)image[i, j].Magnitude;
            }
        }

        return array2d;
    }

    public Bitmap ToBitmap(double[,] image, PixelFormat pixelFormat)
    {
        double[,] imageCopy = (double[,])image.Clone();

        // Image is Grayscale
        // Each element is scaled to (0-255) range.
        int Width = imageCopy.GetLength(0);
        int Height = imageCopy.GetLength(1);

        Bitmap bitmap = new Bitmap(Width, Height, pixelFormat);

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                // In case of a grayscale image, 
                // each pixel has same R,G, and B values.
                double d = imageCopy[x, y];

                int iii = Convert.ToInt32(d * 255.0);

                Color clr = Color.FromArgb(iii, iii, iii);

                bitmap.SetPixel(x, y, clr);
            }
        }

        Grayscale.SetPalette(bitmap);

        return bitmap;
    }

    public double[,] Rescale(double[,] image)
    {
        double[,] imageCopy = (double[,])image.Clone();

        int Width = imageCopy.GetLength(0);
        int Height = imageCopy.GetLength(1);

        double minVal = 0;
        double maxVal = 0;

        for (int j = 0; j < Height; j++)
        {
            for (int i = 0; i < Width; i++)
            {
                double conv = imageCopy[i, j];

                minVal = Math.Min(minVal, conv);
                maxVal = Math.Max(maxVal, conv);
            }
        }

        double minRange = 0.0;
        double maxRange = 1.0;

        double[,] array2d = new double[Width, Height];

        for (int j = 0; j < Height; j++)
        {
            for (int i = 0; i < Width; i++)
            {
                array2d[i, j] = ConstraintDouble(imageCopy[i, j], minVal, maxVal, minRange, maxRange);
            }
        }

        return array2d;
    }

    private double ConstraintDouble(double value, double minVal, double maxVal, double minRange, double maxRange)
    {
        return (maxRange - minRange) * (value - minVal) / (maxVal - minVal) + minRange;
    }
.... ....
}

снова, это никогда не работало.

Что такоеЯ делаю не так?

.

FourierTransform.cs

using System;
using System.Numerics;

public static class FourierTransform
{
    public enum Direction
    {
        Forward = 1,
        Backward = -1
    };

    public static void DFT(Complex[] data, Direction direction)
    {
        int n = data.Length;
        double arg, cos, sin;
        Complex[] dst = new Complex[n];

        for (int i = 0; i < n; i++)
        {
            dst[i] = Complex.Zero;

            arg = -(int)direction * 2.0 * System.Math.PI * (double)i / (double)n;

            for (int j = 0; j < n; j++)
            {
                cos = System.Math.Cos(j * arg);
                sin = System.Math.Sin(j * arg);

                double real = (data[j].Real * cos - data[j].Imaginary * sin);
                double imaginary = (data[j].Real * sin + data[j].Imaginary * cos);

                dst[i] = new Complex(dst[i].Real + real, dst[i].Imaginary + imaginary);
            }
        }

        if (direction == Direction.Forward)
        {
            for (int i = 0; i < n; i++)
            {
                double real = dst[i].Real / n;
                double imaginary = dst[i].Imaginary / n;

                data[i] = new Complex(real, imaginary);
            }
        }
        else
        {
            for (int i = 0; i < n; i++)
            {
                data[i] = new Complex(dst[i].Real, dst[i].Imaginary);
            }
        }
    }

    public static void DFT2(Complex[,] data, Direction direction)
    {
        int n = data.GetLength(0);  
        int m = data.GetLength(1);
        double arg, cos, sin;
        Complex[] dst = new Complex[System.Math.Max(n, m)];

        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                dst[j] = Complex.Zero;

                arg = -(int)direction * 2.0 * System.Math.PI * (double)j / (double)m;

                for (int k = 0; k < m; k++)
                {
                    cos = System.Math.Cos(k * arg);
                    sin = System.Math.Sin(k * arg);

                    double real = (data[i, k].Real * cos - data[i, k].Imaginary * sin);
                    double imaginary = (data[i, k].Real * sin + data[i, k].Imaginary * cos);

                    dst[j] = new Complex(dst[j].Real + real, dst[j].Imaginary + imaginary);
                }
            }

            if (direction == Direction.Forward)
            {
                for (int j = 0; j < m; j++)
                {
                    double real = dst[j].Real / m;
                    double imaginary = dst[j].Imaginary / m;

                    data[i, j] = new Complex(real, imaginary);
                }
            }
            else
            {
                for (int j = 0; j < m; j++)
                {
                    double real = dst[j].Real;
                    double imaginary = dst[j].Imaginary;

                    data[i, j] = new Complex(real, imaginary);
                }
            }
        }

        for (int j = 0; j < m; j++)
        {
            for (int i = 0; i < n; i++)
            {
                dst[i] = Complex.Zero;

                arg = -(int)direction * 2.0 * System.Math.PI * (double)i / (double)n;

                for (int k = 0; k < n; k++)
                {
                    cos = System.Math.Cos(k * arg);
                    sin = System.Math.Sin(k * arg);

                    double real = (data[k, j].Real * cos - data[k, j].Imaginary * sin);
                    double imaginary = (data[k, j].Real * sin + data[k, j].Imaginary * cos);

                    dst[i] = new Complex(dst[i].Real + real, dst[i].Imaginary + imaginary);
                }
            }

            if (direction == Direction.Forward)
            {
                for (int i = 0; i < n; i++)
                {
                    data[i, j] = new Complex(dst[i].Real / n, dst[i].Imaginary / n);
                }
            }
            else
            {
                for (int i = 0; i < n; i++)
                {
                    data[i, j] = new Complex(dst[i].Real,  dst[i].Imaginary);
                }
            }
        }
    }


   public static void FFT(Complex[] data, Direction direction)
    {
        int n = data.Length;
        int m = Tools.Log2(n);

        ReorderData(data);

        int tn = 1, tm;

        for (int k = 1; k <= m; k++)
        {
            Complex[] rotation = FourierTransform.GetComplexRotation(k, direction);

            tm = tn;
            tn <<= 1;

            for (int i = 0; i < tm; i++)
            {
                Complex t = rotation[i];

                for (int even = i; even < n; even += tn)
                {
                    int odd = even + tm;
                    Complex ce = data[even];
                    Complex co = data[odd];

                    double tr = co.Real * t.Real - co.Imaginary * t.Imaginary;
                    double ti = co.Real * t.Imaginary + co.Imaginary * t.Real;

                    data[even] = new Complex (tr + data[even].Real, data[even].Imaginary + ti);

                    data[odd] = new Complex(ce.Real - tr,ce.Imaginary - ti);
                }
            }
        }

        if (direction == Direction.Forward)
        {
            for (int i = 0; i < n; i++)
            {
                double real = data[i].Real / (double)n;
                double imaginary = data[i].Imaginary / (double)n;

                data[i] = new Complex(real, imaginary);
            }
        }
    }

    public static void FFT2(Complex[,] data, Direction direction)
    {
        int k = data.GetLength(0);
        int n = data.GetLength(1);

        if (
            (!Tools.IsPowerOf2(k)) ||
            (!Tools.IsPowerOf2(n)) ||
            (k < minLength) || (k > maxLength) ||
            (n < minLength) || (n > maxLength)
            )
        {
            throw new ArgumentException("Incorrect data length.");
        }

        Complex[] row = new Complex[n];

        for (int i = 0; i < k; i++)
        {
            for (int j = 0; j < n; j++)
                row[j] = data[i, j];

            FourierTransform.FFT(row, direction);

            for (int j = 0; j < n; j++)
                data[i, j] = row[j];
        }

        Complex[] col = new Complex[k];

        for (int j = 0; j < n; j++)
        {
            for (int i = 0; i < k; i++)
                col[i] = data[i, j];

            FourierTransform.FFT(col, direction);

            for (int i = 0; i < k; i++)
                data[i, j] = col[i];
        }
    }

    private const int minLength = 2;
    private const int maxLength = 16384;
    private const int minBits = 1;
    private const int maxBits = 14;
    private static int[][] reversedBits = new int[maxBits][];
    private static Complex[,][] complexRotation = new Complex[maxBits, 2][];

    private static int[] GetReversedBits(int numberOfBits)
    {
        if ((numberOfBits < minBits) || (numberOfBits > maxBits))
            throw new ArgumentOutOfRangeException();

        if (reversedBits[numberOfBits - 1] == null)
        {
            int n = Tools.Pow2(numberOfBits);
            int[] rBits = new int[n];

            for (int i = 0; i < n; i++)
            {
                int oldBits = i;
                int newBits = 0;

                for (int j = 0; j < numberOfBits; j++)
                {
                    newBits = (newBits << 1) | (oldBits & 1);
                    oldBits = (oldBits >> 1);
                }
                rBits[i] = newBits;
            }
            reversedBits[numberOfBits - 1] = rBits;
        }
        return reversedBits[numberOfBits - 1];
    }

    private static Complex[] GetComplexRotation(int numberOfBits, Direction direction)
    {
        int directionIndex = (direction == Direction.Forward) ? 0 : 1;

        if (complexRotation[numberOfBits - 1, directionIndex] == null)
        {
            int n = 1 << (numberOfBits - 1);
            double uR = 1.0;
            double uI = 0.0;
            double angle = System.Math.PI / n * (int)direction;
            double wR = System.Math.Cos(angle);
            double wI = System.Math.Sin(angle);
            double t;
            Complex[] rotation = new Complex[n];

            for (int i = 0; i < n; i++)
            {
                rotation[i] = new Complex(uR, uI);
                t = uR * wI + uI * wR;
                uR = uR * wR - uI * wI;
                uI = t;
            }

            complexRotation[numberOfBits - 1, directionIndex] = rotation;
        }
        return complexRotation[numberOfBits - 1, directionIndex];
    }

    private static void ReorderData(Complex[] data)
    {
        int len = data.Length;

        if ((len < minLength) || (len > maxLength) || (!Tools.IsPowerOf2(len)))
            throw new ArgumentException("Incorrect data length.");

        int[] rBits = GetReversedBits(Tools.Log2(len));

        for (int i = 0; i < len; i++)
        {
            int s = rBits[i];

            if (s > i)
            {
                Complex t = data[i];
                data[i] = data[s];
                data[s] = t;
            }
        }
    }
}

1 Ответ

0 голосов
/ 26 сентября 2018

Я решил проблему.

Мне пришлось использовать функцию с именем Limit() в моем коде, целью которой является сохранение значений от 0 до 1.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        Bitmap bmp = Bitmap.FromFile("lenagr.png") as Bitmap;
        pictureBox1.Image = bmp;

        Complex[,] cImage = ToComplex(bmp);

        for (int y = 0; y < cImage.GetLength(1); y++)
        {
            for (int x = 0; x < cImage.GetLength(0); x++)
            {
                if (((x + y) & 0x1) != 0)
                {
                    double real = cImage[y, x].Real * (-1);
                    double imaginary = cImage[y, x].Imaginary * (-1);

                    cImage[y, x] = new Complex(real, imaginary);
                }
            }
        }

        FourierTransform.FFT2(cImage, FourierTransform.Direction.Forward);

        double[,] intImage = ToDouble(cImage);

        intImage = Limit(intImage);

        Bitmap bmpMagImg = ToBitmap(intImage, PixelFormat.Format24bppRgb);
        pictureBox2.Image = bmpMagImg;
    }

    public static double[,] Limit(double[,] image)
    {
        double[,] imageCopy = (double[,])image.Clone();

        double min = 0;
        double max = 1;

        int Width = imageCopy.GetLength(0);
        int Height = imageCopy.GetLength(1);

        double[,] array2d = new double[Width, Height];

        for (int i = 0; i < Width; i++)
        {
            for (int j = 0; j < Height; j++)
            {
                array2d[i, j] = Math.Max(min, Math.Min(imageCopy[i, j], max));
            }
        }

        return array2d;
    }

    public double[,] ToDouble(Complex[,] image)
    {
        int Width = image.GetLength(0);
        int Height = image.GetLength(1);

        double[,] array2d = new double[Width, Height];

        for (int j = 0; j < Height; j++)
        {
            for (int i = 0; i < Width; i++)
            {
                array2d[i, j] = (double)image[i, j].Magnitude;
            }
        }

        return array2d;
    }

    public Bitmap ToBitmap(double[,] image, PixelFormat pixelFormat)
    {
        double[,] imageCopy = (double[,])image.Clone();

        // Image is Grayscale
        // Each element is scaled to (0-255) range.
        int Width = imageCopy.GetLength(0);
        int Height = imageCopy.GetLength(1);

        Bitmap bitmap = new Bitmap(Width, Height, pixelFormat);

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                // In case of a grayscale image, 
                // each pixel has same R,G, and B values.
                double d = imageCopy[x, y];

                int iii = Convert.ToInt32(d * 255.0);

                Color clr = Color.FromArgb(iii, iii, iii);

                bitmap.SetPixel(x, y, clr);
            }
        }

        Grayscale.SetPalette(bitmap);

        return bitmap;
    }



    public Complex[,] ToComplex(Bitmap image)
    {
        if (!Grayscale.IsGrayscale(image))
        {
            throw new Exception("Source image must not be color");
        }

        int[,] array2d = ToInteger(image);

        return ToComplex(array2d);
    }



    public int[,] ToInteger(Bitmap input)
    {
        if (!Grayscale.IsGrayscale(input))
        {
            throw new Exception("Source image must not be color");
        }

        int Width = input.Width;
        int Height = input.Height;

        int[,] array2d = new int[Width, Height];

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                Color cl = input.GetPixel(x, y);

                int gray = (int)Convert.ChangeType(cl.R * 0.3 + cl.G * 0.59 + cl.B * 0.11, typeof(int));

                array2d[x, y] = gray;
            }
        }

        return array2d;
    }

    public Complex[,] ToComplex(int[,] image)
    {
        int Width = image.GetLength(0);
        int Height = image.GetLength(1);

        Complex[,] array2d = new Complex[Width, Height];

        for (int i = 0; i < Width; i++)
        {
            for (int j = 0; j < Height; j++)
            {
                double d = (double)image[i, j];

                Complex tempComp = new Complex(d, 0.0);
                array2d[i, j] = tempComp;
            }
        }

        return array2d;
    }
}
...