C# BitmapData使用說明


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的使用介紹,首先融會貫通,其次舉一反三,方可熟能生巧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM