ReelCheckUtil.cs 15.4 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.Text;
using System.Threading.Tasks;
using static CodeLibrary.EyemDecode;

namespace OnlineStore.DeviceLibrary
{
   public unsafe class ReelCheckUtil
    {

        public static bool SaveImage = false;
        //结构体
        [StructLayout(LayoutKind.Sequential)]
        public struct EyemHSVModel
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            public double[] dpRangeL, dpRangeU;        // 提取下限,提取上限[H S V]
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
            public double[] dpRangeLExt, dpRangeUExt;  // 额外提取下限,额外提取上限(针对处于跨模型颜色,比如红色)[H S V]
        }// 用于HSV颜色模型分割(H(0-180)、S(0-255)、V(0-255))


        //接口
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern int eyemTrackFeature(EyemImage tpImage, EyemImage tpMask, EyemRect tpRoi, IntPtr tpRois, int ipRoiNum, EyemHSVModel tpHSVModel, [MarshalAs(UnmanagedType.LPArray)] int[] ipResults, out EyemImage tpDstImg);

        /*
 * 参数说明
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);
 

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


        public static int[] ReelCheck(int deviceID, string cameraName, out string imgName)
        {
            imgName = "";
            if (String.IsNullOrEmpty(cameraName))
            {
                return null;
            }
            Bitmap bitmap = MyCamera.AcqImage(cameraName);
            if (bitmap == null)
            {
                string file = ConfigAppSettings.GetValue("TESTFILE", @"D:\皮带线料盘识别\128\r-camera-1-20220128-13134651.bmp");
                if (File.Exists(file))
                {
                    bitmap = new Bitmap(file);
                }
            }
            if (bitmap == null)
            {
                LogUtil.error("ReelCheckUtil :ReelCheck [" + cameraName + "] 获取图片失败 ");
                ExceptionMsgManager.updateMsg("ReelCheck", cameraName, "ReelCheck [" + cameraName + "] 获取图片失败");
                return null;
            }
            else
            {
                ExceptionMsgManager.updateMsg("ReelCheck", cameraName ); 
            }
            //if (SaveImage)
            //{
            //    string path = "D:\\image\\"+ cameraName + "\\SourceImg\\";
            //    if (!Directory.Exists(path))
            //    {
            //        Directory.CreateDirectory(path);
            //    }
            //    bitmap.Save(path + imageName, ImageFormat.Bmp);
            //}
            EyemImage image = eyemCvtToEyemImage(bitmap);
            //绿色分割模型
            EyemHSVModel tpHsvModel = new EyemHSVModel();
            //tpHsvModel.dpRangeL = new double[] { 55, 10, 35 }; tpHsvModel.dpRangeU = new double[] { 100, 255, 255 };
            //tpHsvModel.dpRangeLExt = new double[] { 0, 0, 0 }; tpHsvModel.dpRangeUExt = new double[] { 0, 0, 0 };
             
            //短皮带线三
            tpHsvModel.dpRangeL = new double[] { 78, 10, 60 }; tpHsvModel.dpRangeU = new double[] { 100, 255, 255 };
            tpHsvModel.dpRangeLExt = new double[] { 0, 0, 0 }; tpHsvModel.dpRangeUExt = new double[] { 0, 0, 0 };

            if (deviceID.Equals(301))
            { 
                //短皮带线二
                tpHsvModel.dpRangeL = new double[] { 57, 15, 0 }; tpHsvModel.dpRangeU = new double[] { 93, 255, 255 };
                tpHsvModel.dpRangeLExt = new double[] { 0, 0, 0 }; tpHsvModel.dpRangeUExt = new double[] { 0, 0, 0 };
            }

            //裁剪区域
            EyemRect tpRoi = new EyemRect();
            tpRoi.iXs = 0; tpRoi.iYs = 0;
            tpRoi.iWidth = image.iWidth;
            tpRoi.iHeight = image.iHeight;

            //添加需要监控的位置信息
            List<EyemRect> tpRois = new List<EyemRect>();
            //EyemRect roi1 = new EyemRect();
            //roi1.iXs = 533; roi1.iYs = 187; roi1.iWidth = 345; roi1.iHeight = 310;
            //EyemRect roi2 = new EyemRect();
            //roi2.iXs = 900; roi2.iYs = 137; roi2.iWidth = 240; roi2.iHeight = 197;
            EyemRect roi1 = new EyemRect();
            EyemRect roi2 = new EyemRect();
            roi1.iXs = 470; roi1.iYs = 143; roi1.iWidth = 411; roi1.iHeight = 387;
            roi2.iXs = 882; roi2.iYs = 84; roi2.iWidth = 317; roi2.iHeight = 251;

            //短皮带线三
            if (deviceID.Equals(301))
            {
                //短皮带线二
                roi1.iXs = 1120; roi1.iYs = 737; roi1.iWidth = 296; roi1.iHeight = 282;
                roi2.iXs = 1405; roi2.iYs = 611; roi2.iWidth = 236; roi2.iHeight = 202;
            }

            tpRois.Add(roi1); tpRois.Add(roi2);

            //转指针
            IntPtr hGlobal = eyemStructArray2IntPtr(tpRois.ToArray());

            //短皮带线三
            string maskName = "mask.png";
            if (deviceID.Equals(301))
            {
                //短皮带线二
                maskName = "mask2.png";
            }

            //加载mask
            EyemImage mask;
            eyemImageRead(maskName, -1, out mask);

            //检测
            int[] ipResults = new int[tpRois.Count];
            eyemTrackFeature(image, mask, tpRoi, hGlobal, ipResults.Length, tpHsvModel, ipResults, out EyemImage tpDstImg);

            string resultStr = "";
            int hasReelCount = 0;
            for (int i = 0; i < ipResults.Length; i++)
            {
                if (ipResults[i] == 1)
                {
                    Console.WriteLine("检测到{0}位置有料盘", i);
                    hasReelCount++;
                }
                resultStr += ipResults[i];
            }

            Bitmap dstBitmap = eyemCvtToBitmap(tpDstImg);
            if (dstBitmap != null &&(hasReelCount<2) && SaveImage)
            {
                string dataFolder = DateTime.Now.ToString("yyyyMMdd");
                string hourFolder = DateTime.Now.ToString("HH");
                string date = cameraName.Trim().Replace('_', '-') + "-" + DateTime.Now.ToString("yyyyMMdd-HHmmss") + DateTime.Now.Millisecond;
                string imageName = date + "-" + resultStr + ".bmp";
                imgName = imageName;
                string path = "D:\\image\\" + cameraName + "\\ResOut\\"+ dataFolder+"\\"+hourFolder+"\\"; 
                if (canSavePic(path))
                {
                    dstBitmap.Save(path + imageName, ImageFormat.Jpeg);
                }
            }
            //释放资源
            Marshal.FreeHGlobal(hGlobal);
            //每运行检测一次释放一次
            eyemImageFree(ref tpDstImg);
            eyemImageFree(ref image);
            //mask可以在程序启动与关闭时加载/释放
            eyemImageFree(ref mask);
            return ipResults;

        }

        public static bool canSavePic(string path ="")
        {
            if (path == "")
            { 
                path = "D:\\image\\ResOut\\";
            }
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            string volume = path.Substring(0, path.IndexOf(':'));
            long freespace = GetHardDiskSpace(volume);
            int zhao =(int)( freespace / 1024);
            if (zhao < 5)
            {
                LogUtil.error(volume + "盘剩余空间:" + freespace + "G, 不再保存料盘图片");
                return false;
            }
            return true;
        }
        //单位MB
        private static long GetHardDiskSpace(string str_HardDiskName)
        {
            long totalSize = 0;
            str_HardDiskName = str_HardDiskName + ":\\";
            System.IO.DriveInfo[] drives = System.IO.DriveInfo.GetDrives();
            foreach (System.IO.DriveInfo drive in drives)
            {
                if (drive.Name == str_HardDiskName)
                {
                    totalSize = drive.TotalFreeSpace / (1024 * 1024);
                }
            }
            return totalSize;
        }
        public static EyemImage eyemCvtToEyemImage(Bitmap bitmap)
        {
            EyemImage tpImage = new EyemImage();
            //锁定数据区
            BitmapData bd = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.ReadOnly, bitmap.PixelFormat);

            switch (bitmap.PixelFormat)
            {
                case PixelFormat.Format8bppIndexed:
                    tpImage.iChannels = 1;
                    break;
                case PixelFormat.Format24bppRgb:
                    tpImage.iChannels = 3;
                    break;
                case PixelFormat.Format32bppArgb:
                    tpImage.iChannels = 4;
                    break;
                case PixelFormat.Format32bppRgb:
                    tpImage.iChannels = 4;
                    break;
                default:
                    throw new Exception("Image formats are not supported");
            }
            //仅支持8位
            tpImage.iDepth = 0;
            //图像尺寸
            tpImage.iWidth = bitmap.Width; tpImage.iHeight = bitmap.Height;
            //分配内存(释放不是用eyemImageFree,用Marshal.FreeHGlobal(tpImage.vpImage))
            tpImage.vpImage = Marshal.AllocHGlobal(bd.Stride * bd.Height);
            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 * pd;
                    long offsetDst = y * tpImage.iWidth * tpImage.iChannels;

                    Buffer.MemoryCopy((byte*)(bd.Scan0.ToPointer()) + offsetSrc, (byte*)(tpImage.vpImage.ToPointer()) + offsetDst, bytesToCopy, bytesToCopy);
                }
            }
            finally
            {
                bitmap.UnlockBits(bd);
            }
            return tpImage;
        }

        //public static void eyemCvtToEyemImage(Bitmap bitmap, out EyemImage tpImage)
        //{
        //    int channels = 0;
        //    switch (bitmap.PixelFormat)
        //    {
        //        case PixelFormat.Format8bppIndexed:
        //            channels = 1;
        //            break;
        //        case PixelFormat.Format24bppRgb:
        //            channels = 3;
        //            break;
        //        case PixelFormat.Format32bppArgb:
        //            channels = 4;
        //            break;
        //        default:
        //            break;
        //    }
        //    //锁定数据区
        //    BitmapData bd = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
        //        ImageLockMode.ReadOnly, bitmap.PixelFormat);
        //    try
        //    {
        //        eyemImageFromBitmap(bd.Scan0, bd.Width, bd.Height, 0, channels, out tpImage);
        //    }
        //    finally
        //    {
        //        bitmap.UnlockBits(bd);
        //    }
        //}

        public static IntPtr eyemStructArray2IntPtr<T>(T[] tpArray)
        {
            if (tpArray == null)
                throw new ArgumentNullException(typeof(T).Name.ToString());
            //分配结构体需要的内存,需要释放
            IntPtr hGlobal = Marshal.AllocHGlobal(checked(Marshal.SizeOf(typeof(T)) * tpArray.Length));
            for (int index = 0; index < tpArray.Length; index++)
            {
                Marshal.StructureToPtr(tpArray[index], (IntPtr)(checked((long)hGlobal + index * Marshal.SizeOf(typeof(T)))), false);
            }
            return hGlobal;
        }
        public static Bitmap eyemCvtToBitmap(EyemImage tpImage)
        {
            if (tpImage.vpImage == IntPtr.Zero || tpImage.iDepth != 0)
                return null;
            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.vpImage.ToPointer()) + offsetSrc, (byte*)(bd.Scan0.ToPointer()) + offsetDst, bytesToCopy, bytesToCopy);
                }
            }
            finally
            {
                bitmap.UnlockBits(bd);
            }
            return bitmap;
        }

    }
}