using System; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Diagnostics.Contracts; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using HalconDotNet; using System.Windows.Forms.VisualStyles; using LeatherApp.Utils; using Models; using OpenCvSharp; using OpenCvSharp.Extensions; using PG_Detect; using SqlSugar; using HZH_Controls; namespace LeatherApp.Device { public class DefectLib : IDisposable { //private const string dll_path = "yoloOrt.dll"; //[DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] //extern static IntPtr CreateDetector(string model_path, string labels_path, bool is_gpu, int numberThreads); private const string dll_path = "yolo_trt.dll"; [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] static extern IntPtr CreateDetector(string model_path); [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] extern static bool DestroyDetector(IntPtr detector); /// /// 非0值表示成功,0表示失败 返回小图张数 /// /// /// [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] static extern int GetBatchSize(IntPtr detector); //[DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] //extern static bool Detect1(IntPtr detector, ref byte bgrs_data, // int image_num, int width, int height, int channels, // float conf_threshold, float iou_threshold, // ref int output, int output_size, ref int object_num); [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] static extern bool Detect(IntPtr detector, ref byte bgrs_data, int image_num, int width, int height, int channels, float conf_threshold, float iou_threshold, ref float output, int output_size, ref int object_num, int expand_pixel); //----- //private const string dll_path = "yolo_trt .dll"; //[DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] //static extern IntPtr CreateDetector(string model_path); //[DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] //static extern bool DestroyDetector(IntPtr detector); //[DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)] //static extern bool Detect(IntPtr detector, ref byte bgrs_data, // int image_num, int width, int height, int channels, // float conf_threshold, float iou_threshold, // ref int output, int output_size, ref int object_num); //--- private IntPtr detector = IntPtr.Zero; private readonly int image_width = 2048; private readonly int image_hight = 2048; private readonly int image_channels = 3; private readonly int image_bytes = 2048 * 2048 * 3; private readonly int detect_elem_size = 7; //维度数据结果,x y w h conf classid private readonly int detect_max_object_num = 20;//这个指的是一张子图可能最多给你返回的目标个球 // public Action QueueCountEvent;//0/1/2, 数量 public Action WarningEvent; /// /// 检测结果JSON(原图,结果) /// public Action finishEvent; /// /// 是否打开设备成功 /// public bool IsInit { get; private set; } = false; string rootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); private Thread t_task, t_task_operation ,t_task_maketag; //=======task list private List taskList = new List(); private List taskOperationList = new List(); private List taskMakeTagList = new List(); private string preModelName = ""; //传统算法核心 private PGDetect tPGDetect = new PGDetect(); public DefectLib() { } public bool start() { try { //detector = CreateDetector(Config.model_path, Config.labels_path, true, 6); //if (detector == IntPtr.Zero) // throw new Exception("模型初始化失败!"); preModelName = ""; IsInit = true; taskList.Clear(); taskOperationList.Clear(); taskMakeTagList.Clear(); t_task = new System.Threading.Thread(runStep); t_task.IsBackground = true; t_task.Start(); t_task_operation = new System.Threading.Thread(run2); t_task_operation.IsBackground = true; t_task_operation.Start(); t_task_maketag = new System.Threading.Thread(run3); t_task_maketag.IsBackground = true; t_task_maketag.Start(); return true; } catch (Exception ex) { WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, ex.Message); return false; } } public void stop() { if (!IsInit) return; try { IsInit = false; //timer.Elapsed -= Timer_Elapsed; preModelName = ""; //释放模型 if (detector != IntPtr.Zero) { DestroyDetector(detector); detector = IntPtr.Zero; } if (t_task != null) { bool b = t_task.Join(5000); if (!b) t_task.Abort(); t_task = null; } if (t_task_operation != null) { bool b = t_task_operation.Join(5000); if (!b) t_task_operation.Abort(); t_task_operation = null; } if (t_task_maketag != null) { bool b = t_task_maketag.Join(5000); if (!b) t_task_maketag.Abort(); t_task_maketag = null; } taskList.Clear(); taskOperationList.Clear(); taskMakeTagList.Clear(); } catch { } } /// /// /// /// 多个相机图像总宽(外部去除重合部分) /// public int GetWidthForResize(int sumWidth) { int count =(int) Math.Round(sumWidth * 1.0f / image_width, 0); count = 8; return count * image_width; //int count = sumWidth / image_width; ////int remainder = sumWidth % image_width; //if (count % 2 == 0) // return count * image_width; //else // return count * image_width+ image_width; } /// /// 保存图片 /// /// 图片 /// 保存路径 /// 保存名称 private void SaveImage(Bitmap Img, string pictureUrl, string pictureName) { if (!Directory.Exists(pictureUrl)) { Directory.CreateDirectory(pictureUrl); } FileInfo FileUrl = new FileInfo(pictureUrl);//防止路径中有日期导致路径错误 try { using (Bitmap bitmap = new Bitmap(Img)) { using (MemoryStream stream = new MemoryStream()) { bitmap.Save(stream, ImageFormat.Bmp); System.Drawing.Image img = System.Drawing.Image.FromStream(stream); //img.Save(FileUrl +"\\"+ pictureName); //img.Dispose(); string szURL = FileUrl + "\\" + pictureName; img.Save(szURL, ImageFormat.Bmp); img.Dispose(); } } } catch (Exception) { if (Img != null) { Img.Dispose(); } } } public bool LoadModel(string modelPath) { int step = 0; try { if (!Config.OpenHalconDefect) { if (preModelName != modelPath) { //WarningEvent?.Invoke(DateTime.Now, WarningEnum.Normal, $"模型加载({modelPath})" ); step = 3; //先释放模型 if (detector != IntPtr.Zero) { step = 4; DestroyDetector(detector); detector = IntPtr.Zero; } step = 5; detector = CreateDetector($"./models/{modelPath}"); if (detector == IntPtr.Zero) throw new Exception($"模型({modelPath})初始化失败!"); step = 6; preModelName = modelPath; } } else { HObject obj = new HObject(); Mat mat = new Mat($"./init.bmp"); OpenCVUtil.MatToHObject(mat, out obj); //HOperatorSet.GenImageConst(out obj, "byte", 2048 * 8, 2048 * 2);//生成一幅图像,用byte格式,默认是黑色 //Mat initMat = new Mat(2048 * 2, 2048 * 8, MatType.CV_8UC3); if (!tPGDetect.IniOptimization(obj, Config.HalconParamPath)) throw new Exception($"传统算法({Config.HalconParamPath})初始化失败!"); } return true; } catch (Exception e) { WarningEvent?.Invoke(DateTime.Now, WarningEnum.Low, $"Load Model err({step}):" + e.Message); return false; } } private void runStep() { int step = 0; while (IsInit) { if (taskList.Count < 1) { Thread.Sleep(20); continue; } // step = 1; var task = pop(); try { if (task != null) { Stopwatch stopwatch = Stopwatch.StartNew(); step =2; LoadModel(task.modelName); //源图 //Bitmap bmp = yolo1.Read2Bmp(file_path); //切割图像,输入图像格式14208*10640 stopwatch.Start(); if (!Config.OpenHalconDefect) { //task.resizeBmp = OpenCVUtil.resize( task.bmp.Clone(), task.resize.Width, task.resize.Height);//在外面已做了resize //Cv2.CvtColor(task.bmp, task.bmpBgr2rgb, ColorConversionCodes.BGR2RGB); //task.bmps_cut = OpenCVToCutsMat(task.bmpBgr2rgb, image_width, image_hight); //这里cut时之前加的clone step = 7; task.bmps_cut = OpenCVToCutsMat(task.bmp, image_width, image_hight); //这里cut时之前加的clone stopwatch.Stop(); task.stopwatch[0] = stopwatch.ElapsedMilliseconds; //Resize图像 //stopwatch.Restart(); //task.bmps_resize = yolo1.OpenCVToResizesMat(task.bmps_cut, task.resize.Width, task.resize.Height); //stopwatch.Stop(); //task.stopwatch[1] = stopwatch.ElapsedMilliseconds; //预处理模型 //stopwatch.Restart(); //task.tensors = yolo1.PreprocessImageMat(task.bmps_resize); //stopwatch.Stop(); //task.stopwatch[2] = stopwatch.ElapsedMilliseconds; step = 8; lock (taskOperationList) { taskOperationList.Add(task); QueueCountEvent?.BeginInvoke(1, taskOperationList.Count, null, null); } step = 9; } else { step = 20; int object_num = 0; //转换 OpenCVUtil.MatToHObject(task.bmp, out task.ho_Img); stopwatch.Stop(); task.stopwatch[0] = stopwatch.ElapsedMilliseconds; stopwatch.Restart(); step = 21; //预处理 tPGDetect.Processing(task.ho_Img, out task.ho_imgG, out task.ho_ImageResult3, out task.ho_ImageSub, Config.HalconParamPath, out task.hv_RES, out task.hv_gauss_filter1, out task.hv_gauss_filter2, out task.hv_Energy_value, out task.hv_Region_S_value, out task.hv_AreaThr, out task.hv_class); stopwatch.Stop(); task.stopwatch[1] = stopwatch.ElapsedMilliseconds; lock (taskOperationList) { taskOperationList.Add(task); QueueCountEvent?.BeginInvoke(1, taskOperationList.Count, null, null); } } } } catch (Exception ex) { WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"DefectLib task1 err({step}):" + ex.Message); task.isSucceed = false; task.resultInfo = ex.Message; callback(task); } Thread.Sleep(5); } } //推理 private void run2() { QualifiedLimit qualifiedLimit; while (IsInit) { if (taskOperationList.Count < 1) { Thread.Sleep(20); continue; } // var task = pop2(); int cut_count=0,step = 0; try { if (task != null && !Config.OpenHalconDefect && task.bmps_cut.Count()>0 ) { //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, "DefectLib tasks 运行推理..."); cut_count = task.bmps_cut.Count(); Stopwatch stopwatch = Stopwatch.StartNew(); //====推理(必需单队列) stopwatch.Start(); // 把数据转为byte数组,【h, w, c】的bgr格式,第一张在前,第二张在后 byte[] imgData = new byte[image_bytes * cut_count]; for (int i = 0; i < cut_count; i++) Marshal.Copy(task.bmps_cut[i].Data, imgData, image_bytes * i, image_bytes); step = 1; stopwatch.Stop(); task.stopwatch[1] = stopwatch.ElapsedMilliseconds; stopwatch.Restart(); task.output = new float[cut_count * detect_elem_size * detect_max_object_num]; task.output_num = new int[cut_count]; //执行推理 step =2; bool ok = Detect(detector, ref imgData[0], cut_count, image_width, image_hight, image_channels, 0.25f, 0.45f, ref task.output[0], task.output.Length, ref task.output_num[0],Config.expand_pixel); //bool ok = Detect(_detector, ref imgData[0], imgs.Count, ImageWidth, image_hight, image_channels, // 0.25f, 0.45f, ref output[0], output.Length, ref output_num[0]); step = 3; stopwatch.Stop(); task.stopwatch[2] = stopwatch.ElapsedMilliseconds; //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"DefectLib tasks 结果推理={ok}"); for (int i = 0; i < cut_count; i++) task.bmps_cut[i].Dispose(); if (ok == false) throw new Exception($"推理失败或者输入数组太小({cut_count})"); // lock (taskMakeTagList) { taskMakeTagList.Add(task); QueueCountEvent?.BeginInvoke(2, taskMakeTagList.Count, null, null); } } else { Stopwatch stopwatch = Stopwatch.StartNew(); stopwatch.Start(); step = 22; //算法处理 tPGDetect.Detect(task.ho_Img, task.ho_imgG, task.ho_ImageResult3, task.ho_ImageSub, task.hv_Energy_value, task.hv_Region_S_value, task.hv_AreaThr, task.hv_class, out task.hv_defectinfo, out task.object_num); stopwatch.Stop(); task.stopwatch[2] = stopwatch.ElapsedMilliseconds; lock (taskMakeTagList) { taskMakeTagList.Add(task); QueueCountEvent?.BeginInvoke(2, taskMakeTagList.Count, null, null); } } } catch (Exception ex) { WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"DefectLib task2 err({step}):({cut_count}){ ex.Message}"); task.isSucceed = false; task.resultInfo = ex.Message; callback(task); } Thread.Sleep(5); } } private class DefectLabelInfo { public int x { get; set; } public int y { get; set; } public int w { get; set; } public int h { get; set; } public int classId { get; set; } public double confidence { get; set; } //置信度 public double contrast { get; set; }//对比度 public double cmW { get; set; } public double cmH { get; set; } public int i { get; set; }//小图index public int j { get; set; }//缺陷index } private double ContrastLow = 0.8; private double ContrastTop = 1.2; //private double ContrastToPercent(double val) //{ // if (val < ContrastLow) // return 0; // else if (val > ContrastTop) // return 100; // double temp = 100 / (ContrastTop - ContrastLow); // return temp * (val - ContrastLow); //} //private double PercentToContrast(double val) //{ // double temp = val * (ContrastTop - ContrastLow); // return temp + ContrastLow; //} private double ContrastToPercent(double val) { if (val < ContrastLow) return 0; else if (val > ContrastTop) return 100; double temp = 100 / (ContrastTop - ContrastLow); return Math.Round(temp * (val - ContrastLow), 2); } private double PercentToContrast(double val) { double tt = 1; if (val > 100) tt = 100; else if (val < 0) tt = 0; else tt = val; double temp = tt / 100 * (ContrastTop - ContrastLow); return temp + ContrastLow; } private List HeBingDefect(string modelName, int Width, List DefectLabelInfoList) { List outList = new List(); List HeBingList = new List(); List XcHeBingList = new List(); List xPos = new List(); List yPos = new List(); List ZXD = new List(); List HeBingList2 = new List(); List XcHeBingList2 = new List(); List xPos2 = new List(); List yPos2 = new List(); List ZXD2 = new List(); List HeBingList3 = new List(); List XcHeBingList3 = new List(); List xPos3 = new List(); List yPos3 = new List(); List ZXD3 = new List(); List HeBingList4 = new List(); List XcHeBingList4 = new List(); List xPos4 = new List(); List yPos4 = new List(); List ZXD4 = new List(); List HeBingList5 = new List(); List XcHeBingList5 = new List(); List xPos5 = new List(); List yPos5 = new List(); List ZXD5 = new List(); List HeBingList6 = new List(); List XcHeBingList6 = new List(); List xPos6 = new List(); List yPos6 = new List(); List ZXD6 = new List(); DefectLabelInfo stpoint = DefectLabelInfoList[0]; int colNum = Width / image_width; //寻找在一条线上 for (int q = 0; q < DefectLabelInfoList.Count; q++) { if (Config.getDefectCode(modelName, DefectLabelInfoList[q].classId) == "jietou") { int max = stpoint.y + 2000; int min = stpoint.y - 2000 > 0? stpoint.y - 2000 : 0; if (DefectLabelInfoList[q].y >= min && DefectLabelInfoList[q].y <= max) { HeBingList.Add(DefectLabelInfoList[q]); xPos.Add((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x); yPos.Add((DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y); ZXD.Add(DefectLabelInfoList[q].confidence); } else XcHeBingList.Add(DefectLabelInfoList[q]); } else if (Config.getDefectCode(modelName, DefectLabelInfoList[q].classId) == "hengdang") { int max = stpoint.y + 2000; int min = stpoint.y - 2000 > 0 ? stpoint.y - 2000 : 0; if (DefectLabelInfoList[q].y >= min && DefectLabelInfoList[q].y <= max) { HeBingList2.Add(DefectLabelInfoList[q]); xPos2.Add((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x); yPos2.Add((DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y); ZXD2.Add(DefectLabelInfoList[q].confidence); } else XcHeBingList2.Add(DefectLabelInfoList[q]); } else if (Config.getDefectCode(modelName, DefectLabelInfoList[q].classId) == "jt") { int max = stpoint.y + 2000; int min = stpoint.y - 2000 > 0 ? stpoint.y - 2000 : 0; if (DefectLabelInfoList[q].y >= min && DefectLabelInfoList[q].y <= max) { HeBingList3.Add(DefectLabelInfoList[q]); xPos3.Add((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x); yPos3.Add((DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y); ZXD3.Add(DefectLabelInfoList[q].confidence); } else XcHeBingList3.Add(DefectLabelInfoList[q]); } else if (Config.getDefectCode(modelName, DefectLabelInfoList[q].classId) == "tcy") { int max = stpoint.y + 2000; int min = stpoint.y - 2000 > 0 ? stpoint.y - 2000 : 0; if (DefectLabelInfoList[q].y >= min && DefectLabelInfoList[q].y <= max) { HeBingList4.Add(DefectLabelInfoList[q]); xPos4.Add((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x); yPos4.Add((DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y); ZXD4.Add(DefectLabelInfoList[q].confidence); } else XcHeBingList4.Add(DefectLabelInfoList[q]); } else if (Config.getDefectCode(modelName, DefectLabelInfoList[q].classId) == "zj") { int max = stpoint.y + 2000; int min = stpoint.y - 2000 > 0 ? stpoint.y - 2000 : 0; if (DefectLabelInfoList[q].y >= min && DefectLabelInfoList[q].y <= max) { HeBingList5.Add(DefectLabelInfoList[q]); xPos5.Add((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x); yPos5.Add((DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y); ZXD5.Add(DefectLabelInfoList[q].confidence); } else XcHeBingList5.Add(DefectLabelInfoList[q]); } else if (Config.getDefectCode(modelName, DefectLabelInfoList[q].classId) == "bj") { int max = stpoint.y + 2000; int min = stpoint.y - 2000 > 0 ? stpoint.y - 2000 : 0; if (DefectLabelInfoList[q].y >= min && DefectLabelInfoList[q].y <= max) { HeBingList6.Add(DefectLabelInfoList[q]); xPos6.Add((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x); yPos6.Add((DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y); ZXD6.Add(DefectLabelInfoList[q].confidence); } else XcHeBingList6.Add(DefectLabelInfoList[q]); } else outList.Add(DefectLabelInfoList[q]); } //递归下次合并数据 List dg1 = new List(); List dg2 = new List(); List dg3 = new List(); List dg4 = new List(); List dg5 = new List(); List dg6 = new List(); if (XcHeBingList.Count >0) dg1 = HeBingDefect(modelName, Width, XcHeBingList); if (XcHeBingList2.Count > 0) dg2 = HeBingDefect(modelName, Width, XcHeBingList2); if (XcHeBingList3.Count > 0) dg3 = HeBingDefect(modelName, Width, XcHeBingList3); if (XcHeBingList4.Count > 0) dg4 = HeBingDefect(modelName, Width, XcHeBingList4); if (XcHeBingList5.Count > 0) dg5 = HeBingDefect(modelName, Width, XcHeBingList5); if (XcHeBingList6.Count > 0) dg6 = HeBingDefect(modelName, Width, XcHeBingList6); //多个jietou合并 if (HeBingList.Count>0) { var stIt = HeBingList.Find(x => (x.i % colNum) * image_width + x.x == xPos.Min()); var edIt = HeBingList.Find(x => (x.i % colNum) * image_width + x.x == xPos.Max()); var stIty = HeBingList.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos.Min()); var edIty = HeBingList.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos.Max()); var eZXD = HeBingList.Find(x => x.confidence == ZXD.Max()); int newW = Math.Abs(((edIt.i % colNum) * image_width + edIt.x) - ((stIt.i % colNum) * image_width + stIt.x)) + edIt.w; int newh = Math.Abs(((edIt.i / colNum) * image_hight + edIt.y) - ((stIt.i / colNum) * image_hight + stIt.y)) + edIt.h; outList.Add(new DefectLabelInfo() { x=stIt.x, y= edIty.y, w = newW, //多图叠加 h = newh, classId = eZXD.classId, confidence = eZXD.confidence, contrast = eZXD.contrast, cmH = Math.Round(edIt.h * 1.0 / Config.cm2px_y, 2), cmW = Math.Round(newW * 1.0 / Config.cm2px_x, 2), i = stIt.i, j = stIt.j, }); } //多个hengdang合并 if (HeBingList2.Count > 0) { var stIt = HeBingList2.Find(x => (x.i % colNum) * image_width + x.x == xPos2.Min()); var edIt = HeBingList2.Find(x => (x.i % colNum) * image_width + x.x == xPos2.Max()); var stIty = HeBingList2.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos2.Min()); var edIty = HeBingList2.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos2.Max()); var eZXD = HeBingList2.Find(x => x.confidence == ZXD2.Max()); int newW = Math.Abs(((edIt.i % colNum) * image_width + edIt.x) - ((stIt.i % colNum) * image_width + stIt.x)) + edIt.w; int newh = Math.Abs(((edIt.i / colNum) * image_hight + edIt.y) - ((stIt.i / colNum) * image_hight + stIt.y)) + edIt.h; outList.Add(new DefectLabelInfo() { x = stIt.x, y = edIty.y, w = newW, //多图叠加 h = newh, classId = eZXD.classId, confidence = eZXD.confidence, contrast = eZXD.contrast, cmH = Math.Round(edIt.h * 1.0 / Config.cm2px_y, 2), cmW = Math.Round(newW * 1.0 / Config.cm2px_x, 2), i = stIt.i, j = stIt.j, }); } //多个jt合并 if (HeBingList3.Count > 0) { var stIt = HeBingList3.Find(x => (x.i % colNum) * image_width + x.x == xPos3.Min()); var edIt = HeBingList3.Find(x => (x.i % colNum) * image_width + x.x == xPos3.Max()); var stIty = HeBingList3.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos3.Min()); var edIty = HeBingList3.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos3.Max()); var eZXD = HeBingList3.Find(x => x.confidence == ZXD3.Max()); int newW = Math.Abs(((edIt.i % colNum) * image_width + edIt.x) - ((stIt.i % colNum) * image_width + stIt.x)) + edIt.w; int newh = Math.Abs(((edIt.i / colNum) * image_hight + edIt.y) - ((stIt.i / colNum) * image_hight + stIt.y)) + edIt.h; outList.Add(new DefectLabelInfo() { x = stIt.x, y = edIty.y, w = newW, //多图叠加 h = newh, classId = eZXD.classId, confidence = eZXD.confidence, contrast = eZXD.contrast, cmH = Math.Round(edIt.h * 1.0 / Config.cm2px_y, 2), cmW = Math.Round(newW * 1.0 / Config.cm2px_x, 2), i = stIt.i, j = stIt.j, }); } //多个tcy合并 if (HeBingList4.Count > 0) { var stIt = HeBingList4.Find(x => (x.i % colNum) * image_width + x.x == xPos4.Min()); var edIt = HeBingList4.Find(x => (x.i % colNum) * image_width + x.x == xPos4.Max()); var stIty = HeBingList4.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos4.Min()); var edIty = HeBingList4.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos4.Max()); var eZXD = HeBingList4.Find(x => x.confidence == ZXD4.Max()); int newW = Math.Abs(((edIt.i % colNum) * image_width + edIt.x) - ((stIt.i % colNum) * image_width + stIt.x)) + edIt.w; int newh = Math.Abs(((edIt.i / colNum) * image_hight + edIt.y) - ((stIt.i / colNum) * image_hight + stIt.y)) + edIt.h; outList.Add(new DefectLabelInfo() { x = stIt.x, y = edIty.y, w = newW, //多图叠加 h = newh, classId = eZXD.classId, confidence = eZXD.confidence, contrast = eZXD.contrast, cmH = Math.Round(edIt.h * 1.0 / Config.cm2px_y, 2), cmW = Math.Round(newW * 1.0 / Config.cm2px_x, 2), i = stIt.i, j = stIt.j, }); } //多个zj合并 if (HeBingList5.Count > 0) { var stIt = HeBingList5.Find(x => (x.i % colNum) * image_width + x.x == xPos5.Min()); var edIt = HeBingList5.Find(x => (x.i % colNum) * image_width + x.x == xPos5.Max()); var stIty = HeBingList5.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos5.Min()); var edIty = HeBingList5.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos5.Max()); var eZXD = HeBingList5.Find(x => x.confidence == ZXD5.Max()); int newW = Math.Abs(((edIt.i % colNum) * image_width + edIt.x) - ((stIt.i % colNum) * image_width + stIt.x)) + edIt.w; int newh = Math.Abs(((edIt.i / colNum) * image_hight + edIt.y) - ((stIt.i / colNum) * image_hight + stIt.y)) + edIt.h; outList.Add(new DefectLabelInfo() { x = stIt.x, y = edIty.y, w = newW, //多图叠加 h = newh, classId = eZXD.classId, confidence = eZXD.confidence, contrast = eZXD.contrast, cmH = Math.Round(edIt.h * 1.0 / Config.cm2px_y, 2), cmW = Math.Round(newW * 1.0 / Config.cm2px_x, 2), i = stIt.i, j = stIt.j, }); } //多个bj合并 if (HeBingList6.Count > 0) { var stIt = HeBingList6.Find(x => (x.i % colNum) * image_width + x.x == xPos6.Min()); var edIt = HeBingList6.Find(x => (x.i % colNum) * image_width + x.x == xPos6.Max()); var stIty = HeBingList6.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos6.Min()); var edIty = HeBingList6.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos6.Max()); var eZXD = HeBingList6.Find(x => x.confidence == ZXD6.Max()); int newW = Math.Abs(((edIt.i % colNum) * image_width + edIt.x) - ((stIt.i % colNum) * image_width + stIt.x)) + edIt.w; int newh = Math.Abs(((edIt.i / colNum) * image_hight + edIt.y) - ((stIt.i / colNum) * image_hight + stIt.y)) + edIt.h; outList.Add(new DefectLabelInfo() { x = stIt.x, y = edIty.y, w = newW, //多图叠加 h = newh, classId = eZXD.classId, confidence = eZXD.confidence, contrast = eZXD.contrast, cmH = Math.Round(edIt.h * 1.0 / Config.cm2px_y, 2), cmW = Math.Round(newW * 1.0 / Config.cm2px_x, 2), i = stIt.i, j = stIt.j, }); } outList = outList.Concat(dg1).ToList();//保留重复项 outList = outList.Concat(dg2).ToList();//保留重复项 outList = outList.Concat(dg3).ToList();//保留重复项 outList = outList.Concat(dg4).ToList();//保留重复项 outList = outList.Concat(dg5).ToList();//保留重复项 outList = outList.Concat(dg6).ToList();//保留重复项 return outList; } //打标 private void run3() { QualifiedLimit qualifiedLimit; while (IsInit) { if (taskMakeTagList.Count < 1) { Thread.Sleep(20); continue; } // var task = pop3(); int liStep = 0; try { Stopwatch stopwatch = Stopwatch.StartNew(); stopwatch.Restart(); int colNum = task.bmp.Width / image_width; int rowNum = task.bmp.Height / image_hight; int count = 0; liStep = 3; if (!Config.OpenHalconDefect) { int cut_count = task.bmps_cut.Count();//上面bmps_cut已销毁 //车用革去除接头处横档误判 bool haveJieTou = false; List DefectLabelInfoList = new List(); for (int i = 0; i < cut_count; i++) { liStep = i * 100; //task.resultInfo += $"第 {i}/{cut_count} 张小图(大图索引{task.photoIndex}): 缺陷数 = {task.output_num[i]}\n"; //task.resultInfo +=$"大图({task.tag})[{task.bmp.Width}*{task.bmp.Height}],第 {i + 1}/{cut_count} 张小图[{task.bmps_cut[i].Width}*{task.bmps_cut[i].Height}]: 瑕疵output_num = {output_num[i]}\n"; #region 检测信息汇总 for (int j = 0; j < task.output_num[i]; j++)//缺陷数 { liStep += j;//0 //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"-------"); int index = count * detect_elem_size; // 打印输出信息(示例代码,根据实际情况进行修改和格式化) // 获取输出信息 int x = (int)task.output[index]; int y = (int)task.output[index + 1]; int w = (int)task.output[index + 2]; int h = (int)task.output[index + 3]; int classId = (int)task.output[index + 4]; double confidence = Math.Round(task.output[index + 5], 2); //置信度 double contrast = Math.Round(task.output[index + 6], 3);//对比度 //y = image_hight-y-h;//转到右下角为原点 count++; //var cmW = Math.Round(w * task.widthRatio / Config.cm2px_x, 2); //var cmH = Math.Round(h * task.widthRatio / Config.cm2px_y, 2); var cmW = Math.Round(w * 1.0 / Config.cm2px_x, 2); var cmH = Math.Round(h * 1.0 / Config.cm2px_y, 2); // 打印输出信息 //task.resultInfo += $"----{i}----col:{i % colNum}/{colNum} row:{i / colNum}/{colNum}-----------\n目标:{j + 1} 类别ID:{classId} 置信度:{confidence} 对比度:{contrast} 坐标:({x},{y})-({x + w},{y + h}) 宽高:w={w},h={h}; \n"; DefectLabelInfoList.Add(new DefectLabelInfo() { x = (int)task.output[index], y = (int)task.output[index + 1], w = (int)task.output[index + 2], h = (int)task.output[index + 3], classId = (int)task.output[index + 4], confidence = Math.Round(task.output[index + 5], 2), //置信度 contrast = ContrastToPercent(Math.Round(task.output[index + 6], 3)),//对比度 //cmW = Math.Round(w * task.widthRatio / Config.cm2px_x, 2), //cmH = Math.Round(h * task.widthRatio / Config.cm2px_y, 2), cmW = Math.Round(w * 1.0 / Config.cm2px_x, 2), cmH = Math.Round(h * 1.0 / Config.cm2px_y, 2), i = i, j = j, }); } #endregion #if false for (int j = 0; j < task.output_num[i]; j++)//缺陷数 { liStep += j;//0 //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"-------"); int index = count * detect_elem_size; // 打印输出信息(示例代码,根据实际情况进行修改和格式化) // 获取输出信息 int x = (int)task.output[index]; int y = (int)task.output[index + 1]; int w = (int)task.output[index + 2]; int h = (int)task.output[index + 3]; int classId = (int)task.output[index + 4]; double confidence = Math.Round(task.output[index + 5],2); //置信度 double contrast = Math.Round(task.output[index + 6], 3);//对比度 //y = image_hight-y-h;//转到右下角为原点 count++; var cmW = Math.Round(w * task.widthRatio / Config.cm2px_x, 2); var cmH = Math.Round(h * task.widthRatio / Config.cm2px_y, 2); // 打印输出信息 task.resultInfo += $"----{i}----col:{i % colNum}/{colNum} row:{i / colNum}/{colNum}-----------\n目标:{j + 1} 类别ID:{classId} 置信度:{confidence} 对比度:{contrast} 坐标:({x},{y})-({x + w},{y + h}) 宽高:w={w},h={h}; \n"; //是否满足此产品标准 if (task.qualifiedLimitList != null && task.qualifiedLimitList.Count > 0) { qualifiedLimit = task.qualifiedLimitList.FirstOrDefault(m => m.Code == Config.getDefectCode(classId)); if (qualifiedLimit != null) { //if ((qualifiedLimit.ZXD > 0 && qualifiedLimit.ZXD > confidence) // || (qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower > 0 && x> qualifiedLimit.ContrastLower && x < qualifiedLimit.ContrastTop) // || (qualifiedLimit.Area > 0 && qualifiedLimit.Area > cmW * cmH)) if (confidence <= qualifiedLimit.ZXD)//confidence > qualifiedLimit.ZXD 是瑕疵 才继续判断下面的两个条件 { task.resultInfo += $" 置信度不满足此产品瑕疵标准,跳过! \n"; continue; } //下限<对比度<上限:不是瑕疵 var ContrastTotal = qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower; if (qualifiedLimit.IsOR) { if (!( (qualifiedLimit.Area <= 0 || cmW * cmH >= qualifiedLimit.Area) || (ContrastTotal <= 0 || (contrast < qualifiedLimit.ContrastLower || contrast > qualifiedLimit.ContrastTop)))) { task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n"; //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])"); continue; } } else { if (!( (qualifiedLimit.Area<=0 || cmW * cmH >= qualifiedLimit.Area) && (ContrastTotal <=0 || (contrast < qualifiedLimit.ContrastLower || contrast > qualifiedLimit.ContrastTop)))) { task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n"; //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])"); continue; } } //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])"); } } liStep++;//1 //打标 var point1 = new OpenCvSharp.Point((i % colNum) * image_width + x, (i / colNum) * image_hight + y); var point2 = new OpenCvSharp.Point(point1.X + w, point1.Y + h); liStep++;//2 task.resultInfo += $" 转换到大图坐标(px):p1={point1.X},{point1.Y}; p2={point2.X},{point2.Y}\n"; Cv2.Rectangle(task.bmpTag, point1, point2, new Scalar(0.0, 0.0, 255.0), 1);//画打标点 //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 行缺陷信息;"); var cmX = Math.Round(point1.X * task.widthRatio / Config.cm2px_x, 2); var cmY = Math.Round((task.bmp.Height-point1.Y-h) * task.widthRatio / Config.cm2px_y, 2);//外面计Y从右下角为原点 liStep++;//3 task.resultInfo += $" 转换到大图坐标(cm)[widthRatio={task.widthRatio}]:x={cmX},y={cmY}; w={cmW},h={cmH}\n"; task.excelTable.Rows.Add($"{task.photoIndex}", cmX, cmY, cmW, cmH, j + 1, classId, confidence, contrast); liStep++;//4 //切缺陷小图 //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 个缺陷小图;"); int left, top, decX, decY; decX = (w > 236 ? 20 : 256 - w) / 2; decY = (h > 236 ? 20 : 256 - h) / 2; left = point1.X - decX; top = point1.Y - decY; if (left < 0) left = 0; if (top < 0) top = 0; int width = w + decX * 2; int height = h + decY * 2; if (left + width > task.bmp.Width - 1) width = task.bmp.Width - left - 1; if (top + height > task.bmp.Height - 1) height = task.bmp.Height - top - 1; liStep++;//5 Rect roi = new Rect(left, top, width, height); liStep++;//6 if (height < 1 || width < 1) { task.resultInfo += $" 打标到大图坐标Rect(px):left={left},top={top}; width={width},height={height}\n"; task.resultInfo += $" test point1.Y={point1.Y},h={h}; top={top},mat.Height={ task.bmp.Height}\n================\n"; WarningEvent?.Invoke(DateTime.Now,WarningEnum.Normal, task.resultInfo); } //保存 //string filename = $"{Config.appBasePath}\\temp\\{task.tag}\\{task.tag}_X{mmX.ToString()}_Y{mmY.ToString()}_W{mmW.ToString()}_H{mmH.ToString()}_目标{j + 1}_类别{classId}_置信度{confidence}.bmp"; //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(new Mat(task.bmp, roi)).Save(filename, ImageFormat.Jpeg); task.lstDefectBmp.Add(new Mat(task.bmpTag, roi).Clone()); liStep++;//7 //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"缺陷小图数量:{task.lstDefectBmp.Count}"); } #endif } #region 合并接头横档 liStep = 3000; if (DefectLabelInfoList.Count > 0) DefectLabelInfoList = HeBingDefect(task.modelName, task.bmp.Width, DefectLabelInfoList); liStep++; #endregion //结果过滤 #region 结果过滤 //降序排序,先得到是否有接头检出 List DefectLabelInfoListByDefect = new List(); List DefectLabelInfoListByClassID = DefectLabelInfoList.OrderByDescending(t => t.classId).ToList();//降序 for (int q = 0; q < DefectLabelInfoListByClassID.Count; q++) { //是否满足此产品标准 if (task.qualifiedLimitList != null && task.qualifiedLimitList.Count > 0) { qualifiedLimit = task.qualifiedLimitList.FirstOrDefault(m => m.Code == Config.getDefectCode(task.modelName, DefectLabelInfoListByClassID[q].classId)); if (qualifiedLimit != null) { // 打印输出信息 task.resultInfo += $"----{DefectLabelInfoListByClassID[q].i}----col:{DefectLabelInfoListByClassID[q].i % colNum}/{colNum} row:{DefectLabelInfoListByClassID[q].i / colNum}/{colNum}-----------\n目标:{DefectLabelInfoListByClassID[q].j + 1} 类别ID:{DefectLabelInfoListByClassID[q].classId} 置信度:{DefectLabelInfoListByClassID[q].confidence} 对比度:{DefectLabelInfoListByClassID[q].contrast}\n"; //if ((qualifiedLimit.ZXD > 0 && qualifiedLimit.ZXD > confidence) // || (qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower > 0 && x> qualifiedLimit.ContrastLower && x < qualifiedLimit.ContrastTop) // || (qualifiedLimit.Area > 0 && qualifiedLimit.Area > cmW * cmH)) if (DefectLabelInfoListByClassID[q].confidence <= qualifiedLimit.ZXD)//confidence > qualifiedLimit.ZXD 是瑕疵 才继续判断下面的两个条件 { task.resultInfo += $" 置信度不满足此产品瑕疵标准,跳过! \n"; continue; } //下限<对比度<上限:不是瑕疵 var ContrastTotal = qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower; if (qualifiedLimit.IsOR) { //if (!( // (ContrastTotal <= 0 || (PercentToContrast(DefectLabelInfoListByClassID[q].contrast) < qualifiedLimit.ContrastLower || PercentToContrast(DefectLabelInfoListByClassID[q].contrast) > qualifiedLimit.ContrastTop)))) //{ // task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n"; // //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])"); // continue; //} } else { if (!(ContrastTotal <= 0 || (PercentToContrast(DefectLabelInfoListByClassID[q].contrast) < qualifiedLimit.ContrastLower || PercentToContrast(DefectLabelInfoListByClassID[q].contrast) > qualifiedLimit.ContrastTop))) { task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n"; //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])"); continue; } } if (qualifiedLimit.Area > 0 && DefectLabelInfoListByClassID[q].cmW * DefectLabelInfoListByClassID[q].cmH < qualifiedLimit.Area) { task.resultInfo += $" 不满足此产品瑕疵标准面积,跳过! \n"; continue; } if (Config.getDefectCode(task.modelName, DefectLabelInfoListByClassID[q].classId) == "jietou") haveJieTou = true; if (haveJieTou && (Config.getDefectCode(task.modelName, DefectLabelInfoListByClassID[q].classId) == "hengdang")) { task.resultInfo += $" 判断为接头处横档,跳过! \n"; continue; } if (Config.getDefectCode(task.modelName, DefectLabelInfoListByClassID[q].classId) == "na") { task.resultInfo += $" 判断为正向标签na,跳过! \n"; continue; } //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])"); } } //检测缺陷 DefectLabelInfoListByDefect.Add(DefectLabelInfoListByClassID[q]); liStep++;//1 } //y方向位置排序 List DefectLabelInfoListByYdis = DefectLabelInfoListByDefect.OrderByDescending(t => (t.i / colNum) * image_hight + t.y).ToList();//降序 for (int q = 0; q < DefectLabelInfoListByYdis.Count; q++) { //打标 int penLine = 50; int xx = (DefectLabelInfoListByYdis[q].i % colNum) * image_width + DefectLabelInfoListByYdis[q].x - 2 * penLine; int yy = (DefectLabelInfoListByYdis[q].i / colNum) * image_hight + DefectLabelInfoListByYdis[q].y - 2 * penLine; var point1 = new OpenCvSharp.Point(xx >0? xx:0, yy >0? yy:0); var point2 = new OpenCvSharp.Point(point1.X + DefectLabelInfoListByYdis[q].w + 4 * penLine, point1.Y + DefectLabelInfoListByYdis[q].h + 4 * penLine); liStep++;//2 //task.resultInfo += $" 转换到大图坐标(px):p1={point1.X},{point1.Y}; p2={point2.X},{point2.Y}\n"; Cv2.Rectangle(task.bmpTag, point1, point2, new Scalar(0.0, 0.0, 255.0), penLine);//画打标点 //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 行缺陷信息;"); int px = (point1.X - task.xw) > 0 ? (point1.X - task.xw) : 0; //var cmX = Math.Round(px * task.widthRatio / Config.cm2px_x, 2); var cmX = Math.Round((double)px / Config.cm2px_x, 2); //var cmY = Math.Round((task.bmp.Height - point1.Y - DefectLabelInfoListByClassID[q].h) * task.widthRatio / Config.cm2px_y, 2);//外面计Y从右下角为原点 var cmY = Math.Round((task.bmp.Height - point1.Y - DefectLabelInfoListByYdis[q].h) * 1.0 / Config.cm2px_y, 2);//外面计Y从右下角为原点 liStep++;//3 //task.resultInfo += $" 转换到大图坐标(cm)[widthRatio={task.widthRatio}]:x={cmX},y={cmY}; w={DefectLabelInfoList[q].cmW},h={DefectLabelInfoList[q].cmH}\n"; task.excelTable.Rows.Add($"{task.photoIndex}", cmX, cmY, DefectLabelInfoListByYdis[q].cmW, DefectLabelInfoListByYdis[q].cmH, DefectLabelInfoListByYdis[q].j + 1, DefectLabelInfoListByYdis[q].classId, DefectLabelInfoListByYdis[q].confidence, DefectLabelInfoListByYdis[q].contrast); liStep++;//4 //切缺陷小图 //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 个缺陷小图;"); int left, top, decX, decY; decX = ((DefectLabelInfoListByYdis[q].w + 4 * penLine) > 236 ? 20 : (256 - DefectLabelInfoListByYdis[q].w - 4 * penLine)) / 2; decY = ((DefectLabelInfoListByYdis[q].h + 4 * penLine) > 236 ? 20 : (256 - DefectLabelInfoListByYdis[q].h - 4 * penLine)) / 2; //left = point1.X - decX; //top = point1.Y - decY; left = point1.X - 20; top = point1.Y - 20; if (left < 0) left = 0; if (top < 0) top = 0; //int width = DefectLabelInfoListByClassID[q].w + decX * 2; //int height = DefectLabelInfoListByClassID[q].h + decY * 2; int width = point2.X - point1.X + 20 * 2; int height = point2.Y - point1.Y + 20 * 2; if (left + width > task.bmp.Width - 1) width = task.bmp.Width - left - 1; if (top + height > task.bmp.Height - 1) height = task.bmp.Height - top - 1; liStep++;//5 Rect roi = new Rect(left, top, width, height); liStep++;//6 if (height < 1 || width < 1) { //task.resultInfo += $" 打标到大图坐标Rect(px):left={left},top={top}; width={width},height={height}\n"; //task.resultInfo += $" test point1.Y={point1.Y},h={DefectLabelInfoList[q].h}; top={top},mat.Height={task.bmp.Height}\n================\n"; WarningEvent?.Invoke(DateTime.Now, WarningEnum.Normal, task.resultInfo); } //保存 //string filename = $"{Config.appBasePath}\\temp\\{task.tag}\\{task.tag}_X{mmX.ToString()}_Y{mmY.ToString()}_W{mmW.ToString()}_H{mmH.ToString()}_目标{j + 1}_类别{classId}_置信度{confidence}.bmp"; //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(new Mat(task.bmp, roi)).Save(filename, ImageFormat.Jpeg); task.lstDefectBmp.Add(new Mat(task.bmpTag, roi).Clone()); liStep++;//7 } #endregion } else { stopwatch.Restart(); //打标 var defectinfo = task.hv_defectinfo.ToOArr(); List DefectLabelInfoList = new List(); for (int i = 0; i < task.object_num; i++) { liStep = 23 + i; #region 检测信息汇总 int index = i * 6; // 打印输出信息(示例代码,根据实际情况进行修改和格式化) // 获取输出信息 int x = (int)defectinfo[index].ToInt(); int y = (int)defectinfo[index + 1].ToInt(); int w = (int)defectinfo[index + 2].ToInt(); int h = (int)defectinfo[index + 3].ToInt(); int classId = -99;//(int)defectinfo[index + 4].ToInt(); double confidence = Math.Round(defectinfo[index + 5].ToDouble(), 2); //置信度 int px = (x - task.xw) > 0 ? (x - task.xw) : 0; ; var cmX = Math.Round(px * 1.0 / Config.cm2px_x, 2); var cmY = Math.Round((task.bmp.Height - y - h) * 1.0 / Config.cm2px_y, 2);//外面计Y从右下角为原点 DefectLabelInfoList.Add(new DefectLabelInfo() { x = x, y = y, w = w, h = h, classId = classId, confidence = confidence, //置信度 cmW = Math.Round(w * 1.0 / Config.cm2px_x, 2), cmH = Math.Round(h * 1.0 / Config.cm2px_y, 2), i = i, j = i, }); //y = image_hight-y-h;//转到右下角为原点 task.excelTable.Rows.Add($"{task.photoIndex}", cmX, cmY, Math.Round(w * 1.0 / Config.cm2px_x, 2), Math.Round(h * 1.0 / Config.cm2px_y, 2), i, classId, confidence, 0); int penLine = 20; //打标 int xx = x - 2 * penLine; int yy = y - 2 * penLine; var point1 = new OpenCvSharp.Point(xx >0? xx:0, yy >0?yy:0); var point2 = new OpenCvSharp.Point(point1.X + w + 4* penLine , point1.Y + h + 4 * penLine); Cv2.Rectangle(task.bmpTag, point1, point2, new Scalar(0.0, 0.0, 255.0), penLine);//画打标点 //切小图 int left, top, decX, decY; //int tdecX = (w / 2) / 2; //int tdecY = w / h > 4 ? w / 8 : (h / 1) / 2; //decX = (w > 236 ? tdecX : 256 - w) / 2; //decY = (h > 236 ? tdecY : 256 - h) / 2; //left = point1.X - decX; //top = point1.Y - decY; left = point1.X - 20; top = point1.Y - 20; if (left < 0) left = 0; if (top < 0) top = 0; //int width = w + decX * 2; //int height = h + decY * 2; int width = point2.X - point1.X + 20 * 2; int height = point2.Y - point1.Y + 20 * 2; if (left + width > task.bmp.Width - 1) width = task.bmp.Width - left - 1; if (top + height > task.bmp.Height - 1) height = task.bmp.Height - top - 1; Rect roi = new Rect(left, top, width, height); task.lstDefectBmp.Add(new Mat(task.bmpTag, roi).Clone()); #endregion } } liStep = 99; stopwatch.Stop(); task.stopwatch[3] = stopwatch.ElapsedMilliseconds; task.isSucceed = true; callback(task); } catch (Exception ex) { WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"DefectLib task3 err({liStep}):" + ex.Message); task.isSucceed = false; task.resultInfo = ex.Message; callback(task); } Thread.Sleep(5); } } private void callback(DefectTask task) { //返回成功/失败,异步调用 if (task.finishEvent != null || (task.finishEvent = finishEvent) != null) //task.finishEvent.BeginInvoke(result, errInfo, res => task.finishEvent.EndInvoke(res), null); System.Threading.ThreadPool.QueueUserWorkItem(waitCallback, task); } //异步回调 WaitCallback waitCallback = new WaitCallback(o => { var task = (DefectTask)o; task.finishEvent(task); }); /// /// 切割(先左右,后上下) /// /// /// /// /// private Mat[] OpenCVToCutsMat(Mat mat, int width, int height) { Mat[] array = new Mat[mat.Width / width * mat.Height / height]; int num = 0; for (int i = 0; i < mat.Height / height; i++) { for (int j = 0; j < mat.Width / width; j++) { int x = j * width; int y = i * height; System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(x, y, width, height); Rect roi = new Rect(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); array[num] = new Mat(mat, roi).Clone(); num++; } } return array; } public class DefectTask { public DefectTask() { // 创建一个 DataTable 对象来存储数据 excelTable = new DataTable("MyData"); // 添加列到 DataTable excelTable.Columns.Add("FileName", typeof(string)); excelTable.Columns.Add("X", typeof(decimal)); excelTable.Columns.Add("Y", typeof(decimal)); excelTable.Columns.Add("W", typeof(decimal)); excelTable.Columns.Add("H", typeof(decimal)); excelTable.Columns.Add("目标", typeof(int)); excelTable.Columns.Add("类别", typeof(int)); excelTable.Columns.Add("置信度", typeof(decimal)); excelTable.Columns.Add("对比度", typeof(decimal)); // 向 DataTable 中添加数据行 //excelTable.Rows.Add("John Doe", 30); //excelTable.Rows.Add("Jane Smith", 25); } /// /// 模型名字 /// public string modelName; public Models.Records record; //public string bmpPath;//源图路径(仅目录) /// /// 源图(resize后的) /// public Mat bmp; //public Mat bmpBgr2rgb=new Mat(); public System.Drawing.Size resize = new System.Drawing.Size(224, 224); //public Mat resizeBmp;//resize后 BGR2RGB图,只用于识别 public Mat bmpTag; /// /// 图片索引0-n /// public int photoIndex;//excel中对应的图像路径标识 public float widthRatio;//宽度比例,resize前/resize后 //切割后 public Mat[] bmps_cut; //用于比对参数 }//置信度 面积 对比度 public List qualifiedLimitList; //推理后结果用于打标 public float[] output; public int[] output_num; // /// /// 完成后回调 /// public Action finishEvent; //==结果返回 public bool isSucceed;//转换是否成功 public string resultInfo = "";//成功或失败信息 public List lstDefectBmp=new List(); /// /// fileIndex,x_mm,y_mm,w_mm,h_mm,目标,类别ID,置信度 /// public DataTable excelTable=new DataTable(); public long[] stopwatch = new long[4]; public int xw; //传统算法使用 public HObject ho_Img = new HObject(); public HObject ho_imgG = new HObject(); public HObject ho_ImageResult3 = new HObject(); public HObject ho_ImageSub = new HObject(); public HTuple hv_RES, hv_gauss_filter1, hv_gauss_filter2, hv_Energy_value, hv_Region_S_value, hv_AreaThr, hv_class, hv_defectinfo; public int object_num = 0; //图片位置 public double CurrDis; } public void add(DefectTask task) { lock (taskList) { taskList.Add(task); QueueCountEvent?.BeginInvoke(0, taskList.Count, null, null); } } private DefectTask pop() { lock (taskList) { if (taskList.Count < 1) return null; //int index = 0;// taskList.FindIndex(p => { return p.isSync; }); //if (index < 0) index = 0; var task = taskList[0]; taskList.RemoveAt(0); QueueCountEvent?.BeginInvoke(0, taskList.Count, null, null); return task; } } private DefectTask pop2() { lock (taskOperationList) { if (taskOperationList.Count < 1) return null; //int index = 0;// taskList.FindIndex(p => { return p.isSync; }); //if (index < 0) index = 0; var task = taskOperationList[0]; taskOperationList.RemoveAt(0); QueueCountEvent?.BeginInvoke(1, taskOperationList.Count, null, null); return task; } } private DefectTask pop3() { lock (taskMakeTagList) { if (taskMakeTagList.Count < 1) return null; //int index = 0;// taskList.FindIndex(p => { return p.isSync; }); //if (index < 0) index = 0; var task = taskMakeTagList[0]; taskMakeTagList.RemoveAt(0); QueueCountEvent?.BeginInvoke(2, taskMakeTagList.Count, null, null); return task; } } public void Dispose() { stop(); } } }