public static int OtsuThreshold(this BitmapSource bitmapSource)
        {
            int[]  histogram                = bitmapSource.BrightnessHistogram();
            int    histogramSum             = histogram.Sum();
            double preThresholdProbability  = 0;
            double postThresholdProbability = 1;
            Dictionary <int, double> withinClassVariances = new Dictionary <int, double>();

            for (int potentialThreshold = 0; potentialThreshold < histogram.Length; potentialThreshold++)
            {
                preThresholdProbability  += (double)histogram[potentialThreshold] / histogramSum;
                postThresholdProbability -= (double)histogram[potentialThreshold] / histogramSum;
                // TODO: Zamienić wszystko na prawdopodobieństwa
                if (preThresholdProbability == 0)
                {
                    continue;
                }
                if (postThresholdProbability == 0)
                {
                    break;
                }

                double preThresholdAvg  = 0;
                double postThresholdAvg = 0;
                for (int i = 0; i <= potentialThreshold; i++)
                {
                    preThresholdAvg += (double)histogram[i] / histogramSum * i;
                }
                for (int i = potentialThreshold + 1; i < histogram.Length; i++)
                {
                    postThresholdAvg += (double)histogram[i] / histogramSum * i;
                }
                preThresholdAvg  /= preThresholdProbability;
                postThresholdAvg /= postThresholdProbability;

                double preThresholdVariance  = 0;
                double postThresholdVariance = 0;
                for (int i = 0; i <= potentialThreshold; i++)
                {
                    preThresholdVariance += (i - preThresholdAvg) * (i - preThresholdAvg) * ((double)histogram[i] / histogramSum);
                }
                for (int i = potentialThreshold + 1; i < histogram.Length; i++)
                {
                    postThresholdVariance += (i - postThresholdAvg) * (i - postThresholdAvg) * ((double)histogram[i] / histogramSum);
                }
                preThresholdVariance  /= preThresholdProbability;
                postThresholdVariance /= postThresholdProbability;

                double withinClassVariance = preThresholdProbability * preThresholdVariance + postThresholdProbability * postThresholdVariance;
                withinClassVariances.Add(potentialThreshold, withinClassVariance);
            }
            return(withinClassVariances.Aggregate((l, r) => l.Value < r.Value ? l : r).Key);
        }
        public static byte MeanIterativeThreshold(this BitmapSource bitmapSource)
        {
            int[] Histogram = bitmapSource.BrightnessHistogram();
            int   X;
            int   MeanValueOne, MeanValueTwo, SumOne, SumTwo, SumIntegralOne, SumIntegralTwo;
            int   MinValue, MaxValue;
            int   Threshold, NewThreshold;

            for (MinValue = 0; MinValue < 256 && Histogram[MinValue] == 0; MinValue++)
            {
                ;
            }
            for (MaxValue = 255; MaxValue > MinValue && Histogram[MinValue] == 0; MaxValue--)
            {
                ;
            }

            if (MaxValue == MinValue)
            {
                return(Convert.ToByte(MaxValue));
            }
            if (MinValue + 1 == MaxValue)
            {
                return(Convert.ToByte(MinValue));
            }

            Threshold    = MinValue;
            NewThreshold = (MaxValue + MinValue) >> 1;
            for (int i = 0; Threshold != NewThreshold; i++)
            {
                SumOne    = 0; SumIntegralOne = 0;
                SumTwo    = 0; SumIntegralTwo = 0;
                Threshold = NewThreshold;
                for (X = MinValue; X <= Threshold; X++)
                {
                    SumIntegralOne += Histogram[X] * X;
                    SumOne         += Histogram[X];
                }
                MeanValueOne = SumIntegralOne / SumOne;
                for (X = Threshold + 1; X <= MaxValue; X++)
                {
                    SumIntegralTwo += Histogram[X] * X;
                    SumTwo         += Histogram[X];
                }
                MeanValueTwo = SumIntegralTwo / SumTwo;
                NewThreshold = (MeanValueOne + MeanValueTwo) >> 1;
            }
            return(Convert.ToByte(Threshold));
        }
        public static byte BlackPercentageThreshold(this BitmapSource bitmapSource, int percentage)
        {
            int[]  histogram = bitmapSource.BrightnessHistogram();
            int    allPixelsCount = histogram.Sum(), pixelsCount = 0;
            double nPercentage      = Convert.ToDouble(percentage) / 100.0;
            var    blackPixelsCount = allPixelsCount * nPercentage;

            for (byte threshold = 0; threshold <= 255; threshold++)
            {
                pixelsCount += histogram[threshold];
                if (pixelsCount >= blackPixelsCount)
                {
                    return(threshold);
                }
            }
            return(255);
        }
        public static byte EntropyThreshold(this BitmapSource bitmapSource)
        {
            int[] Histogram = bitmapSource.BrightnessHistogram();
            int   X, Y, Amount = 0;

            double[] HistGramD = new double[256];
            double   SumIntegral, EntropyBack, EntropyFore, MaxEntropy;
            int      MinValue, MaxValue;
            int      Threshold = 0;

            for (MinValue = 0; MinValue < 256 && Histogram[MinValue] == 0; MinValue++)
            {
                ;
            }
            for (MaxValue = 255; MaxValue > MinValue && Histogram[MinValue] == 0; MaxValue--)
            {
                ;
            }
            if (MaxValue == MinValue)
            {
                return(Convert.ToByte(MaxValue));
            }
            if (MinValue + 1 == MaxValue)
            {
                return(Convert.ToByte(MinValue));
            }

            for (Y = MinValue; Y <= MaxValue; Y++)
            {
                Amount += Histogram[Y];
            }

            for (Y = MinValue; Y <= MaxValue; Y++)
            {
                HistGramD[Y] = (double)Histogram[Y] / Amount + 1e-17;
            }

            MaxEntropy = double.MinValue;
            for (Y = MinValue + 1; Y < MaxValue; Y++)
            {
                SumIntegral = 0;
                for (X = MinValue; X <= Y; X++)
                {
                    SumIntegral += HistGramD[X];
                }
                EntropyBack = 0;
                for (X = MinValue; X <= Y; X++)
                {
                    EntropyBack += (-HistGramD[X] / SumIntegral * Math.Log(HistGramD[X] / SumIntegral));
                }
                EntropyFore = 0;
                for (X = Y + 1; X <= MaxValue; X++)
                {
                    EntropyFore += (-HistGramD[X] / (1 - SumIntegral) * Math.Log(HistGramD[X] / (1 - SumIntegral)));
                }
                if (MaxEntropy < EntropyBack + EntropyFore)
                {
                    Threshold  = Y;
                    MaxEntropy = EntropyBack + EntropyFore;
                }
            }
            return(Convert.ToByte(Threshold));
        }