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