将HObject类型转为Qimage类型

本文介绍了如何将Halcon的HObject图像类型转换为Qt的QImage类型,详细阐述了转换思路,包括从HObject获取图像数据、理解两种图像数据的存储格式和类型,以及使用QImage的不同构造函数。通过代码实现,转换速度已显著提升,但还存在转换后的图像前几个像素异常的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

差不多一个月前,在尝试解决将halcon的图像显示在Qt的窗口界面时,考虑过将halcon的HObject类型转换成qt的QImage类型,结果因为太菜了(网上也找不到类似的例子)而没能成功,具体见原来的文章qt窗口中显示halcon的图像

这两天花了点时间,理清思路,参考网上资料加上自己摸索出来方法然后实践了一下,能实现两种格式的转换(halcon to Qt)并能显示出来,就是转化耗时有点不尽人意。

先说说思路历程:

虽然网上没有找到Hobject和Qimage间转化的例子,但是有很多HObject转Vc或者转opencv类型的例子,

如:

VC中bmp图片和Halcon中图片类型相互转换

Halcon图像与Opencv图像相互转换(C++代码)

从这些例子中可以学到一些图像转换的思路:

先获取Hobject类型图像的图像数据指针及尺寸大小,再根据目标图像类型格式初始化一个相应大小的数据空间,然后按照一定的格式将HObject图像数据copy到目标图像数据空间,最后使用生成目标图像的函数。(这里大致说下思路,细节在后面写)

从halcon的Hobject图像类型中获取图像数据指针比较简单,问题是如何图像数据里面的值给复制到目标图像数据空间的对应位置,这就得弄清Hobject图像数据的存储格式和数据类型,以及QImage图像数据的存储格式和数据类型。

首先了解下HObject图像(像素?)的数据类型:

有byte, (u)int1/2/4,real, complex, direction, cyclic, vector_field这些,但一般都是byte类型,这里做图像转换也是用的byte这种类型。

HObject图像的byte类型的特点:(这里都是按自己理解编的)每个像素的一个通道的灰度值用byte类型来存储(byte类型,即一个字节,为8bit,也就是说图像的位深为8位,可以表示范围0到255的值,所以bmp图像灰度值的范围也是0~255),比如三通道图就是每个像素点都有rgb三个通道的灰度值,每个通道用一个byte来存值,单通道图的话每个像素就一个byte来存值。

然后了解下生成QImage图像需要的数据格式:

QImage 图像格式小结 这篇文章对我的帮助很大,整篇文章内容都有用 ,看完对我启发很大。

    比如要用到的根据公式: W = ( w * bitcount + 31 )/32 * 4 计算得到的W是QImage图像每行的字节数

    比如三通道和单通道需要不同的图像格式:

        QImage::Format_RGB888,存入格式为R, G, B 对应 0,1,2

        QImage::Format_Indexed8,需要设定颜色表,QVector<QRgb>

    以及,采用指针取值,行扫的方式对每个像素处理,还解决了数据补齐的问题。

然后是如何从图像数据生成QImage:

参考了这篇文章【QT】处理图像数据 中:

通过数据流读取:

QImage::QImage(uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = Q_NULLPTR, void *cleanupInfo = Q_NULLPTR) //连续内存的读写版本

