前言
HALCON 是一款由德国 MVTec 公司开发的功能强大的机器视觉软件,广泛应用于图像处理和机器视觉领域。
它提供了丰富的图像处理算法和工具,支持多种编程语言接口(如 C、C++、C#、Python 等)。并且能够在 Windows、Linux 和 macOS 等多种操作系统上运行。
此案例C# + Halcon实现图像转换Bitmap 转 HImage (8,24,32通道)
环境
操作系统:win11
Halcon版本:HDevelop 20.11 Steady - MVTec HALCON
.Net 版本: .Net Framework 4.6
软件工具:Visual Studio 2022
转换实现步骤
1、加载图像。
2、锁定图像数据。
3、执行图像转换。
4、解锁图像数据。
5、输出图像。
此案例使用GenImageInterleaved 方法实现Halcon图像转Bitmap图像。
///<summary>
/// Bitmap转HImage(32位4通道)
/// </summary>
public static void BitmapToHImageBpp32(Bitmap bmp, out HImage image, PixelFormat pixelFormat)
{
try
{
image = new HImage();
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, pixelFormat);
image.GenImageInterleaved(srcBmpData.Scan0, "rgbx", bmp.Width, bmp.Height, 0, "byte", bmp.Width, bmp.Height, 0, 0, -1, 0);
bmp.UnlockBits(srcBmpData);
}
catch (Exception ex)
{
image = null;
}
}
代码
public class ImageFormatTools
{
public class ImageFormatTools
{
#region 判断图像的正确格式
/// <summary>
/// 图像格式工具:获取正确的图像格式,通过图像文件的二进制头部图像格式标识。
/// </summary>
public static ImageFormat GetImageFormat(string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
using (BinaryReader br = new BinaryReader(fs))
{
// 读取文件的前几个字节
byte[] headerBytes = br.ReadBytes(16);
// 根据文件的前几个字节判断图像的实际格式
if (IsJpeg(headerBytes))
{
return ImageFormat.Jpeg;
}
else if (IsPng(headerBytes))
{
return ImageFormat.Png;
}
else if (IsGif(headerBytes))
{
return ImageFormat.Gif;
}
else if (IsBmp(headerBytes))
{
return ImageFormat.Bmp;
}
else
{
// 默认返回未知格式
return null;
}
}
}
}
private static bool IsJpeg(byte[] headerBytes)
{
// JPEG 文件的前两个字节是 0xFF, 0xD8
return headerBytes.Length >= 2 && headerBytes[0] == 0xFF && headerBytes[1] == 0xD8;
}
private static bool IsPng(byte[] headerBytes)
{
// PNG 文件的前八个字节是固定的签名:137 80 78 71 13 10 26 10
return headerBytes.Length >= 8 && headerBytes[0] == 137
&& headerBytes[1] == 80 && headerBytes[2] == 78
&& headerBytes[3] == 71 && headerBytes[4] == 13
&& headerBytes[5] == 10 && headerBytes[6] == 26
&& headerBytes[7] == 10;
}
private static bool IsGif(byte[] headerBytes)
{
// GIF 文件的前三个字节是 "GIF"
return headerBytes.Length >= 3 && headerBytes[0] == 71
&& headerBytes[1] == 73 && headerBytes[2] == 70;
}
private static bool IsBmp(byte[] headerBytes)
{
// BMP 文件的前两个字节是 "BM"
return headerBytes.Length >= 2 && headerBytes[0] == 66
&& headerBytes[1] == 77;
}
#endregion
/// <summary>
/// 获取图像通道数、图像类型
/// </summary>
public static int GetImageChannelCount(string imagePath ,out Bitmap bitmap,out PixelFormat format)
{
try
{
Image image = Image.FromFile(imagePath);
//bitmap = new Bitmap(imagePath);
bitmap = new Bitmap(image);
// 获取图像的PixelFormat
format = bitmap.PixelFormat;
image.Dispose();
// 根据PixelFormat判断通道数
switch (format)
{
case PixelFormat.Format8bppIndexed: // 灰度图
return 1;
case PixelFormat.Format24bppRgb: // RGB图
return 3;
case PixelFormat.Format32bppRgb: //
case PixelFormat.Format32bppArgb: // RGBA图 RGB + Alpha
return 4;
default:
return -1;
}
}
catch (Exception ex)
{
throw new ArgumentException($"参数异常:{ex.Message}");
}
}
/// <summary>
/// 读取图像,并返回读取信息:输入图像路径,返回HImage图像(8,24,32位(1,3,4通道))
/// </summary>
public static void ReadImage(string path,out HImage hImage,out string info)
{
hImage = new HImage();
Random random = new Random();
info = null;
int channel = GetImageChannelCount(path, out Bitmap bitmap, out PixelFormat format);
switch (format)
{
case PixelFormat.Format8bppIndexed:
try
{
hImage.ReadImage(path);
}
catch (Exception ex)
{
BitmapToHImageBpp8(bitmap, out hImage);
info= ex.Message;
}
break;
case PixelFormat.Format24bppRgb:
try
{
hImage.ReadImage(path);
}
catch (Exception ex)
{
BitmapToHImageBpp24(bitmap, out hImage);
info = ex.Message;
}
break;
case PixelFormat.Format32bppRgb:
case PixelFormat.Format32bppArgb:
try
{
hImage.ReadImage(path);
}
catch (Exception ex)
{
BitmapToHImageBpp32(bitmap, out hImage, format);
info = ex.Message;
}
break;
default:
try
{
hImage.ReadImage(path);
}
catch (Exception ex)
{
BitmapToHImageBpp8(bitmap, out hImage);
info = ex.Message;
}
break;
}
}
///<summary>
/// Bitmap转HImage(24位3通道)
/// </summary>
public static void BitmapToHImageBpp24(Bitmap bmp, out HImage image)
{
try
{
HObject tempImage = new HObject();
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
//image.GenImageInterleaved(srcBmpData.Scan0, "rgb", bmp.Width, bmp.Height, 0, "byte", bmp.Width, bmp.Height, 0, 0, -1, 0);
HOperatorSet.GenImageInterleaved(out tempImage, srcBmpData.Scan0, "bgr", bmp.Width, bmp.Height, 0, "byte", 0, 0, 0, 0, -1, 0);
bmp.UnlockBits(srcBmpData);
image = (HImage)tempImage.Clone();
}
catch (Exception ex)
{
image = null;
}
}
///<summary>
/// Bitmap转HImage(32位4通道)
/// </summary>
public static void BitmapToHImageBpp32(Bitmap bmp, out HImage image, PixelFormat pixelFormat,int channel)
{
try
{
image = new HImage();
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, pixelFormat);
image.GenImageInterleaved(srcBmpData.Scan0, "rgbx", bmp.Width, bmp.Height, 0, "byte", bmp.Width, bmp.Height, 0, 0, -1, 0);
bmp.UnlockBits(srcBmpData);
}
catch (Exception ex)
{
image = null;
}
}
/// <summary>
/// Bitmap转HImage(8位单通道)
/// </summary>
public static void BitmapToHImageBpp8(Bitmap bmp,out HImage image)
{
try
{
image = new HImage();
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
image.GenImage1("byte", bmp.Width, bmp.Height, srcBmpData.Scan0);
bmp.UnlockBits(srcBmpData);
}
catch (Exception ex)
{
image = null;
}
}
/// <summary>
/// Bitmap 转HObject(24位彩色3通道)
/// </summary>
public static void BitmapToHObjectBpp24(Bitmap bmp ,out HObject image)
{
try
{
image = new HObject();
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
HOperatorSet.GenImageInterleaved(out image, srcBmpData.Scan0, "bgr", bmp.Width, bmp.Height, 0, "byte", 0, 0, 0, 0, -1, 0);
bmp.UnlockBits(srcBmpData);
}
catch (Exception ex)
{
image = null;
}
}
}
public static int GetImageChannelCount(string imagePath ,out Bitmap bitmap,out PixelFormat format)
{
try
{
Image image = Image.FromFile(imagePath);
//bitmap = new Bitmap(imagePath);
bitmap = new Bitmap(image);
// 获取图像的PixelFormat
format = bitmap.PixelFormat;
image.Dispose();
// 根据PixelFormat判断通道数
switch (format)
{
case PixelFormat.Format8bppIndexed: // 灰度图
return 1;
case PixelFormat.Format24bppRgb: // RGB图
return 3;
case PixelFormat.Format32bppRgb: //
case PixelFormat.Format32bppArgb: // RGBA图 RGB + Alpha
return 4;
default:
return -1;
}
}
catch (Exception ex)
{
throw new ArgumentException($"参数异常:{ex.Message}");
}
}
///<summary>
/// Bitmap转HImage(24位3通道)
/// </summary>
public static void BitmapToHImageBpp24(Bitmap bmp, out HImage image)
{
try
{
HObject tempImage = new HObject();
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
//image.GenImageInterleaved(srcBmpData.Scan0, "rgb", bmp.Width, bmp.Height, 0, "byte", bmp.Width, bmp.Height, 0, 0, -1, 0);
HOperatorSet.GenImageInterleaved(out tempImage, srcBmpData.Scan0, "bgr", bmp.Width, bmp.Height, 0, "byte", 0, 0, 0, 0, -1, 0);
bmp.UnlockBits(srcBmpData);
image = (HImage)tempImage.Clone();
}
catch (Exception ex)
{
image = null;
}
}
///<summary>
/// Bitmap转HImage(32位4通道)
/// </summary>
public static void BitmapToHImageBpp32(Bitmap bmp, out HImage image, PixelFormat pixelFormat)
{
try
{
image = new HImage();
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, pixelFormat);
image.GenImageInterleaved(srcBmpData.Scan0, "rgbx", bmp.Width, bmp.Height, 0, "byte", bmp.Width, bmp.Height, 0, 0, -1, 0);
bmp.UnlockBits(srcBmpData);
}
catch (Exception ex)
{
image = null;
}
}
/// <summary>
/// Bitmap转HImage(8位单通道)
/// </summary>
public static void BitmapToHImageBpp8(Bitmap bmp,out HImage image)
{
try
{
image = new HImage();
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
image.GenImage1("byte", bmp.Width, bmp.Height, srcBmpData.Scan0);
bmp.UnlockBits(srcBmpData);
}
catch (Exception ex)
{
image = null;
}
}
/// <summary>
/// Bitmap 转HObject(24位彩色3通道)
/// </summary>
public static void BitmapToHObjectBpp24(Bitmap bmp ,out HObject image)
{
try
{
image = new HObject();
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
HOperatorSet.GenImageInterleaved(out image, srcBmpData.Scan0, "bgr", bmp.Width, bmp.Height, 0, "byte", 0, 0, 0, 0, -1, 0);
bmp.UnlockBits(srcBmpData);
}
catch (Exception ex)
{
image = null;
}
}
}
总结
在C#联合halcon中Bitmap转换Halcon图像时常用的代码,如果Bitmap是32位的转换成HImage时显示图像倾斜的。网上搜了好多都无用,后来找到了要将GenImageInterleaved方法的第二个参数"bgr" 改成"bgrx"。
获取图像正确格式的方法,是因为有时候直接改图像后缀名,读取图像时与图像后缀不符报错,目前暂时使用读取图像文件的二进制头部图像格式标识来判断。
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。
也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!
优秀是一种习惯,欢迎大家留言学习!
作者:吾与谁归in
出处:blog.csdn.net/weixin_43626218/article/details/141324211
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!