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