I want to make a program that implements sobel edge detection. This is my code :
private Bitmap SobelEdgeDetect(Bitmap ori)
{
Bitmap b = original;
You really need to use LockBits instead of GetPixel
and SetPixel
.
So you create a BitmapData
object that contains all of the pixel data:
// lock the input bitmap's bits
System.Drawing.Imaging.BitmapData bmpData =
original.LockBits(new Rectangle(0, 0, original.Width, original.Height),
System.Drawing.Imaging.ImageLockMode.Read, original.PixelFormat);
Then, you can get the address of the first scan line (i.e. the first row of pixels):
IntPtr ptr = bmpData.Scan0;
Now you have two choices. If you're happy to mark your function as unsafe
then you can access the pixels directly using pointer arithmetic, like this
byte* pPixels = (byte*)ptr.ToPointer();
which gives you a pointer to the first byte of an RGB pixel (assuming 24bpp). Then you can access an individual pixel at (x,y)
using pointer arithmetic. First you determine how many bytes per pixel (if you don't already know)
int nBytesPerPixel = Image.GetPixelFormatSize(original.PixelFormat) / 8;
Then calculate the index to the pixel you want
byte* pPixelAtXY = pPixels + (y * bmpData.Stride) + (x * nBytesPerPixel);
This gives you unsafe
access to the pixels in a Bitmap
which you can do for the input and output bitmaps for fastest speed. Note that to use unsafe code, you need to mark your function as unsafe and edit your project properties.
If you don't want to use unsafe
code, you can still speed things up by copying all of the pixel data to a byte
array before processing and then copy it back afterwards. As the MSDN example showed
// 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);
// Set every third value to 255. A 24bpp bitmap will look red.
for (int counter = 2; counter < rgbValues.Length; counter += 3)
rgbValues[counter] = 255;
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
Whichever method you use, when you have finished with the pixel data, you must release it using UnlockBits
original.UnlockBits(bmpData);