3 votes

Extraire RVB d'un pixel sans objet couleur en C#

J'essaie d'extraire les valeurs R G B d'un pixel dans le code suivant :

for ( int i=0; i < pixeldata.length; i++)
    {
        IntPtr ptr = bmd.Scan0+i;
        byte* pixel = (byte*)ptr;

        //here is the problem :O

        float r = pixel[1];
        float g = pixel[2];
        float b = pixel[3];
     }
....

où bmd est un tableau de données de pixels :

BitmapData bmd = source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat);

et la source est le bitmap de mon entrée, qui est une image. J'essaie d'éviter l'utilisation de l'objet Color. J'ai déjà fait cela et cela fonctionne, je veux utiliser cette autre façon, mais le problème est que ptr est un nombre et je dois extraire le R G B de celui-ci.

3voto

Payam Points 359

C'est la solution qui vous donne la bonne réponse.

Bitmap source = new Bitmap(image);

            Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);

            BitmapData bmd = source.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            int totalPixels = rect.Height * rect.Width;
            int[] pixelData = new int[totalPixels];
            for (int i = 0; i < totalPixels; i++)
            {
                byte* pixel = (byte*)bmd.Scan0;
                pixel = pixel + (i * 4);

                byte b = pixel[0];
                byte g = pixel[1];
                byte r = pixel[2];

                int luma = (int)(r * 0.3 + g * 0.59 + b * 0.11);
                pixelData[i] = luma;
            }

0voto

Eric J. Points 73338

Si vous disposez d'un format qui stocke R, V et B sous la forme d'un octet chacun de manière linéaire dans la mémoire et dans cet ordre, le code pour extraire les valeurs RVB devrait ressembler à ce qui suit

byte r = pixel[0];
byte g = pixel[1];
byte b = pixel[2];

Notez que l'index commence à 0 et que les valeurs renvoyées sont les suivantes byte no float (bien que vous puissiez le faire si vous le souhaitez).

En outre, vous devez incrémenter i par 3 au lieu de 1 car 3 octets adjacents représentent un seul pixel.

Il serait judicieux de tester cela source.PixelFormat utilise en effet le format que vous supposez.

Vous devez également compiler avec le commutateur /unsafe afin d'utiliser les pointeurs en C#.

MISE À JOUR

Selon le commentaire de @Don et le vôtre, l'ordre dans la mémoire linéaire serait ABGR. Cela signifie que le code serait :

for ( int i=0; i < pixeldata.length; i+=4)
{
    IntPtr ptr = bmd.Scan0+i;
    byte* pixel = (byte*)ptr;

    byte a = pixel[0]; // You can ignore if you do not need alpha.
    byte b = pixel[1];
    byte g = pixel[2];
    byte r = pixel[3];
}

0voto

SergeyS Points 2547

Ok, c'était intéressant, et j'ai écrit un peu de code pour jouer avec. En supposant que votre image ait des pixels au format Format24bppRgb (plus d'informations sur les formats ici : http://msdn.microsoft.com/en-us/library/system.drawing.imaging.pixelformat.aspx ). Ce format stocke les valeurs B, G, R en 24 bits, l'une après l'autre.

Le code ci-dessous analysera quelques d:\\24bits.bmp de votre disque dur et en crée une nouvelle identique "d:\\24bits_1.bmp" en utilisant les informations B, G, R du tableau d'octets des premières données d'image.

unsafe private static void TestBMP()
{
    Bitmap bmp = new Bitmap("d:\\24bits.bmp");

    // Ensure that format is Format24bppRgb.
    Console.WriteLine(bmp.PixelFormat);

    Bitmap copyBmp = new Bitmap(bmp.Width, bmp.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

    // Copy all pixels of initial image for verification.
    int pixels = bmp.Height * bmp.Width;
    Color[,] allPixels = new Color[bmp.Height, bmp.Width];
    for (int i = 0; i < bmp.Height; i++)
        for (int j = 0; j < bmp.Width; j++)
            allPixels[i, j] = bmp.GetPixel(j, i);

    // 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.ReadOnly,
        bmp.PixelFormat);

    IntPtr ptr = bmpData.Scan0;

    byte* stream = (byte*)ptr;

    for (int y = 0; y < bmp.Height; y++)
        for (int x = 0; x < bmp.Width; x++)
        {
            int byteIndex = y * bmpData.Stride + x * 3;

            byte r = stream[byteIndex + 2];
            byte g = stream[byteIndex + 1];
            byte b = stream[byteIndex];

            Color c = allPixels[y, x];
            if (r != c.R || g != c.G || b != c.B)
            {
                Console.WriteLine("This should never appear");
            }
            copyBmp.SetPixel(x, y, Color.FromArgb(255, r, g, b));
        }

    // Save new image. It should be the same as initial one.
    copyBmp.Save("d:\\24bits_1.bmp");
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X