c# - Bitmap.MakeTransparent() 太慢

标签 c# algorithm optimization drawing

我使用黑白图片作为蒙版,在应用矩形后生成漂亮的轮廓。不幸的是,为了消除黑色,我使用了 MakeTransparent 方法,不幸的是它非常慢,在我的代码中我必须执行这样的过程两次,在 20 个图像的情况下大约需要 5 秒。还有其他解决方案可以加快此过程吗?

Bitmap contour = new Bitmap(
    imageMaskCountour.Width, imageMaskCountour.Height, PixelFormat.Format32bppArgb);

using (Graphics g = Graphics.FromImage(contour))
{
    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
    g.FillRectangle(ContourBrush, 0, 0, contour.Width, contour.Height);
    g.DrawImage(
        imageMaskCountour,
        new Rectangle(0, 0, contour.Width, contour.Height),
        new Rectangle(0, 0, imageMaskCountour.Width, imageMaskCountour.Height),
        GraphicsUnit.Pixel);
}

contour.MakeTransparent(Color.Black);

编辑:

我尝试添加LockBitmap并添加以下方法:

public void MakeTransparent(Color color)
{
    for (int y = 0; y < this.Height; y++)
    {
        for (int x = 0; x < this.Width; x++)
        {
            if (this.GetPixel(x, y) == color)
            {
                this.SetPixel(x, y, Color.Transparent);
            }
        }
    }
}

但是速度要慢得多。

最佳答案

您在位图上执行的每个操作都需要锁定和解锁位。这使得它非常慢。请参阅this answer如何通过锁定一次、操作所有数据并最终解锁来直接访问位图数据。

以下代码是使用刚才提到的直接访问的常规位图的扩展方法。它实现了您的方法的逻辑。请注意,我将 HeightWidth 保存到局部变量中。我这样做是因为我认识到如果像循环条件一样多次使用它会慢得多。

警告:

底层代码仅适用于PixelFormat.Format32bppArgbsee PixelFormat reference 。 该代码让您了解如何直接访问像素数据,并且也可以适应其他像素格式。

如果要适应其他像素格式,必须遵守以下几点。

  • 正确写入颜色值的一个目标像素的字节大小。
  • 通过 Bitmap.Stride 属性进行正确的行寻址,see Stride for reference 。在 PixelFormat.Format32bppArgb 的情况下,步幅通过以下方式与宽度匹配:Bitmap.Stride == Bitmap.Width * 4,因此不需要调整行地址。

public static void FastMakeTransparent(this Bitmap bitmap, Color color)
{
    BitmapData bitmapData = bitmap.LockBits(
        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
        ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

    unsafe
    {
        int* pixelPointer = (int*)bitmapData.Scan0;

        int bitmapHeight = bitmap.Height;
        int bitmapWidth = bitmap.Width;
        int colorInt = color.ToArgb();
        int transparentInt = Color.Transparent.ToArgb();

        for (int i = 0; i < bitmapHeight; ++i)
        {
            for (int j = 0; j < bitmapWidth; ++j)
            {
                if (*pixelPointer == colorInt)
                    *pixelPointer = transparentInt;
                ++pixelPointer;
            }
        }
    }

    bitmap.UnlockBits(bitmapData);
}

在我的 Intel Core2Duo P8400 (2.26 GHz) CPU 上使用秒表类进行基准测试。

Bitmap size 1000x1000 random filled accumulated time of 100 runs
Target AnyCPU .NetFramework 4.5.2

Release build

MakeTransparent      Ticks: 24224801 | Time: 2422 ms
FastMakeTransparent  Ticks: 1332730  | Time: 133 ms


Debug build

MakeTransparent      Ticks: 24681178 | Time: 2468 ms
FastMakeTransparent  Ticks: 5976810  | Time: 597 ms

关于c# - Bitmap.MakeTransparent() 太慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43133902/

相关文章:

algorithm - 对大型无向图进行采样

algorithm - 稀疏矩阵乘法复杂度

c# - 这个振荡功能如何实现

javascript - 优化正则表达式以过滤数千个 HTML 选择选项

javascript - 如何从 JavaScript 执行 asp.net 按钮单击事件?

c# - ASP.NET 成员资格 : how to set the user as logged in

c# - 在 Visual Studio 中使用引用调试项目

c# - C#中变量类型的多态性

mysql - 让服务器拥有持久的 mySQL 连接或在需要时连接会更高效

c# - 使用泛型转换代码