/*
         * 1位深度图像 颜色表数组255个元素 只有用前两个 0对应0  1对应255
         * 1位深度图像每个像素占一位
         * 8位深度图像每个像素占一个字节  是1位的8倍
         */

        /// <summary>
        /// 将源灰度图像二值化,并转化为1位二值图像。
        /// </summary>
        /// <param name="bmp"> 源灰度图像。 </param>
        /// <returns> 1位二值图像。 </returns>
        public static BitmapImage GTo2Bit(BitmapImage bitmapImage)
        {
            if (bitmapImage != null)
            {
                Bitmap bitmap = HelpClass.BitmapImage2Bitmap(bitmapImage);
                //将源图像内存区域锁定
                Rectangle  rect       = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
                BitmapData bitmapData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);

                //获取图像参数
                int    leng, offset_1bit = 0;
                int    width           = bitmapData.Width;
                int    height          = bitmapData.Height;
                int    stride          = bitmapData.Stride; //扫描线的宽度,比实际图片要大
                int    offset          = stride - width;    //显示宽度与扫描线宽度的间隙
                IntPtr ptr             = bitmapData.Scan0;  //获取bitmapData的内存起始位置的指针
                int    scanBytesLength = stride * height;   //用stride宽度,表示这是内存区域的大小

                if (width % 32 == 0)
                {
                    leng = width / 8;
                }
                else
                {
                    leng = width / 8 + (4 - (width / 8 % 4));
                    if (width % 8 != 0)
                    {
                        offset_1bit = leng - width / 8;
                    }
                    else
                    {
                        offset_1bit = leng - width / 8;
                    }
                }

                //分别设置两个位置指针,指向源数组和目标数组
                int    posScan = 0, postDst = 0;
                byte[] rgbValues = new byte[scanBytesLength];     //为目标数组分配内存
                Marshal.Copy(ptr, rgbValues, 0, scanBytesLength); //将图像数据拷贝到rgbValues中

                //分配二值数组
                byte[] grayValues = new byte[leng * height]; //不含未用空间
                //计数二值数组
                int x, v, t = 0;
                for (int i = 0; i < height; i++)
                {
                    for (x = 0; x < width; x++)
                    {
                        v = rgbValues[posScan];
                        t = (t << 1) | (v > 100 ? 1 : 0);

                        if (x % 8 == 7)
                        {
                            grayValues[posScan] = (byte)t;
                            postDst++;
                            t = 0;
                        }
                        posScan++;
                    }

                    if ((x %= 8) != 7)
                    {
                        t <<= 8 - x;
                        grayValues[postDst] = (byte)t;
                    }
                    //跳过图像数据每行未用空间的字节,length=stride-width*bytePerPixel
                    posScan += offset;
                    postDst += offset_1bit;
                }

                //内存解锁
                Marshal.Copy(rgbValues, 0, ptr, scanBytesLength);
                bitmap.UnlockBits(bitmapData);

                //构建1位二值位图
                Bitmap retBitmap = two(grayValues, width, height);
                return(HelpClass.Bitmap2BitmapImage(retBitmap));
            }
            else
            {
                return(null);
            }
        }
        //Otsu阈值
        public static BitmapImage OtsuThreshold(BitmapImage bitmapImage)
        {
            Bitmap bitmap = HelpClass.BitmapImage2Bitmap(bitmapImage);

            //图像灰度化
            // bitmap = Gray(bitmap);
            int  width     = bitmap.Width;
            int  height    = bitmap.Height;
            byte threshold = 0;

            int[] hist = new int[256];

            int AllPixelNumber = 0, PixelNumberSmall = 0, PixelNumberBig = 0;

            double     MaxValue, AllSum = 0, SumSmall = 0, SumBig, ProbabilitySmall, ProbabilityBig, Probability;
            BitmapData data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

            unsafe
            {
                byte *p      = (byte *)data.Scan0;
                int   offset = data.Stride - width * 4;
                for (int j = 0; j < height; j++)
                {
                    for (int i = 0; i < width; i++)
                    {
                        hist[p[0]]++;
                        p += 4;
                    }
                    p += offset;
                }
                bitmap.UnlockBits(data);
            }
            //计算灰度为I的像素出现的概率
            for (int i = 0; i < 256; i++)
            {
                AllSum         += i * hist[i]; //质量矩
                AllPixelNumber += hist[i];     //质量
            }
            MaxValue = -1.0;
            for (int i = 0; i < 256; i++)
            {
                PixelNumberSmall += hist[i];
                PixelNumberBig    = AllPixelNumber - PixelNumberSmall;
                if (PixelNumberBig == 0)
                {
                    break;
                }
                SumSmall        += i * hist[i];
                SumBig           = AllSum - SumSmall;
                ProbabilitySmall = SumSmall / PixelNumberSmall;
                ProbabilityBig   = SumBig / PixelNumberBig;
                Probability      = PixelNumberSmall * ProbabilitySmall * ProbabilitySmall + PixelNumberBig * ProbabilityBig * ProbabilityBig;
                if (Probability > MaxValue)
                {
                    MaxValue  = Probability;
                    threshold = (byte)i;
                }
            }

            return(HelpClass.Bitmap2BitmapImage(Thresholding(bitmap, threshold)));
        }