Пример #1
0
 public static void binary_autoinvert(Bytearray image)
 {
     check_binary(image);
     int count = 0;
     for (int i = 0; i < image.Length1d(); i++)
         if (image.At1d(i) > 0) count++;
     if (count > image.Length1d() / 2)
         binary_invert(image);
 }
Пример #2
0
 public static void make_binary(Bytearray image)
 {
     for (int i = 0; i < image.Length1d(); i++)
     {
         image.Put1d(i, (byte)(image.At1d(i) > 0 ? 255 : 0));
     }
 }
Пример #3
0
 public static int binarize_simple(Bytearray result, Bytearray image)
 {
     int threshold = (NarrayUtil.Max(image)/* + NarrayUtil.Min(image)*/) / 2;
     result.MakeLike(image);
     for (int i = 0; i < image.Length1d(); i++)
         result.Put1d(i, image.At1d(i) < threshold ? (byte)0 : (byte)255);
     return threshold;
 }
Пример #4
0
        public static void binary_autoinvert(Bytearray image)
        {
            check_binary(image);
            int count = 0;

            for (int i = 0; i < image.Length1d(); i++)
            {
                if (image.At1d(i) > 0)
                {
                    count++;
                }
            }
            if (count > image.Length1d() / 2)
            {
                binary_invert(image);
            }
        }
Пример #5
0
 public static void binary_invert(Bytearray image)
 {
     check_binary(image);
     for (int i = 0; i < image.Length1d(); i++)
     {
         image.Put1d(i, (byte)(255 - image.At1d(i)));
     }
 }
Пример #6
0
 public static void binarize_with_threshold(Bytearray result, Bytearray image, int threshold)
 {
     result.MakeLike(image);
     for (int i = 0; i < image.Length1d(); i++)
     {
         result.Put1d(i, image.At1d(i) < threshold ? (byte)0 : (byte)255);
     }
 }
Пример #7
0
        public static void Invert(Bytearray a)
        {
            int n = a.Length1d();

            for (int i = 0; i < n; i++)
            {
                a.Put1d(i, (byte)(255 - a.At1d(i)));
            }
        }
Пример #8
0
        public static void Thin(ref Bytearray uci)
        {
            int w = uci.Dim(0) - 1;
            int h = uci.Dim(1) - 1;

            for (int i = 0, n = uci.Length1d(); i < n; i++)
            {
                if (uci.At1d(i) > 0)
                    uci.Put1d(i, ON);
                else
                    uci.Put1d(i, OFF);
            }

            bool flag;
            do
            {
                flag = false;
                for (int j = 0; j < 8; j += 2)
                {
                    for (int x = 1; x < w; x++)
                        for (int y = 1; y < h; y++)
                        {
                            if (uci[x, y] != ON)
                                continue;
                            if (uci[x + nx[j], y + ny[j]] != OFF)
                                continue;
                            int b = 0;
                            for (int i = 7; i >= 0; i--)
                            {
                                b <<= 1;
                                b |= (uci[x + nx[i], y + ny[i]] != OFF ? 1 : 0);
                            }
                            if (ttable[b] > 0)
                                uci[x, y] = SKEL;
                            else
                            {
                                uci[x, y] = DEL;
                                flag = true;
                            }
                        }
                    if (!flag)
                        continue;
                    for (int x = 1; x < w; x++)
                        for (int y = 1; y < h; y++)
                            if (uci[x, y] == DEL)
                                uci[x, y] = OFF;
                }
            } while (flag);

            for (int i = 0, n = uci.Length1d(); i < n; i++)
            {
                if (uci.At1d(i) == SKEL)
                    uci.Put1d(i, 255);
                else
                    uci.Put1d(i, 0);
            }
        }