QImage::QImage(const uchar *data, int width, int height, For

<think>好的,用户现在的问题是如何将System.Drawing.Bitmap换为System.Windows.Media.ImageSource。之前他们询问过如何在WPF中嵌入WinForm的PictureBox显示Bitmap,现在可能想改用原生的WPF控件,避免混合使用WinForm带来的问题。首先,我需要回忆之前的回答,其中提到了替代方案,使用Imaging.CreateBitmapSourceFromHBitmap方法。 用户的需求可能是优化代码,或者遇到线程、内存管理的问题,比如内存泄漏。需要详细说明换步骤,包括如何正确释放资源,因为直接使用GetHbitmap可能会导致GDI对象泄漏。另外,用户可能不了解需要调用DeleteObject来释放句柄,所以必须强调这一点。 另外,线程安全也是关键点,确保换过程在UI线程执行,或者使用Dispatcher。可能还需要提到性能优化,比如使用using语句管理Bitmap的生命周期,或者提供更高效的换方法,比如处理PixelFormat不同的问题。 用户可能没有意识到使用不安全代码的必要性,所以需要提醒在项目文件中启用AllowUnsafeBlocks。此外,是否应该封装成辅助方法,方便重用?或者如何处理不同的图像来源,比如从文件、流或资源加载的Bitmap。 需要检查是否有常见的错误点,比如忘记释放HBitmap,导致内存泄漏。或者是否应该使用其他方法,比如通过MemoryStream和BitmapImage来换,避免使用不安全代码,但可能影响性能。 最后,是否需要比较不同方法的优缺点,比如使用Interop方法更快但需要不安全代码,而流换方法更安全但可能更慢。根据用户的使用场景,比如实时处理需要高效,还是普通显示更注重安全,给出合适的建议。</think>在 WPF 中通过原生方式将 `System.Drawing.Bitmap` 换为 `System.Windows.Media.ImageSource` 需要以下关键步骤: --- ### **核心原理** WPF 使用 `BitmapSource`(`ImageSource` 的子类)处理图像,而 `System.Drawing.Bitmap` 属于 GDI+ 对象。需通过 **平台互操作** 实现两者的桥梁。 --- ### **完整代码实现** ```csharp using System.Drawing; using System.Windows.Interop; using System.Windows.Media.Imaging; public static class BitmapConverter { // 核心换方法 public static BitmapSource ToBitmapSource(this System.Drawing.Bitmap bitmap) { if (bitmap == null) return null; try { // 获取 GDI 位图句柄 IntPtr hBitmap = bitmap.GetHbitmap(); // 通过句柄创建 WPF 位图源 var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap( hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions() ); // 删除 GDI 对象句柄(避免内存泄漏) DeleteObject(hBitmap); return bitmapSource; } catch { return null; } } // 清理 GDI 资源 [System.Runtime.InteropServices.DllImport("gdi32.dll")] private static extern bool DeleteObject(IntPtr hObject); } ``` --- ### **使用示例** ```csharp // 加载 GDI+ Bitmap using (var gdiBitmap = new System.Drawing.Bitmap("image.jpg")) { // 换为 WPF 的 ImageSource var wpfImageSource = BitmapConverter.ToBitmapSource(gdiBitmap); // 绑定到 WPF 控件 wpfImage.Source = wpfImageSource; } ``` --- ### **关键注意事项** 1. **内存泄漏风险** - 必须调用 `DeleteObject` 释放 `GetHbitmap` 生成的句柄 - 建议将换逻辑封装在 `using` 语句中确保资源释放 2. **线程安全** - 此操作需在 **UI 线程** 执行(WPF 图像资源与界面线程绑定) 3. **像素格式兼容性** - 如果 `System.Drawing.Bitmap` 使用 `Format32bppPArgb` 格式,需在 WPF 中设置 `BitmapSource` 的 `CreateOptions`: ```csharp bitmapSource.Freeze(); // 提升跨线程访问性能 ``` 4. **项目配置** 在 `.csproj` 文件中启用非安全代码: ```xml <PropertyGroup> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> </PropertyGroup> ``` --- ### **替代方案(避免不安全代码)** ```csharp // 通过 MemoryStream 换(性能较低但更安全) public static BitmapSource ConvertWithStream(Bitmap bitmap) { using (var stream = new MemoryStream()) { bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png); stream.Position = 0; var bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.CacheOption = BitmapCacheOption.OnLoad; bitmapImage.StreamSource = stream; bitmapImage.EndInit(); return bitmapImage; } } ``` --- ### **性能优化建议** - 优先使用 `Format32bppPArgb` 格式的 `System.Drawing.Bitmap`(与 WPF 的预乘 Alpha 通道兼容) - 对静态图像使用 `Freeze()` 方法提升渲染性能 - 高频操作场景建议复用 `BitmapSource` 对象 通过这种换方案,可在 WPF 中高效利用现有的 GDI+ 图像处理逻辑,同时保持原生渲染性能。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值