/// <summary>
        /// Efficient Algorithm to Get Min and Max pixel number at the same time
        /// </summary>
        /// <param name="ImageMatrix">2D ImageMatrixay that contains the image</param>
        /// <param name="redmin">The least minimum red color in the whole image</param>
        /// <param name="redmax">The most maximum red color in the whole image</param>
        /// <param name="bluemin">The least minimum blue color in the whole image</param>
        /// <param name="bluemax">The most maximum blue color in the whole image</param>
        /// <param name="greenmin">The least minimum green color in the whole image</param>
        /// <param name="greenmax">The most maximum green color in the whole image</param>
        public static void GetMinMax_Efficient(MyColor[,] ImageMatrix, ref double redmin, ref double redmax, ref double bluemin, ref double bluemax, ref double greenmin, ref double greenmax)
        {
            redmin = 100000;
            redmax = 0;
            bluemin = 100000;
            bluemax = 0;
            greenmin = 100000;
            greenmax = 0;

            int n = GetWidth(ImageMatrix) * GetHeight(ImageMatrix);

            for (int i = 0; i < GetHeight(ImageMatrix) - 1; i++)
            {
                for (int j = 0; j < GetWidth(ImageMatrix) - 1; )
                {
                    //if n is even
                    if (n % 2 == 0)
                    {
                        if (ImageMatrix[i, j].red < ImageMatrix[i, j + 1].red)
                        {
                            if (redmin > ImageMatrix[i, j].red)
                            {
                                redmin = ImageMatrix[i, j].red;
                            }
                            if (redmax < ImageMatrix[i, j + 1].red)
                            {
                                redmax = ImageMatrix[i, j + 1].red;
                            }
                        }
                        else
                        {
                            if (redmin > ImageMatrix[i, j + 1].red)
                            {
                                redmin = ImageMatrix[i, j + 1].red;
                            }
                            if (redmax < ImageMatrix[i, j].red)
                            {
                                redmax = ImageMatrix[i, j].red;
                            }
                        }

                        if (ImageMatrix[i, j].blue < ImageMatrix[i, j + 1].blue)
                        {
                            if (bluemin > ImageMatrix[i, j].blue)
                            {
                                bluemin = ImageMatrix[i, j].blue;
                            }
                            if (bluemax < ImageMatrix[i, j + 1].blue)
                            {
                                bluemax = ImageMatrix[i, j + 1].blue;
                            }
                        }
                        else
                        {
                            if (bluemin > ImageMatrix[i, j + 1].blue)
                            {
                                bluemin = ImageMatrix[i, j + 1].blue;
                            }
                            if (bluemax < ImageMatrix[i, j].blue)
                            {
                                bluemax = ImageMatrix[i, j].blue;
                            }
                        }

                        if (ImageMatrix[i, j].green < ImageMatrix[i, j + 1].green)
                        {
                            if (greenmin > ImageMatrix[i, j].green)
                            {
                                greenmin = ImageMatrix[i, j].green;
                            }
                            if (greenmax < ImageMatrix[i, j + 1].green)
                            {
                                greenmax = ImageMatrix[i, j + 1].green;
                            }
                        }
                        else
                        {
                            if (greenmin > ImageMatrix[i, j + 1].green)
                            {
                                greenmin = ImageMatrix[i, j + 1].green;
                            }
                            if (greenmax < ImageMatrix[i, j].green)
                            {
                                greenmax = ImageMatrix[i, j].green;
                            }
                        }

                        j += 2;
                    }

                    // if n is odd , make one comparison first then loop
                    else if (n % 2 == 1)
                    {
                        if ((i == 0 && j == 0) || j == 0)
                        {
                            if (redmin > ImageMatrix[i, j].red)
                            {
                                redmin = ImageMatrix[i, j].red;
                            }

                            else if (redmax < ImageMatrix[i, j].red)
                            {
                                redmax = ImageMatrix[i, j].red;
                            }

                            if (bluemin > ImageMatrix[i, j].blue)
                            {
                                bluemin = ImageMatrix[i, j].blue;
                            }

                            else if (bluemax < ImageMatrix[i, j].blue)
                            {
                                bluemax = ImageMatrix[i, j].blue;
                            }

                            if (greenmin > ImageMatrix[i, j].green)
                            {
                                greenmin = ImageMatrix[i, j].green;
                            }

                            else if (greenmax < ImageMatrix[i, j].green)
                            {
                                greenmax = ImageMatrix[i, j].green;
                            }

                            j++;
                        }

                        else
                        {
                            if (ImageMatrix[i, j].red < ImageMatrix[i, j + 1].red)
                            {
                                if (redmin > ImageMatrix[i, j].red)
                                {
                                    redmin = ImageMatrix[i, j].red;
                                }
                                if (redmax < ImageMatrix[i, j + 1].red)
                                {
                                    redmax = ImageMatrix[i, j + 1].red;
                                }
                            }
                            else
                            {
                                if (redmin > ImageMatrix[i, j + 1].red)
                                {
                                    redmin = ImageMatrix[i, j + 1].red;
                                }
                                if (redmax < ImageMatrix[i, j].red)
                                {
                                    redmax = ImageMatrix[i, j].red;
                                }
                            }

                            if (ImageMatrix[i, j].blue < ImageMatrix[i, j + 1].blue)
                            {
                                if (bluemin > ImageMatrix[i, j].blue)
                                {
                                    bluemin = ImageMatrix[i, j].blue;
                                }
                                if (bluemax < ImageMatrix[i, j + 1].blue)
                                {
                                    bluemax = ImageMatrix[i, j + 1].blue;
                                }
                            }
                            else
                            {
                                if (bluemin > ImageMatrix[i, j + 1].blue)
                                {
                                    bluemin = ImageMatrix[i, j + 1].blue;
                                }
                                if (bluemax < ImageMatrix[i, j].blue)
                                {
                                    bluemax = ImageMatrix[i, j].blue;
                                }
                            }

                            if (ImageMatrix[i, j].green < ImageMatrix[i, j + 1].green)
                            {
                                if (greenmin > ImageMatrix[i, j].green)
                                {
                                    greenmin = ImageMatrix[i, j].green;
                                }
                                if (greenmax < ImageMatrix[i, j + 1].green)
                                {
                                    greenmax = ImageMatrix[i, j + 1].green;
                                }
                            }
                            else
                            {
                                if (greenmin > ImageMatrix[i, j + 1].green)
                                {
                                    greenmin = ImageMatrix[i, j + 1].green;
                                }
                                if (greenmax < ImageMatrix[i, j].green)
                                {
                                    greenmax = ImageMatrix[i, j].green;
                                }
                            }

                            j += 2;
                        }
                    }
                }
            }
        }
        /// <summary>
        ///  Normal Algorithm to get Min and Max pixel number separetly 
        /// </summary>
        /// <param name="ImageMatrix">2D ImageMatrixay that contains the image</param>
        /// <param name="redmin">The least minimum red color in the whole image</param>
        /// <param name="redmax">The most maximum red color in the whole image</param>
        /// <param name="bluemin">The least minimum blue color in the whole image</param>
        /// <param name="bluemax">The most maximum blue color in the whole image</param>
        /// <param name="greenmin">The least minimum green color in the whole image</param>
        /// <param name="greenmax">The most maximum green color in the whole image</param>
        public static void GetMinMax_Normal(MyColor[,] ImageMatrix, ref double redmin, ref double redmax, ref double bluemin, ref double bluemax, ref double greenmin, ref double greenmax)
        {
            redmin = 100000;
            redmax = 0;
            bluemin = 100000;
            bluemax = 0;
            greenmin = 100000;
            greenmax = 0;

            for (int i = 0; i < GetHeight(ImageMatrix) - 1; i++)
            {
                for (int j = 0; j < GetWidth(ImageMatrix) - 1; j++)
                {

                    if (ImageMatrix[i, j].red < redmin)
                        redmin = ImageMatrix[i, j].red;

                    if (ImageMatrix[i, j].blue < bluemin)
                        bluemin = ImageMatrix[i, j].blue;

                    if (ImageMatrix[i, j].green < greenmin)
                        greenmin = ImageMatrix[i, j].green;
                }

            }

            for (int i = 0; i < GetHeight(ImageMatrix); i++)
            {
                for (int j = 0; j < GetWidth(ImageMatrix); j++)
                {

                    if (ImageMatrix[i, j].red > redmax)
                        redmax = ImageMatrix[i, j].red;

                    if (ImageMatrix[i, j].blue > bluemax)
                        bluemax = ImageMatrix[i, j].blue;

                    if (ImageMatrix[i, j].green > greenmax)
                        greenmax = ImageMatrix[i, j].green;
                }
            }
        }
        /// <summary>
        /// Gamma - Contrast Image
        /// </summary>
        public static MyColor[,] GammaContrastImage(MyColorDouble[,] GImageMatrix)
        {
            MyColorDouble Old_Min, Old_Max;
            Old_Min.red = 0; Old_Min.green = 0; Old_Min.blue = 0;
            Old_Max.red = 0; Old_Max.green = 0; Old_Max.blue = 0;
            double NewPixelRed, NewPixelBlue, NewPixelGreen;

            MyColor X = new MyColor();
            MyColor[,] NewImageMatrix = new MyColor[GetHeightDouble(GImageMatrix), GetWidthDouble(GImageMatrix)];

            Gamma_GetMinMax(GImageMatrix, ref Old_Min.red, ref Old_Max.red, ref Old_Min.blue, ref Old_Max.blue, ref Old_Min.green, ref Old_Max.green);

            for (int i = 0; i < GetHeightDouble(GImageMatrix); i++)
            {
                for (int j = 0; j < GetWidthDouble(GImageMatrix); j++)
                {
                    NewPixelRed = ((GImageMatrix[i, j].red - Old_Min.red) / (Old_Max.red - Old_Min.red)) * (255 - 0) + 0;
                    NewPixelBlue = ((GImageMatrix[i, j].blue - Old_Min.blue) / (Old_Max.blue - Old_Min.blue)) * (255 - 0) + 0;
                    NewPixelGreen = ((GImageMatrix[i, j].green - Old_Min.green) / (Old_Max.green - Old_Min.green)) * (255 - 0) + 0;

                    if (NewPixelRed > 255)
                        NewPixelRed = 255;
                    if (NewPixelRed < 0)
                        NewPixelRed = 0;

                    if (NewPixelBlue > 255)
                        NewPixelBlue = 255;
                    if (NewPixelBlue < 0)
                        NewPixelBlue = 0;

                    if (NewPixelGreen > 255)
                        NewPixelGreen = 255;
                    if (NewPixelGreen < 0)
                        NewPixelGreen = 0;

                    X.red = (byte)(NewPixelRed);
                    X.blue = (byte)(NewPixelBlue);
                    X.green = (byte)(NewPixelGreen);

                    NewImageMatrix[i, j] = X;
                }
            }
            return NewImageMatrix;
        }
 //for byte image
 //==========================================
 /// <summary>
 /// Get the height of the image 
 /// </summary>
 /// <param name="ImageMatrix">2D ImageMatrixay that contains the image</param>
 /// <returns>Image Height</returns>
 public static int GetHeight(MyColor[,] ImageMatrix)
 {
     return ImageMatrix.GetLength(0);
 }
        //=======================================================
        /// <summary>
        /// Display the given image on the given PictureBox object
        /// </summary>
        /// <param name="ImageMatrix">2D ImageMatrixay that contains the image</param>
        /// <param name="PicBox">PictureBox object to display the image on it</param>
        public static void DisplayImage(MyColor[,] ImageMatrix, PictureBox PicBox)
        {
            // Create Image:
            //==============
            int Height = ImageMatrix.GetLength(0);
            int Width = ImageMatrix.GetLength(1);

            Bitmap ImageBMP = new Bitmap(Width, Height, PixelFormat.Format24bppRgb);

            unsafe
            {
                BitmapData bmd = ImageBMP.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, ImageBMP.PixelFormat);
                int nWidth = 0;
                nWidth = Width * 3;
                int nOffset = bmd.Stride - nWidth;
                byte* p = (byte*)bmd.Scan0;
                for (int i = 0; i < Height; i++)
                {
                    for (int j = 0; j < Width; j++)
                    {
                        p[0] = ImageMatrix[i, j].red;
                        p[1] = ImageMatrix[i, j].green;
                        p[2] = ImageMatrix[i, j].blue;
                        p += 3;
                    }

                    p += nOffset;
                }
                ImageBMP.UnlockBits(bmd);
            }

            PicBox.Image = ImageBMP;
        }
        /// <summary>
        /// Blur Image - Efficient Algorithm
        /// </summary>
        /// <param name="ImageMatrix">2D ImageMatrix that contains the image</param>
        /// <param name="BlurMaskSize">Blur Degree</param>
        /// <returns>2D ImageMatrix of contrasted image colors</returns>
        public static MyColor[,] BlurImage_Efficient(MyColor[,] ImageMatrix, int BlurMaskSize)
        {
            // Start a new StopWatch object for calculating the time
            // The variable stopWatch is a GLOBAL variable.
            stopWatch = Stopwatch.StartNew();

            // MAP stores blurr degree and index of center of mask
            Dictionary<int, int> MaskCenterElement = new Dictionary<int, int>();
            MaskCenterElement.Add(3, 1);
            MaskCenterElement.Add(5, 2);
            MaskCenterElement.Add(7, 3);
            MaskCenterElement.Add(9, 4);
            MaskCenterElement.Add(11, 5);
            MaskCenterElement.Add(13, 6);
            MaskCenterElement.Add(15, 7);
            MaskCenterElement.Add(17, 8);

            double MaskElementValue = 1.0 / (BlurMaskSize * BlurMaskSize);
            double Value = 1.0 / BlurMaskSize;

            // Center Index of needed blurr degree
            int MaskCenterIndex = 0;
            foreach (var index in MaskCenterElement)
            {
                if (index.Key == BlurMaskSize)
                {
                    MaskCenterIndex = index.Value;
                    break;
                }
            }

            // Original image matrix (size: Height+(CenterIndex * 2) x Width+(CenterIndex * 2))
            MyColor[,] OriginalImage = new MyColor[GetHeight(ImageMatrix) + (MaskCenterIndex * 2), GetWidth(ImageMatrix) + (MaskCenterIndex * 2)];
            for (int x = MaskCenterIndex; x < GetHeight(ImageMatrix) + MaskCenterIndex; x++)
            {
                for (int y = MaskCenterIndex; y < GetWidth(ImageMatrix) + MaskCenterIndex; y++)
                    OriginalImage[x, y] = ImageMatrix[x - MaskCenterIndex, y - MaskCenterIndex];
            }

            // The new blurred image matrix
            MyColor[,] NewImageMatrix = new MyColor[GetHeight(ImageMatrix), GetWidth(ImageMatrix)];

            MyColor[,] tempMatrix = new MyColor[GetHeight(OriginalImage), GetWidth(OriginalImage)];

            MyColorDouble SumOfMaskTimesOldPixel = new MyColorDouble();
            SumOfMaskTimesOldPixel.red = 0; SumOfMaskTimesOldPixel.green = 0;
            SumOfMaskTimesOldPixel.blue = 0;

            //Move Horizontally
            //"mRows" moves all the rows in the picture
            //"nCols" ONLY is constrained to the #of columns - BlurMaskSize
            for (int mRows = 0; mRows < GetHeight(OriginalImage); mRows++)
            {
                for (int nCols = 0; nCols < GetWidth(OriginalImage) - BlurMaskSize; nCols++)
                {
                    SumOfMaskTimesOldPixel.red = 0;
                    SumOfMaskTimesOldPixel.green = 0;
                    SumOfMaskTimesOldPixel.blue = 0;
                    for (int k = 0; k < BlurMaskSize; k++)
                    {
                        SumOfMaskTimesOldPixel.red += (Value * OriginalImage[mRows, nCols + k].red);
                        SumOfMaskTimesOldPixel.green += (Value * OriginalImage[mRows, nCols + k].green);
                        SumOfMaskTimesOldPixel.blue += (Value * OriginalImage[mRows, nCols + k].blue);
                    }

                    tempMatrix[mRows, nCols + MaskCenterIndex].red = (byte)SumOfMaskTimesOldPixel.red;
                   tempMatrix[mRows, nCols + MaskCenterIndex].green = (byte)SumOfMaskTimesOldPixel.green;
                    tempMatrix[mRows, nCols + MaskCenterIndex].blue = (byte)SumOfMaskTimesOldPixel.blue;
                }
            }

            //Move Vertically
            /*"nCols" moves all the columns in the picture minus CenterIndex
             *"mRows" ONLY is constrained to the #of rows - BlurMaskSize
             *"nCols" starts at the CenterIndex column b/z NewImageMatrix starts from the 2nd column in tempMatrix and not the first.
             *For the same reason it ends at the last column "-1", because NewImageMatrix doesn't have the last column in the tempMatrix.
             */
            for (int mRows = 0; mRows < GetHeight(tempMatrix) - BlurMaskSize; mRows++)
            {
                for (int nCols = MaskCenterIndex; nCols < GetWidth(tempMatrix)-MaskCenterIndex; nCols++)
                {
                    SumOfMaskTimesOldPixel.red = 0;
                    SumOfMaskTimesOldPixel.green = 0;
                    SumOfMaskTimesOldPixel.blue = 0;
                    for (int k = 0; k < BlurMaskSize; k++)
                    {
                        SumOfMaskTimesOldPixel.red += (Value * tempMatrix[mRows + k, nCols].red);
                        SumOfMaskTimesOldPixel.green += (Value * tempMatrix[mRows + k, nCols].green);
                        SumOfMaskTimesOldPixel.blue += (Value * tempMatrix[mRows + k, nCols].blue);
                    }

                    NewImageMatrix[mRows, nCols - MaskCenterIndex].red = (byte)SumOfMaskTimesOldPixel.red;
                    NewImageMatrix[mRows, nCols - MaskCenterIndex].green = (byte)SumOfMaskTimesOldPixel.green;
                    NewImageMatrix[mRows, nCols - MaskCenterIndex].blue = (byte)SumOfMaskTimesOldPixel.blue;
                }
            }

            // Calculating the time
            stopWatch.Stop();
            elapsedMs = stopWatch.ElapsedMilliseconds;

            // Return the new blurred image
            return NewImageMatrix;
        }
        /// <summary>
        /// Calculate Gamma Correction - Normal
        /// </summary>
        public static MyColor[,] CalculateGammaCorrection_Normal(MyColor[,] ImageMatrix, MyColor[,] NonImageMatrix)
        {
            // Start a new StopWatch object for calculating the time
            // The variable stopWatch is a GLOBAL variable.
            stopWatch = Stopwatch.StartNew();

            MyColorDouble Y = new MyColorDouble();
            MyColorDouble[,] GammaCImage = new MyColorDouble[GetHeight(ImageMatrix), GetWidth(ImageMatrix)];
            MyColor[,] ModGammaCImage = new MyColor[GetHeight(ImageMatrix), GetWidth(ImageMatrix)];
            var errors = new Dictionary<double, double>();

            MyColor X = new MyColor();
            MyColor[,] GammaCorrImage = new MyColor[GetHeight(ImageMatrix), GetWidth(ImageMatrix)];

            MyColorDouble New, diff;
            double error, sum, minerror = 10000000, difference;
            double Height = GetHeight(ImageMatrix);
            double Width = GetWidth(ImageMatrix);

            for (double x = 0.1; x < 5; x += 0.1)
            {
                sum = 0;
                difference = 0;
                diff.red = 0;
                diff.blue = 0;
                diff.green = 0;

                for (int i = 0; i < Height; i++)
                {
                    for (int j = 0; j < Width; j++)
                    {
                        New.red = Math.Pow(NonImageMatrix[i, j].red, x);
                        New.blue = Math.Pow(NonImageMatrix[i, j].blue, x);
                        New.green = Math.Pow(NonImageMatrix[i, j].green, x);

                        Y.red = New.red;
                        Y.blue = New.blue;
                        Y.green = New.green;

                        GammaCImage[i, j] = Y;
                    }
                }

                ModGammaCImage = GammaContrastImage(GammaCImage);

                for (int i = 0; i < Height; i++)
                {
                    for (int j = 0; j < Width; j++)
                    {
                        diff.red = ImageMatrix[i, j].red - ModGammaCImage[i, j].red;
                        diff.blue = ImageMatrix[i, j].blue - ModGammaCImage[i, j].blue;
                        diff.green = ImageMatrix[i, j].green - ModGammaCImage[i, j].green;

                        difference = Math.Abs(diff.red) + Math.Abs(diff.blue) + Math.Abs(diff.green);
                        sum += Math.Pow(difference, 2);
                    }
                }
                error = (1 / (Height * Width)) * sum;
                errors[x] = error;
            }

            foreach (var index in errors)
            {
                if (minerror >= index.Value)
                {
                    minerror = index.Value;
                    gammavalueNormal = index.Key;
                }
            }

            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    New.red = Math.Pow(NonImageMatrix[i, j].red, gammavalueNormal);
                    New.blue = Math.Pow(NonImageMatrix[i, j].blue, gammavalueNormal);
                    New.green = Math.Pow(NonImageMatrix[i, j].green, gammavalueNormal);

                    Y.red = New.red;
                    Y.blue = New.blue;
                    Y.green = New.green;

                    GammaCImage[i, j] = Y;
                }
            }

            ModGammaCImage = GammaContrastImage(GammaCImage);

            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    X.red = (byte)(ModGammaCImage[i, j].red);
                    X.blue = (byte)(ModGammaCImage[i, j].blue);
                    X.green = (byte)(ModGammaCImage[i, j].green);

                    GammaCorrImage[i, j] = X;
                }
            }

            // Calculating the time
            stopWatch.Stop();
            elapsedMs = stopWatch.ElapsedMilliseconds;

            return GammaCorrImage;
        }
        /// <summary>
        /// Contrast Image - Normal/Efficient Min-Max Algorithm
        /// </summary>
        /// <param name="ImageMatrix">2D ImageMatrix that contains the image</param>
        /// <param name="New">Contrast degree</param>
        /// <returns>2D ImageMatrix of contrasted image colors</returns>
        public static MyColor[,] ContrastImage_Normal(MyColor[,] ImageMatrix, double New)
        {
            // Start a new StopWatch object for calculating the time
            // The variable stopWatch is a GLOBAL variable.
            stopWatch = Stopwatch.StartNew();

            MyColorDouble OldMin = new MyColorDouble();
            MyColorDouble OldMax = new MyColorDouble();
            MyColorDouble NewMin = new MyColorDouble();
            MyColorDouble NewMax = new MyColorDouble();

            MyColorDouble NewPixel = new MyColorDouble();

            MyColor X = new MyColor();
            MyColor[,] NewImageMatrix = new MyColor[GetHeight(ImageMatrix), GetWidth(ImageMatrix)];

            /* To calculate Minimum and Maximum Pixel in the image */
            /* Normal Algorithm */
            GetMinMax_Normal(ImageMatrix, ref OldMin.red, ref OldMax.red, ref OldMin.blue, ref OldMax.blue, ref OldMin.green, ref OldMax.green);

            NewMin.red = OldMin.red - New;
            NewMax.red = OldMax.red + New;

            NewMin.blue = OldMin.red - New;
            NewMax.blue = OldMax.red + New;

            NewMin.green = OldMin.red - New;
            NewMax.green = OldMax.red + New;

            for (int i = 0; i < GetHeight(ImageMatrix); i++)
            {
                for (int j = 0; j < GetWidth(ImageMatrix); j++)
                {
                    NewPixel.red = ((ImageMatrix[i, j].red - OldMin.red) / (OldMax.red - OldMin.red)) * (NewMax.red - NewMin.red) + NewMin.red;
                    NewPixel.blue = ((ImageMatrix[i, j].blue - OldMin.blue) / (OldMax.red - OldMin.blue)) * (NewMax.blue - NewMin.blue) + NewMin.blue;
                    NewPixel.green = ((ImageMatrix[i, j].green - OldMin.green) / (OldMax.green - OldMin.green)) * (NewMax.green - NewMin.green) + NewMin.green;

                    if (NewPixel.red > 255)
                        NewPixel.red = 255;
                    if (NewPixel.red < 0)
                        NewPixel.red = 0;

                    if (NewPixel.blue > 255)
                        NewPixel.blue = 255;
                    if (NewPixel.blue < 0)
                        NewPixel.blue = 0;

                    if (NewPixel.green > 255)
                        NewPixel.green = 255;
                    if (NewPixel.green < 0)
                        NewPixel.green = 0;

                    X.red = (byte)(NewPixel.red);
                    X.blue = (byte)(NewPixel.blue);
                    X.green = (byte)(NewPixel.green);

                    NewImageMatrix[i, j] = X;
                }
            }

            // Calculating the time
            stopWatch.Stop();
            elapsedMs = stopWatch.ElapsedMilliseconds;

            // Return the new contrasted image
            return NewImageMatrix;
        }
        /// <summary>
        /// Blur Image - Normal Algorithm
        /// </summary>
        /// <param name="ImageMatrix">2D ImageMatrix that contains the image</param>
        /// <param name="BlurMaskSize">Blur Degree</param>
        /// <returns>2D ImageMatrix of contrasted image colors</returns>
        public static MyColor[,] BlurImage_Normal(MyColor[,] ImageMatrix, int BlurMaskSize)
        {
            // Start a new StopWatch object for calculating the time
            // The variable stopWatch is a GLOBAL variable.
            stopWatch = Stopwatch.StartNew();

            // MAP stores blurr degree and index of center of mask
            Dictionary<int, int> MaskCenterElement = new Dictionary<int, int>();
            MaskCenterElement.Add(3, 1);
            MaskCenterElement.Add(5, 2);
            MaskCenterElement.Add(7, 3);
            MaskCenterElement.Add(9, 4);
            MaskCenterElement.Add(11, 5);
            MaskCenterElement.Add(13, 6);
            MaskCenterElement.Add(15, 7);
            MaskCenterElement.Add(17, 8);

            // Blur Scalar number
            double MaskElementValue = 1.0 / (BlurMaskSize * BlurMaskSize);

            // Center Index of needed blurr degree
            int MaskCenterIndex = 0;
            foreach (var index in MaskCenterElement)
            {
                if (index.Key == BlurMaskSize)
                {
                    MaskCenterIndex = index.Value;
                    break;
                }
            }

            // Original image matrix (size: Height+(CenterIndex * 2) x Width+(CenterIndex * 2))
            MyColor[,] OriginalImage = new MyColor[GetHeight(ImageMatrix) + (MaskCenterIndex * 2), GetWidth(ImageMatrix) + (MaskCenterIndex * 2)];
            for (int x = MaskCenterIndex; x < GetHeight(ImageMatrix) + MaskCenterIndex; x++)
            {
                for (int y = MaskCenterIndex; y < GetWidth(ImageMatrix) + MaskCenterIndex; y++)
                    OriginalImage[x, y] = ImageMatrix[x - MaskCenterIndex, y - MaskCenterIndex];
            }

            // The new blurred image matrix
            MyColor[,] NewImageMatrix = new MyColor[GetHeight(ImageMatrix), GetWidth(ImageMatrix)];
            // Blur Mask Matrix
            MyColor[,] BlurMask = new MyColor[BlurMaskSize, BlurMaskSize];

            // N rows
            for (int m = 0; m < GetHeight(OriginalImage) - BlurMaskSize; m++)
            {
                // N columns
                for (int n = 0; n < GetWidth(OriginalImage) - BlurMaskSize; n++)
                {
                    MyColorDouble BlurMaskPixel = new MyColorDouble();
                    BlurMaskPixel.red = 0; BlurMaskPixel.green = 0; BlurMaskPixel.blue = 0;

                    MyColorDouble SumOfMaskTimesOldPixel = new MyColorDouble();
                    SumOfMaskTimesOldPixel.red = 0;
                    SumOfMaskTimesOldPixel.green = 0;
                    SumOfMaskTimesOldPixel.blue = 0;

                    // Create-Fill Mask Values
                    for (int i = 0, v = m; v < m + BlurMaskSize; i++, v++)  //k  rows
                    {
                        for (int j = 0, x = n; x < n + BlurMaskSize; j++, x++)  //k cols
                        {
                            BlurMaskPixel.red = (MaskElementValue * OriginalImage[v, x].red);
                            BlurMaskPixel.green = (MaskElementValue * OriginalImage[v, x].green);
                            BlurMaskPixel.blue = (MaskElementValue * OriginalImage[v, x].blue);

                            SumOfMaskTimesOldPixel.red += BlurMaskPixel.red;
                            SumOfMaskTimesOldPixel.green += BlurMaskPixel.green;
                            SumOfMaskTimesOldPixel.blue += BlurMaskPixel.blue;
                        }
                    }

                    NewImageMatrix[m, n].red = (byte)SumOfMaskTimesOldPixel.red;
                    NewImageMatrix[m, n].green = (byte)SumOfMaskTimesOldPixel.green;
                    NewImageMatrix[m, n].blue = (byte)SumOfMaskTimesOldPixel.blue;
                }
            }

            // Calculating the time
            stopWatch.Stop();
            elapsedMs = stopWatch.ElapsedMilliseconds;

            // Return the new blurred image
            return NewImageMatrix;
        }
        /// <summary>
        /// Calculate Gamma Correction - Efficient
        /// </summary>
        public static MyColor[,] CalculateGammaCorrection_Efficient(MyColor[,] ImageMatrix, MyColor[,] NonImageMatrix)
        {
            // Start a new StopWatch object for calculating the time
            // The variable stopWatch is a GLOBAL variable.
            stopWatch = Stopwatch.StartNew();

            MyColorDouble New ;
            MyColor X = new MyColor();
            MyColor[,] GammaCorrImage = new MyColor[GetHeight(ImageMatrix), GetWidth(ImageMatrix)];
            MyColor[,] ModGammaCImage = new MyColor[GetHeight(ImageMatrix), GetWidth(ImageMatrix)];
            MyColorDouble Y = new MyColorDouble();
            MyColorDouble[,] GammaCImage = new MyColorDouble[GetHeight(ImageMatrix), GetWidth(ImageMatrix)];

            double Height = GetHeight(ImageMatrix);
            double Width = GetWidth(ImageMatrix);

            gammavalueEfficient = UNIMODALSEARCH(ImageMatrix, NonImageMatrix, 0.1, 5);

            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    New.red = Math.Pow(NonImageMatrix[i, j].red, gammavalueEfficient);
                    New.blue = Math.Pow(NonImageMatrix[i, j].blue, gammavalueEfficient);
                    New.green = Math.Pow(NonImageMatrix[i, j].green, gammavalueEfficient);

                    Y.red = New.red;
                    Y.blue = New.blue;
                    Y.green = New.green;

                    GammaCImage[i, j] = Y;
                }
            }

            ModGammaCImage = GammaContrastImage(GammaCImage);

            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    X.red = (byte)(ModGammaCImage[i, j].red);
                    X.blue = (byte)(ModGammaCImage[i, j].blue);
                    X.green = (byte)(ModGammaCImage[i, j].green);

                    GammaCorrImage[i, j] = X;
                }
            }

            // Calculating the time
            stopWatch.Stop();
            elapsedMs = stopWatch.ElapsedMilliseconds;

            return GammaCorrImage;
        }
        /// <summary>
        /// Unimodel Search
        /// </summary>
        public static double UNIMODALSEARCH(MyColor[,] ImageMatrix, MyColor[,] NonImageMatrix, double low, double high)
        {
            double mid = 0;
            MyColor[,] ModGammaCImage = new MyColor[GetHeight(ImageMatrix), GetWidth(ImageMatrix)];
            MyColorDouble Y = new MyColorDouble();
            MyColorDouble[,] GammaCImage = new MyColorDouble[GetHeight(ImageMatrix), GetWidth(ImageMatrix)];

            MyColorDouble New,diff;
            double Height = GetHeight(ImageMatrix);
            double Width = GetWidth(ImageMatrix);
            double difference , sum , error;

            double[] errors = new double[3];
            int a = 0;

            if (low == high)
            {
                return low;
            }

            if ( (high+1) % 2 == 0)
                mid = (low + high) / 2;
            else
                mid = (low + high) / 2 + 1;

            for (double k = mid - 1 ; k <= mid + 1; k++)
            {
                sum = 0;

                for (int i = 0; i < GetHeight(ImageMatrix); i++)
                {
                    for (int j = 0; j < GetWidth(ImageMatrix); j++)
                    {

                        New.red = Math.Pow(NonImageMatrix[i, j].red, k);
                        New.blue = Math.Pow(NonImageMatrix[i, j].blue, k);
                        New.green = Math.Pow(NonImageMatrix[i, j].green, k);

                        Y.red = New.red;
                        Y.blue = New.blue;
                        Y.green = New.green;

                        GammaCImage[i, j] = Y;
                    }
                }

                ModGammaCImage = GammaContrastImage(GammaCImage);

                for (int i = 0; i < Height; i++)
                {
                    for (int j = 0; j < Width; j++)
                    {
                        diff.red = ImageMatrix[i, j].red - ModGammaCImage[i, j].red;
                        diff.blue = ImageMatrix[i, j].blue - ModGammaCImage[i, j].blue;
                        diff.green = ImageMatrix[i, j].green - ModGammaCImage[i, j].green;

                        difference = Math.Abs(diff.red) + Math.Abs(diff.blue) + Math.Abs(diff.green);
                        sum += Math.Pow(difference, 2);
                    }
                }
                error = (1 / (Height * Width)) * sum;
                errors[a] = error;
                a++;
            }

            if (errors[1] < errors[0] && errors[1] < errors[2])
                return mid;

            if (errors[1] < errors[0])
                return UNIMODALSEARCH(ImageMatrix , NonImageMatrix, mid + 1, high);

            else
                return UNIMODALSEARCH(ImageMatrix, NonImageMatrix, low, mid - 1);
        }
        /// <summary>
        /// Save the blurred image on the given PictureBox object
        /// </summary>
        /// <param name="ImageMatrix">2D ImageMatrix that contains the image</param>
        public static void SaveImage(MyColor[,] ImageMatrix)
        {
            // Create New Image:
            //======================
            int Height = ImageMatrix.GetLength(0);
            int Width = ImageMatrix.GetLength(1);

            Bitmap NewImageBMP = new Bitmap(Width, Height, PixelFormat.Format24bppRgb);
            unsafe
            {
                BitmapData bmd = NewImageBMP.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, NewImageBMP.PixelFormat);
                int nWidth = 0;
                nWidth = Width * 3;
                int nOffset = bmd.Stride - nWidth;
                byte* p = (byte*)bmd.Scan0;
                for (int i = 0; i < Height; i++)
                {
                    for (int j = 0; j < Width; j++)
                    {
                        p[0] = ImageMatrix[i, j].red;
                        p[1] = ImageMatrix[i, j].green;
                        p[2] = ImageMatrix[i, j].blue;
                        p += 3;
                    }

                    p += nOffset;
                }
                NewImageBMP.UnlockBits(bmd);
            }

            if (NewImageBMP != null)
            {
                SaveFileDialog saveFileDialog1 = new SaveFileDialog();

                if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    string fileExtension = Path.GetExtension(saveFileDialog1.FileName).ToUpper();
                    ImageFormat imgFormat = ImageFormat.Bmp;

                    if (fileExtension == "JPG")
                    {
                        imgFormat = ImageFormat.Jpeg;
                    }

                    string saveFile = saveFileDialog1.FileName + "." + imgFormat;
                    StreamWriter streamWriter = new StreamWriter(saveFile, false);
                    NewImageBMP.Save(streamWriter.BaseStream, imgFormat);
                    streamWriter.Flush();
                    streamWriter.Close();

                    NewImageBMP = null;
                }
            }
        }
        /// <summary>
        /// Open an image and load it into 2D ImageMatrixay of colors (size: Height x Width)
        /// </summary>
        /// <param name="ImagePath">Image file path</param>
        /// <returns>2D ImageMatrixay of colors</returns>
        public static MyColor[,] OpenImage(string ImagePath)
        {
            Bitmap original_bm = new Bitmap(ImagePath);

            int Height = original_bm.Height;
            int Width = original_bm.Width;

            MyColor[,] Buffer = new MyColor[Height, Width];

            unsafe
            {
                BitmapData bmd = original_bm.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, original_bm.PixelFormat);
                int x, y;
                int nWidth = 0;
                bool Format32 = false;
                bool Format24 = false;
                bool Format8 = false;

                if (original_bm.PixelFormat == PixelFormat.Format24bppRgb)
                {
                    Format24 = true;
                    nWidth = Width * 3;
                }
                else if (original_bm.PixelFormat == PixelFormat.Format32bppArgb || original_bm.PixelFormat == PixelFormat.Format32bppRgb || original_bm.PixelFormat == PixelFormat.Format32bppPArgb)
                {
                    Format32 = true;
                    nWidth = Width * 4;
                }
                else if (original_bm.PixelFormat == PixelFormat.Format8bppIndexed)
                {
                    Format8 = true;
                    nWidth = Width;
                }
                int nOffset = bmd.Stride - nWidth;
                byte* p = (byte*)bmd.Scan0;
                for (y = 0; y < Height; y++)
                {
                    for (x = 0; x < Width; x++)
                    {
                        if (Format8)
                        {
                            Buffer[y, x].red = Buffer[y, x].green = Buffer[y, x].blue = p[0];
                            p++;
                        }
                        else
                        {
                            Buffer[y, x].red = p[0];
                            Buffer[y, x].green = p[1];
                            Buffer[y, x].blue = p[2];
                            if (Format24) p += 3;
                            else if (Format32) p += 4;
                        }
                    }
                    p += nOffset;
                }
                original_bm.UnlockBits(bmd);
            }

            return Buffer;
        }
        /// <summary>
        /// Normal resize of an image
        /// </summary>
        /// <param name="ImageMatrix">2D array of image values</param>
        /// <param name="NewWidth">desired width</param>
        /// <param name="NewHeight">desired height</param>
        /// <returns>Resized image</returns>
        public static MyColor[,] NormalResize(MyColor[,] ImageMatrix, int NewWidth, int NewHeight)
        {
            int i = 0, j = 0;
            int Height = ImageMatrix.GetLength(0);
            int Width = ImageMatrix.GetLength(1);

            double WidthRatio = (double)(Width) / (double)(NewWidth);
            double HeightRatio = (double)(Height) / (double)(NewHeight);

            int OldWidth = Width;
            int OldHeight = Height;

            MyColor P1, P2, P3, P4;

            MyColor Y1, Y2, X = new MyColor();

            MyColor[,] Data = new MyColor[NewHeight, NewWidth];

            Width = NewWidth;
            Height = NewHeight;

            int floor_x, ceil_x;
            int floor_y, ceil_y;

            double x, y;
            double fraction_x, one_minus_x;
            double fraction_y, one_minus_y;

            for (j = 0; j < NewHeight; j++)
                for (i = 0; i < NewWidth; i++)
                {
                    x = (double)(i) * WidthRatio;
                    y = (double)(j) * HeightRatio;

                    floor_x = (int)(x);
                    ceil_x = floor_x + 1;
                    if (ceil_x >= OldWidth) ceil_x = floor_x;

                    floor_y = (int)(y);
                    ceil_y = floor_y + 1;
                    if (ceil_y >= OldHeight) ceil_y = floor_y;

                    fraction_x = x - floor_x;
                    one_minus_x = 1.0 - fraction_x;

                    fraction_y = y - floor_y;
                    one_minus_y = 1.0 - fraction_y;

                    P1 = ImageMatrix[floor_y, floor_x];
                    P2 = ImageMatrix[ceil_y, floor_x];
                    P3 = ImageMatrix[floor_y, ceil_x];
                    P4 = ImageMatrix[ceil_y, ceil_x];

                    Y1.red = (byte)(one_minus_y * P1.red + fraction_y * P2.red);
                    Y1.green = (byte)(one_minus_y * P1.green + fraction_y * P2.green);
                    Y1.blue = (byte)(one_minus_y * P1.blue + fraction_y * P2.blue);

                    Y2.red = (byte)(one_minus_y * P3.red + fraction_y * P4.red);
                    Y2.green = (byte)(one_minus_y * P3.green + fraction_y * P4.green);
                    Y2.blue = (byte)(one_minus_y * P3.blue + fraction_y * P4.blue);

                    X.red = (byte)(one_minus_x * Y1.red + fraction_x * Y2.red);
                    X.green = (byte)(one_minus_x * Y1.green + fraction_x * Y2.green);
                    X.blue = (byte)(one_minus_x * Y1.blue + fraction_x * Y2.blue);

                    Data[j, i] = X;
                }

            return Data;
        }
 /// <summary>
 /// Get the width of the image 
 /// </summary>
 /// <param name="ImageMatrix">2D ImageMatrixay that contains the image</param>
 /// <returns>Image Width</returns>
 public static int GetWidth(MyColor[,] ImageMatrix)
 {
     return ImageMatrix.GetLength(1);
 }