RegionFeature.cs 9.0 KB
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Drawing.Imaging;
using System.Drawing;

using Asa.CameraFactory;

namespace Asa.Region
{
    /// <summary>
    /// 区域特征
    /// </summary>
    public class Feature
    {
        private Bitmap sourceImage;
        private Bitmap compareImage;
        private API.EyemImage source;
        private readonly List<API.EyemRegion> eyemReg;
        private readonly Dictionary<string, bool> isExist;
        private readonly Dictionary<PixelFormat, API.EyemImage> eyemImageList;
        private readonly Dictionary<int, PixelFormat> imagePixelList;

        /// <summary>
        /// 区域特征
        /// </summary>
        /// <param name="configPath"></param>
        /// <param name="cameraName"></param>
        /// <param name="logName"></param>
        public Feature(string configPath, string cameraName, string logName = "Region.Feature")
        {
            eyemReg = new List<API.EyemRegion>();
            isExist = new Dictionary<string, bool>();
            CameraName = cameraName;
            GetConfig(configPath);
            if (!string.IsNullOrWhiteSpace(logName))
                Log.Load(logName);

            eyemImageList = new()
            {
                { PixelFormat.Format8bppIndexed, new API.EyemImage { Depth = 0, Channel = 1 } },
                { PixelFormat.Format24bppRgb, new API.EyemImage { Depth = 0, Channel = 3 } },
                { PixelFormat.Format32bppArgb, new API.EyemImage { Depth = 0, Channel = 4 } }
            };

            imagePixelList = new()
            {
                { 1, PixelFormat.Format8bppIndexed },
                { 3, PixelFormat.Format24bppRgb },
                { 4, PixelFormat.Format32bppArgb }
            };
        }

        /// <summary>
        /// 相机名称
        /// </summary>
        public string CameraName { private set; get; }

        /// <summary>
        /// 原始图像
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public bool OriginalImage(Bitmap image)
        {
            sourceImage = new(image);
            return Bitmap2IntPtr(sourceImage, out source);
        }

        /// <summary>
        /// 比较图像
        /// </summary>
        /// <param name="image"></param>
        /// <param name="exist"></param>
        /// <returns></returns>
        public bool CompareImage(Bitmap image, out Dictionary<string, bool> exist)
        {
            exist = null;
            if (!image.Size.Equals(sourceImage.Size))  //两个图尺寸不一致
            {
                Log.Info("比较图像和原始图像尺寸不一致");
                return false;
            }

            compareImage = new(image);
            bool rtn = Bitmap2IntPtr(compareImage, out API.EyemImage dest);
            if (!rtn) return false;
            rtn = Contrast(dest, out Bitmap dspImage);
            exist = isExist;
            return rtn;
        }

        /// <summary>
        /// 比较图像
        /// </summary>
        /// <param name="image"></param>
        /// <param name="exist"></param>
        /// <param name="dspImage"></param>
        /// <returns></returns>
        public bool CompareImage(Bitmap image, out Dictionary<string, bool> exist, out Bitmap dspImage)
        {
            exist = null;
            dspImage = null;
            if (!image.Size.Equals(sourceImage.Size))  //两个图尺寸不一致
            {
                Log.Info("比较图像和原始图像尺寸不一致");
                return false;
            }

            compareImage = new(image);
            bool rtn = Bitmap2IntPtr(compareImage, out API.EyemImage dest);
            if (!rtn) return false;
            rtn = Contrast(dest, out dspImage);
            exist = isExist;
            return rtn;
        }

        /// <summary>
        /// 比较图像
        /// </summary>
        /// <param name="bmpPtr"></param>
        /// <param name="format"></param>
        /// <param name="exist"></param>
        /// <param name="dspImage"></param>
        /// <returns></returns>
        public bool CompareImage(IntPtr bmpPtr, PixelFormat format, out Dictionary<string, bool> exist, out Bitmap dspImage)
        {
            exist = null;
            dspImage = null;
            bool rtn = Bitmap2IntPtr(bmpPtr, format, out API.EyemImage dest);
            if (!rtn) return false;
            rtn = Contrast(dest, out dspImage);
            exist = isExist;
            return rtn;
        }





