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

  • 摘要: C# + Halcon实现图像转换Bitmap 转 HImage (8,24,32通道)案例。

  • 前言

    • HALCON 是一款由德国 MVTec 公司开发的功能强大的机器视觉软件,广泛应用于图像处理和机器视觉领域。
    • 它提供了丰富的图像处理算法和工具,支持多种编程语言接口(如 C、C++、C#、Python 等)。
    • 支持 Windows、Linux 和 macOS 等多种操作系统上运行。
    • 此案例C# + Halcon实现图像转换Bitmap 转 HImage (8,24,32通道)。
    • 使用GenImageInterleaved 方法实现Halcon图像转Bitmap图像。

  • 功能介绍

    • 1. 图像格式判断

      • GetImageFormat() 方法通过读取文件头部字节来判断图像的实际格式(JPEG、PNG、GIF、BMP)
      • 包含四个私有方法 IsJpeg(), IsPng(), IsGif(), IsBmp() 分别用于检测不同格式的特征字节。
      • 2. 图像通道数获取

        • GetImageChannelCount() 方法获取图像的通道数和像素格式。
          • 8bpp (1通道) - 灰度图。
          • 24bpp (3通道) - RGB图。
          • 32bpp (4通道) - RGBA图。
      • 3. 图像读取和转换

        • ReadImage() 方法读取图像并转换为 HImage 格式,根据不同的像素格式使用不同的处理方法。
        • 提供了多种 Bitmap 到 HImage/HObject 的转换方法:
          • BitmapToHImageBpp8() - 8位单通道转换。
          • BitmapToHImageBpp24() - 24位3通道转换。
          • BitmapToHImageBpp32() - 32位4通道转换。
          • BitmapToHObjectBpp24() - 24位彩色转HObject。

  • 核心步骤

    • 1、加载图像。
    • 2、锁定图像数据。
    • 3、执行图像转换。
    • 4、解锁图像数据。
    • 5、输出图像。

  • 运行环境

    • 操作系统: Windows11
    • 编程软件: Visual Studio 2022
    • .Net版本: .Net Framework 4.6.0
    • Halcon : HALCON 20.11

  • 核心方法

     ///<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;
            }
        }
    }
    

  • 总结

    • 1、Bitmap转换Halcon图像时常用的代码,如果Bitmap是32位的转换成HImage时显示图像倾斜的。
      • 网上搜了好多都无用,后来找到了要将GenImageInterleaved方法的第二个参数“bgr” 改成“bgrx”。
    • 2、获取图像正确格式的方法,是因为有时候直接改图像后缀名,读取图像时与图像后缀不符报错。
      • 目前暂时使用读取图像文件的二进制头部图像格式标识来判断。

  • 最后

    • 如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!
    • 如有疑问,欢迎评论区留言。
    • 也可以关注微信公众号 [编程笔记in] ,一起交流学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程笔记in

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值