You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化获取白色背景图像中首个黑色像素索引的慢代码?

优化白色背景图像首个非白色像素查找速度

我有一张白色背景的图像,需要获取首个非白色(黑色)像素的坐标。目前用下面的代码实现,但运行速度特别慢:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 14:25:45