        private bool Contrast(API.EyemImage dest, out Bitmap bmp)
        {
            bmp = null;
            try
            {
                IntPtr hGlobal = API.StructArray2IntPtr(eyemReg.ToArray());
                int[] res = new int[eyemReg.Count];
                IntPtr ptr = System.Runtime.InteropServices.Marshal.UnsafeAddrOfPinnedArrayElement(res, 0);
                int iRet = API.eyemTrackFeature(source, dest, hGlobal, res.Length, ptr, out API.EyemImage dstImg);

                if (iRet == 0)
                {
                    for (int i = 0; i < isExist.Count; i++)
                    {
                        KeyValuePair<string, bool> pair = isExist.ElementAt(i);
                        isExist[pair.Key] = res[i] == 1;
                    }
                    IntPtr2Bitmap(dstImg, out bmp);
                }
                else
                {
                    Log.Info("eyemTrackFeature return " + iRet);
                }

                System.Runtime.InteropServices.Marshal.FreeHGlobal(hGlobal);
                return iRet == 0;
            }
            catch (Exception ex)
            {
                Log.Error("Contrast", ex);
                return false;
            }
        }

        private bool Bitmap2IntPtr(Bitmap bmp, out API.EyemImage eyem)
        {
            eyem = eyemImageList[bmp.PixelFormat];

            try
            {
                Rectangle rect = new(0, 0, bmp.Width, bmp.Height);
                BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
                IntPtr ptr = bmpData.Scan0;
                bmp.UnlockBits(bmpData);

                eyem.Handle = ptr;
                eyem.Width = bmp.Width;
                eyem.Height = bmp.Height;
                return true;
            }
            catch (Exception ex)
            {
                Log.Error("Bitmap2IntPtr", ex);
                return false;
            }
        }

        private bool IntPtr2Bitmap(API.EyemImage eyem, out Bitmap bmp)
        {
            bmp = null;
            try
            {
                PixelFormat format = imagePixelList[eyem.Channel];
                bmp = new Bitmap(eyem.Width, eyem.Height, eyem.Width * eyem.Channel, format, eyem.Handle);
                return true;
            }
            catch (Exception ex)
            {
                Log.Error("IntPtr2Bitmap", ex);
                return false;
            }
        }

        private bool Bitmap2IntPtr(IntPtr bmpPtr, PixelFormat format, out API.EyemImage eyem)
        {
            eyem = eyemImageList[format];

            try
            {
                eyem.Handle = bmpPtr;
                eyem.Width = sourceImage.Width;
                eyem.Height = sourceImage.Height;
                return true;
            }
            catch (Exception ex)
            {
                Log.Error("Bitmap2IntPtr", ex);
                return false;
            }
        }

        private void GetConfig(string path)
        {
            string json = System.IO.File.ReadAllText(path);
            System.Web.Script.Serialization.JavaScriptSerializer serializer = new();
            Dictionary<string, object> dic = (Dictionary<string, object>)serializer.DeserializeObject(json);
            if (!dic.ContainsKey("Region")) return;

            object[] obj = (object[])dic["Region"];
            int x = 0, y = 0, w = 0, h = 0;
            double r = 0;
            for (int i = 0; i < obj.Length; i++)
            {
                Dictionary<string, object> param = (Dictionary<string, object>)obj[i];
                if (!param.TryGetValue("CameraName", out object value))
                    continue;
                if (CameraName != value.ToString())
                    continue;
                if (param.TryGetValue("RegionName", out value))
                    isExist.Add(value.ToString(), false);
                if (param.TryGetValue("X", out value))
                    int.TryParse(value.ToString(), out x);
                if (param.TryGetValue("Y", out value))
                    int.TryParse(value.ToString(), out y);
                if (param.TryGetValue("Width", out value))
                    int.TryParse(value.ToString(), out w);
                if (param.TryGetValue("Height", out value))
                    int.TryParse(value.ToString(), out h);
                if (param.TryGetValue("Ratio", out value))
                    double.TryParse(value.ToString(), out r);
                API.EyemRegion region = new() { X = x, Y = y, Width = w, Height = h, Ratio = r };
                eyemReg.Add(region);
            }

        }

    }
}