C# - Windows 窗体应用程序位图 SetPixel 和 GetPixel 的更快替代方案

2024-04-24

我正在尝试自学 C#,并且从各种来源听说函数 get 和 setpixel 可能非常慢。有哪些替代方案?性能改进真的那么显着吗?

我的一段代码供参考:

public static Bitmap Paint(Bitmap _b, Color f)
{
  Bitmap b = new Bitmap(_b);
  for (int x = 0; x < b.Width; x++) 
  {
    for (int y = 0; y < b.Height; y++) 
    {
      Color c = b.GetPixel(x, y);
      b.SetPixel(x, y, Color.FromArgb(c.A, f.R, f.G, f.B));
    }
  }
  return b;
}

立即可用的代码

public class DirectBitmap : IDisposable
{
    public Bitmap Bitmap { get; private set; }
    public Int32[] Bits { get; private set; }
    public bool Disposed { get; private set; }
    public int Height { get; private set; }
    public int Width { get; private set; }

    protected GCHandle BitsHandle { get; private set; }

    public DirectBitmap(int width, int height)
    {
        Width = width;
        Height = height;
        Bits = new Int32[width * height];
        BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned);
        Bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject());
    }

    public void SetPixel(int x, int y, Color colour)
    {
        int index = x + (y * Width);
        int col = colour.ToArgb();

        Bits[index] = col;
    }

    public Color GetPixel(int x, int y)
    {
        int index = x + (y * Width);
        int col = Bits[index];
        Color result = Color.FromArgb(col);

        return result;
    }

    public void Dispose()
    {
        if (Disposed) return;
        Disposed = true;
        Bitmap.Dispose();
        BitsHandle.Free();
    }
}

没有必要LockBits or SetPixel。使用上面的类可以直接访问位图数据。

使用此类,可以将原始位图数据设置为 32 位数据。请注意,它是 PARGB,即预乘 alpha。看维基百科上的 Alpha 合成 https://en.wikipedia.org/wiki/Alpha_compositing有关其工作原理的更多信息以及MSDN 文章中有关 BLENDFUNCTION 的示例 https://msdn.microsoft.com/en-us/library/dd183393(v=vs.85).aspx了解如何正确计算 alpha。

如果预乘可能会使事情变得过于复杂,请使用PixelFormat.Format32bppArgb反而。当它被绘制时,性能会受到影响,因为它在内部被转换为PixelFormat.Format32bppPArgb。如果图像在绘制之前不必更改,则可以在预乘之前完成工作,绘制到PixelFormat.Format32bppArgb缓冲区,并从那里进一步使用。

获取标准Bitmap成员通过以下方式暴露Bitmap财产。位图数据可以使用以下命令直接访问Bits财产。

Using byte代替int对于原始像素数据

更改两个实例Int32 to byte,然后更改这一行:

Bits = new Int32[width * height];

To this:

Bits = new byte[width * height * 4];

当使用字节时,格式依次为 Alpha/Red/Green/Blue。每个像素占用 4 个字节的数据,每个通道一个。 GetPixel 和 SetPixel 函数需要相应地重新设计或删除。

使用上述类的好处

  • 仅仅为了操作数据而分配内存是不必要的;对原始数据所做的更改会立即应用于位图。
  • 没有其他对象需要管理。这实现了IDisposable就像Bitmap.
  • 它不需要unsafe block.

注意事项

  • 固定内存无法移动。为了使这种内存访问起作用,这是必需的副作用。这降低了垃圾收集器的效率(MSDN 文章 https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle.addrofpinnedobject(v=vs.100).aspx)。仅对需要性能的位图执行此操作,并确保Dispose当你完成后,就可以将它们解开。

通过访问Graphics object

因为Bitmap属性实际上是一个.NETBitmap对象,使用它执行操作很简单Graphics class.

var dbm = new DirectBitmap(200, 200);
using (var g = Graphics.FromImage(dbm.Bitmap))
{
    g.DrawRectangle(Pens.Black, new Rectangle(50, 50, 100, 100));
}

性能比较

该问题询问性能,因此这里的表格应显示答案中提出的三种不同方法之间的相对性能。这是使用基于 .NET Standard 2 的应用程序和 NUnit 完成的。

