eyemDecode.cs 13.8 KB
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CodeLibrary
{
    public unsafe class EyemDecode
    {
        public static  bool IsInit = false;
        /// <summary>
             /// 识别图像二维码
             /// </summary>
             /// <param name="bmap">需要手动释放这个bitmap</param>
             /// <param name="file">如果传文件的话,bmp传null</param>
             /// <returns></returns>
        public static List<CodeInfo> ModelDecoder(ref Bitmap bmap, string file = null)
        {

            if (!IsInit)
            {
                //string detectorConfigPath = Application.StartupPath + @"\\model\\" + "detect-tiny.cfg"; 
                //string detectorModelPath = Application.StartupPath + @"\\model\\" + "detect-tiny.weights";
                //string superResolutionConfigPath = Application.StartupPath + @"\\model\\" + "sr.caffemodel";
                //string superResolutionModelPath = Application.StartupPath + @"\\model\\" + "sr.prototxt";
                string detectorConfigPath =   ".\\model\\" + "detect-tiny.cfg";
                string detectorModelPath =  ".\\model\\" + "detect-tiny.weights";
                string superResolutionConfigPath =  ".\\model\\" + "sr.caffemodel";
                string superResolutionModelPath =  ".\\model\\" + "sr.prototxt";
                if (File.Exists(detectorConfigPath)&& File.Exists(detectorModelPath)  )
                {
                    int result = eyemInitNNDataCodeModel(detectorConfigPath, detectorModelPath, "", "");
                    HDLogUtil.info("eyemInitNNDataCodeModel: " + result);
                    IsInit = true;
                    Console.WriteLine("eyemInitNNDataCodeModel: " + result);
                }
                else
                {
                    HDLogUtil.error("eyemInitNNDataCodeModel 模型文件不完整");
                }
               
            }

            List<CodeInfo> codelist = new List<CodeInfo>();

            try
            {
                //创建图像引用

                EyemImage eyemImage;
                BitmapData bitmapData = null;
                if (file == null)
                {
                    Rectangle rect = new Rectangle(0, 0, bmap.Width, bmap.Height);
                    bitmapData = bmap.LockBits(rect, ImageLockMode.ReadOnly, bmap.PixelFormat);
                    eyemImage = new EyemImage();
                    eyemImage.vpImage = bitmapData.Scan0;
                    eyemImage.iWidth = rect.Width;
                    eyemImage.iHeight = rect.Height;
                
                    if (bmap.PixelFormat.Equals(PixelFormat.Format8bppIndexed))
                    {
                        eyemImage.iChannels = 1;
                    }else
                    {
                        eyemImage.iChannels = 3;
                    }
                    eyemImage.iDepth = 0;

                    if (bitmapData != null)
                        bmap.UnlockBits(bitmapData);
                }
                else
                {
                    eyemImageRead(file, 3, out eyemImage);
                }
                EyemImage outImage ;
                //创建扫描区域
                EyemRect eyemRect = new EyemRect();
                eyemRect.iXs = 0;
                eyemRect.iYs = 0;
                eyemRect.iWidth = eyemImage.iWidth;
                eyemRect.iHeight = eyemImage.iHeight;
                string codeType = "QR_CODE|DATA_MATRIX"; //QRCode

                int ipNum;
                EyemBarCode* tpResults;
                DataCodeHandle hObject = null;
                try
                {
                    int result = eyemDetectAndDecodeUseNN(eyemImage, eyemRect, out hObject, out tpResults, out ipNum,out outImage);
                    HDLogUtil.info($"eyemDetectAndDecode:{result},ipNum:{ipNum}");
                    if (result != 0 || ipNum == 0)
                        return codelist;

                    for (int i = 0; i < ipNum; i++)
                    {
                        CodeInfo ci = new CodeInfo(Marshal.PtrToStringAnsi(tpResults[i].hText), tpResults[i].iCenterX, tpResults[i].iCenterY);
                        ci.CodeType = Marshal.PtrToStringAnsi(tpResults[i].hType);
                        codelist.Add(ci);
                    }
                }
                finally
                {
                    if (hObject != null)
                    {
                        hObject.Dispose();
                    }
                    if (bitmapData != null)
                    {
                        try
                        {
                            bmap.UnlockBits(bitmapData);
                        }catch(Exception ex)
                        {

                        }
                    }
                    if (file != null)
                    {
                        eyemImageFree(ref eyemImage);
                    }
                    //bmap.Dispose();
                }
            }
            catch (Exception ex)
            {
                HDLogUtil.error(ex.ToString());
            }
            //eyemImageFree(eyemImage.ucpImage);
            return codelist;
        }
        /// <summary>
        /// 识别图像二维码
        /// </summary>
        /// <param name="bmap">需要手动释放这个bitmap</param>
        /// <param name="file">如果传文件的话,bmp传null</param>
        /// <returns></returns>
        public static List<CodeInfo> Decoder(ref Bitmap bmap, string file = null)
        {
            List<CodeInfo> codelist = new List<CodeInfo>();

            try
            {
                //创建图像引用

                EyemImage eyemImage;
                BitmapData bitmapData = null;
                if (file == null)
                {
                    Rectangle rect = new Rectangle(0, 0, bmap.Width, bmap.Height);
                    bitmapData = bmap.LockBits(rect, ImageLockMode.ReadOnly, bmap.PixelFormat);
                    eyemImage = new EyemImage();
                    eyemImage.vpImage = bitmapData.Scan0;
                    eyemImage.iWidth = rect.Width;
                    eyemImage.iHeight = rect.Height;
                    if (bmap.PixelFormat.Equals(PixelFormat.Format8bppIndexed))
                    {
                        eyemImage.iChannels = 1;
                    }
                    else
                    {
                        eyemImage.iChannels = 3;
                    }
                    eyemImage.iDepth = 0;
                }
                else
                {
                    eyemImageRead(file, 3, out eyemImage);
                }

                //创建扫描区域
                EyemRect eyemRect = new EyemRect();
                eyemRect.iXs = 0;
                eyemRect.iYs = 0;
                eyemRect.iWidth = eyemImage.iWidth;
                eyemRect.iHeight = eyemImage.iHeight;
                string codeType = "QR_CODE|DATA_MATRIX"; //QRCode

                int ipNum;
                EyemBarCode* tpResults;
                DataCodeHandle hObject = null;
                try
                {
                    int result = eyemDetectAndDecode(eyemImage, eyemRect, "", codeType, out hObject, out tpResults, out ipNum, false, 19, 5, 128, 215);
                    HDLogUtil.info($"eyemDetectAndDecode:{result},ipNum:{ipNum}");
                    if (result != 0 || ipNum == 0)
                        return codelist;

                    for (int i = 0; i < ipNum; i++)
                    {
                        CodeInfo ci = new CodeInfo(Marshal.PtrToStringAnsi(tpResults[i].hText), tpResults[i].iCenterX, tpResults[i].iCenterY);
                        ci.CodeType = Marshal.PtrToStringAnsi(tpResults[i].hType);
                        codelist.Add(ci);
                    }
                }
                finally
                {
                    if (hObject != null)
                        hObject.Dispose();
                    if (bitmapData != null)
                        bmap.UnlockBits(bitmapData);
                    if (file != null)
                        eyemImageFree(ref eyemImage);
                    //bmap.Dispose();
                }
            }
            catch (Exception ex)
            {
                HDLogUtil.error(ex.ToString());
            }
            //eyemImageFree(eyemImage.ucpImage);
            return codelist;
        }
        //释放解码句柄
        private class DataCodeHandle : SafeHandleZeroOrMinusOneIsInvalid
        {
            public DataCodeHandle() : base(true) { }
            protected override bool ReleaseHandle()
            {
                return eyemDetectAndDecodeFree(handle);
            }
        }
        //基于深度学习读码程序(仅支持QR、DataMatrix)
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern int eyemDetectAndDecodeUseNN(EyemImage tpImage, EyemRect tpRoi, out DataCodeHandle hObject, out EyemBarCode* tpResults, out int ipNum, out EyemImage tpDstImg);
        //加载模型配置文件
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern int eyemInitNNDataCodeModel(string detectorConfigPath, string detectorModelPath, string superResolutionConfigPath, string superResolutionModelPath);
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, string fileName, string strCodeType, out DataCodeHandle hObject, out EyemBarCode* tpResults, out int ipNum, bool bUseNiBlack, int iBlockSize, int iRangeC, int iSymbolMin, int iSymbolMax, double dScaleUpAndDown = 0.5, double dToleErr = 0.5, double dMinorStep = 1.0);
        /*
         * 参数说明
        tpImage 输入图像,可使用”eyemImageRead“接口读取图片(需与“eyemImageFree”配合使用),也可直接创建EyemImage对象。
        tpRoi 感兴趣区域,尺寸不能小于iSymbolMax。
        fileName 文件名,可不填。
        strCodeType 所要识别条码类型,“QRCode|DataMatrix|CODE_128”等等。
        hObject 结果释放句柄,配合eyemDetectAndDecodeFree使用
        tpResults           识别结果
        ipNum               结果数量
        bUseNiBlack         使用NiBlack二值化,默认值 false。
        iBlockSize 定位块大小(奇数),略大于最大定位块(只二维码),佳世达一般设置为11。
        iRangeC 搜索范围,范围越大识别越好时间也相应越长,佳世达一般设置为5。
        iSymbolMin 最小二维码尺寸,默认128。
        iSymbolMax 最大二维码尺寸,佳世达一般设置为215。
        dScaleUpAndDown 缩放,<1表示缩小,>1表示放大,=1表示不缩放
        dToleErr            最大允许误差默认50%,越小越严格但可能会识别不到。
        dMinorStep 步进,默认1.0。
        //返回值
        -3		图像不存在
        -1		内存不足
        0		正常
        -100	未识别到条码或参数设置不正确
        */
        /// <summary>
        /// 读取图像
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="iFalgs"></param>
        /// <param name="ucpImage"></param>
        /// <returns></returns>
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern int eyemImageRead(string filename, int iFalgs, out EyemImage ucpImage);

        ///// <summary>
        ///// 释放图像资源
        ///// </summary>
        ///// <param name="ipImage"></param>
        //[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        //private static extern void eyemImageFree(IntPtr ipImage);

        //释放图像资源
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern void eyemImageFree(ref EyemImage tpImage);

        //释放工具
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool eyemDetectAndDecodeFree(IntPtr hObject);

        [StructLayout(LayoutKind.Sequential)] 
        public struct EyemImage
        {
            public IntPtr vpImage;                     // 地址
            public int iWidth;                         // 图像内存 x 方向大小
            public int iHeight;                        // 图像内存 y 方向大小
            public int iDepth;                         // 图像位深度(详见说明)
            public int iChannels;                      // 图像通道数
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct EyemRect
        {
            public int iXs;                            // 起始点(左上角) x 坐标
            public int iYs;                            // 起始点(左上角) y 坐标
            public int iWidth;                         // x 方向大小(宽度)
            public int iHeight;                        // y 方向大小(高度)
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct EyemBarCode
        {
            public double dAngle;                      // 角度
            public int iCenterX;                       // y坐标
            public int iCenterY;                       // y坐标
            public IntPtr hType;                       // 码类型
            public IntPtr hText;                       // 码内容
        }
    }

}