RegionFeature.cs 10.5 KB
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Drawing.Imaging;
using System.Drawing;
using CameraVisionLib.Model;

namespace Asa.Region
{
    /// <summary>
    /// 区域特征
    /// </summary>
    internal class Feature
    {
        private Bitmap sourceImage;    // 原图
        private Bitmap compareImage;   // 对比图
        private RegionAPI.EyemImage source;  // 原图结构
        private readonly List<RegionAPI.EyemRegion> eyemReg;  // 区域列表
        private readonly Dictionary<string, bool> isExist;    // 区域结果
        private readonly Dictionary<PixelFormat, RegionAPI.EyemImage> eyemImageList;
        private readonly Dictionary<int, PixelFormat> imagePixelList;

        /// <summary>
        /// 区域特征
        /// </summary>
        /// <param name="name"></param>
        /// <param name="regions"></param>
        public Feature(List<string> name, List<RegionAPI.EyemRegion> regions)
        {
            eyemReg = regions;
            isExist = new();
            for (int i = 0; i < name.Count; i++)
                isExist.Add(name[i], false);

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

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

            int rtn = RegionAPI.eyemInitNNDetector(@".\EyemLib\detect-tiny-label.cfg", @".\EyemLib\detect-tiny-label.weights");
            Common.log.Info("Feature init " + rtn);
        }

        /// <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))  //两个图尺寸不一致
            {
                Common.log.Info("比较图像和原始图像尺寸不一致");
                return false;
            }

            try
            {
                compareImage = new(image);
                bool rtn = Bitmap2IntPtr(compareImage, out RegionAPI.EyemImage dest);
                if (!rtn) return false;
                rtn = Contrast(dest, out Bitmap dspImage);
                exist = isExist;
                System.Runtime.InteropServices.Marshal.FreeHGlobal(dest.Handle);
                compareImage.Dispose();
                Common.log.Info("CompareImage OK");
                return rtn;
            }
            catch (Exception ex)
            {
                Common.log.Error("CompareImage", ex);
                return false;
            }
        }

        /// <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))  //两个图尺寸不一致
            {
                Common.log.Info("比较图像和原始图像尺寸不一致");
                return false;
            }

            try
            {
                compareImage = new(image);
                bool rtn = Bitmap2IntPtr(compareImage, out RegionAPI.EyemImage dest);
                if (!rtn) return false;
                rtn = Contrast(dest, out dspImage);
                exist = isExist;
                System.Runtime.InteropServices.Marshal.FreeHGlobal(dest.Handle);
                compareImage.Dispose();
                Common.log.Info("CompareImage OK");
                return rtn;
            }
            catch (Exception ex)
            {
                Common.log.Error("CompareImage", ex);
                return false;
            }
        }

        /// <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 RegionAPI.EyemImage dest);
            if (!rtn) return false;
            rtn = Contrast(dest, out dspImage);
            exist = isExist;
            System.Runtime.InteropServices.Marshal.FreeHGlobal(dest.Handle);
            return rtn;
        }

        /// <summary>
        /// 比较单张图像,没有原图
        /// </summary>
        /// <param name="image"></param>
        /// <param name="exist"></param>
        /// <returns></returns>
        public bool CompareSingleImage(Bitmap image, out Dictionary<string, bool> exist)
        {
            exist = null;

            try
            {
                compareImage = new(image);
                bool rtn = Bitmap2IntPtr(compareImage, out RegionAPI.EyemImage dest);
                if (!rtn)
                {
                    Common.log.Info("Bitmap2IntPtr false");
                    return false;
                }

                RegionAPI.BboxContainer container = new();
                int res = RegionAPI.eyemNNDetector(dest, out int ipNum, ref container);
                if (res != 0)
                {
                    Common.log.Info(string.Format("eyemNNDetector {0}, ipNum={1}", res, ipNum));
                    return false;
                }

                //中心点
                Point[] center = new Point[ipNum];
                for (int i = 0; i < center.Length; i++)
                    center[i] = new Point(container.bboxes[i].iXs + container.bboxes[i].iWidth / 2, container.bboxes[i].iYs + container.bboxes[i].iHeight / 2);

                for (int i = 0; i < isExist.Count; i++)
                {
                    KeyValuePair<string, bool> pair = isExist.ElementAt(i);
                    isExist[pair.Key] = false;

                    Rectangle rect = new(eyemReg[i].X, eyemReg[i].Y, eyemReg[i].Width, eyemReg[i].Height);
                    for (int j = 0; j < center.Length; j++)
                    {
                        if (rect.Contains(center[j]))
                        {
                            isExist[pair.Key] = true;
                            break;
                        }
                    }
                }

                exist = isExist;
                Common.log.Info("CompareImage OK");
                return true;
            }
            catch (Exception ex)
            {
                Common.log.Error("CompareImage", ex);
                return false;
            }

        }


        private bool Contrast(RegionAPI.EyemImage dest, out Bitmap bmp)
        {
            bmp = null;
            try
            {

                IntPtr hGlobal = RegionAPI.StructArray2IntPtr(eyemReg.ToArray());
                int[] res = new int[eyemReg.Count];
                IntPtr ptr = System.Runtime.InteropServices.Marshal.UnsafeAddrOfPinnedArrayElement(res, 0);
                int iRet = RegionAPI.eyemTrackFeature(source, dest, hGlobal, res.Length, ptr, out RegionAPI.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
                {
                    Common.log.Info("eyemTrackFeature return " + iRet);
                }

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

        private bool Bitmap2IntPtr(Bitmap bmp, out RegionAPI.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)
            {
                Common.log.Error("Bitmap2IntPtr", ex);
                return false;
            }
        }

        private bool IntPtr2Bitmap(RegionAPI.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)
            {
                Common.log.Error("IntPtr2Bitmap", ex);
                return false;
            }
        }

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

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


    }
}