Halcon HObject和C# Bitmap图像互转的几种方式及转换时间测试

分别使用了HOperatorSet.GenImageInterleaved直接转换、C#获取图像各个通道内存首地址和HOperatorSet.GenImage3合成、OpenCV获取图像各通道内存首地址和HOperatorSet.GenImage3合成的三种方式。经测试发现还是使用HOperatorSet.GenImageInterleaved方法转换速度最快。

详细测试代码如下:

using HalconDotNet;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace bitmaptohobject
{
    class Program
    {
        static void Main(string[] args)
        {
            Bitmap bit = new Bitmap(@"D:/图片/ocr/MaxImage.bmp");  //100M的.bmp格式文件,
            HObject ho;
            HOperatorSet.GenEmptyObj(out ho);
            Stopwatch st = new Stopwatch();
            st.Start();
            // Bitmap2HImageBpp24(bit,out ho);
            Bitmap2CVHImageBpp24(bit, out ho);
            //Bitmap2HObjectBpp24(bit, out ho);
            st.Stop();
            HOperatorSet.WriteImage(ho,"png",0,"1.png");
           
            Console.WriteLine(st.ElapsedMilliseconds.ToString());
            Console.ReadKey();
        }
        public static void Bitmap2HObjectBpp24(Bitmap bmp, out HObject image)  //90ms
        {
            try
            {
                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 void Bitmap2HImageBpp24(Bitmap bmp, out HObject image) //转换500ms
        {
            try
            {
                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

                BitmapData bmp_data = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
                byte[] arrayR = new byte[bmp_data.Width * bmp_data.Height];//红色数组 
                byte[] arrayG = new byte[bmp_data.Width * bmp_data.Height];//绿色数组 
                byte[] arrayB = new byte[bmp_data.Width * bmp_data.Height];//蓝色数组 
                unsafe
                {
                    byte* pBmp = (byte*)bmp_data.Scan0;//BitMap的头指针 
                                                       //下面的循环分别提取出红绿蓝三色放入三个数组 
                    for (int R = 0; R < bmp_data.Height; R++)
                    {
                        for (int C = 0; C < bmp_data.Width; C++)
                        {
                            //因为内存BitMap的储存方式,行宽用Stride算,C*3是因为这是三通道,另外BitMap是按BGR储存的 
                            byte* pBase = pBmp + bmp_data.Stride * R + C * 3;
                            arrayR[R * bmp_data.Width + C] = *(pBase + 2);
                            arrayG[R * bmp_data.Width + C] = *(pBase + 1);
                            arrayB[R * bmp_data.Width + C] = *(pBase);
                        }
                    }
                    fixed (byte* pR = arrayR, pG = arrayG, pB = arrayB)
                    {
                        HOperatorSet.GenImage3(out image, "byte", bmp_data.Width, bmp_data.Height,
                                                                   new IntPtr(pR), new IntPtr(pG), new IntPtr(pB));
                        //如果这里报错,仔细看看前面有没有写错 
                    }
                }             


            }
            catch (Exception ex)
            {
                image = null;
            }
        }

        public static void Bitmap2CVHImageBpp24(Bitmap bmp, out HObject image)   //150ms
        {
            try
            {
                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

                BitmapData bmp_data = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);


                Mat M = new Mat(bmp.Height,bmp.Width,MatType.CV_8UC3,bmp_data.Scan0,0);
                Mat[] MS = M.Split();
                IntPtr red= MS[0].Ptr(); IntPtr g = MS[1].Ptr();
                IntPtr b = MS[2].Ptr();

                HOperatorSet.GenImage3(out image, "byte", bmp_data.Width, bmp_data.Height, red, g, b);

            }
            catch (Exception ex)
            {
                image = null;
            }
        }

        public static void Bitmap2HObjectBpp8(Bitmap bmp, out HObject image)
        {
            try
            {
                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

                BitmapData srcBmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);

                HOperatorSet.GenImage1(out image, "byte", bmp.Width, bmp.Height, srcBmpData.Scan0);
                bmp.UnlockBits(srcBmpData);
            }
            catch (Exception ex)
            {
                image = null;
            }
        }

    }
}

