C# BitmapData使用說明
msdn關於BitmapData原文解釋地址:
http://msdn.microsoft.com/zh-cn/library/5ey6h79d(v=vs.110).aspx
以下是msdn原文給出的例子
private void LockUnlockBitsExample(PaintEventArgs e)
{
// Create a new bitmap.
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
// Set every third value to 255. A 24bpp bitmap will look red.
for (int counter = 2; counter < rgbValues.Length; counter += 3)
rgbValues[counter] = 255;
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
// Unlock the bits.
bmp.UnlockBits(bmpData);
// Draw the modified image.
e.Graphics.DrawImage(bmp, 0, 150);
}
原文給出的例子已經可以理解出部分意思了,按照土鱉國王本人實驗然後理解如下,如有誤還請大神斧正
C#專門為影像處理提供了BitmapData,這個是真正的對點陣圖的處理,首先將點陣圖鎖定到記憶體中,然後對點陣圖的每一個畫素進行處理,效率還是非常高的,下面先給出偶自己轉化影像灰度值的例子,以函式的形式給出
以便需要的朋友直接可以使用,可以說是任何操作都是依次為基礎的,如果覺得註釋太多,可將註釋直接刪除,然後將程式碼烤白可直接使用,指標法效率更高,這裡只給出記憶體法先理解,然後便可大展身手了,哈哈
/// 獲取灰度值返回byte[]
/// <summary>
/// 獲取灰度值返回byte[]
/// </summary>
/// <param name="srcBmp">源影像</param>
/// <param name="rect">要鎖定的影像區域</param>
/// <returns>返回byte[]</returns>
public static byte[] GetGrayArray(Bitmap srcBmp, Rectangle rect)
{
//將Bitmap鎖定到系統記憶體中
//rect是指源影像中需要鎖定那一塊矩形區域進行處理
//ImageLockMode.ReadWrite是指對影像出操作的許可權,列舉有隻讀,只寫,使用者輸入緩衝區,還是讀寫
//PixelFormat.Format24bppRgb
//引數確定了該影像資訊時rgb儲存還是Argb儲存,如果是Format24ppRgb則處理的影像畫素就是BGR方式儲存,我們這裡沒有特別指出,均是Format24bppRgb方式儲存處理
BitmapData srcBmpData = srcBmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
//點陣圖中第一個畫素資料的地址。它也可以看成是點陣圖中的第一個掃描行
IntPtr srcPtr = srcBmpData.Scan0;
//將Bitmap物件的資訊存放到byte陣列中
//假設本影像的寬度和高度為5*3
/*
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //這裡儲存為一維陣列,所以是一行,
寬度為5,高度為3,則畫素總數為15,這裡要清楚,每一個畫素是rgb三個值,故而,一維陣列中
儲存為
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
15...44
這裡分行是為了便於理解,一維陣列儲存類似是一行,但是我們的影像的寬度是5也就是我們影像的第一行是0123...到14,下一行是15...29,下一行是30...44,高度為3,所以就是3行
012 345 678 91011 121314
bgr bgr bgr bgr bgr
151617 181920 ...
bgr bgr ...
這樣儲存
*/
//所以才有了這裡的*3就是指一個畫素是三個分量值
int scanWidth = rect.Width * 3;
//而每行的實際的位元組數將變成大於等於它的那個離它最近的4的整倍數,此時的實際位元組數就是Stride,如果上面的第三個引數Format24ppRgb如果設定為Format32ppRgb,這個時候儲存的時候就是4位儲存一個畫素,如果是Format32bppArgb同樣也是4為儲存一個畫素,這4位除了bgr三個分量之外還有透明度A的值
//至於為什麼是24,32,這是因為計算機儲存資料為8bit儲存1個位元組,
//bgr3個就是3*8=24,4個就是4*8=32了,為什麼是16,8位等,索引圖等原理是一樣的
//int srcStride = srcBmpData.Stride;
int src_bytes = scanWidth * rect.Height; //這裡就是計算出了需要儲存的畫素所佔用的空間大小
byte[] srcValues = new byte[src_bytes]; //定義源影像的元資訊
byte[] grayValues = new byte[rect.Width * rect.Height]; //定義轉化為灰度後需要儲存的陣列
//複製GRB資訊到byte陣列,將從srcPtr開始的第一個掃描行開始掃描資訊,然後讀取到srcValues陣列中
Marshal.Copy(srcPtr, srcValues, 0, src_bytes);
//解鎖點陣圖
srcBmp.UnlockBits(srcBmpData); //讀取完元資訊,這裡就不用了,一定要記得解鎖,否則會報錯
//下面就是你想怎麼處理都成了,,灰度化,轉換空間模式,除噪聲,腐蝕,膨脹,反色,二值化等等均可
//灰度化處理
int m = 0, j = 0;
int k = 0;
byte gray;
//根據重要性及其它指標,將三個分量以不同的權值進行加權平均。由於人眼對綠色的敏感最高,對藍色敏感最低,因此,按下式對RGB三分量進行加權平均能得到較合理的灰度影像
//根據Y = 0.299*R + 0.587*G + 0.114*B //加權平均法
for (int i = 0; i < rect.Height; i++)
{
for (j = 0; j < rect.Width; j++)
{
//注意點陣圖結構中RGB按BGR的順序儲存
k = 3 * j;
gray = (byte)(srcValues[i * scanWidth + k + 2] * 0.299
+ srcValues[i * scanWidth + k + 1] * 0.587
+ srcValues[i * scanWidth + k + 0] * 0.114);
grayValues[m] = gray; //將灰度值存到double的陣列中
m++;
}
}
return grayValues;
}
//接下來就很簡單了,下面在給出獲得到灰度值儲存為2位陣列的方法,按照習慣二維處理起來比較好理解
/// 獲取灰度值存到二維double陣列中,這個是將rgb轉化為灰度值
/// <summary>
/// 獲取灰度值存到二維double陣列中,這個是將rgb轉化為灰度值
/// </summary>
/// <param name="srcBmp"></param>
/// <returns>2Dimension</returns>
public static byte[,] GetGrayArray2D(Bitmap srcBmp,Rectangle rect)
{
int width = rect.Width;
int height = rect.Height;
BitmapData srcBmpData = srcBmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
IntPtr srcPtr = srcBmpData.Scan0;
int scanWidth = width * 3;
int src_bytes = scanWidth * height;
//int srcStride = srcBmpData.Stride;
byte[] srcRGBValues = new byte[src_bytes];
byte[,] grayValues = new byte[height, width];
//RGB[] rgb = new RGB[srcBmp.Width * rows];
//複製GRB資訊到byte陣列
Marshal.Copy(srcPtr, srcRGBValues, 0, src_bytes);
//解鎖點陣圖
srcBmp.UnlockBits(srcBmpData);
//灰度化處理
int m = 0, i = 0, j = 0; //m表示行,j表示列
int k = 0;
byte gray;
for (i = 0; i < height; i++) //只獲取圖片的rows行畫素值
{
for (j = 0; j < width; j++)
{
//只處理每行中影像畫素資料,捨棄未用空間
//注意點陣圖結構中RGB按BGR的順序儲存
k = 3 * j;
gray = (byte)(srcRGBValues[i * scanWidth + k + 2] * 0.299
+ srcRGBValues[i * scanWidth + k + 1] * 0.587
+ srcRGBValues[i * scanWidth + k + 0] * 0.114);
grayValues[m, j] = gray; //將灰度值存到double的陣列中
}
m++;
}
return grayValues;
}
//此方法是直接得到灰度圖
/// 獲取灰度影像,將制定圖片轉化為灰度圖
/// <summary>
/// 獲取灰度影像,將制定圖片轉化為灰度圖
/// </summary>
/// <param name="srcBmp"></param>
/// <returns></returns>
public static Bitmap GetGrayImage(Bitmap srcBmp)
{
Rectangle rect = new Rectangle(0, 0, srcBmp.Width, srcBmp.Height);
BitmapData srcBmpData = srcBmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
IntPtr srcPtr = srcBmpData.Scan0;
int scanWidth = srcBmpData.Width * 3;
int src_bytes = scanWidth * srcBmp.Height;
byte[] srcRGBValues = new byte[src_bytes];
Marshal.Copy(srcPtr, srcRGBValues, 0, src_bytes);
//灰度化處理
int k = 0;
for (int i = 0; i < srcBmp.Height; i++)
{
for (int j = 0; j < srcBmp.Width; j++)
{
k = j * 3;
//0.299*R + 0.587*G + 0.144*B = 亮度或灰度
//只處理每行中影像畫素資料,捨棄未用空間
//注意點陣圖結構中RGB按BGR的順序儲存
byte intensity = (byte)(srcRGBValues[i * scanWidth + k + 2] * 0.299
+ srcRGBValues[i * scanWidth + k + 1] * 0.587
+ srcRGBValues[i * scanWidth + k + 0] * 0.114);
srcRGBValues[i * scanWidth + k + 0] = intensity;
srcRGBValues[i * scanWidth + k + 1] = intensity;
srcRGBValues[i * scanWidth + k + 2] = intensity;
}
}
Marshal.Copy(srcRGBValues, 0, srcPtr, src_bytes);
//解鎖點陣圖
srcBmp.UnlockBits(srcBmpData);
return srcBmp;
}
以上就是C# BitmapData的使用介紹,首先融會貫通,其次舉一反三,方可熟能生巧