Question Need help moving from GetPixel/SetPixel to Lockbits

AARRGGHHH

New member
Joined
May 31, 2015
Messages
1
Programming Experience
Beginner
This is my GetPixel/SetPixel code for increasing the reds and purples in an image

C#:
[COLOR=#00008b]private[/COLOR][COLOR=#00008b]void[/COLOR][COLOR=#000000] redsAndPurplesToolStripMenuItem_Click([/COLOR][COLOR=#00008b]object[/COLOR][COLOR=#000000] sender, [/COLOR][COLOR=#2b91af]EventArgs[/COLOR][COLOR=#000000] e)[/COLOR]
[COLOR=#000000]{[/COLOR][INDENT][COLOR=#808080]// Get bitmap from picturebox[/COLOR]
[COLOR=#2b91af]Bitmap[/COLOR][COLOR=#000000] bmpMain = ([/COLOR][COLOR=#2b91af]Bitmap[/COLOR][COLOR=#000000])pictureBoxMain.[/COLOR][COLOR=#2b91af]Image[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Clone[/COLOR][COLOR=#000000]();[/COLOR]

[COLOR=#808080]// search through each pixel via x, y coordinates, examine and make changes. Dont let values exceed 255 or fall under 0.  [/COLOR]
[COLOR=#00008b]for[/COLOR][COLOR=#000000] ([/COLOR][COLOR=#2b91af]int[/COLOR][COLOR=#000000] y = [/COLOR][COLOR=#800000]0[/COLOR][COLOR=#000000]; y < bmpMain.[/COLOR][COLOR=#2b91af]Height[/COLOR][COLOR=#000000]; y++)[/COLOR]
[COLOR=#00008b]   for[/COLOR][COLOR=#000000] ([/COLOR][COLOR=#2b91af]int[/COLOR][COLOR=#000000] x = [/COLOR][COLOR=#800000]0[/COLOR][COLOR=#000000]; x < bmpMain.[/COLOR][COLOR=#2b91af]Width[/COLOR][COLOR=#000000]; x++)[/COLOR]
[COLOR=#000000]   {[/COLOR]
[COLOR=#000000]        bmpMain[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]GetPixel[/COLOR][COLOR=#000000](x, y);[/COLOR]
[COLOR=#2b91af]        Color[/COLOR][COLOR=#000000] c = bmpMain.[/COLOR][COLOR=#2b91af]GetPixel[/COLOR][COLOR=#000000](x, y);[/COLOR]
[COLOR=#2b91af]        int[/COLOR][COLOR=#000000] myRed = c.R, myGreen = c.G, myBlue = c.B;[/COLOR]
[COLOR=#000000]        myGreen [/COLOR][COLOR=#000000]-= [/COLOR][COLOR=#800000]128[/COLOR][COLOR=#000000];[/COLOR]
[COLOR=#00008b]        if[/COLOR][COLOR=#000000] (myGreen < [/COLOR][COLOR=#800000]0[/COLOR][COLOR=#000000]) myGreen = [/COLOR][COLOR=#800000]0[/COLOR][COLOR=#000000];[/COLOR][COLOR=#000000] 
         bmpMain.[/COLOR][COLOR=#2b91af]SetPixel[/COLOR][COLOR=#000000](x, y, [/COLOR][COLOR=#2b91af]Color[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]FromArgb[/COLOR][COLOR=#000000]([/COLOR][COLOR=#800000]255[/COLOR][COLOR=#000000], myRed, myGreen, myBlue));[/COLOR]
[COLOR=#000000]   }[/COLOR]

[COLOR=#808080]// assign the new bitmap to the picturebox[/COLOR]
[COLOR=#000000]pictureBoxMain[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Image[/COLOR][COLOR=#000000] = ([/COLOR][COLOR=#2b91af]Bitmap[/COLOR][COLOR=#000000])bmpMain;[/COLOR]

[COLOR=#808080]// Save a copy to the HD for undo / redo.[/COLOR]
[COLOR=#00008b]string[/COLOR][COLOR=#000000] myString = [/COLOR][COLOR=#2b91af]Environment[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]GetEnvironmentVariable[/COLOR][COLOR=#000000]([/COLOR][COLOR=#800000]"temp"[/COLOR][COLOR=#000000], [/COLOR][COLOR=#2b91af]EnvironmentVariableTarget[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Machine[/COLOR][COLOR=#000000]);[/COLOR]
[COLOR=#000000]pictureBoxMain[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Image[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Save[/COLOR][COLOR=#000000](myString + [/COLOR][COLOR=#800000]"\\ColorAppRedo.png"[/COLOR][COLOR=#000000], [/COLOR][COLOR=#2b91af]System[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Drawing[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Imaging[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]ImageFormat[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Png[/COLOR][COLOR=#000000])[/COLOR][/INDENT]
[COLOR=#000000]}
[/COLOR]

This is my first attempt at lockbits:

C#:
[COLOR=#00008b]private[/COLOR][COLOR=#00008b]void[/COLOR][COLOR=#000000] redsAndPurplesToolStripMenuItem_Click([/COLOR][COLOR=#00008b]object[/COLOR][COLOR=#000000] sender, [/COLOR][COLOR=#2b91af]EventArgs[/COLOR][COLOR=#000000] e)[/COLOR]
[COLOR=#000000]{[/COLOR][INDENT][COLOR=#808080]
// Get bitmap from picturebox[/COLOR]
[COLOR=#2b91af]Bitmap[/COLOR][COLOR=#000000] bmpMain = ([/COLOR][COLOR=#2b91af]Bitmap[/COLOR][COLOR=#000000])pictureBoxMain.[/COLOR][COLOR=#2b91af]Image[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Clone[/COLOR][COLOR=#000000]();[/COLOR]

[COLOR=#2b91af]Rectangle[/COLOR][COLOR=#000000] rect = [/COLOR][COLOR=#00008b]new[/COLOR][COLOR=#2b91af]Rectangle[/COLOR][COLOR=#000000]([/COLOR][COLOR=#2b91af]Point[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Empty[/COLOR][COLOR=#000000], bmpMain.[/COLOR][COLOR=#2b91af]Size[/COLOR][COLOR=#000000]);[/COLOR][COLOR=#000000] 
[/COLOR][COLOR=#2b91af]BitmapData[/COLOR][COLOR=#000000] bmpData = bmpMain.[/COLOR][COLOR=#2b91af]LockBits[/COLOR][COLOR=#000000](rect, [/COLOR][COLOR=#2b91af]ImageLockMode[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]ReadOnly[/COLOR][COLOR=#000000], bmpMain.[/COLOR][COLOR=#2b91af]PixelFormat[/COLOR][COLOR=#000000]);[/COLOR][COLOR=#000000] 

[/COLOR][COLOR=#808080]// search through each pixel via x, y coordinates, examine and make changes. Dont let values exceed 255 or fall under 0.  [/COLOR]
[COLOR=#00008b]for[/COLOR][COLOR=#000000] ([/COLOR][COLOR=#2b91af]int[/COLOR][COLOR=#000000] y = [/COLOR][COLOR=#800000]0[/COLOR][COLOR=#000000]; y < bmpMain.[/COLOR][COLOR=#2b91af]Height[/COLOR][COLOR=#000000]; y++)[/COLOR]
[COLOR=#00008b]   for[/COLOR][COLOR=#000000] ([/COLOR][COLOR=#2b91af]int[/COLOR][COLOR=#000000] x = [/COLOR][COLOR=#800000]0[/COLOR][COLOR=#000000]; x < bmpMain.[/COLOR][COLOR=#2b91af]Width[/COLOR][COLOR=#000000]; x++)[/COLOR]
[COLOR=#000000]   {[/COLOR]
[COLOR=#000000]       bmpMain[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]GetPixel[/COLOR][COLOR=#000000](x, y);[/COLOR]
[COLOR=#2b91af]       Color[/COLOR][COLOR=#000000] c = [/COLOR][COLOR=#00008b]new[/COLOR][COLOR=#2b91af]Color[/COLOR][COLOR=#000000]();[/COLOR][COLOR=#000000] 
        [/COLOR][COLOR=#2b91af]int[/COLOR][COLOR=#000000] myRed = c.R, myGreen = c.G, myBlue = c.B;[/COLOR]
[COLOR=#000000]       myGreen [/COLOR][COLOR=#000000]-= [/COLOR][COLOR=#800000]128[/COLOR][COLOR=#000000];[/COLOR]
[COLOR=#00008b]       if[/COLOR][COLOR=#000000] (myGreen < [/COLOR][COLOR=#800000]0[/COLOR][COLOR=#000000]) myGreen = [/COLOR][COLOR=#800000]0[/COLOR][COLOR=#000000];[/COLOR][COLOR=#000000] 
        bmpMain.[/COLOR][COLOR=#2b91af]SetPixel[/COLOR][COLOR=#000000](x, y, [/COLOR][COLOR=#2b91af]Color[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]FromArgb[/COLOR][COLOR=#000000]([/COLOR][COLOR=#800000]255[/COLOR][COLOR=#000000], myRed, myGreen, myBlue));[/COLOR]
[COLOR=#000000]   }[/COLOR]
[COLOR=#000000]
bmpMain[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]UnlockBits[/COLOR][COLOR=#000000](bmpData);
[/COLOR][COLOR=#808080]
// assign the new bitmap to the picturebox
[/COLOR][COLOR=#000000]pictureBoxMain[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Image[/COLOR][COLOR=#000000] = ([/COLOR][COLOR=#2b91af]Bitmap[/COLOR][COLOR=#000000])bmpMain;[/COLOR]

[COLOR=#808080]// Save a copy to the HD for undo / redo.[/COLOR]
[COLOR=#00008b]string[/COLOR][COLOR=#000000] myString = [/COLOR][COLOR=#2b91af]Environment[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]GetEnvironmentVariable[/COLOR][COLOR=#000000]([/COLOR][COLOR=#800000]"temp"[/COLOR][COLOR=#000000], [/COLOR][COLOR=#2b91af]EnvironmentVariableTarget[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Machine[/COLOR][COLOR=#000000]);[/COLOR]
[COLOR=#000000]pictureBoxMain[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Image[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Save[/COLOR][COLOR=#000000](myString + [/COLOR][COLOR=#800000]"\\ColorAppRedo.png"[/COLOR][COLOR=#000000], [/COLOR][COLOR=#2b91af]System[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Drawing[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Imaging[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]ImageFormat[/COLOR][COLOR=#000000].[/COLOR][COLOR=#2b91af]Png[/COLOR][COLOR=#000000]);[/COLOR][/INDENT]
[COLOR=#000000]} [/COLOR]

The problem is that inside the nested loop, I do not understand how to convert the GetPixel/SetPixel code to Lockbits code. I have read tutorials, what I need is an example. What is the proper way to convert the nested loop code from GetPixel/SetPixel to Lockbits? Thank you very much
 

SumantraChoudry

New member
Joined
Aug 27, 2015
Messages
1
Programming Experience
5-10
One of the problems in your attempt is that you used ImageLockMode.ReadOnly, which does not allow you to modify the pixel data.
Another problem is to properly use the Scan0 pointer in the bitmap data. Here's the code to use the pointer for the 24-bit BGR case:
// Get bitmap from picturebox
Bitmap bmpMain = (Bitmap)pictureBoxMain.Image.Clone();

Rectangle rect = new Rectangle(Point.Empty, bmpMain.Size);
BitmapData bmpData = bmpMain.LockBits(rect, ImageLockMode.ReadWrite, bmpMain.PixelFormat);

unsafe
{
if (bmpData.PixelFormat == PixelFormat.Format24bppRgb)
{
for (int y = 0; y < bmpData.Height; y++)
{
byte* pByte = (byte*)bmpData.Scan0.ToPointer(); //begin from the first pixel
pByte += y * bmpData.Stride; //go to the correct scanline

for (int x = 0; x < bmpData.Width; x++)
{
int myBlue = *pByte;
//Do something with the Blue component
*pByte = (byte)myBlue;
pByte++;

int myGreen = *pByte;
myGreen -= 128;
if (myGreen < 0) myGreen = 0;
*pByte = (byte)myGreen;
pByte++;

int myRed = *pByte;
//Do something with the Red component
*pByte = (byte)myRed;
pByte++;
}
}
}
}
bmpMain.UnlockBits(bmpData);

// assign the new bitmap to the picturebox
pictureBoxMain.Image = (Bitmap)bmpMain;

Note that working with the pixels directly using LockBits and BitmapData can have speed advantages over using GetPixel and SetPixel, but there's a price to be paid:
1) The pixel location arithmetic becomes complex. The code sample I pasted above does it for the specific case of PixelFormat.Format24bppRgb. If your image is any other pixel format, the calculations will be different. If you want to handle all possible bitmap formats, brace yourself for a long project.
2) To gain the speed advantage, you must use unsafe pointers. For the most part, C# shields you from such unsafe code and even allows you to handle the pixels by using System.Runtime.InteropServices.Marshal.Copy(). But if you do that, the code loses a significant part of the speed advantage.
Unless you're proficient in pointers and unsafe code, you might be better off using an optimized image processing library such as leadtools if processing speed is a major issue for you.
 
Top Bottom