附HObject转Bitmap代码:

//其中CopyMemory的API引用 需要引入命名空间 using System.Runtime.InteropServices; 和如下代码

        [DllImport("kernel32.dll")]
        public static extern void CopyMemory(int Destination, int add, int Length);
 
        /// <summary>
        /// HObject转8位Bitmap(单通道)
        /// </summary>
        /// <param name="image"></param>
        /// <param name="res"></param>
        private static void HObject2Bpp8(HObject image, out Bitmap res)
        {
            try
            {
                HTuple hpoint, type, width, height;

                const int Alpha = 255;
                int[] ptr = new int[2];
                HOperatorSet.GetImagePointer1(image, out hpoint, out type, out width, out height);

                res = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
                ColorPalette pal = res.Palette;
                for (int i = 0; i <= 255; i++)
                {
                    pal.Entries[i] = Color.FromArgb(Alpha, i, i, i);
                }
                res.Palette = pal;
                Rectangle rect = new Rectangle(0, 0, width, height);
                BitmapData bitmapData = res.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
                int PixelSize = Bitmap.GetPixelFormatSize(bitmapData.PixelFormat) / 8;
                ptr[0] = bitmapData.Scan0.ToInt32();
                ptr[1] = hpoint.I;
                if (width % 4 == 0)
                    CopyMemory(ptr[0], ptr[1], width * height * PixelSize);
                else
                {
                    for (int i = 0; i < height - 1; i++)
                    {
                        ptr[1] += width;
                        CopyMemory(ptr[0], ptr[1], width * PixelSize);
                        ptr[0] += bitmapData.Stride;
                    }
                }
                res.UnlockBits(bitmapData);
            }
            catch(Exception ex)
            {
                res = null;
                throw ex;
            }
        }
        /// <summary>
        /// HObject转24位Bitmap
        /// </summary>
        /// <param name="image"></param>
        /// <param name="res"></param>
        private static void HObject2Bpp24(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;
            }
        }  

20190902更新:

如评论一楼朋友weixin_43930542提出的使用 HObject转Bitmap代码 时遇到的问题:

我在使用Halcon转位图的时候在bptr[i * 4] = (b)[i]; bptr[i * 4 + 1] = (g)[i]; bptr[i * 4 + 2] = (r)[i]; bptr[i * 4 + 3] = 255; 的时候总是抛异常“尝试读取或写入受保护的内存。这通常指示其他内存已损坏” 请问博主有遇到过吗?怎么解决这个问题?

我同事使用的时候也出现类似的问题,我再次测试该段代码时也出现了类似问题(在公司电脑),然后在家里测试这段代码正常,也没找到具体原因,猜测可能是halcon环境问题。下面将我的测试demo连接发出来,大家可以测试一下。

注意:使用时,需要将Demo中的halcon引用删除,重新添加引用,halcon控件删除,重新添加halcon控件,然后再编译后调试。

20191015更新Demo:

Demo中halcon版本为Halcon18-Steady版本。

Demo下载连接:

链接:https://pan.baidu.com/s/1OgNo--w7K5QbxwRxtoajLg 
提取码:rk7r 


2019-12-23更新:

如本文评论中朋友weixin_42269849提出的在.net4.5及以上版本中会报错,并给出了解决方法,特此添加进文章,供大家学习。

        //net4.5及以上环境的hobject转bitmap24方法

        /// <summary>
        /// HObject转24位Bitmap,net4.5及以上版本
        /// </summary>
        /// <param name="image"></param>
        /// <param name="res"></param>
        public static void HObject2Bpp24Net45(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.L);
                    byte* g = ((byte*)hgreen.L);
                    byte* b = ((byte*)hblue.L);
                    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;
            }
        }

 

评论 40
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值