2011-01-20 53 views
8

我目前正在編寫一個我用Java編寫的小程序的C#實現。從C#中的圖像獲取RGB數組

我在我的Java應用程序中使用了BufferedImage.getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)函數。但我不能在C#中完全找到這個版本,我不知道如何手動編寫它。

回答

16

在.NET Framework中,這種方法沒有直接的等價物。但是,如果圖像是System.Drawing.Bitmap,則可以調用LockBits方法,這將返回一個包含第一條掃描線地址的BitmapData結構。然後您可以使用它創建應該是API兼容包裝的東西。我假設你使用的是C#3.5或更高版本,所以我使用擴展方法 - 如果您使用的是舊版本,請通過從Bitmap參數中刪除「this」將其更改爲常規方法:

public static void getRGB(this Bitmap image, int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) 
    { 
     const int PixelWidth = 3; 
     const PixelFormat PixelFormat = PixelFormat.Format24bppRgb; 

     // En garde! 
     if (image == null) throw new ArgumentNullException("image"); 
     if (rgbArray == null) throw new ArgumentNullException("rgbArray"); 
     if (startX < 0 || startX + w > image.Width) throw new ArgumentOutOfRangeException("startX"); 
     if (startY < 0 || startY + h > image.Height) throw new ArgumentOutOfRangeException("startY"); 
     if (w < 0 || w > scansize || w > image.Width) throw new ArgumentOutOfRangeException("w"); 
     if (h < 0 || (rgbArray.Length < offset + h * scansize) || h > image.Height) throw new ArgumentOutOfRangeException("h"); 

     BitmapData data = image.LockBits(new Rectangle(startX, startY, w, h), System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat); 
     try 
     { 
      byte[] pixelData = new Byte[data.Stride]; 
      for (int scanline = 0; scanline < data.Height; scanline++) 
      { 
       Marshal.Copy(data.Scan0 + (scanline * data.Stride), pixelData, 0, data.Stride); 
       for (int pixeloffset = 0; pixeloffset < data.Width; pixeloffset++) 
       { 
        // PixelFormat.Format32bppRgb means the data is stored 
        // in memory as BGR. We want RGB, so we must do some 
        // bit-shuffling. 
        rgbArray[offset + (scanline * scansize) + pixeloffset] = 
         (pixelData[pixeloffset * PixelWidth + 2] << 16) + // R 
         (pixelData[pixeloffset * PixelWidth + 1] << 8) + // G 
         pixelData[pixeloffset * PixelWidth];    // B 
       } 
      } 
     } 
     finally 
     { 
      image.UnlockBits(data); 
     } 
    } 

此包裝,現在可以這樣調用:

 Bitmap foo = Bitmap.FromFile(@"somefile.jpg") as Bitmap; 
     int[] rgbArray = new int[100]; 
     foo.getRGB(1, 1, 10, 10, rgbArray, 0, 10); 

希望這會有所幫助,並歡迎到.NET!

2

我認爲最接近的一個是Bitmap.GetPixel(x,y),它在某點返回一個像素顏色。 爲了模擬java函數,您需要編寫一些幫助程序。

1

這取決於你需要多快才能做到這一點。

BitmapGetPixel()方法,它適用於一個像素。

如果你需要做快速圖像處理,你需要使用LockBits,你可以在這裏找到一個示例。

Bitmap img = (Bitmap) Image.FromFile(imageFileName); 
BitmapData data = img.LockBits(new Rectangle(0,0,img.Width, img.Height), ImageLockMode.ReadWrite, img.PixelFormat); 
byte* ptr = (byte*) data.Scan0; 
for (int j = 0; j < data.Height; j++) 
{ 
    byte* scanPtr = ptr + (j * data.Stride); 
    for (int i = 0; i < data.width; i++, scanPtr+=NO_OF_CHANNELS) 
    { 
     for (int m = 0; m < NO_OF_CHANNELS; m++) 
      Console.WriteLine(*scanPtr); // value of each channel 
    } 
} 

img.UnlockBits(data); 
+0

@Lazarus你爲什麼編輯我的回覆? – Aliostad 2011-01-20 13:10:31

6

您會使用Bitmap.LockBits來直接訪問位圖中的像素。下面是一個示例實現,它從傳遞的位圖返回一條掃描線,並將其作爲int []:

int[] getRGB(Bitmap bmp, int line) { 
     var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), 
      System.Drawing.Imaging.ImageLockMode.ReadOnly, 
      System.Drawing.Imaging.PixelFormat.Format32bppRgb); 
     try { 
      var ptr = (IntPtr)((long)data.Scan0 + data.Stride * (bmp.Height - line - 1)); 
      var ret = new int[bmp.Width]; 
      System.Runtime.InteropServices.Marshal.Copy(ptr, ret, 0, ret.Length * 4); 
      return ret; 
     } 
     finally { 
      bmp.UnlockBits(data); 
     } 
    }