* Time to fill the entire bitmap with red pixels *
- Not including the time to create and dispose the bitmap
- Best out of 100 runs taken
- Lower is better
- Time is measured in Stopwatch ticks to emphasize magnitude rather than actual time elapsed
- Tests were performed on an Intel Core i7-4790 based workstation

              Bitmap size
Method        4x4   16x16   64x64   256x256   1024x1024   4096x4096
DirectBitmap  <1    2       28      668       8219        178639
LockBits      2     3       33      670       9612        197115
SetPixel      45    371     5920    97477     1563171     25811013

* Test details *

- LockBits test: Bitmap.LockBits is only called once and the benchmark
                 includes Bitmap.UnlockBits. It is expected that this
                 is the absolute best case, adding more lock/unlock calls
                 will increase the time required to complete the operation.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# - Windows 窗体应用程序位图 SetPixel 和 GetPixel 的更快替代方案 的相关文章

  • 函数“sum”的隐式声明在 C99 中无效

    我一直在寻找解决方案 但没有找到任何有帮助的东西 我收到以下错误 Implicit declaration of function sum is invalid in C99 Implicit declaration of function
  • 为什么在排序输入上插入到树中比随机输入更快?

    现在我一直听说从随机选择的数据构建二叉搜索树比有序数据更快 这仅仅是因为有序数据需要显式重新平衡以将树高度保持在最低限度 最近我实现了一个不可变的treap http en wikipedia org wiki Treap 一种特殊的二叉搜
  • 如何进行Visual Studio格式字典初始化?

    所有 Visual Studio 也包括 2012 不格式化以下内容 messageProcessor new Dictionary
  • C++ 中可以使用匿名类作为返回类型吗?

    有没有办法在 C 中使用匿名类作为返回类型 我用谷歌搜索这可能有效 struct Test fun 但是这段代码无法编译 错误信息是 新类型不能在返回类型中定义 其实代码没有任何意义 我只是想弄清楚匿名类是否可以用作C 中的返回类型 这是我
  • 使用正则表达式解析日志文件

    我目前正在为我们的内部日志文件 由 log4php log4net 和 log4j 生成 开发一个解析器 到目前为止 我有一个很好的正则表达式来解析日志 除了一个烦人的一点 一些日志消息跨越多行 我无法正确匹配 我现在的正则表达式是这样的
  • 如何修复此 YCrCb -> RBG 转换公式?

    我使用的公式来自这个问题 https stackoverflow com questions 8838481 kcvpixelformattype 420ypcbcr8biplanarfullrange frame to uiimage c
  • 我们什么时候应该在.NET中使用NativeMemory.Alloc()? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 NET6 C 引入NativeMemory类 但我不知道什么时候应该使用NativeMemory Alloc 而不是普通的数组实例化
  • 无法在 Visual Studio 和 vcpkg 中构建 cmake 项目(致命错误 C1083)

    我今天安装了vcpkg 启用了与Visual Studio的集成 即 vcpkg集成安装 并开始安装库 我基本上安装了 cpprestsdk 并触发了 boost 库的安装 然后我在 Visual Studio CMake 中打开该项目 当
  • 哪个更快?按引用传递与按值传递 C++

    我认为按引用传递应该比按值传递更快 因为计算机不复制数据 它只是指向数据的地址 但是 请考虑以下 C 代码 include
  • 使用 C# 的异步 WebRequest

    您好 我有一个函数 它将 url Get 参数传递到网络服务器上的 php 文件 并等待文件的响应 通常需要 10 20 秒 我想将其放入一个循环中 因为我必须一次将这些 Get 请求发送到大约 5 个不同的 php 文件 但是当我尝试将其
  • PowerShell 与 MongoDB C# 驱动程序方法不兼容?

    由 C 泛型引起的最新 MongoDB 驱动程序的问题 Cannot find an overload for GetCollection and the argument count 1 我可能可以使用其他没有泛型的 GetCollect
  • C# 从今天起 30 天

    我需要我的应用程序从今天起 30 天后过期 我会将当前日期存储在应用程序配置中 如何检查应用程序是否已过期 我不介意用户是否将时钟调回来并且应用程序可以正常工作 用户太愚蠢而不会这样做 if appmode Trial string dat
  • 如何在RcppParallel中调用用户定义的函数?

    受到文章的启发http gallery rcpp org articles parallel distance matrix http gallery rcpp org articles parallel distance matrix 我
  • 没有 FPU 的处理器中的浮点计算

    是否可以在没有浮点单元的嵌入式处理器中执行浮点运算 是的 您只需要在软件中完成即可 你的编译器可能会提供支持 http gcc gnu org onlinedocs gccint Soft float library routines ht
  • 为什么在 C++ 类中的数据成员上使用像 m_ 这样的前缀?

    许多 C 代码使用语法约定来标记数据成员 常见的例子包括 m memberName对于公共成员 在所有使用公共成员的情况下 memberName对于私人会员或所有会员 其他人尝试强制使用this gt member每当使用数据成员时 根据我
  • 如何编写完全可移植的 4 字节字符常量的编译时初始化

    遗留 代码大致如下所示 define MAKEID a b c d UInt32 a lt lt 24 UInt32 b lt lt 16 UInt32 c lt lt 8 UInt32 d define ID FORM MAKEID F
  • 查找文本文件中每行的行大小

    如何计算每行中的字符或数字数量 是否有类似 EOF 的东西更像是行尾 您可以遍历行中的每个字符并不断增加计数器直到行尾 n 遇到 确保以文本模式打开文件 r 而不是二进制模式 rb 否则流不会自动将不同平台的行结束序列转换为 n 人物 这是
  • 使用 List.Contains 方法为 LINQ 构建表达式树

    Problem 我正在重构一些LINQ查询我们的 Web 应用程序中的多个报告 并且我尝试将一些重复的查询谓词移至它们自己的中IQueryable扩展方法 以便我们可以将它们重新用于这些报告以及将来的报告 正如您可能推断的那样 我已经重构了
  • 从 git 签出后 nuget dll 丢失

    I have a C solution containing different projects On those projects I have some normal nuget packages like Newtonsoft Js
  • C#“var”关键字在 VB.NET 中的等价物是什么?

    例如 我如何获得 VB NET静态类型局部变量是static赋值右侧的表达式的类型 像这样 Dim http msdn microsoft com en us library 7ee5a7s1 aspx我的变量 3 你还需要 选项推断 ht

