C#与Halcon学习——Bitmap转换为HObject

前两天掉进一个大坑,记录一下。写接口的时候要求输入为Image或Bitmap的数据类型,所以在用Halcon处理之前要先把它们编程Hobject的数据类型,在网上搜了一下相关的转换方法,大多是先利用了BitmapData中的LockBits和UnLockBits,取出位图的存储首地址,然后再利用Halcon里的GenImage系列函数根据位图地址创建一个新的HObject。根据这种方法我对图像类型进行了转换,然后就发现原来的算法不起作用了,将转换后的图像用Halcon打开,发现变成了如下这样。

C#与Halcon学习——Bitmap转换为HObject_第1张图片

C#与Halcon学习——Bitmap转换为HObject_第2张图片 

整个图就已经扭曲了。。

产生这种结果的代码如下:

public void Bitmap2HObjectBpp8(Bitmap SrcImage, out HObject image)
        {
            try
            {
                Point po = new Point(0, 0);
                Size so = new Size(SrcImage.Width, SrcImage.Height);//template.Width, template.Height
                Rectangle ro = new Rectangle(po, so);

                Bitmap DstImg = new Bitmap(SrcImage.Width, SrcImage.Height, PixelFormat.Format8bppIndexed);
                DstImg = SrcImage.Clone(ro, PixelFormat.Format8bppIndexed);

                Rectangle rect = new Rectangle(0, 0, DstImg.Width, DstImg.Height);
                BitmapData srcBmpData = DstImg.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
                HOperatorSet.GenImage1(out image, "byte", DstImg.Width, DstImg.Height, srcBmpData.Scan0);
                DstImg.UnlockBits(srcBmpData);
                
            }
            catch (Exception ex)
            {
                image = null;
            }
        }

最开始以为是图像的位数导致的,然后就把所有的图像转为Format8bppIndexed型,还是存在这个问题,就又仔细去看了GenImage1的文档,里面有一句话是Care must be taken not to truncate 64-bit pointers on 64-bit architectures,以为是指针有问题,弄了半天也搞懂为什么。然后偶然间发现这个转换方法对某些图是起作用的,然后看了图的尺寸为4032*3024(在此感谢上苍感谢我的手机。。),发现4032是64的倍数,此刻便开始怀疑这种方法的遍历是不是并非想象中的那样。

于是把目标转移到Scan0上,确实它是位图的首地址,而GenImage1里提到The pixels in PixelPointer are stored line-sequentially,在我们的结果中可以看到一条明显的分割线。

C#与Halcon学习——Bitmap转换为HObject_第3张图片

因此猜测是扫描的问题,去数了一下图中黑线在每一行的像素。。发现是delta=64*n-width,其中delta的取值范围是0~3,在此基本就真相大白了,去查了一下BitmapData类,发现其中的有一个属性是Stride,也就是扫描一行的字节数,它是4的倍数,所以说如果按照这个顺序来赋值内存的话,对于宽度不是64倍数的图片来说,不仅会丢失信息,还会造成图片的扭曲,并产生一个黑线。所以在使用GenImage系列的函数时,我们不能直接用Bitmap里面的Scan0指针。

对相关代码进行修改:

public static HObject BitmapToHImage(Bitmap SrcImage)
        {
            HObject Hobj;
            HOperatorSet.GenEmptyObj(out Hobj);

            Point po = new Point(0, 0);
            Size so = new Size(SrcImage.Width, SrcImage.Height);//template.Width, template.Height
            Rectangle ro = new Rectangle(po, so);

            Bitmap DstImage = new Bitmap(SrcImage.Width, SrcImage.Height, PixelFormat.Format8bppIndexed);
            DstImage = SrcImage.Clone(ro, PixelFormat.Format8bppIndexed);

            int width = DstImage.Width;
            int height = DstImage.Height;
            
            Rectangle rect = new Rectangle(0, 0, width, height);
            System.Drawing.Imaging.BitmapData dstBmpData =
                DstImage.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);//pImage.PixelFormat
            int PixelSize = Bitmap.GetPixelFormatSize(dstBmpData.PixelFormat) / 8;
            int stride = dstBmpData.Stride;
            
            //重点在此
            unsafe
            {
                int count = height * width;
                byte[] data = new byte[count];
                byte* bptr = (byte*)dstBmpData.Scan0;
                fixed (byte* pData = data)
                {
                    for (int i = 0; i < height; i++)
                        for (int j = 0; j < width; j++ )
                            {
                                 data[i * width + j ] = bptr[i * stride + j];
                            }
                    HOperatorSet.GenImage1(out Hobj, "byte", width, height, new IntPtr(pData));
                }
            }

            DstImage.UnlockBits(dstBmpData);

            return Hobj;
        }

修改之后,就可以发现转换的结果没有问题啦!同样的方法也可以用在转换24位彩色图像上,只要记得这个Stride就行了。。

C#与Halcon学习——Bitmap转换为HObject_第4张图片

C#与Halcon学习——Bitmap转换为HObject_第5张图片

 

你可能感兴趣的:(C#与Halcon学习——Bitmap转换为HObject)