Пример #9
0
 public static Bitmap read_image_binary(Bytearray image, string path)
 {
     Bitmap bitmap = LoadBitmapFromFile(path);
     image.Resize(bitmap.Width, bitmap.Height);
     ImgRoutine.NarrayFromBitmap(image, bitmap);
     double threshold = (NarrayUtil.Min(image) + NarrayUtil.Max(image)) / 2.0;
     for (int i = 0; i < image.Length1d(); i++)
         image.Put1d(i, (byte)((image.At1d(i) < threshold) ? 0 : 255));
     return bitmap;
 }
Пример #10
0
        public static int binarize_simple(Bytearray result, Bytearray image)
        {
            int threshold = (NarrayUtil.Max(image) /* + NarrayUtil.Min(image)*/) / 2;

            result.MakeLike(image);
            for (int i = 0; i < image.Length1d(); i++)
            {
                result.Put1d(i, image.At1d(i) < threshold ? (byte)0 : (byte)255);
            }
            return(threshold);
        }
Пример #11
0
 public static void check_binary(Bytearray image)
 {
     for (int i = 0; i < image.Length1d(); i++)
     {
         int value = image.At1d(i);
         if (!(value == 0 || value == 255))
         {
             throw new Exception("check_binary: value must be 0 or 255");
         }
     }
 }
Пример #12
0
 public static void segmentation_as_bitmap(Bytearray image, Intarray cseg)
 {
     image.MakeLike(cseg);
     for (int i = 0; i < image.Length1d(); i++)
     {
         int value = cseg.At1d(i);
         if (value == 0 || value == 0xffffff)
         {
             image.Put1d(i, 255);
         }
         //if (value == 0xffffff) image.Put1d(i, 255);
     }
 }
Пример #13
0
        public static Bitmap read_image_binary(Bytearray image, string path)
        {
            Bitmap bitmap = LoadBitmapFromFile(path);

            image.Resize(bitmap.Width, bitmap.Height);
            ImgRoutine.NarrayFromBitmap(image, bitmap);
            double threshold = (NarrayUtil.Min(image) + NarrayUtil.Max(image)) / 2.0;

            for (int i = 0; i < image.Length1d(); i++)
            {
                image.Put1d(i, (byte)((image.At1d(i) < threshold) ? 0 : 255));
            }
            return(bitmap);
        }
Пример #14
0
        /// <summary>
        /// Remove segments from start to end.
        /// </summary>
        /// <param name="cseg">Output</param>
        /// <param name="rseg">Input</param>
        /// <param name="start">start remove position</param>
        /// <param name="end">end remove position</param>
        public static void rseg_to_cseg_remove(Intarray cseg, Intarray rseg,
                                               Bytearray outimg, Bytearray img, int start, int end)
        {
            int maxSegNum = NarrayUtil.Max(rseg);

            if (start > end)
            {
                throw new Exception("segmentation encoded in IDs looks seriously broken!");
            }
            if (start > maxSegNum || end > maxSegNum)
            {
                throw new Exception("segmentation encoded in IDs doesn't fit!");
            }
            if (rseg.Length1d() != img.Length1d())
            {
                throw new Exception("rseg and img must have same a dimension!");
            }
            Intarray map = new Intarray(maxSegNum + 1);

            map.Fill(0);

            int color = 1;

            for (int i = 1; i <= maxSegNum; i++)
            {
                map[i] = color;
                if (i < start || i > end)
                {
                    color++;
                }
                else
                {
                    map[i] = 0;
                }
            }
            cseg.MakeLike(rseg);
            outimg.Copy(img);
            for (int i = 0; i < cseg.Length1d(); i++)
            {
                int val = rseg.At1d(i);
                cseg.Put1d(i, map[val]);
                if (val > 0 && map[val] == 0)
                {
                    outimg.Put1d(i, 255);
                }
            }
        }
