EyemManager.cs 10.2 KB
using OnlineStore.Common;
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.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace OnlineStore.DeviceLibrary
{
    public class EyemManager
    {

        public static bool Init()
        {
            try
            {
                int flag = eyemInitNNDetector(".\\darknet\\detect-tiny-label.cfg", ".\\darknet\\detect-tiny-label.weights", 640, 640);
                if (flag != 0)
                {
                    LogUtil.error("EyemManager" + $"初始化模型失败");
                    return false;
                    //MessageBox.Show("初始化模型失败!", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
                }
                LogUtil.info("EyemManager" + $"init ok ,flag="+ flag);
                eyemNNDetectorParams(0.35f, 0.45f);
            }
            catch (Exception ex)
            {
                LogUtil.error(" EyemManager Init error :" + ex.ToString());
            }

            return true;
        }
        public static bool record = false;//是否保存结果图片
        public static bool ReelCheck(Bitmap a)
        {
            try
            {
                Bitmap b = GetReducedImage(a, 1024, 0);
                a.Dispose();

                EyemImage image = new EyemImage();
                image.iWidth = b.Width;
                image.iHeight = b.Height;
                image.iChannels = 4;
                image.iDepth = 0;
                //b.Dispose();
                //b = new Bitmap("temp.bmp");
                //eyemImageRead("temp.bmp", -1, out EyemImage image);
                var bl = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, b.PixelFormat);
                image.ucpImage = bl.Scan0;

                int ipNum;
                BboxContainer bboxes = new BboxContainer();
                eyemNNDetector(image, out ipNum, ref bboxes, out EyemImage tpDstImg);

                LogUtil.info("EyemManager" + $"eyemNNDetector   ,ipNum=" + ipNum);
                if (record)
                {
                    var c = eyemCvtToBitmap(tpDstImg);
                    b.Save($"CameraDebug\\{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.jpg");
                    c.Save($"CameraDebug\\{DateTime.Now:yyyy-MM-dd-HH-mm-ss}_m.jpg");
                    c.Dispose();
                }
                eyemImageFree(ref tpDstImg);
                //eyemImageFree(ref image);
                b.UnlockBits(bl);
                b.Dispose();

                //for (int i = 0; i < ipNum; i++)
                //{ }
                if (ipNum > 0)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                LogUtil.error(" EyemManager ReelCheck error :" + ex.ToString());
            }
            return false;
        }

        #region 通用
        //读取图像,支持彩色与多深度
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern int eyemImageRead(string filename, int iFlags, out EyemImage tpImage);
        //释放图像资源
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern void eyemImageFree(ref EyemImage tpImage);
        #endregion
        #region 项目
        /// <summary>
        /// 初始化检测器
        /// </summary>
        /// <param name="detectorConfigPath">配置文件</param>
        /// <param name="detectorModelPath">模型文件</param>
        /// <returns></returns>
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern int eyemInitNNDetector(string detectorConfigPath, string detectorModelPath, int iNetSizew, int iNetSizeh);

        /// <summary>
        /// 目标检测器
        /// </summary>
        /// <param name="tpImage">输入图像</param>
        /// <returns></returns>
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern int eyemNNDetector(EyemImage tpImage, out int ipNum, ref BboxContainer container, out EyemImage tpDstImg);
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern int eyemNNDetectorParams(float fConfidence, float fNMSThreshold);
        #endregion
        #region 结构体
        //图像信息
        [StructLayout(LayoutKind.Sequential)]
        public struct EyemImage
        {
            public IntPtr ucpImage;                     // 地址
            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 BboxContainer
        {
            //最多支持100个目标
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
            public EyemRect[] bboxes;
        }
        #endregion



        /// <summary> 
        /// 生成缩略图重载方法1,返回缩略图的Image对象 
        /// </summary> 
        /// <param name="width">缩略图的宽度</param> 
        /// <param name="height">缩略图的高度</param> 
        /// <returns>缩略图的Image对象</returns> 
        private static Bitmap GetReducedImage(Bitmap resourceImage, int width, int height)
        {
            if (height == 0)
            {
                var sc = resourceImage.Width / (float)width;
                height = (int)(resourceImage.Height / sc);
            }

            try
            {
                Bitmap data = null;
                //用指定的大小和格式初始化Bitmap类的新实例 
                using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb))
                {
                    //从指定的Image对象创建新Graphics对象 
                    using (Graphics graphics = Graphics.FromImage(bitmap))
                    {
                        //清除整个绘图面并以透明背景色填充 
                        //graphics.Clear(Color.Transparent);
                        //在指定位置并且按指定大小绘制原图片对象 
                        graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
                        graphics.DrawImage(resourceImage, new Rectangle(0, 0, width, height));
                    }
                    data = new Bitmap(bitmap);
                }
                return data;
            }
            catch (Exception e)
            {
                throw e;
            }
        }
        public T DeepClone<T>(T _object)
        {
            T dstobject;
            using (MemoryStream mStream = new MemoryStream())
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(mStream, _object);
                mStream.Seek(0, SeekOrigin.Begin);//指定当前流的位置为流的开头。
                dstobject = (T)bf.Deserialize(mStream);
                mStream.Close();
            }
            return dstobject;
        }

        #region EyemImage转换成Bitmap
        public static unsafe Bitmap eyemCvtToBitmap(EyemImage tpImage)
        {
            if (tpImage.ucpImage == IntPtr.Zero)
                throw new ArgumentNullException("图像不存在");

            if (tpImage.iDepth != 0)
                throw new ArgumentException("图像必须是8位无符号整型");

            PixelFormat format;

            switch (tpImage.iChannels)
            {
                case 1:
                    format = PixelFormat.Format8bppIndexed;
                    break;
                case 3:
                    format = PixelFormat.Format24bppRgb;
                    break;
                case 4:
                    format = PixelFormat.Format32bppArgb;
                    break;
                default:
                    return null;
            }

            Bitmap bitmap = new Bitmap(tpImage.iWidth, tpImage.iHeight, format);

            //对于输出灰度图像
            if (format == PixelFormat.Format8bppIndexed)
            {
                ColorPalette palette = bitmap.Palette;
                for (int i = 0; i < 256; i++)
                {
                    palette.Entries[i] = Color.FromArgb(i, i, i);
                }
                bitmap.Palette = palette;
            }

            //锁定数据区
            BitmapData bd = bitmap.LockBits(new Rectangle(0, 0, tpImage.iWidth, tpImage.iHeight),
                ImageLockMode.WriteOnly, format);

            try
            {
                int pd = ((tpImage.iWidth * tpImage.iChannels) + 3) / 4 * 4;

                long bytesToCopy = tpImage.iWidth * tpImage.iChannels;

                for (int y = 0; y < tpImage.iHeight; y++)
                {
                    long offsetSrc = (y * tpImage.iWidth * tpImage.iChannels);
                    long offsetDst = (y * pd);

                    Buffer.MemoryCopy((byte*)(tpImage.ucpImage.ToPointer()) + offsetSrc, (byte*)(bd.Scan0.ToPointer()) + offsetDst, bytesToCopy, bytesToCopy);
                }
            }
            catch (Exception ex)
            {
                LogUtil.error("EyemManager eyemCvtToBitmap error:" + ex);
            }
            finally
            {
                bitmap.UnlockBits(bd);
            }
            return bitmap;
        }
        #endregion
    }
}