Esempio n. 1
0
        /// <summary>
        /// Two dimensional Fast Fourier Transform.
        /// </summary>
        /// <param name="width">Image width.</param>
        /// <param name="height">Image height.</param>
        /// <param name="stride">Image stride.</param>
        /// <param name="data">Data to transform.</param>
        /// <param name="direction">Transformation direction.</param>
        ///
        /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size
        /// only in each dimension, where <b>n</b> may vary in the [1, 14] range. For example, 16x16 array
        /// is valid, but 15x15 is not.</note></para></remarks>
        ///
        /// <exception cref="ArgumentException">Incorrect data length.</exception>
        ///
        public unsafe static void FFT2(ComplexF *data, int width, int height, int stride, Direction direction)
        {
            int k = height;
            int n = width;

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

            // process rows
            ComplexF *dataPtr = data; //get row

            for (int i = 0; i < height; i++)
            {
                // transform it
                FourierTransform.FFT(dataPtr, n, direction);

                dataPtr += stride / sizeof(ComplexF);
            }

            // process columns
            dataPtr = data; //get column

            fixed(ComplexF *_col = new ComplexF[k])
            {
                ComplexF *col = _col;

                for (int j = 0; j < height; j++)
                {
                    // copy column
                    ComplexF *dataColPtr = &dataPtr[j];
                    for (int i = 0; i < k; i++)
                    {
                        col[i]      = *dataColPtr;
                        dataColPtr += stride / sizeof(ComplexF);
                    }

                    // transform it
                    FourierTransform.FFT(col, k, direction);

                    // copy back
                    dataColPtr = &dataPtr[j];
                    for (int i = 0; i < k; i++)
                    {
                        *dataColPtr = col[i];
                        dataColPtr += stride / sizeof(ComplexF);
                    }
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Two dimensional Fast Fourier Transform.
        /// </summary>
        ///
        /// <param name="data">Data to transform.</param>
        /// <param name="direction">Transformation direction.</param>
        ///
        /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size
        /// only in each dimension, where <b>n</b> may vary in the [1, 14] range. For example, 16x16 array
        /// is valid, but 15x15 is not.</note></para></remarks>
        ///
        /// <exception cref="ArgumentException">Incorrect data length.</exception>
        ///
        public static void FFT2(ComplexF[,] data, Direction direction)
        {
            int k = data.GetLength(0);
            int n = data.GetLength(1);

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

            // process rows
            ComplexF[] row = new ComplexF[n];

            for (int i = 0; i < k; i++)
            {
                // copy row
                for (int j = 0; j < n; j++)
                {
                    row[j] = data[i, j];
                }
                // transform it
                FourierTransform.FFT(row, direction);
                // copy back
                for (int j = 0; j < n; j++)
                {
                    data[i, j] = row[j];
                }
            }

            // process columns
            ComplexF[] col = new ComplexF[k];

            for (int j = 0; j < n; j++)
            {
                // copy column
                for (int i = 0; i < k; i++)
                {
                    col[i] = data[i, j];
                }
                // transform it
                FourierTransform.FFT(col, direction);
                // copy back
                for (int i = 0; i < k; i++)
                {
                    data[i, j] = col[i];
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// One dimensional Fast Fourier Transform.
        /// </summary>
        ///
        /// <param name="data">Data to transform.</param>
        /// <param name="length">Array length.</param>
        /// <param name="direction">Transformation direction.</param>
        ///
        /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size
        /// only, where <b>n</b> may vary in the [1, 14] range.</note></para></remarks>
        ///
        /// <exception cref="ArgumentException">Incorrect data length.</exception>
        ///
        public unsafe static void FFT(ComplexF *data, int length, Direction direction)
        {
            int n = length;
            int m = AForge.Math.Tools.Log2(n);

            // reorder data first
            ReorderData(data, length);

            // compute FFT
            int tn = 1, tm;

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

                tm   = tn;
                tn <<= 1;

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

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

                        float tr = co->Re * t.Re - co->Im * t.Im;
                        float ti = co->Re * t.Im + co->Im * t.Re;

                        co->Re = ce->Re - tr;
                        co->Im = ce->Im - ti;

                        ce->Re += tr;
                        ce->Im += ti;
                    }
                }
            }

            if (direction == Direction.Backward)
            {
                for (int i = 0; i < n; i++)
                {
                    data[i].Re /= n;
                    data[i].Im /= n;
                }
            }
        }
Esempio n. 4
0
        /*
         * /// <summary>
         * /// One dimensional Fast Fourier Transform.
         * /// </summary>
         * /// <param name="data">Data to transform.</param>
         * /// <param name="direction">Transformation direction.</param>
         * public static void FFT(ComplexF[] data, Direction direction){
         *      int length = data.Length;
         *      int n = length;
         *      int m = AForge.Math.Tools.Log2(n);
         *
         *      // reorder data first
         *      ReorderData(data, length);
         *
         *      // compute FFT
         *      int tn = 1, tm;
         *
         *      for (int k = 1; k <= m; k++)
         *      {
         *              ComplexF[] rotation = FourierTransform.GetComplexRotation(k,  direction);
         *
         *              tm = tn;
         *              tn <<= 1;
         *
         *              for (int i = 0; i < tm; i++)
         *              {
         *                      ComplexF t = rotation[i];
         *
         *                      for (int even = i; even < n; even += tn)
         *                      {
         *                              int odd = even + tm;
         *                              ComplexF* ce = &data[even];
         *                              ComplexF* co = &data[odd];
         *
         *                              float tr = co->Re * t.Re - co->Im * t.Im;
         *                              float ti = co->Re * t.Im + co->Im * t.Re;
         *
         *                              co->Re = ce->Re - tr;
         *                              co->Im = ce->Im - ti;
         *
         *                              ce->Re += tr;
         *                              ce->Im += ti;
         *                      }
         *              }
         *      }
         *
         *      if (direction == Direction.Backward)
         *      {
         *              for (int i = 0; i < n; i++)
         *              {
         *                      data[i].Re /= n;
         *                      data[i].Im /= n;
         *              }
         *      }
         * }
         *
         *
         * /// <summary>
         * /// Two dimensional Fast Fourier Transform.
         * /// </summary>
         * /// <param name="data">Data to transform.</param>
         * /// <param name="direction">Transformation direction.</param>
         * public unsafe static void FFT2(ComplexF[,] data, Direction direction)
         * {
         *      int width = data.GetLength(1);
         *      int height = data.GetLength(0);
         *
         *      fixed (ComplexF* dataPtr = data)
         * {
         * FFT2(dataPtr, width, height, width, direction);
         * }
         * }
         *
         * /// <summary>
         * /// Two dimensional Fast Fourier Transform.
         * /// </summary>
         * /// <param name="width">Image width.</param>
         * /// <param name="height">Image height.</param>
         * /// <param name="stride">Image stride.</param>
         * /// <param name="data">Data to transform.</param>
         * /// <param name="direction">Transformation direction.</param>
         * ///
         * /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size
         * /// only in each dimension, where <b>n</b> may vary in the [1, 14] range. For example, 16x16 array
         * /// is valid, but 15x15 is not.</note></para></remarks>
         * ///
         * /// <exception cref="ArgumentException">Incorrect data length.</exception>
         * ///
         * public unsafe static void FFT2(ComplexF* data, int width, int height, int stride, Direction direction)
         * {
         * const int MIN_PATCH_SIZE = 32; //how much rows/columns should one thread process
         *
         * int k = height;
         * int n = width;
         *
         * // check data size
         * if (
         *  (!AForge.Math.Tools.IsPowerOf2(k)) ||
         *  (!AForge.Math.Tools.IsPowerOf2(n)) ||
         *  (k < minLength) || (k > maxLength) ||
         *  (n < minLength) || (n > maxLength)
         *  )
         * {
         * throw new ArgumentException("Incorrect data length.");
         * }
         *
         * // process rows
         * var procRow = new ParallelProcessor<bool, bool>(
         * new Size(
         *      1 // does not matter
         *                      , height
         *              )
         *              ,
         *  () => true,
         *  (_, __, area) =>
         *  {
         *      ComplexF* dataPatchPtr = data + area.Y * stride / sizeof(ComplexF); //get row
         *
         *      for (int i = 0; i < area.Height; i++)
         *      {
         *          // transform it
         *          FourierTransform.FFT(dataPatchPtr, n, direction);
         *
         *          dataPatchPtr += stride / sizeof(ComplexF);
         *      }
         *  },
         *  new ParallelOptions2D {
         *                      ParallelTrigger = (size) => size.Height >= MIN_PATCH_SIZE
         *                      //,ForceSequential = true
         *              }
         *      );
         *
         * // process columns
         * //(y and x are swaped => proc thinks it is diving horizontal pacthes but instead we are using them as vertical ones)
         * var procCol = new ParallelProcessor<bool, bool>(
         * new Size(
         *      1 // does not matter
         *      , width
         * )
         * ,
         *  () => true,
         *  (_, __, area) =>
         *  {
         *      ComplexF* dataPatchPtr = &data[area.Y]; //get column
         *
         *      fixed (ComplexF* _col = new ComplexF[k])
         *      {
         *          ComplexF* col = _col;
         *
         *          for (int j = 0; j < area.Height; j++)
         *          {
         *              // copy column
         *              ComplexF* dataColPtr = &dataPatchPtr[j];
         *              for (int i = 0; i < k; i++)
         *              {
         *                  col[i] = *dataColPtr;
         *                  dataColPtr += stride / sizeof(ComplexF);
         *              }
         *
         *              // transform it
         *              FourierTransform.FFT(col, k, direction);
         *
         *              // copy back
         *              dataColPtr = &dataPatchPtr[j];
         *              for (int i = 0; i < k; i++)
         *              {
         * dataColPtr = col[i];
         *                  dataColPtr += stride / sizeof(ComplexF);
         *              }
         *          }
         *      }
         *  },
         *  new ParallelOptions2D {
         *                      ParallelTrigger = (size) => size.Height >= MIN_PATCH_SIZE
         *      //,ForceSequential = true
         *              }
         *      );
         *
         * procRow.Process(true);
         * procCol.Process(true);
         * }
         *
         #region Private Region
         *
         * private static ComplexF[,][] complexRotation = new ComplexF[maxBits, 2][];
         *
         * // Get rotation of complex number
         * private static ComplexF[] GetComplexRotation(int numberOfBits, Direction direction)
         * {
         * int directionIndex = (direction == Direction.Forward) ? 1 : 0;
         *
         * // check if the array is already calculated
         * if (complexRotation[numberOfBits - 1, directionIndex] == null)
         * {
         * int n = 1 << (numberOfBits - 1);
         * float uR = 1.0f;
         * float uI = 0.0f;
         * double angle = System.Math.PI / n * (-(int)(direction));
         * float wR = (float)System.Math.Cos(angle);
         * float wI = (float)System.Math.Sin(angle);
         * float t;
         * ComplexF[] rotation = new ComplexF[n];
         *
         * for (int i = 0; i < n; i++)
         * {
         *  rotation[i] = new ComplexF { Re = uR, Im = uI};
         *  t = uR * wI + uI * wR;
         *  uR = uR * wR - uI * wI;
         *  uI = t;
         * }
         *
         * complexRotation[numberOfBits - 1, directionIndex] = rotation;
         * }
         * return complexRotation[numberOfBits - 1, directionIndex];
         * }
         *
         * // Reorder data for FFT using
         * private static void ReorderData(ComplexF[] data){
         *      int length = data.Length;
         *
         * // check data length
         *      if ((length < minLength) || (length > maxLength) || (!AForge.Math.Tools.IsPowerOf2(length)))
         * throw new ArgumentException("Incorrect data length.");
         *
         * int[] rBits = GetReversedBits(AForge.Math.Tools.Log2(len));
         *
         * for (int i = 0; i < len; i++)
         * {
         * int s = rBits[i];
         *
         * if (s > i)
         * {
         *  ComplexF t = data[i];
         *  data[i] = data[s];
         *  data[s] = t;
         * }
         * }
         * }
         #endregion
         */

        /// <summary>
        /// One dimensional Fast Fourier Transform.
        /// </summary>
        ///
        /// <param name="data">Data to transform.</param>
        /// <param name="direction">Transformation direction.</param>
        ///
        /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size
        /// only, where <b>n</b> may vary in the [1, 14] range.</note></para></remarks>
        ///
        /// <exception cref="ArgumentException">Incorrect data length.</exception>
        ///
        public static void FFT(ComplexF[] data, Direction direction)
        {
            int n = data.Length;
            int m = Tools.Log2(n);

            // reorder data first
            ReorderData(data);

            // compute FFT
            int tn = 1, tm;

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

                tm   = tn;
                tn <<= 1;

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

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

                        float tr = co.Re * t.Re - co.Im * t.Im;
                        float ti = co.Re * t.Im + co.Im * t.Re;

                        data[even].Re += tr;
                        data[even].Im += ti;

                        data[odd].Re = ce.Re - tr;
                        data[odd].Im = ce.Im - ti;
                    }
                }
            }

            if (direction == Direction.Forward)
            {
                for (int i = 0; i < n; i++)
                {
                    data[i].Re /= (float)n;
                    data[i].Im /= (float)n;
                }
            }
        }
        /// <summary>
        /// Calculates Fast Fourier transform.
        /// </summary>
        /// <param name="image">Input image.</param>
        /// <param name="direction">Forward or backward direction.</param>
        /// <param name="inPlace">Process in place or not.</param>
        /// <returns>Processed image. If <paramref name="inPlace"/> is used the result is the same as input image therefore may be omitted.</returns>
        public unsafe static ComplexF[,] FFT(this ComplexF[,] image, FourierTransform.Direction direction, bool inPlace = false)
        {
            ComplexF[,] dest = null;
            if (inPlace)
                dest = image;
            else
                dest = (ComplexF[,])image.Clone();

            using (var uDest = dest.Lock())
            {
                FourierTransform.FFT2((ComplexF*)uDest.ImageData, uDest.Width, uDest.Height, uDest.Stride, direction);
            }

            return dest;
        }