Пример #15
0
        public override void Binarize(Bytearray bin_image, Bytearray gray_image)
        {
            w     = PGeti("w");
            k     = (float)PGetf("k");
            whalf = w >> 1;
            // fprintf(stderr,"[sauvola %g %d]\n",k,w);
            if (k < 0.001 || k > 0.999)
            {
                throw new Exception("Binarize: CHECK_ARG(k>=0.001 && k<=0.999)");
            }
            if (w == 0 || k >= 1000)
            {
                throw new Exception("Binarize: CHECK_ARG(w>0 && k<1000)");
            }
            if (bin_image.Length1d() != gray_image.Length1d())
            {
                bin_image.MakeLike(gray_image);
            }

            if (NarrayUtil.contains_only(gray_image, (byte)0, (byte)255))
            {
                bin_image.Copy(gray_image);
                return;
            }

            int image_width  = gray_image.Dim(0);
            int image_height = gray_image.Dim(1);

            whalf = w >> 1;

            // Calculate the integral image, and integral of the squared image
            Narray <long> integral_image = new Narray <long>(), rowsum_image = new Narray <long>();
            Narray <long> integral_sqimg = new Narray <long>(), rowsum_sqimg = new Narray <long>();

            integral_image.MakeLike(gray_image);
            rowsum_image.MakeLike(gray_image);
            integral_sqimg.MakeLike(gray_image);
            rowsum_sqimg.MakeLike(gray_image);
            int    xmin, ymin, xmax, ymax;
            double diagsum, idiagsum, diff, sqdiagsum, sqidiagsum, sqdiff, area;
            double mean, std, threshold;

            for (int j = 0; j < image_height; j++)
            {
                rowsum_image[0, j] = gray_image[0, j];
                rowsum_sqimg[0, j] = gray_image[0, j] * gray_image[0, j];
            }
            for (int i = 1; i < image_width; i++)
            {
                for (int j = 0; j < image_height; j++)
                {
                    rowsum_image[i, j] = rowsum_image[i - 1, j] + gray_image[i, j];
                    rowsum_sqimg[i, j] = rowsum_sqimg[i - 1, j] + gray_image[i, j] * gray_image[i, j];
                }
            }

            for (int i = 0; i < image_width; i++)
            {
                integral_image[i, 0] = rowsum_image[i, 0];
                integral_sqimg[i, 0] = rowsum_sqimg[i, 0];
            }
            for (int i = 0; i < image_width; i++)
            {
                for (int j = 1; j < image_height; j++)
                {
                    integral_image[i, j] = integral_image[i, j - 1] + rowsum_image[i, j];
                    integral_sqimg[i, j] = integral_sqimg[i, j - 1] + rowsum_sqimg[i, j];
                }
            }

            //Calculate the mean and standard deviation using the integral image

            for (int i = 0; i < image_width; i++)
            {
                for (int j = 0; j < image_height; j++)
                {
                    xmin = Math.Max(0, i - whalf);
                    ymin = Math.Max(0, j - whalf);
                    xmax = Math.Min(image_width - 1, i + whalf);
                    ymax = Math.Min(image_height - 1, j + whalf);
                    area = (xmax - xmin + 1) * (ymax - ymin + 1);
                    // area can't be 0 here
                    // proof (assuming whalf >= 0):
                    // we'll prove that (xmax-xmin+1) > 0,
                    // (ymax-ymin+1) is analogous
                    // It's the same as to prove: xmax >= xmin
                    // image_width - 1 >= 0         since image_width > i >= 0
                    // i + whalf >= 0               since i >= 0, whalf >= 0
                    // i + whalf >= i - whalf       since whalf >= 0
                    // image_width - 1 >= i - whalf since image_width > i
                    // --IM
                    if (area <= 0)
                    {
                        throw new Exception("Binarize: area can't be 0 here");
                    }
                    if (xmin == 0 && ymin == 0)
                    { // Point at origin
                        diff   = integral_image[xmax, ymax];
                        sqdiff = integral_sqimg[xmax, ymax];
                    }
                    else if (xmin == 0 && ymin > 0)
                    { // first column
                        diff   = integral_image[xmax, ymax] - integral_image[xmax, ymin - 1];
                        sqdiff = integral_sqimg[xmax, ymax] - integral_sqimg[xmax, ymin - 1];
                    }
                    else if (xmin > 0 && ymin == 0)
                    { // first row
                        diff   = integral_image[xmax, ymax] - integral_image[xmin - 1, ymax];
                        sqdiff = integral_sqimg[xmax, ymax] - integral_sqimg[xmin - 1, ymax];
                    }
                    else
                    { // rest of the image
                        diagsum    = integral_image[xmax, ymax] + integral_image[xmin - 1, ymin - 1];
                        idiagsum   = integral_image[xmax, ymin - 1] + integral_image[xmin - 1, ymax];
                        diff       = diagsum - idiagsum;
                        sqdiagsum  = integral_sqimg[xmax, ymax] + integral_sqimg[xmin - 1, ymin - 1];
                        sqidiagsum = integral_sqimg[xmax, ymin - 1] + integral_sqimg[xmin - 1, ymax];
                        sqdiff     = sqdiagsum - sqidiagsum;
                    }

                    mean      = diff / area;
                    std       = Math.Sqrt((sqdiff - diff * diff / area) / (area - 1));
                    threshold = mean * (1 + k * ((std / 128) - 1));
                    if (gray_image[i, j] < threshold)
                    {
                        bin_image[i, j] = 0;
                    }
                    else
                    {
                        bin_image[i, j] = (byte)(MAXVAL - 1);
                    }
                }
            }
            if (PGeti("debug_binarize") > 0)
            {
                ImgIo.write_image_gray("debug_binarize.png", bin_image);
            }
        }
