/// <summary>
        /// Apply a function with the signature FrequencyFilterEquation to the real and the imaginary
        /// components of each complex "pixel" in a ComplexImage.
        /// </summary>
        /// <param name="complex">The image to apply the filter to.</param>
        /// <param name="equation">The equation of the filter.</param>
        /// <returns>The resulting ComplexImage.</returns>
        public static ComplexImage ApplyFilter(
                ComplexImage complex,
                FrequencyFilterEquation equation)
        {
            ComplexImage ret = new ComplexImage(complex);
            double filter_mult;

            // Apply equation...
            for (int u = 0; u < ret.Width; ++u)
            {
                for (int v = 0; v < ret.Height; ++v)
                {
                    filter_mult = equation(u, v);

                    ret[u, v].real *= filter_mult;
                    ret[u, v].imag *= filter_mult;
                }
            }

            return ret;
        }
 // To be implemented by frequency domain filters
 /// <summary>
 /// Apply filter to a ComplexImage. Override to implement a filter in frequency domain.
 /// </summary>
 /// <param name="complexImg"></param>
 /// <param name="configs"></param>
 /// <returns></returns>
 public abstract ComplexImage ApplyFilter(ComplexImage complexImg, SortedDictionary<string, object> configs);
 // Dummy override
 /// <summary>
 /// Apply filter to a ComplexImage. This method will throw a NotImplementedException.
 /// </summary>
 /// <param name="complexImg"></param>
 /// <param name="configs"></param>
 /// <exception cref="NotImplementedException">Spatial Domain Filters do not operate on ComplexImage.</exception>
 /// <returns></returns>
 public override ComplexImage ApplyFilter(ComplexImage complexImg, SortedDictionary<string, object> configs)
 {
     // Throw exception ... to turn a ComplexImage into bytes, you have to know
     // which forward-transform and reverse-transform to perform!
     throw new NotImplementedException("Spatial Domain Filters do not operate on ComplexImage. Apply the inverse transform first!");
 }
        /// <summary>
        /// Performs the following tests on the transform instance:
        ///  * checks the size of the data after a transform or a reverse-transform
        ///  * checks the data after a transform or a reverse-transform
        ///  * checks null output
        ///</summary>
        ///<remarks>
        /// Comparision of doubles conformant with the documentation at: http://msdn.microsoft.com/en-us/library/ya2zha7s.aspx
        ///</remarks>
        private void TransformTestTestData(
                TransformCoreBase<ComplexImage> df, int i, double[,] wellKnownData, ComplexImage wellKnownTransform)
        {
            // Perform transform
            ComplexImage calculatedTransform = df.ApplyTransformBase(wellKnownData);

            // ** Check Reference
            Assert.IsNotNull(calculatedTransform, "Test #{0}: Generated transform is null :(.");

            // ** Check Sizes
            Assert.AreEqual(wellKnownData.GetLength(0), calculatedTransform.Width,
                    "Test #{0}: Width of transform does not match width of original data.", i);
            Assert.AreEqual(wellKnownData.GetLength(1), calculatedTransform.Height,
                    "Test #{0}: Height of transform does not match width of original data.", i);

            // ** Check Data
            int x, y;

            const double tollerance = 0.0001;

            for (x = 0; x < wellKnownData.GetLength(0); ++x)
            {
                for (y = 0; y < wellKnownData.GetLength(1); ++y)
                {
                    Assert.AreEqual(wellKnownTransform[x, y].real, calculatedTransform[x, y].real,
                            tollerance, "Test #{0}: Expected {1}, but found {2} in the transform @({3}, {4}).real .",
                            i, wellKnownTransform[x, y].real, calculatedTransform[x, y].real, x, y);

                    Assert.AreEqual(wellKnownTransform[x, y].imag, calculatedTransform[x, y].imag,
                            tollerance, "Test #{0}: Expected {1}, but found {2} in the transform @({3}, {4}).imag .",
                            i, wellKnownTransform[x, y].imag, calculatedTransform[x, y].imag, x, y);
                }
            }

            // Perform reverse-transform
            double[,] calculatedData = df.ApplyReverseTransformBase(calculatedTransform);

            // ** Check Reference
            Assert.IsNotNull(calculatedData, "Test #{0}: Generated reverse-transform is null :(.");

            // ** Check Sizes
            Assert.AreEqual(calculatedTransform.Width, calculatedData.GetLength(0),
                    "Width of reverse-transform does not match width of transform.");
            Assert.AreEqual(calculatedTransform.Height, calculatedData.GetLength(1),
                    "Height of reverse-transform does not match width of transform.");

            // ** Check Data
            for (x = 0; x < wellKnownData.GetLength(0); ++x)
            {
                for (y = 0; y < wellKnownData.GetLength(1); ++y)
                {
                    // Be careful with rounding error in the double datatype >:(

                    Assert.AreEqual(wellKnownData[x, y], calculatedData[x, y],
                           tollerance, "Test #{0}: Expected {1}, but found {2} in the reverse-transform @({3}, {4}).",
                           i, wellKnownData[x, y], calculatedData[x, y], x, y);

                }
            }
        }
 public FourierForm(ComplexImage complexImage)
     : this()
 {
     _complex = complexImage;
 }
        /// <summary>
        /// Creates a copy of a ComplexImage.
        /// </summary>
        /// <param name="copy">The ComplexImage to copy.</param>
        public ComplexImage(ComplexImage copy)
        {
            int width = copy.Width;
            int height = copy.Height;

            _elemns = new Complex[width, height];

            for (int x = 0; x < width; ++x)
            {
                for (int y = 0; y < height; ++y)
                {
                    _elemns[x, y] = copy[x, y].Clone();
                }
            }
        }
        /// <summary>
        /// Converts the ComplexImage to a bitmap (for display purposes).
        /// Is applied a log to the data for better plotting.
        /// </summary>
        /// <param name="bitmapType">The type of bitmap to generate.</param>
        /// <returns>Bitmap representation of the ComplexImage.</returns>
        public Bitmap ToBitmap(ComplexImageBitmapType bitmapType)
        {
            int x, y;
            int width = this.Width, height = this.Height;
            Bitmap ret = null;

            ComplexImage transform = new ComplexImage(this);

            double[,] logs = new double[width, height];
            double[,] data = new double[width, height];
            int[,] normalized = new int[width, height];

            for (x = 0; x < width; ++x)
            {
                for (y = 0; y < height; ++y)
                {
                    switch (bitmapType)
                    {
                        case ComplexImageBitmapType.Magnitude:
                            data[x, y] = transform[x, y].Magnitude();
                            logs[x, y] = (float)(Math.Log(0.1 + data[x, y]));
                            break;
                        case ComplexImageBitmapType.Phase:
                            data[x, y] = transform[x, y].Phase();
                            logs[x, y] = (float)Math.Log(0.1 + Math.Abs(data[x, y]));
                            break;
                    }
                }
            }

            // get max and min
            double max = double.MinValue, min = double.MaxValue;
            for (x = 0; x < width; ++x)
            {
                for (y = 0; y < height; ++y)
                {
                    max = Math.Max(max, logs[x, y]);
                    min = Math.Min(min, logs[x, y]);
                }
            }

            double range = max - min;

            // Normalize data

            for (x = 0; x < width; ++x)
            {
                for (y = 0; y < height; ++y)
                {
                    //normalized[x, y] = (int)(byte.MaxValue * (logs[x, y] / max));
                    normalized[x, y] = (int)(byte.MaxValue * ((logs[x, y] - min) / range));
                }
            }

            // write to bitmap ...
            ret = Facilities.ToBitmap(normalized);

            //switch (bitmapType)
            //{
            //    case ComplexImageBitmapType.Magnitude:
            //        // divide by max and normalize
            //        for (x = 0; x < width; ++x)
            //        {
            //            for (y = 0; y < height; ++y)
            //            {
            //                //normalized[x, y] = (int)(byte.MaxValue * (logs[x, y] / max));
            //                normalized[x, y] = (int) (byte.MaxValue * ((logs[x, y] - min) / range));
            //            }
            //        }
            //        // write to bitmap ...
            //        ret = Facilities.ToBitmap(normalized);
            //        break;
            //    case ComplexImageBitmapType.Phase:
            //        // divide by max and normalize
            //        for (x = 0; x < width; ++x)
            //        {
            //            for (y = 0; y < height; ++y)
            //            {
            //                //normalized[x, y] = (int)(byte.MaxValue * (logs[x, y] / max));
            //                normalized[x, y] = (int)(byte.MaxValue * ((logs[x, y] - min) / range));
            //            }
            //        }
            //        // write to bitmap ...
            //        ret = Facilities.ToBitmap(normalized);
            //        break;
            //}

            return ret;
        }