使用lockbits进行图像处理,替代getpixel?

我试图使用lockbits增加我的图像检测类,但这会导致代码出现问题,因此无法运行。 我怎样才能同时使用lockbits和getpixel来加速图像检测,或者有人能给我看一个同样快的替代方案吗?

码:

static IntPtr Iptr = IntPtr.Zero; static BitmapData bitmapData = null; static public byte[] Pixels { get; set; } static public int Depth { get; private set; } static public int Width { get; private set; } static public int Height { get; private set; } static public void LockBits(Bitmap source) { // Get width and height of bitmap Width = source.Width; Height = source.Height; // get total locked pixels count int PixelCount = Width * Height; // Create rectangle to lock Rectangle rect = new Rectangle(0, 0, Width, Height); // get source bitmap pixel format size Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat); // Lock bitmap and return bitmap data bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat); // create byte array to copy pixel values int step = Depth / 8; Pixels = new byte[PixelCount * step]; Iptr = bitmapData.Scan0; // Copy data from pointer to array Marshal.Copy(Iptr, Pixels, 0, Pixels.Length); } static public bool SimilarColors(int R1, int G1, int B1, int R2, int G2, int B2, int Tolerance) { bool returnValue = true; if (Math.Abs(R1 - R2) > Tolerance || Math.Abs(G1 - G2) > Tolerance || Math.Abs(B1 - B2) > Tolerance) { returnValue = false; } return returnValue; } public bool findImage(Bitmap small, Bitmap large, out Point location) { unsafe { LockBits(small); LockBits(large); //Loop through large images width for (int largeX = 0; largeX < large.Width; largeX++) { //And height for (int largeY = 0; largeY < large.Height; largeY++) { //Loop through the small width for (int smallX = 0; smallX < small.Width; smallX++) { //And height for (int smallY = 0; smallY < small.Height; smallY++) { //Get current pixels for both image Color currentSmall = small.GetPixel(smallX, smallY); Color currentLarge = large.GetPixel(largeX + smallX, largeY + smallY); //If they dont match (ie the image is not there) if (!colorsMatch(currentSmall, currentLarge)) //Goto the next pixel in the large image goto nextLoop; } } //If all the pixels match up, then return true and change Point location to the top left co-ordinates where it was found location = new Point(largeX, largeY); return true; //Go to next pixel on large image nextLoop: continue; } } //Return false if image is not found, and set an empty point location = Point.Empty; return false; } } 

您不希望依赖getPixel()进行图像处理; 可以偶尔调用一个点值(例如鼠标hover),但一般情况下,最好在图像存储器或某些2D数组中进行图像处理,必要时可以转换为位图。

首先,您可以尝试编写一个使用LockBits / UnlockBits提取方便操作的数组的方法。 完成操作数组后,可以使用不同的LockBits / UnlockBits函数将其写回位图。

这是我过去使用过的一些示例代码。 第一个函数从Bitmap返回一维值数组。 由于您知道位图的宽度,因此可以将此1Darrays转换为2Darrays以进行进一步处理。 完成处理后,可以调用第二个函数将(修改的)1D数组再次转换为位图。

 public static byte[] Array1DFromBitmap(Bitmap bmp){ if (bmp == null) throw new NullReferenceException("Bitmap is null"); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData data = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); IntPtr ptr = data.Scan0; //declare an array to hold the bytes of the bitmap int numBytes = data.Stride * bmp.Height; byte[] bytes = new byte[numBytes]; //copy the RGB values into the array System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, numBytes); bmp.UnlockBits(data); return bytes; } public static Bitmap BitmapFromArray1D(byte[] bytes, int width, int height) { Bitmap grayBmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed); Rectangle grayRect = new Rectangle(0, 0, grayBmp.Width, grayBmp.Height); BitmapData grayData = grayBmp.LockBits(grayRect, ImageLockMode.ReadWrite, grayBmp.PixelFormat); IntPtr grayPtr = grayData.Scan0; int grayBytes = grayData.Stride * grayBmp.Height; ColorPalette pal = grayBmp.Palette; for (int g = 0; g < 256; g++){ pal.Entries[g] = Color.FromArgb(g, g, g); } grayBmp.Palette = pal; System.Runtime.InteropServices.Marshal.Copy(bytes, 0, grayPtr, grayBytes); grayBmp.UnlockBits(grayData); return grayBmp; } 

这些方法假设Bitmap像素格式可能不适合您,但我希望一般的想法很明确:使用LockBits / UnlockBits从Bitmap中提取字节数组,以便您可以最轻松地编写和调试算法,以及然后再次使用LockBits / UnlockBits将数组再次写入Bitmap。

为了便于移植,我建议您的方法返回所需的数据类型,而不是在方法本身内操作全局变量。

如果你一直在使用getPixel(),那么如上所述转换到数组或从数组转换可以大大加快你的代码,只需少量的编码工作。

好的从哪里开始。 更好地了解你正在使用lockBits做什么。 首先要确保,你不要用你的字节数组覆盖。

 LockBits(small); LockBits(large); 

由于第二次通话,所有第一次通话都是锁定你的图像,这是不好的,因为你没有再解锁它。 因此添加另一个表示图像的字节数组。 你可以做这样的事情

 LockBits(small, true); LockBits(large, false); 

并更改您的Lockbits方法

 static public void LockBits(Bitmap source, bool flag) { ... Marshal.Copy(Iptr, Pixels, 0, Pixels.Length); if(flag) PixelsSmall=Pixels; else PixelsLarge=Pixels; } 

其中PixelsLarge和PixelsSmall是全局的,像素不是那些2包含你的图像。 现在你必须比较它。 现在你必须比较每个“字节集”,因此你必须知道Pixelformat。 是32b / pix 24还是仅8(ARGB,RGB,灰度)让我们拍摄ARGB图像。 在这种情况下,一个集合将包含4个字节(= 32/8)我不确定订单,但我认为一个集合的顺序是ABGR或BGRA。

希望这可以帮到你。 如果你不弄清楚如何比较正确的像素,那么再问一遍。 啊,别忘了使用UnlockBits命令。