2010-03-30 24 views
1

D'après ce que j'ai lu sur Internet, la valeur Y est la valeur de luminance et peut être utilisée pour créer une image en niveaux de gris. Le lien suivant: http://www.bobpowell.net/grayscale.htm, a peu de code C# sur l'élaboration de la luminance d'une image bitmap:Échelle de gris Image provenant des données YUV420p

{ 
    Bitmap bm = new Bitmap(source.Width,source.Height); 
    for(int y=0;y<bm.Height;y++)  public Bitmap ConvertToGrayscale(Bitmap source) 
    { 
    for(int x=0;x<bm.Width;x++) 
    { 
     Color c=source.GetPixel(x,y); 
     int luma = (int)(c.R*0.3 + c.G*0.59+ c.B*0.11); 
     bm.SetPixel(x,y,Color.FromArgb(luma,luma,luma)); 
    } 
    } 
    return bm; 
} 

I ont une méthode qui renvoie les valeurs YUV et que les données Y dans un tableau d'octets. J'ai le morceau actuel de code et il échoue sur Marshal.Copy - a essayé de lire ou écrire la mémoire protégée.

public Bitmap ConvertToGrayscale2(byte[] yuvData, int width, int height) 
     { 
      Bitmap bmp; 
      IntPtr blue = IntPtr.Zero; 

      int inputOffSet = 0; 
      long[] pixels = new long[width * height]; 

      try 
      { 
       for (int y = 0; y < height; y++) 
       { 
        int outputOffSet = y * width; 
        for (int x = 0; x < width; x++) 
        { 
         int grey = yuvData[inputOffSet + x] & 0xff; 
         unchecked 
         { 
          pixels[outputOffSet + x] = UINT_Constant | (grey * INT_Constant); 
         } 
        } 

        inputOffSet += width; 
       } 

       blue = Marshal.AllocCoTaskMem(pixels.Length); 
       Marshal.Copy(pixels, 0, blue, pixels.Length); // fails here : Attempted to read or write protected memory 


       bmp = new Bitmap(width, height, width, PixelFormat.Format24bppRgb, blue); 

      } 
      catch (Exception) 
      { 

       throw; 
      } 
      finally 
      { 
       if (blue != IntPtr.Zero) 
       { 
        Marshal.FreeHGlobal(blue); 
        blue = IntPtr.Zero; 
       } 

      } 

      return bmp; 
     } 

Toute aide serait appréciée?

Répondre

0

-je obtenir une image en noir avec quelques pixels dans le coin en haut à gauche si j'utilise ce code et ceci est stable lors de l'exécution:

public static Bitmap ToGrayscale(byte[] yData, int width, int height) 
    { 
     Bitmap bm = new Bitmap(width, height, PixelFormat.Format32bppRgb); 
     Rectangle dimension = new Rectangle(0, 0, bm.Width, bm.Height); 
     BitmapData picData = bm.LockBits(dimension, ImageLockMode.ReadWrite, bm.PixelFormat); 
     IntPtr pixelStateAddress = picData.Scan0; 

     int stride = 4 * (int)Math.Ceiling(3 * width/4.0); 
     byte[] pixels = new byte[stride * height]; 

     try 
     { 
      for (int y = 0; y < height; y++) 
      { 
       for (int x = 0; x < width; x++) 
       { 
        byte grey = yData[y * width + x]; 
        pixels[y * stride + 3 * x] = grey; 
        pixels[y * stride + 3 * x + 1] = grey; 
        pixels[y * stride + 3 * x + 2] = grey; 

       } 
      } 

      Marshal.Copy(pixels, 0, pixelStateAddress, pixels.Length); 
      bm.UnlockBits(picData); 
     } 
     catch (Exception) 
     { 
      throw; 
     } 

     return bm; 
    } 
+0

Lors de l'utilisation de LockBits(), vous devez utiliser picData.Stride au lieu de le calculer vous-même. Notez également qu'il peut être négatif (dans ce cas, Scan0 pointe vers la dernière ligne de balayage). Aussi, avec le multiplicateur 3 * x, vous devriez utiliser Format24bppRb au lieu de 32. –

+0

Ok, il s'avère que je n'obtenais pas les données Y correctes, donc cela a été corrigé et je reçois maintenant une image en niveaux de gris en utilisant ce qui précède code. Merci pour votre aide Saxon. – fergs

