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

如何提升GraphicsPath.IsVisible方法的执行效率?

优化C#中GraphicsPath.IsVisible判断效率的方案

一、预生成路径区域掩码(最有效优化)

把GraphicsPath对应的区域提前绘制到一张同尺寸的掩码位图中,后续判断点是否在路径内时,直接读取掩码的像素值即可,彻底避免反复调用IsVisible的昂贵计算。

实现步骤

  • 创建与目标位图(bmptest)尺寸一致的掩码Bitmap,推荐用Format32bppArgb格式。
  • 用绘图上下文先填充掩码为黑色(代表路径外区域),再用白色填充GraphicsPath覆盖的区域(代表路径内)。
  • 对掩码执行LockBits获取像素指针,后续通过坐标计算偏移量直接读取像素值判断归属。

代码示例

// 预生成路径掩码(建议在窗体加载或路径变更时执行,不要放在Paint事件重复生成)
private Bitmap CreatePathMask(Bitmap targetBmp, GraphicsPath path)
{
    Bitmap mask = new Bitmap(targetBmp.Width, targetBmp.Height, PixelFormat.Format32bppArgb);
    using (Graphics g = Graphics.FromImage(mask))
    {
        g.FillRectangle(Brushes.Black, 0, 0, mask.Width, mask.Height);
        g.FillPath(Brushes.White, path);
    }
    return mask;
}

// 在FindPoints中使用掩码判断
private void FindPoints(Bitmap bmp1, Bitmap bmp2, Bitmap bmptest, Bitmap pathMask)
{
    // 省略获取bmp1、bmp2、bmptest像素数据的LockBits代码...
    
    // 锁定掩码像素数据
    Rectangle maskRect = new Rectangle(0, 0, pathMask.Width, pathMask.Height);
    BitmapData maskData = pathMask.LockBits(maskRect, ImageLockMode.ReadOnly, pathMask.PixelFormat);
    IntPtr maskPtr = maskData.Scan0;
    int maskStride = maskData.Stride;
    int pixelByteSize = 4; // 32bppArgb每个像素占4字节

    try
    {
        foreach (var point in cloudPoints)
        {
            int x = point.X;
            int y = point.Y;
            if (x < 0 || x >= pathMask.Width || y < 0 || y >= pathMask.Height)
                continue;

            // 计算掩码像素的内存偏移量
            int offset = y * maskStride + x * pixelByteSize;
            // 读取红色通道值(白色的R通道为255)
            byte r = Marshal.ReadByte(maskPtr, offset + 2);
            if (r == 255)
            {
                // 设置bmptest对应像素为黄色的代码...
            }
        }
    }
    finally
    {
        pathMask.UnlockBits(maskData);
        // 解锁其他位图的BitmapData...
    }
}

二、先过滤差异点范围

先获取GraphicsPath的外接矩形Bounds,只对落在这个矩形内的差异点执行IsVisible判断,减少无效调用:

Rectangle pathBounds = path.GetBounds().ToRectangle();
foreach (var point in cloudPoints)
{
    if (!pathBounds.Contains(point))
        continue;
    if (path.IsVisible(point))
    {
        // 设置黄色像素...
    }
}

三、并行处理差异点

如果差异点数量极大,可利用多核CPU并行处理:

Rectangle pathBounds = path.GetBounds().ToRectangle();
Parallel.ForEach(cloudPoints, point =>
{
    if (pathBounds.Contains(point) && path.IsVisible(point))
    {
        // 注意:操作bmptest像素时,若用LockBits指针则线程安全(每个点内存地址独立)
        // 设置黄色像素的代码...
    }
});

注意事项

  • 路径掩码要缓存,仅当GraphicsPath发生变化时重新生成,避免重复计算。
  • LockBits操作必须放在try-finally块中,确保位图能正常解锁,防止内存泄漏。

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:21:00