近期需要halcon图片格式Hobject到windows图片格式Bitmap 24位的转换,在网上搜寻多时,没有发现合适的。普遍的做法是Hobject格式转为Bitmap32位,然后再从Bitmap32位转为24位,这种做法虽然能达到目的,但是对于有时间要求的算法来说,显然不是最优解。因此本文提出一种基于halcon库的转换方式,从rgb模式的Hobject直转Bitmap24位,同时兼顾耗时要求。
要点:
1.Halcon图像格式与Bitmap格式的不同,如下图所示,左侧为halcon的中RGB三通道图的各个通道排布,右侧为Bitmap的RGB排布,可以看出Bitmap中使用的是交错图像格式。Hobject向Bitmap转换的关键即从独立排布生成交错排布。图片源:HALCON: Bitmap HImage Conversion
2.Bitmap的存储方式要求每行的字节数必须能被4整除,因此不满足的需要进行padding。这个特性决定了转换时转成32位即Format32bppRgb格式是最方便的,单通道位图和三通道位图可以转换为32位/像素格式,这意味着位图的每一行可以直接被4整除,而不需要padding。但是有的时候并不需要32位的bitmap,而是24的。
网上容易搜得到的,针对不同尺寸图像均适用的Hobejct转24位Bitmap的方式:Hobject——>Bitmap32——>Bitmap24。
代码如下:
Hobject转32为Bitmap,代码参考:《Halcon HObject和C# Bitmap图像互转的几种方式及转换时间测试》
此文中虽然写的是转24位,但是代码实际还是转32位。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using HalconDotNet;
using System.Drawing.Imaging;
///
[DllImport("kernel32.dll")]
public static extern void CopyMemory(int Destination, int add, int Length);
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
System.Diagnostics.Stopwatch watch2 = new System.Diagnostics.Stopwatch();
/// HObject转32位Bitmap(四通道)
///
///
///
private void HObject2Bpp32(HObject image, out Bitmap res)
{
try
{
HTuple hred, hgreen, hblue, type, width, height;
HOperatorSet.GetImagePointer3(image, out hred, out hgreen, out hblue, out type, out width, out height);
res = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
Rectangle rect = new Rectangle(0, 0, width, height);
BitmapData bitmapData = res.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
int imglength = width * height;
unsafe
{
byte* bptr = (byte*)bitmapData.Scan0;
byte* r = ((byte*)hred.I);
byte* g = ((byte*)hgreen.I);
byte* b = ((byte*)hblue.I);
for (int i = 0; i < imglength; i++)
{
bptr[i * 4] = (b)[i];
bptr[i * 4 + 1] = (g)[i];
bptr[i * 4 + 2] = (r)[i];
bptr[i * 4 + 3] = 255;
}
}
res.UnlockBits(bitmapData);
}
catch(Exception ex)
{
res = null;
throw ex;
}
}
Bitmap 32转Bitmap 24,构造新的Bitmap对象然后进行重绘操作得到24位Bitmap
Bitmap _tobmpImage;
//Hobject转32位Bitmap
HObject2Bpp32(ho_image, out _tobmpImage);
//32位Bitmap转24位
res24 = new Bitmap(_tobmpImage.Width, _tobmpImage.Height, PixelFormat.Format24bppRgb);
Graphics graphics = Graphics.FromImage(res24);
graphics.DrawImage(_tobmpImage, new Rectangle(0, 0, _tobmpImage.Width, _tobmpImage.Height));
主要利用halcon中inter_leave_channels()算子来创建符合bitmap的交错图片格式,此算子的参数可以参看halcon的帮助文档,关键为rowBytes参数值选择,默认为“match”,即默认图片不需要padding,若图片尺寸不满足直接转为24位的条件,需要使用padding时,则其值设定为4倍的图像宽度。具体代码如下:
//获取图像尺寸
HOperatorSet.GetImageSize(ho_image, out width0, out height0);
//创建交错格式图像
HOperatorSet.InterleaveChannels(ho_image, out HObject InterImage, "rgb", 4 * width0, 0);
//获取交错格式图像指针
HOperatorSet.GetImagePointer1(InterImage, out HTuple Pointer, out type, out width, out height);
IntPtr ptr = Pointer;
//构建新Bitmap图像
res24 = new Bitmap(width/4, height, width, PixelFormat.Format24bppRgb, ptr);
通过测试,方法2在转换速度上约为方法1的3~4倍(具体速度提升数值取决于硬件性能),同时能满足不同尺寸的RGB彩图转换。在笔者电脑实测4096×3000的1200万像素彩图,方法2耗时35ms,方法1耗时115ms,图像尺寸越大,速度差异对比越发明显。因此方法2适合在算法耗时要求较为严格的情况下使用,代码更加简洁,速度更快。
后续补充完整实验对比数据,及完整测试代码。转载请注明出处,谢谢合作。