/* * 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))); }