随机推荐

  • 无法在 NestedScrollView 内完全滚动

    不知何故 我无法在 NestedScrollView 内完全滚动 我的 NestedScrollView 内部是一个 TextView 其中有很多文本 下面有一个按钮 当我向下滚动时 我只能看到按钮的顶部 只有几个像素 它滚动得不够远 这是
  • 在Kestrel中重写后获取原始URL

    Apache 将根据重写的 URL 选择要提供服务的文件 但原始 URL 将传递给脚本 Kestrel 将重写的 URL 传递到管道中 可通过HttpContext Request Path 是否可以访问原网址来自中间件重写后 遵循 Tse
  • .Net Core 2.0 - 获取 AAD 访问令牌以与 Microsoft Graph 一起使用

    当使用 Azure AD 身份验证启动新的 Net Core 2 0 项目时 您将获得一个可以登录租户的工作示例 太棒了 现在我想获取登录用户的访问令牌并使用它来使用 Microsoft Graph API 我没有找到任何有关如何实现这一目
  • 在 odoo12 的表单视图中隐藏操作/更多按钮

    我想在 odoo12 中仅隐藏操作 更多按钮而不是打印按钮 我发现一些类似的问题在 odoo12 中不起作用 不是一个像样的答案 而是你的一个方向 源码中 我的版本是11 odoo 11 0 addons web static src js
  • 在分布式 dask 中,我们如何为每个工作人员选择 --nthreads 和 --nprocs ?

    我们如何选择 nthreads and nprocsDask 中每个工人的分布情况 我有 3 个工作线程 2 个工作线程有 4 个核心 每个核心有一个线程 1 个工作线程有 8 个核心 根据输出lscpu每个worker上的Linux命令
  • 如何将基数词转换为序数词

    有没有一种简单的方法可以将数字 1 2 3 转换为 1st 2nd 3rd 并且以这种方式我可以为该函数提供一种语言并具有它会返回我目标语言的正确形式吗 标准 C stl 或 boost 都可以 MFC 或 ATL win32 api 或我
  • 如何简洁地赋值并立即调用函数变量?

    以下是在闭包中定义匿名函数 调用该函数并忽略它的方法 function do stuff 这用于维持有限的范围而不向脚本添加大量内容 IIFE 立即调用函数表达式 如果您希望立即执行某个函数 同时仍保留该函数以供将来使用 该怎么办 如下所示
  • 在重新激活 WiFi/移动网络之前,服务中的 Android 位置侦听器无法工作

    我的位置侦听器工作正常 收集数据没有任何问题 但有时它不收集任何数据 我此时必须关闭并重新启动我的位置提供程序 重新启动可以解决问题 但是 这可能不是用户期望做的最好的事情 当我使用 GPS 作为提供商时 没有问题 位置侦听器在服务中工作
  • 在react-router-dom中隐藏某些页面的标题

    有没有办法可以仅隐藏 React Router 中某些路由的页面标题 我现在的问题是我的App组件呈现我的Main组件 其中包含我的BrowserRouter 和我的Header呈现在我的App组件 所以我无法根据路由路径渲染标题 这是一些
  • 如何从access中的表中获取选择性记录

    下面给出的是我的查询结果 但有很多冗余记录 因此 我想过滤掉这个查询的结果 我的目标是每个角度仅提取两个记录 第一个和最后一个 例如当角度为195 我想获得它的第一条记录日期 2 27 2017 时间 2 00 00 AM和 日期为的第二条
  • 禁用 Chrome 严格 MIME 类型检查

    有什么办法可以禁用strict MIME type checking在 Chrome 中 实际上我正在跨域发出 JSONP 请求 它在 Firefox 上工作正常 但是在使用 chrome 时 它 在控制台中出现一些错误 拒绝执行来自 的脚
  • 批处理文件随机删除文本文件的一半行?

    我需要一种方法来使用批处理来查看文本文件的每一行 并删除该文本文件中的一半行 随机选择要删除的行 这是为了模拟 D D 游戏中的锦标赛 我所需要的只是一种方法来淘汰每轮比赛的获胜者 我可以轻松地制作一个批处理文件 复制文本文件并为每一轮重命
  • Ionic 4:Cordova 不可用。确保包含 cordova.js 或在设备/模拟器中运行

    我正在尝试在新的 ionic 4 项目中使用 cordova 插件 但我总是遇到有关 cordova 的错误 该插件已正确安装并显示在插件文件夹中 Error 本机 尝试调用 SplashScreen hide 但 Cordova 不可用
  • 使用 ggplot 为长格式数据创建散点图

    我研究了一个长格式的 data frame 在每种情况下都有不同数量的实体 如下所示 Condition rating Control 2 1596456 Control 0 2385878 Control 3 0042808 Contro
  • 如何从下拉框中获取用户选择的值并将其添加到模型中? [复制]

    这个问题在这里已经有答案了 我有一个表单 用户在其中创建新考试 并在表单中用户从下拉菜单中选择一个主题 该下拉列表包含主题字符串 而不是实际的主题对象 在我的程序中 存在与考试具有一对多关系的实际主题对象 如何找到用户选择的值 我想将其添加
  • 配置 Sonar 以从 Maven pom.xml 中排除文件

    我有一个在maven中配置的项目 代码分析是由SonarQube完成的 我正在尝试在 pom xml 文件中配置 SonarQube 以从代码分析中排除一些文件 这些文件可以通过它们的类名来识别 它们在扩展名之前包含下划线字符 它们是元模型
  • 操作系统状态错误-50?

    我刚刚收到从 ExtAudioFileWrite 返回的结果代码 50 而我在 扩展音频文件服务参考 中并没有找到关于这个结果代码的信息 请帮我解决它 Thanks 该错误代码在CarbonCore框架的MacErrors h中声明 50
  • R-sqldf 错误原始与双精度

    我有一个矢量 lims 有分数限制 1 0 000000 7 025894 9 871630 12 411131 15 155998 18 099176 21 431354 25 391163 30 616550 40 356630 我创建
  • 如何使用 JAXB 从 xsd 生成实现 Serialized 接口的 Java 类?

    我想将缓存引入到现有的 Spring 项目中 该项目使用 JAXB 来公开 WebServices 缓存将在端点级别完成 为了做到这一点 使用 JAXB 从 XSD 生成的类需要实现Serializable接口和覆盖Object s toS
  • C# - Windows 窗体应用程序位图 SetPixel 和 GetPixel 的更快替代方案

    我正在尝试自学 C 并且从各种来源听说函数 get 和 setpixel 可能非常慢 有哪些替代方案 性能改进真的那么显着吗 我的一段代码供参考 public static Bitmap Paint Bitmap b Color f Bit