Пример #16
0
        public override void Binarize(Bytearray bin_image, Bytearray gray_image)
        {
            if (bin_image.Length1d() != gray_image.Length1d())
            {
                bin_image.MakeLike(gray_image);
            }

            if (NarrayUtil.contains_only(gray_image, (byte)0, (byte)255))
            {
                bin_image.Copy(gray_image);
                return;
            }

            int image_width  = gray_image.Dim(0);
            int image_height = gray_image.Dim(1);

            int[]    hist = new int[MAXVAL];
            double[] pdf  = new double[MAXVAL]; //probability distribution
            double[] cdf  = new double[MAXVAL]; //cumulative probability distribution
            double[] myu  = new double[MAXVAL]; // mean value for separation
            double   max_sigma;

            double[] sigma = new double[MAXVAL]; // inter-class variance

            /* Histogram generation */
            for (int i = 0; i < MAXVAL; i++)
            {
                hist[i] = 0;
            }
            for (int x = 0; x < image_width; x++)
            {
                for (int y = 0; y < image_height; y++)
                {
                    hist[gray_image[x, y]]++;
                }
            }

            /* calculation of probability density */
            for (int i = 0; i < MAXVAL; i++)
            {
                pdf[i] = (double)hist[i] / (image_width * image_height);
            }

            /* cdf & myu generation */
            cdf[0] = pdf[0];
            myu[0] = 0.0;       /* 0.0 times prob[0] equals zero */
            for (int i = 1; i < MAXVAL; i++)
            {
                cdf[i] = cdf[i - 1] + pdf[i];
                myu[i] = myu[i - 1] + i * pdf[i];
            }

            /* sigma maximization
             * sigma stands for inter-class variance
             * and determines optimal threshold value */
            int threshold = 0;

            max_sigma = 0.0;
            for (int i = 0; i < MAXVAL - 1; i++)
            {
                if (cdf[i] != 0.0 && cdf[i] != 1.0)
                {
                    double p1p2       = cdf[i] * (1.0 - cdf[i]);
                    double mu1mu2diff = myu[MAXVAL - 1] * cdf[i] - myu[i];
                    sigma[i] = mu1mu2diff * mu1mu2diff / p1p2;
                }
                else
                {
                    sigma[i] = 0.0;
                }
                if (sigma[i] > max_sigma)
                {
                    max_sigma = sigma[i];
                    threshold = i;
                }
            }


            for (int x = 0; x < image_width; x++)
            {
                for (int y = 0; y < image_height; y++)
                {
                    if (gray_image[x, y] > threshold)
                    {
                        bin_image[x, y] = (byte)(MAXVAL - 1);
                    }
                    else
                    {
                        bin_image[x, y] = 0;
                    }
                }
            }

            if (PGeti("debug_otsu") > 0)
            {
                Logger.Default.Format("Otsu threshold value = {0}\n", threshold);
                //ImgIo.write_image_gray("debug_otsu.png", bin_image);
            }
        }
