2011-01-20 19 views
8

Attualmente sto scrivendo un'implementazione C# di un piccolo programma che ho scritto in Java.Ottenere l'array RGB dall'immagine in C#

Avevo utilizzato la funzione BufferedImage.getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) nella mia app Java. Ma non riuscivo a trovare esattamente una versione di questo in C# e non sono sicuro di come scriverlo manualmente.

risposta

16

Non c'è un equivalente diretto in .NET Framework a questo metodo. Tuttavia, se l'immagine è un System.Drawing.Bitmap, puoi chiamare il metodo LockBits e questo restituirà una struttura BitmapData che contiene l'indirizzo della prima scanline. Puoi quindi usarlo per creare quello che dovrebbe essere un wrapper compatibile API. Suppongo che tu stia utilizzando C# 3.5 o superiore, quindi sto utilizzando un metodo di estensione: se stai utilizzando un aroma meno recente, sostituiscilo con un metodo normale rilasciando "questo" dall'argomento Bitmap:

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

questo involucro può ora essere chiamato in questo modo:

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

Spero che questo aiuti, e benvenuto a .NET!

2

Penso che il più vicino sia Bitmap.GetPixel(x,y) che restituisce un singolo pixel di colore in un punto. Per simulare la funzione java, è necessario scrivere un helper.

1

Dipende da quanto velocemente è necessario farlo.

Bitmap ha il metodo GetPixel() che funziona bene per un pixel.

Se è necessario eseguire l'elaborazione rapida delle immagini, è necessario utilizzare LockBits che è possibile trovare qui.

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 perché hai modificato la mia risposta? – Aliostad

+0

"Dipende da come ** grassi ** devi farlo." Se preferisci che abbia lasciato i tuoi errori di ortografia, allora devi solo dire. – Lazarus

+0

@Lazarus Nessun problema. Per qualche ragione che ha rimosso anche il mio codice che ho incollato. Grazie per aver rimosso il mio errore di ortografia, ho ripubblicato il mio codice. – Aliostad

6

Utilizzerai Bitmap.LockBits per ottenere l'accesso diretto ai pixel in una bitmap. Ecco un esempio di implementazione, restituisce uno scanline dal bitmap passata come un 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); 
     } 
    }