Frage

I am creating a program that scans all the pixels of an image, and whenever it finds a pixel that contains the color pink. It makes the pixel black. But it doesn't seem to find a pink pixel when there is two of them on the image. I do not know if I am using LockBits correctly, maybe I am using it wrong. Can someone please help me solve this I would greatly appreciate it.

Here is the code below:

            Bitmap bitmap = pictureBox1.Image as Bitmap;
            System.Drawing.Imaging.BitmapData d = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap.PixelFormat);
            IntPtr ptr = d.Scan0;
            byte[] rgbs = new byte[Math.Abs(d.Stride) * bitmap.Height];
            Marshal.Copy(ptr, rgbs, 0, rgbs.Length);
            Graphics g = pictureBox1.CreateGraphics();
            for (int index = 2; index < rgbs.Length; index += 3)
            {


                if (rgbs[index] == 255 &&  rgbs[index - 1] == 0 && rgbs[index - 2] == 255) // If color = RGB(255, 0, 255) Then ...
                {
                     // This never gets executed!
                     rgbs[index] = 0;
                     rgbs[index - 1] = 0;
                     rgbs[index - 2] = 0;

                }
            }
            Marshal.Copy(rgbs, 0, ptr, rgbs.Length); // Copy rgb values back to the memory location of the bitmap.
            pictureBox1.Image = bitmap;
            bitmap.UnlockBits(d); 
War es hilfreich?

Lösung

You don't need to copy the pixel data into an array. The point of LockBits is it gives you direct (unsafe) access the memory. You can just iterate the pixels and change them as you find them. You will need to know the format of the image to do this successfully.

  BitmapData bmd=bm.LockBits(new Rectangle(0, 0, 10, 10), 
                       ImageLockMode.ReadOnly, bm.PixelFormat);
  // Blue, Green, Red, Alpha (Format32BppArgb)
  int pixelSize=4;

  for(int y=0; y<bmd.Height; y++)
  {
    byte* row=(byte *)bmd.Scan0+(y*bmd.Stride);
    for(int x=0; x<bmd.Width; x++) 
    {
      int offSet = x*pixelSize;
      // read pixels
      byte blue = row[offSet];
      byte green = row[offSet+1];
      byte red = row[offSet+2];
      byte alpha = row[offSet+3];

      // set blue pixel
      row[x*pixelSize]=255;
    }
  }

It's a little more tricky in VB than C# as VB has no knowledge of pointers and requires the use of the marshal class to access unmanaged data. Here's some sample code. (For some reason I originally though this was a VB question).

  Dim x As Integer
  Dim y As Integer
  ' Blue, Green, Red, Alpha (Format32BppArgb)
  Dim PixelSize As Integer = 4 
  Dim bmd As BitmapData = bm.LockBits(new Rectangle(0, 0, 10, 10),
                                      ImageLockMode.ReadOnly, bm.PixelFormat)

  For y = 0 To bmd.Height - 1
    For x = 0 To bmd.Width - 1
      Dim offSet As Int32 = (bmd.Stride * y) + (4 * x)
      ' read pixel data
      Dim blue As Byte = Marshal.ReadByte(bmd.Scan0, offSet)
      Dim green As Byte = Marshal.ReadByte(bmd.Scan0, offSet + 1)
      Dim red As Byte = Marshal.ReadByte(bmd.Scan0, offSet + 2)
      Dim alpha As Byte = Marshal.ReadByte(bmd.Scan0, offSet + 3)
      ' set blue pixel
      Marshal.WriteByte(bmd.Scan0, offSet , 255)
    Next
  Next
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top