Esempio n. 6
0
        /// <summary>
        /// Two dimensional Fast Fourier Transform.
        /// </summary>
        /// <param name="width">Image width.</param>
        /// <param name="height">Image height.</param>
        /// <param name="stride">Image stride.</param>
        /// <param name="data">Data to transform.</param>
        /// <param name="direction">Transformation direction.</param>
        ///
        /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size
        /// only in each dimension, where <b>n</b> may vary in the [1, 14] range. For example, 16x16 array
        /// is valid, but 15x15 is not.</note></para></remarks>
        ///
        /// <exception cref="ArgumentException">Incorrect data length.</exception>
        ///
        public unsafe static void FFT2(ComplexF *data, int width, int height, int stride, Direction direction)
        {
            const int MIN_PATCH_SIZE = 32; //how much rows/columns should one thread process

            int k = height;
            int n = width;

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

            // process rows
            var procRow = new ParallelProcessor <bool, bool>(new Size(1 /*does not matter*/, height),
                                                             () => true,
                                                             (_, __, area) =>
            {
                ComplexF *dataPatchPtr = data + area.Y * stride / sizeof(ComplexF);                                                 //get row

                for (int i = 0; i < area.Height; i++)
                {
                    // transform it
                    FourierTransform.FFT(dataPatchPtr, n, direction);

                    dataPatchPtr += stride / sizeof(ComplexF);
                }
            },
                                                             new ParallelOptions2D {
                ParallelTrigger = (size) => size.Height >= MIN_PATCH_SIZE
                                  /*,ForceSequential = true*/ }
                                                             );

            // process columns
            //(y and x are swaped => proc thinks it is diving horizontal pacthes but instead we are using them as vertical ones)
            var procCol = new ParallelProcessor <bool, bool>(new Size(1 /*does not matter*/, width),
                                                             () => true,
                                                             (_, __, area) =>
            {
                ComplexF *dataPatchPtr = &data[area.Y];                                                 //get column

                fixed(ComplexF * _col = new ComplexF[k])
                {
                    ComplexF *col = _col;

                    for (int j = 0; j < area.Height; j++)
                    {
                        // copy column
                        ComplexF *dataColPtr = &dataPatchPtr[j];
                        for (int i = 0; i < k; i++)
                        {
                            col[i]      = *dataColPtr;
                            dataColPtr += stride / sizeof(ComplexF);
                        }

                        // transform it
                        FourierTransform.FFT(col, k, direction);

                        // copy back
                        dataColPtr = &dataPatchPtr[j];
                        for (int i = 0; i < k; i++)
                        {
                            *dataColPtr = col[i];
                            dataColPtr += stride / sizeof(ComplexF);
                        }
                    }
                }
            },
                                                             new ParallelOptions2D {
                ParallelTrigger = (size) => size.Height >= MIN_PATCH_SIZE
                                  /*,ForceSequential = true */ }
                                                             );

            procRow.Process(true);
            procCol.Process(true);
        }