/// <summary>
        /// 将源图像灰度化,并转化为8位灰度图像。
        /// </summary>
        /// <param name="original"> 源图像。 </param>
        /// <returns> 8位灰度图像。 </returns>
        public static BitmapImage Decolorize(BitmapImage bitmapImage)
        {
            if (bitmapImage != null)
            {
                Bitmap original = HelpClass.BitmapImage2Bitmap(bitmapImage);

                // 将源图像内存区域锁定
                Rectangle  rect    = new Rectangle(0, 0, original.Width, original.Height);
                BitmapData bmpData = original.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

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

                // 分别设置两个位置指针,指向源数组和目标数组
                int    posScan = 0, posDst = 0;
                byte[] rgbValues = new byte[scanBytesLength];     // 为目标数组分配内存
                Marshal.Copy(ptr, rgbValues, 0, scanBytesLength); // 将图像数据拷贝到rgbValues中
                // 分配灰度数组
                byte[] grayValues = new byte[width * height];     // 不含未用空间。
                // 计算灰度数组

                byte blue, green, red, YUI;

                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {
                        blue  = rgbValues[posScan];
                        green = rgbValues[posScan + 1];
                        red   = rgbValues[posScan + 2];
                        YUI   = (byte)(0.229 * red + 0.587 * green + 0.144 * blue);
                        //grayValues[posDst] = (byte)((blue + green + red) / 3);
                        grayValues[posDst] = YUI;
                        posScan           += 3;
                        posDst++;
                    }
                    // 跳过图像数据每行未用空间的字节,length = stride - width * bytePerPixel
                    posScan += offset;
                }

                // 内存解锁
                Marshal.Copy(rgbValues, 0, ptr, scanBytesLength);
                original.UnlockBits(bmpData);  // 解锁内存区域

                // 构建8位灰度位图
                Bitmap retBitmap = BuiltGrayBitmap(grayValues, width, height);
                return(HelpClass.Bitmap2BitmapImage(retBitmap));
            }
            else
            {
                return(null);
            }
        }
        //灰度 指针法
        public static BitmapImage Decolorize(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.ReadWrite, bitmap.PixelFormat);

                byte temp = 0;
                //启用不安全模式
                unsafe
                {
                    //得到首地址
                    byte *ptr = (byte *)(bitmapData.Scan0);
                    //二维图像循环
                    for (int i = 0; i < bitmapData.Height; i++)
                    {
                        for (int j = 0; j < bitmapData.Width; j++)
                        {
                            //利用公式计算灰度值
                            temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                            //R=G=B
                            ptr[0] = ptr[1] = ptr[2] = temp;
                            //指向下一个像素
                            ptr += 3;
                        }
                        //指向下一行数组的首个字节
                        ptr += bitmapData.Stride - bitmapData.Width * 3;
                    }
                }
                //解锁位图像素
                bitmap.UnlockBits(bitmapData);
                return(HelpClass.Bitmap2BitmapImage(bitmap));
            }
            else
            {
                return(null);
            }
        }
        /*
         * 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)));
        }