如何优化获取白色背景图像中首个黑色像素索引的慢代码?
优化白色背景图像首个非白色像素查找速度
我有一张白色背景的图像,需要获取首个非白色(黑色)像素的坐标。目前用下面的代码实现,但运行速度特别慢:
public Element? GetFirstIndex(Image img) { Color c = new(); for(int i=0; i<300; i++) { for(int j=0; j <300; j++) { c = GetDominantColor(new(img), i, j, 1, 1); if (c.Name != "ffffffff") return new Element() { XPosition = j, YPosition = i, Heigh = 1, Width = 1 }; } } return null; }
原代码慢的原因
- 循环中每次都
new(img)创建新的Image实例,对象创建和内存开销极大 - 用
GetDominantColor获取1x1区域的颜色完全是大材小用,这个方法本来是用来取区域主色的,单像素场景下效率极低 - 硬编码了300x300的尺寸,不管图像实际大小都循环这么多次,做了很多无用功
方案1:直接使用Bitmap.GetPixel(简单高效)
把图像转成Bitmap后,直接调用GetPixel读取单个像素,避免重复创建对象和冗余计算:
public Element? GetFirstNonWhitePixel(Image img) { using var bmp = new Bitmap(img); int width = bmp.Width; int height = bmp.Height; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Color pixelColor = bmp.GetPixel(x, y); // 检查是否不是白色(白色对应ARGB全为255) if (pixelColor.A != 255 || pixelColor.R != 255 || pixelColor.G != 255 || pixelColor.B != 255) { return new Element { XPosition = x, YPosition = y, Height = 1, Width = 1 }; } } } return null; }
方案2:使用LockBits操作内存(极致性能)
如果图像尺寸较大,GetPixel还是有一定开销,这时可以用LockBits直接操作图像内存,速度会快很多:
public Element? GetFirstNonWhitePixelFast(Image img) { using var bmp = new Bitmap(img); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); var bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat); IntPtr ptr = bmpData.Scan0; int bytesPerPixel = Image.GetPixelFormatSize(bmp.PixelFormat) / 8; int stride = bmpData.Stride; byte[] pixels = new byte[stride * bmp.Height]; System.Runtime.InteropServices.Marshal.Copy(ptr, pixels, 0, pixels.Length); try { for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { int index = y * stride + x * bytesPerPixel; // 处理32位ARGB格式(最常见) if (bmp.PixelFormat == System.Drawing.Imaging.PixelFormat.Format32bppArgb) { byte b = pixels[index]; byte g = pixels[index + 1]; byte r = pixels[index + 2]; byte a = pixels[index + 3]; if (a != 255 || r != 255 || g != 255 || b != 255) { return new Element { XPosition = x, YPosition = y, Height = 1, Width = 1 }; } } // 处理24位RGB格式 else if (bmp.PixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb) { byte b = pixels[index]; byte g = pixels[index + 1]; byte r = pixels[index + 2]; if (r != 255 || g != 255 || b != 255) { return new Element { XPosition = x, YPosition = y, Height = 1, Width = 1 }; } } } } } finally { bmp.UnlockBits(bmpData); } return null; }
优化点总结
- 只创建一次Bitmap实例,避免循环内重复创建对象的开销
- 直接读取单个像素,替代冗余的
GetDominantColor方法 - 使用图像实际尺寸循环,避免硬编码带来的无用计算
- LockBits方式直接操作内存,比GetPixel的速度提升一个数量级以上
内容的提问来源于stack exchange,提问作者Jawad Ab
相关产品推荐
相关产品推荐

