现在网上的例子多数都是24位图像转24位灰度图的,即使有转8位灰度的,也是通过GetPixel(转换速度太慢)或者指针方式(一来C#并不推荐这种模式,二来我也没有学过c++之类的对指针实在不熟悉)来实现的,而没有c#推荐的数组方式的. 因为bmp在内存中储存的时候,每行都是必须是4的倍数才可以,开始忘记处理这个间隙,结果导致有的图片可以正常转换,有的图片就发生图像扭曲. 处理完这个后,又发现输出的都是一些带颜色的色点组成的图像,不是灰度图,经过查资料才知道输出的是伪彩色,要转成灰度才可以. 全部代码如下
/// <summary>
/// 灰度处理(BitmapData类) /// </summary> /// <returns>输出8位灰度图片</returns> public static Bitmap 灰度处理(Bitmap 图像) { Bitmap bmp = new Bitmap(图像.Width, 图像.Height, PixelFormat.Format8bppIndexed);
//设定实例BitmapData相关信息 Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData data = 图像.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); //锁定bmp到系统内存中 BitmapData data2 = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
//获取位图中第一个像素数据的地址 IntPtr ptr = data.Scan0; IntPtr ptr2 = data2.Scan0; int numBytes = data.Stride * data.Height; int numBytes2 = data2.Stride * data2.Height; int n2 = data2.Stride - bmp.Width; //// 显示宽度与扫描线宽度的间隙 byte[] rgbValues = new byte[numBytes]; byte[] rgbValues2 = new byte[numBytes2]; //将bmp数据Copy到申明的数组中 Marshal.Copy(ptr, rgbValues, 0, numBytes); Marshal.Copy(ptr2, rgbValues2, 0, numBytes2); int n = 0; for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width * 3; x += 3) { int i = data.Stride * y + x; double value = rgbValues[i + 2] * 0.299 + rgbValues[i + 1] * 0.587 + rgbValues[i] * 0.114; //计算灰度
n++; } n += n2; //跳过差值 } //将数据Copy到内存指针 Marshal.Copy(rgbValues, 0, ptr, numBytes); Marshal.Copy(rgbValues2, 0, ptr2, numBytes2); //// 下面的代码是为了修改生成位图的索引表,从伪彩修改为灰度 ColorPalette tempPalette; using (Bitmap tempBmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed)) { tempPalette = tempBmp.Palette; } for (int i = 0; i < 256; i++) { tempPalette.Entries[i] = Color.FromArgb(i, i, i); } bmp.Palette = tempPalette; //从系统内存解锁bmp 图像.UnlockBits(data); bmp.UnlockBits(data2); return bmp; } |
|