Question

I'm working on optimizing a program I'm working on, which currently reads byte data using lock bits, but writes pixel data using setPixel. So how do I actually modify the pixel data that I'm reading in? If I try setting pp, cp, or np, the method won't work (since it loops and needs pp, cp, and np to represent the pixel data), so I'm completely confused. Do I need to write to the pixel data to a byte[] and manipulate it, or what?

Here's a code sample:

BitmapData data = img.LockBits(new Rectangle(0, 0, img.Width, img.Height),
    ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

int scaledPercent = (int)(Math.Round(percentageInt * 255)) - 47;
Debug.WriteLine("percent " + scaledPercent);
unsafe
{
    Debug.WriteLine("Woah there, unsafe stuff");
    byte* prevLine = (byte*)data.Scan0;
    byte* currLine = prevLine + data.Stride;
    byte* nextLine = currLine + data.Stride;

    for (int y = 1; y < img.Height - 1; y++)
    {
        byte* pp = prevLine + 3;
        byte* cp = currLine + 3;
        byte* np = nextLine + 3;
        for (int x = 1; x < img.Width - 1; x++)
        {
            if (IsEdgeOptimized(pp, cp, np, scaledPercent))
            {
                //Debug.WriteLine("x " + x + "y " + y);
                img2.SetPixel(x, y, Color.Black);
            }
            else
            {
                img2.SetPixel(x, y, Color.White);
            }
            pp += 3; cp += 3; np += 3;
        }
        prevLine = currLine;
        currLine = nextLine;
        nextLine += data.Stride;
    }
}
img.UnlockBits(data);
pictureBox2.Image = img2;
Was it helpful?

Solution

SetPixel is slow to use compared to getting the raw bits as an array. Looks like you're doing some kind of edge-detection (?). The example for LockBits on MSDN (http://msdn.microsoft.com/en-us/library/5ey6h79d.aspx) shows how to get the raw array out and work with that, saving the result back to the original image.

The interesting bits of that example is where the bytes are copied of the pointer using Marshal.copy:

        // Get the address of the first line.
        IntPtr ptr = bmpData.Scan0;

        // Declare an array to hold the bytes of the bitmap. 
        int bytes  = Math.Abs(bmpData.Stride) * bmp.Height;
       byte[] rgbValues = new byte[bytes];

        // Copy the RGB values into the array.
        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

Now you have the values you need in the rgbValues array and can start manipulating these

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top