C# + Halcon 实现图像转换 Bitmap 转 HImage

200 阅读4分钟

前言

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

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!