Пример #17
0
 public static void make_binary(Bytearray image)
 {
     for (int i = 0; i < image.Length1d(); i++)
         image.Put1d(i, (byte)(image.At1d(i) > 0 ? 255 : 0));
 }
Пример #18
0
 public static void check_binary(Bytearray image)
 {
     for (int i = 0; i < image.Length1d(); i++)
     {
         int value = image.At1d(i);
         if (!(value == 0 || value == 255))
             throw new Exception("check_binary: value must be 0 or 255");
     }
 }
Пример #19
0
 public static void binary_invert(Bytearray image)
 {
     check_binary(image);
     for (int i = 0; i < image.Length1d(); i++)
         image.Put1d(i, (byte)(255 - image.At1d(i)));
 }
Пример #20
0
        public static void Thin(ref Bytearray uci)
        {
            int w = uci.Dim(0) - 1;
            int h = uci.Dim(1) - 1;

            for (int i = 0, n = uci.Length1d(); i < n; i++)
            {
                if (uci.At1d(i) > 0)
                {
                    uci.Put1d(i, ON);
                }
                else
                {
                    uci.Put1d(i, OFF);
                }
            }

            bool flag;

            do
            {
                flag = false;
                for (int j = 0; j < 8; j += 2)
                {
                    for (int x = 1; x < w; x++)
                    {
                        for (int y = 1; y < h; y++)
                        {
                            if (uci[x, y] != ON)
                            {
                                continue;
                            }
                            if (uci[x + nx[j], y + ny[j]] != OFF)
                            {
                                continue;
                            }
                            int b = 0;
                            for (int i = 7; i >= 0; i--)
                            {
                                b <<= 1;
                                b  |= (uci[x + nx[i], y + ny[i]] != OFF ? 1 : 0);
                            }
                            if (ttable[b] > 0)
                            {
                                uci[x, y] = SKEL;
                            }
                            else
                            {
                                uci[x, y] = DEL;
                                flag      = true;
                            }
                        }
                    }
                    if (!flag)
                    {
                        continue;
                    }
                    for (int x = 1; x < w; x++)
                    {
                        for (int y = 1; y < h; y++)
                        {
                            if (uci[x, y] == DEL)
                            {
                                uci[x, y] = OFF;
                            }
                        }
                    }
                }
            } while (flag);

            for (int i = 0, n = uci.Length1d(); i < n; i++)
            {
                if (uci.At1d(i) == SKEL)
                {
                    uci.Put1d(i, 255);
                }
                else
                {
                    uci.Put1d(i, 0);
                }
            }
        }
