// Source - https://jivp-eurasipjournals.springeropen.com/articles/10.1186/s13640-016-0138-1
        public static Image <Bgr, Byte> Adaptive(Image <Bgr, Byte> image, bool showWindows = false)
        {
            Image <Hsv, Byte>    hsvImage;
            Image <Gray, Byte>   grayImage;
            Image <Gray, double> grayImageNormilized;
            Image <Gray, Byte>   grayImageEnhanced;
            Image <Gray, double> grayImageEnhancedNormilized;
            Image <Hsv, Byte>    hsvImageEnhanced;
            Image <Bgr, Byte>    result;

            // Color image?
            // FOR NOW CONSIDER ONLY COLOR IMAGES
            bool isColorImage = true;

            // RGB to HSV and take V
            hsvImage = ImageHelper.ToHsv(image);
            var hsvChannels = hsvImage.Split();

            grayImage = hsvChannels.ElementAt(2);

            // Normalize image
            grayImageNormilized = ImageHelper.NormalizeImage(grayImage);

            // Low contrast image?
            bool isLowContrastImage;
            bool isDarkImage;

            double[] pixelValues         = ImageHelper.GetImagePixels(grayImageNormilized);
            double[] positivePixelValues = pixelValues.Where(x => x > 0).ToArray();   // filter 0 values to retrieve more accurate results (according to article)
            double   mu    = StatisticsHelper.Average(positivePixelValues);           // mean of the image intensity
            double   sigma = StatisticsHelper.StandartDeviation(positivePixelValues); // standard deviation

            Func <List <string> > g = () =>
            {
                string Q1 = "Q1"; // low-contrast class
                string Q2 = "Q2"; // high (or moderate) contrast class

                string QSubclassDark   = "Dark";
                string QSubclassBright = "Bright";

                string Q;
                string QSubclass;

                // D=diff((μ+2σ),(μ−2σ))
                //double D = (mu + 2.0 * sigma) - (mu - 2.0 * sigma);
                double D = 4.0 * sigma; // seci=ond criteria

                //  τ is a parameter used for defining the contrast of an image
                double tao = 3.0; // τ=3 is a suitable choice for characterizing the contrasts of different images.

                if (D <= (1.0 / tao))
                {
                    Q = Q1;
                }
                else
                {
                    Q = Q2;
                }

                if (mu >= 0.5)
                {
                    QSubclass = QSubclassBright;
                }
                else
                {
                    QSubclass = QSubclassDark;
                }

                return(new List <string>()
                {
                    Q,
                    QSubclass
                });
            };

            List <string> imageClasses = g();

            isLowContrastImage = imageClasses[0] == "Q1" ? true : false;
            isDarkImage        = imageClasses[1] == "Dark" ? true : false;

            // Intensity transformation

            // c and γ are two parameters that control the shape of the transformation curve
            //  In contrast to traditional gamma correction, AGC sets the values of γ and c automatically using image information, making it an adaptive method
            double c     = default(double);
            double gamma = default(double);

            Func <double, double> Heaviside = (x) =>
            {
                if (x <= 0)
                {
                    return(0);
                }
                else // (x > 0)
                {
                    return(1);
                }
            };

            grayImageEnhancedNormilized = new Image <Gray, double>(grayImage.Size);

            for (int m = 0; m < grayImageNormilized.Rows; m++)
            {
                for (int n = 0; n < grayImageNormilized.Cols; n++)
                {
                    Gray   pixel = grayImageNormilized[m, n];
                    double I_in  = pixel.Intensity;

                    //// Enhancement of low-contrast image
                    if (isLowContrastImage)
                    {
                        // calc gamma
                        gamma = -Math.Log(sigma, newBase: 2);

                        // calc k
                        double I_gamma = Math.Pow(I_in, gamma);
                        double k       = I_gamma + (1 - I_gamma) * Math.Pow(mu, gamma);

                        // calc c
                        c = 1.0 / (1.0 + Heaviside(0.5 - mu) * (k - 1.0));

                        // Bright image in Q1
                        if (isDarkImage == false)
                        {
                            // mu  >= 0.5 => c = 1
                            //c = 1;
                        }
                        // Dark image in Q1
                        if (isDarkImage == true)
                        {
                            // mu < 0.5 => c = 1/k
                            //c = 1.0 / k;
                        }
                    }

                    ////  Enhancement of high- or moderate-contrast image
                    if (isLowContrastImage == false)
                    {
                        // calc gamma
                        gamma = Math.Exp((1.0 - (mu + sigma)) / 2.0);

                        // calc k
                        double I_gamma = Math.Pow(I_in, gamma);
                        double k       = I_gamma + (1.0 - I_gamma) * Math.Pow(mu, gamma);

                        // calc c
                        c = 1.0 / (1.0 + Heaviside(0.5 - mu) * (k - 1.0));

                        // Dark image in Q2
                        if (isDarkImage == true)
                        {
                            // For images with μ<0.5, (μ+σ)≤1, since both μ and σ are less than (or equal to) 0.5 which implies γ≥1
                        }

                        // Bright image in ϱ 2
                        if (isDarkImage == false)
                        {
                        }
                    }

                    // apply final formula
                    // I_out = c * I_in
                    double val = c * Math.Pow(I_in, gamma);
                    grayImageEnhancedNormilized[m, n] = new Gray(val);
                }
            }

            // DeNormalize image
            grayImage         = ImageHelper.DeNormalizeImage(grayImageNormilized);
            grayImageEnhanced = ImageHelper.DeNormalizeImage(grayImageEnhancedNormilized);

            // get enhanced hsv image
            hsvImageEnhanced = new Image <Hsv, byte>(new Image <Gray, Byte>[] { hsvChannels[0], hsvChannels[1], grayImageEnhanced });

            // convert hsv to rgb
            result = ImageHelper.ToBgr(hsvImageEnhanced);

            if (showWindows)
            {
                EmguCvWindowManager.Display(image, "AGC_V2_1 image");
                EmguCvWindowManager.Display(hsvImage, "AGC_V2_2 hsvImage");
                EmguCvWindowManager.Display(grayImage, "AGC_V2_3 grayImage");
                EmguCvWindowManager.Display(grayImageEnhanced, "AGC_V2_4 grayImageEnhanced");
                EmguCvWindowManager.Display(hsvImageEnhanced, "AGC_V2_5 hsvImageEnhanced");
                EmguCvWindowManager.Display(result, "AGC_V2_6 result");
            }

            return(result);
        }