2

Je pense que vous avez alloué pixels.Length octets, mais copiez pixels.Length désire ardemment, ce qui est 8 fois plus de mémoire (longue est de 64 bits ou 8 octets).

Vous pouvez essayer:

blue = Marshal.AllocCoTaskMem(Marshal.SizeOf(pixels[0]) * pixels.Length); 

Vous pourriez aussi avoir besoin d'utiliser int [] pour les pixels et PixelFormat.Format32bppRgb dans le constructeur Bitmap (car ils sont tous les deux 32 bits). L'utilisation de long [] vous donne 64 bits par pixel, ce qui n'est pas ce à quoi s'attend un format de pixel de 24 bits.

Vous pourriez vous retrouver avec des nuances de bleu au lieu de gris - cela dépend de ce que sont vos valeurs de UINT_Constant et INT_Constant.

Il n'est pas nécessaire de faire "& 0xff", car yuvData [] contient déjà un octet.

+0

J'ai pixels changement int [] et changé pixelFormat comme suggéré. Maintenant j'obtiens: Impossible de convertir le type 'long' en 'int'. Je devine que je devrais changer ces à quelque chose d'autre: privé const uint UINT_Constant = 0xFF000000; private const int INT_Constant = 0x00010101; – fergs

+0

Quelle ligne a ce message d'erreur? –

+0

pixels [outputOffSet + x] = UINT_Constant | (gris * INT_Constant); – fergs

1

Voici deux autres approches que vous pourriez essayer.

public Bitmap ConvertToGrayScale(byte[] yData, int width, int height) 
{ 
    // 3 * width bytes per scanline, rounded up to a multiple of 4 bytes 
    int stride = 4 * (int)Math.Ceiling(3 * width/4.0); 

    byte[] pixels = new byte[stride * height]; 
    for (int y = 0; y < height; y++) 
    { 
     for (int x = 0; x < width; x++) 
     { 
      byte grey = yData[y * width + x]; 
      pixels[y * stride + 3 * x] = grey; 
      pixels[y * stride + 3 * x + 1] = grey; 
      pixels[y * stride + 3 * x + 2] = grey; 
     } 
    } 

    IntPtr pixelsPtr = Marshal.AllocCoTaskMem(pixels.Length); 
    try 
    { 
     Marshal.Copy(pixels, 0, pixelsPtr, pixels.Length); 

     Bitmap bitmap = new Bitmap(
      width, 
      height, 
      stride, 
      PixelFormat.Format24bppRgb, 
      pixelsPtr); 
     return bitmap; 
    } 
    finally 
    { 
     Marshal.FreeHGlobal(pixelsPtr); 
    } 
} 

public Bitmap ConvertToGrayScale(byte[] yData, int width, int height) 
{ 
    // 3 * width bytes per scanline, rounded up to a multiple of 4 bytes 
    int stride = 4 * (int)Math.Ceiling(3 * width/4.0); 

    IntPtr pixelsPtr = Marshal.AllocCoTaskMem(stride * height); 
    try 
    { 
     for (int y = 0; y < height; y++) 
     { 
      for (int x = 0; x < width; x++) 
      { 
       byte grey = yData[y * width + x]; 
       Marshal.WriteByte(pixelsPtr, y * stride + 3 * x, grey); 
       Marshal.WriteByte(pixelsPtr, y * stride + 3 * x + 1, grey); 
       Marshal.WriteByte(pixelsPtr, y * stride + 3 * x + 2, grey); 
      } 
     } 

     Bitmap bitmap = new Bitmap(
      width, 
      height, 
      stride, 
      PixelFormat.Format24bppRgb, 
      pixelsPtr); 
     return bitmap; 
    } 
    finally 
    { 
     Marshal.FreeHGlobal(pixelsPtr); 
    } 
} 
+0

Essayé les deux exemples. Obtenir 'AccessViolationException' après un certain temps, arrive surtout quand je redimensionne le formulaire, sur les deux exemples. "Tentative de lecture ou d'écriture de la mémoire protégée L'image affichée est une bande de pyjamas à échelle de gris – fergs

+0

Sur quelle ligne obtenez-vous la violation d'accès? –