http://blog.csdn.net/slzlren/article/details/4318400
現在網上的例子多數都是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; //計算灰度 rgbValues2[n] = (byte)value; 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; }