代码之家  ›  专栏  ›  技术社区  ›  user366312

为什么2d-FFT的输出是全黑的?

  •  -2
  • user366312  · 技术社区  · 6 年前

    注: 我解决了这个问题。

    FourierTransform -从forge.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 回复  |  直到 6 年前
        1
  •  1
  •   user366312    6 年前

    我已经解决了这个问题。

    我不得不使用一个叫做 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;
        }
    }