Пример #21
0
        public override void Binarize(Bytearray bin_image, Bytearray gray_image)
        {
            w = PGeti("w");
            k = (float)PGetf("k");
            whalf = w >> 1;
            // fprintf(stderr,"[sauvola %g %d]\n",k,w);
            if(k<0.001 || k>0.999)
                throw new Exception("Binarize: CHECK_ARG(k>=0.001 && k<=0.999)");
            if(w==0 || k>=1000)
                throw new Exception("Binarize: CHECK_ARG(w>0 && k<1000)");
            if(bin_image.Length1d() != gray_image.Length1d())
                bin_image.MakeLike(gray_image);

            if(NarrayUtil.contains_only(gray_image, (byte)0, (byte)255))
            {
                bin_image.Copy(gray_image);
                return;
            }

            int image_width  = gray_image.Dim(0);
            int image_height = gray_image.Dim(1);
            whalf = w >> 1;

            // Calculate the integral image, and integral of the squared image
            Narray<long> integral_image = new Narray<long>(), rowsum_image = new Narray<long>();
            Narray<long> integral_sqimg = new Narray<long>(), rowsum_sqimg = new Narray<long>();
            integral_image.MakeLike(gray_image);
            rowsum_image.MakeLike(gray_image);
            integral_sqimg.MakeLike(gray_image);
            rowsum_sqimg.MakeLike(gray_image);
            int xmin,ymin,xmax,ymax;
            double diagsum,idiagsum,diff,sqdiagsum,sqidiagsum,sqdiff,area;
            double mean,std,threshold;

            for (int j = 0; j < image_height; j++)
            {
                rowsum_image[0, j] = gray_image[0, j];
                rowsum_sqimg[0, j] = gray_image[0, j] * gray_image[0, j];
            }
            for (int i = 1; i < image_width; i++)
            {
                for (int j = 0; j < image_height; j++)
                {
                    rowsum_image[i, j] = rowsum_image[i - 1, j] + gray_image[i, j];
                    rowsum_sqimg[i, j] = rowsum_sqimg[i - 1, j] + gray_image[i, j] * gray_image[i, j];
                }
            }

            for (int i = 0; i < image_width; i++)
            {
                integral_image[i, 0] = rowsum_image[i, 0];
                integral_sqimg[i, 0] = rowsum_sqimg[i, 0];
            }
            for (int i = 0; i < image_width; i++)
            {
                for (int j = 1; j < image_height; j++)
                {
                    integral_image[i, j] = integral_image[i, j - 1] + rowsum_image[i, j];
                    integral_sqimg[i, j] = integral_sqimg[i, j - 1] + rowsum_sqimg[i, j];
                }
            }

            //Calculate the mean and standard deviation using the integral image

            for(int i=0; i<image_width; i++){
                for(int j=0; j<image_height; j++){
                    xmin = Math.Max(0,i-whalf);
                    ymin = Math.Max(0, j - whalf);
                    xmax = Math.Min(image_width - 1, i + whalf);
                    ymax = Math.Min(image_height - 1, j + whalf);
                    area = (xmax-xmin+1)*(ymax-ymin+1);
                    // area can't be 0 here
                    // proof (assuming whalf >= 0):
                    // we'll prove that (xmax-xmin+1) > 0,
                    // (ymax-ymin+1) is analogous
                    // It's the same as to prove: xmax >= xmin
                    // image_width - 1 >= 0         since image_width > i >= 0
                    // i + whalf >= 0               since i >= 0, whalf >= 0
                    // i + whalf >= i - whalf       since whalf >= 0
                    // image_width - 1 >= i - whalf since image_width > i
                    // --IM
                    if (area <= 0)
                        throw new Exception("Binarize: area can't be 0 here");
                    if (xmin == 0 && ymin == 0)
                    { // Point at origin
                        diff = integral_image[xmax, ymax];
                        sqdiff = integral_sqimg[xmax, ymax];
                    }
                    else if (xmin == 0 && ymin > 0)
                    { // first column
                        diff = integral_image[xmax, ymax] - integral_image[xmax, ymin - 1];
                        sqdiff = integral_sqimg[xmax, ymax] - integral_sqimg[xmax, ymin - 1];
                    }
                    else if (xmin > 0 && ymin == 0)
                    { // first row
                        diff = integral_image[xmax, ymax] - integral_image[xmin - 1, ymax];
                        sqdiff = integral_sqimg[xmax, ymax] - integral_sqimg[xmin - 1, ymax];
                    }
                    else
                    { // rest of the image
                        diagsum = integral_image[xmax, ymax] + integral_image[xmin - 1, ymin - 1];
                        idiagsum = integral_image[xmax, ymin - 1] + integral_image[xmin - 1, ymax];
                        diff = diagsum - idiagsum;
                        sqdiagsum = integral_sqimg[xmax, ymax] + integral_sqimg[xmin - 1, ymin - 1];
                        sqidiagsum = integral_sqimg[xmax, ymin - 1] + integral_sqimg[xmin - 1, ymax];
                        sqdiff = sqdiagsum - sqidiagsum;
                    }

                    mean = diff/area;
                    std  = Math.Sqrt((sqdiff - diff*diff/area)/(area-1));
                    threshold = mean*(1+k*((std/128)-1));
                    if(gray_image[i,j] < threshold)
                        bin_image[i,j] = 0;
                    else
                        bin_image[i,j] = (byte)(MAXVAL-1);
                }
            }
            if(PGeti("debug_binarize") > 0) {
                ImgIo.write_image_gray("debug_binarize.png", bin_image);
            }
        }
