eyemDecode2.cs 10.6 KB
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ScanCodeServer
{
    public unsafe class EyemDecode2
    {
        public static string codeType = "QR_CODE|DATA_MATRIX";
        public static int Init()
        {
            if (!File.Exists(".\\darknet\\detect-tiny.cfg") || !File.Exists(".\\darknet\\detect-tiny.weights"))
            {
                throw new Exception("找不到darknet\\detect-tiny.cfg|detect-tiny.weights");
            }
            return eyemInitNNDataCodeModel(".\\darknet\\detect-tiny.cfg", ".\\darknet\\detect-tiny.weights", "", "");
        }
        static EyemDecode2()
        {
            Init();
        }
        //public static List<CodeInfo> Decoder(ref Bitmap bmap, string file = null) {
        //    return Decoder(ref bmap, file);
        //}
        /// <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>();
            Common.log.Info("开始 DecodeCode[eyem]");
            Stopwatch sw = new Stopwatch();
            sw.Start();
            try
            {
                //创建图像引用

                EyemImage eyemImage;
                BitmapData bitmapData = null;
                if (file == null)
                {
                    Rectangle rect = new Rectangle(0, 0, bmap.Width, bmap.Height);
                    bitmapData = bmap.LockBits(rect, ImageLockMode.ReadWrite, bmap.PixelFormat);
                    eyemImage = new EyemImage();
                    eyemImage.ucpImage = bitmapData.Scan0;
                    eyemImage.iWidth = rect.Width;
                    eyemImage.iHeight = rect.Height;
                    eyemImage.iChannels = 1;
                    eyemImage.iDepth = 0;
                }
                else
                {
                    eyemImageRead(file, -1, 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
                {
                    EyemImage tpDstImg;
                    int result = eyemDetectAndDecodeUseNN(eyemImage, eyemRect, out hObject, out tpResults, out ipNum, out _);
                    // eyemImageFree(ref tpDstImg);
                    //hObject.Dispose();
                    //int result = eyemDetectAndDecode(eyemImage, eyemRect, "", codeType, out hObject, out tpResults, out ipNum, false, iBlockSize, iRangeC, iSymbolMin, iSymbolMax);
                    //Common.log.Info($"eyemDetectAndDecode:{result},ipNum:{ipNum}");
                    sw.Stop();
                    Common.log.Info("结束 DecodeCode[eyem][" + (sw.ElapsedMilliseconds / 1000f).ToString("0.00") + $"]返回数量:result:{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);
                    }


                }
                catch (Exception ex)
                {
                    Common.log.Error($"" + ex.ToString());
                }
                finally
                {
                    if (hObject != null)
                        hObject.Dispose();
                    if (bitmapData != null)
                        bmap.UnlockBits(bitmapData);
                    if (file != null)
                        eyemImageFree(ref eyemImage);
                    //bmap.Dispose();
                }
            }
            catch (Exception ex)
            {
                Common.log.Error(ex.ToString());
            }
            //eyemImageFree(eyemImage.ucpImage);
            return codelist;
        }
        //释放解码句柄
        public class DataCodeHandle : SafeHandleZeroOrMinusOneIsInvalid
        {
            public DataCodeHandle() : base(true) { }
            protected override bool ReleaseHandle()
            {
                return eyemDetectAndDecodeFree(handle);
            }
        }
        [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 = 1, 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="eyemImage"></param>
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        public static extern void eyemImageFree(ref EyemImage eyemImage);

        //释放解码句柄
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool eyemDetectAndDecodeFree(IntPtr hObject);
        //基于深度学习读码程序(仅支持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);

        [StructLayout(LayoutKind.Sequential)]
        public struct EyemImage
        {
            /// <summary>
            /// 地址
            /// </summary>
            public IntPtr ucpImage;
            /// <summary>
            /// 图像内存 x 方向大小
            /// </summary>
            public int iWidth;
            /// <summary>
            /// 图像内存 y 方向大小
            /// </summary>
            public int iHeight;
            /// <summary>
            /// iDepth:
            /// uint8_t 取值范围[0, 255], iDepth = 0(常用,解码图像一般为此种格式)
            /// int8_t 取值范围[-128, 127], iDepth = 1
            /// uint16_t 取值范围[0, 56635], iDepth = 2(常用,点料机图像一般为此种格式)
            /// int16_t 取值范围[-32768, 32767], iDepth = 3
            /// int32_t 取值范围[-2147483648, 2147483647], iDepth = 4
            /// float_t 取值范围[-3.4028235E38, 3.4028235E38], iDepth = 5
            /// double_t 取值范围[-1.7E-308, 1.7E+308], iDepth = 6
            /// </summary>
            public int iDepth;
            /// <summary>
            /// 彩色图		iChannels=3或4(比RGB多了Alpha通道),一般为3
            /// 灰度图 iChannels = 1
            /// </summary>
            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;                       // 码内容
        }
    }

}