Пример #22
0
 public static void binarize_with_threshold(Bytearray result, Bytearray image, int threshold)
 {
     result.MakeLike(image);
     for (int i = 0; i < image.Length1d(); i++)
         result.Put1d(i, image.At1d(i) < threshold ? (byte)0 : (byte)255);
 }
Пример #23
0
 public static void Invert(Bytearray a)
 {
     int n = a.Length1d();
     for (int i = 0; i < n; i++)
     {
         a.Put1d(i, (byte)(255 - a.At1d(i)));
     }
 }
Пример #24
0
        public override void Binarize(Bytearray bin_image, Bytearray gray_image)
        {
            if(bin_image.Length1d() != gray_image.Length1d())
                bin_image.MakeLike(gray_image);

            if(NarrayUtil.contains_only(gray_image, (byte)0, (byte)255))
            {
                bin_image.Copy(gray_image);
                return;
            }

            int image_width  = gray_image.Dim(0);
            int image_height = gray_image.Dim(1);
            int[]    hist = new int[MAXVAL];
            double[] pdf = new double[MAXVAL]; //probability distribution
            double[] cdf = new double[MAXVAL]; //cumulative probability distribution
            double[] myu = new double[MAXVAL];   // mean value for separation
            double max_sigma;
            double[] sigma = new double[MAXVAL]; // inter-class variance

            /* Histogram generation */
            for(int i=0; i<MAXVAL; i++){
                hist[i] = 0;
            }
            for(int x=0; x<image_width; x++){
                for(int y=0; y<image_height; y++){
                    hist[gray_image[x,y]]++;
                }
            }

            /* calculation of probability density */
            for(int i=0; i<MAXVAL; i++){
                pdf[i] = (double)hist[i] / (image_width * image_height);
            }

            /* cdf & myu generation */
            cdf[0] = pdf[0];
            myu[0] = 0.0;       /* 0.0 times prob[0] equals zero */
            for(int i=1; i<MAXVAL; i++){
                cdf[i] = cdf[i-1] + pdf[i];
                myu[i] = myu[i-1] + i*pdf[i];
            }

            /* sigma maximization
               sigma stands for inter-class variance
               and determines optimal threshold value */
            int threshold = 0;
            max_sigma = 0.0;
            for(int i=0; i<MAXVAL-1; i++){
                if(cdf[i] != 0.0 && cdf[i] != 1.0){
                    double p1p2 = cdf[i]*(1.0 - cdf[i]);
                    double mu1mu2diff = myu[MAXVAL-1]*cdf[i]-myu[i];
                    sigma[i] = mu1mu2diff * mu1mu2diff / p1p2;
                }
                else
                    sigma[i] = 0.0;
                if(sigma[i] > max_sigma){
                    max_sigma = sigma[i];
                    threshold = i;
                }
            }

            for(int x=0; x<image_width; x++){
                for(int y=0; y<image_height; y++){
                     if (gray_image[x,y] > threshold)
                        bin_image[x,y] = (byte)(MAXVAL-1);
                    else
                        bin_image[x,y] = 0;
                }
            }

            if(PGeti("debug_otsu") > 0) {
                Logger.Default.Format("Otsu threshold value = {0}\n", threshold);
                //ImgIo.write_image_gray("debug_otsu.png", bin_image);
            }
        }