革博士V2程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1201 lines
61 KiB

  1. //#define Online_One
  2. using CCWin.Win32.Const;
  3. using DocumentFormat.OpenXml.Office2010.ExcelAc;
  4. using GeBoShi.SysCtrl;
  5. using HZH_Controls.Controls;
  6. using MaiMuControl.Device;
  7. using Models;
  8. using OpenCvSharp;
  9. using S7.Net.Types;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Data;
  13. using System.Diagnostics;
  14. using System.Linq;
  15. using System.Reflection;
  16. using System.Runtime.InteropServices;
  17. using System.Text;
  18. using System.Threading;
  19. using System.Threading.Tasks;
  20. using static System.ComponentModel.Design.ObjectSelectorEditor;
  21. namespace GeBoShi.ImageDefect
  22. {
  23. public class DefectLib
  24. {
  25. #region C++dll
  26. private const string dll_path = "yolo_trt.dll";
  27. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
  28. static extern IntPtr CreateDetector(string model_path);
  29. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
  30. extern static bool DestroyDetector(IntPtr detector);
  31. /// <summary>
  32. /// 非0值表示成功,0表示失败 返回小图张数
  33. /// </summary>
  34. /// <param name="detector"></param>
  35. /// <returns></returns>
  36. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
  37. static extern int GetBatchSize(IntPtr detector);
  38. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
  39. static extern bool Detect(IntPtr detector, ref byte bgrs_data,
  40. int image_num, int width, int height, int channels,
  41. float conf_threshold, float iou_threshold,
  42. ref float output, int output_size, ref int object_num,
  43. int expand_pixel);
  44. #endregion
  45. public Action<WarningEnum, string> WarningEvent;
  46. /// <summary>
  47. /// 检测结果JSON(原图,结果)
  48. /// </summary>
  49. public Action<DefectTask> finishEvent;
  50. /// <summary>
  51. /// 是否打开设备成功
  52. /// </summary>
  53. public bool IsInit { get; private set; } = false;
  54. private IntPtr detector = IntPtr.Zero;
  55. private Thread t_task, t_task_operation, t_task_maketag, t_task_defectover;
  56. //=======task list
  57. private List<DefectTask> taskList = new List<DefectTask>();
  58. private List<DefectTask> taskOperationList = new List<DefectTask>();
  59. private List<DefectTask> taskMakeTagList = new List<DefectTask>();
  60. private List<DefectTask> taskDefectOverList = new List<DefectTask>();
  61. private string preModelName = "";
  62. #region 图片处理参数
  63. private readonly int image_width = 2048;
  64. private readonly int image_hight = 2048;
  65. private readonly int image_channels = 3;
  66. private readonly int image_bytes = 2048 * 2048 * 3;
  67. private readonly int detect_elem_size = 7; //维度数据结果,x y w h conf classid
  68. private readonly int detect_max_object_num = 20;//这个指的是一张子图可能最多给你返回的目标个球
  69. public Action<int, int> QueueCountEvent;//0/1/2, 数量
  70. #endregion
  71. public DefectLib()
  72. {
  73. }
  74. public bool start()
  75. {
  76. try
  77. {
  78. //detector = CreateDetector(Config.model_path, Config.labels_path, true, 6);
  79. //if (detector == IntPtr.Zero)
  80. // throw new Exception("模型初始化失败!");
  81. preModelName = "";
  82. IsInit = true;
  83. taskList.Clear();
  84. taskOperationList.Clear();
  85. taskMakeTagList.Clear();
  86. #if Online_One
  87. t_task = new System.Threading.Thread(run);
  88. t_task.IsBackground = true;
  89. t_task.Start();
  90. #else
  91. t_task = new System.Threading.Thread(runStep);
  92. t_task.IsBackground = true;
  93. t_task.Start();
  94. t_task_operation = new System.Threading.Thread(run2);
  95. t_task_operation.IsBackground = true;
  96. t_task_operation.Start();
  97. t_task_maketag = new System.Threading.Thread(run3);
  98. t_task_maketag.IsBackground = true;
  99. t_task_maketag.Start();
  100. //t_task_defectover = new System.Threading.Thread(run4);
  101. //t_task_defectover.IsBackground = true;
  102. //t_task_defectover.Start();
  103. #endif
  104. return true;
  105. }
  106. catch (Exception ex)
  107. {
  108. WarningEvent?.Invoke(WarningEnum.High, ex.Message);
  109. return false;
  110. }
  111. }
  112. public void stop()
  113. {
  114. if (!IsInit) return;
  115. try
  116. {
  117. IsInit = false;
  118. //timer.Elapsed -= Timer_Elapsed;
  119. preModelName = "";
  120. //释放模型
  121. if (detector != IntPtr.Zero)
  122. {
  123. DestroyDetector(detector);
  124. detector = IntPtr.Zero;
  125. }
  126. if (t_task != null)
  127. {
  128. bool b = t_task.Join(5000);
  129. if (!b) t_task.Abort();
  130. t_task = null;
  131. }
  132. if (t_task_operation != null)
  133. {
  134. bool b = t_task_operation.Join(5000);
  135. if (!b) t_task_operation.Abort();
  136. t_task_operation = null;
  137. }
  138. if (t_task_maketag != null)
  139. {
  140. bool b = t_task_maketag.Join(5000);
  141. if (!b) t_task_maketag.Abort();
  142. t_task_maketag = null;
  143. }
  144. //if (t_task_defectover != null)
  145. //{
  146. // bool b = t_task_defectover.Join(5000);
  147. // if (!b) t_task_defectover.Abort();
  148. // t_task_defectover = null;
  149. //}
  150. taskList.Clear();
  151. taskOperationList.Clear();
  152. taskMakeTagList.Clear();
  153. taskDefectOverList.Clear();
  154. }
  155. catch { }
  156. }
  157. /// <summary>
  158. /// 切割(先左右,后上下)
  159. /// </summary>
  160. /// <param name="mat"></param>
  161. /// <param name="width"></param>
  162. /// <param name="height"></param>
  163. /// <returns></returns>
  164. private Mat[] OpenCVToCutsMat(Mat mat, int width, int height)
  165. {
  166. Mat[] array = new Mat[mat.Width / width * mat.Height / height];
  167. int num = 0;
  168. for (int i = 0; i < mat.Height / height; i++)
  169. {
  170. for (int j = 0; j < mat.Width / width; j++)
  171. {
  172. int x = j * width;
  173. int y = i * height;
  174. System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(x, y, width, height);
  175. Rect roi = new Rect(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
  176. array[num] = new Mat(mat, roi).Clone();
  177. num++;
  178. }
  179. }
  180. return array;
  181. }
  182. public static string ToGB2312(int codepage, string str)
  183. {
  184. try
  185. {
  186. Encoding cp850 = Encoding.GetEncoding(codepage);
  187. Encoding gb2312 = Encoding.GetEncoding("gb2312");//Encoding.Default ,936
  188. byte[] temp = cp850.GetBytes(str);
  189. return Encoding.GetEncoding("gb2312").GetString(temp, 0, temp.Length);
  190. }
  191. catch (Exception ex)//(UnsupportedEncodingException ex)
  192. {
  193. Console.Write(ex.Message);
  194. return null;
  195. }
  196. }
  197. private void runStep()
  198. {
  199. int step = 0;
  200. while (IsInit)
  201. {
  202. if (taskList.Count < 1)
  203. {
  204. Thread.Sleep(25);
  205. continue;
  206. }
  207. //
  208. step = 1;
  209. var task = pop();
  210. try
  211. {
  212. if (task != null)
  213. {
  214. Stopwatch stopwatch = Stopwatch.StartNew();
  215. step = 2;
  216. if (preModelName != task.modelName)
  217. {
  218. step = 3;
  219. //先释放模型
  220. if (detector != IntPtr.Zero)
  221. {
  222. step = 4;
  223. DestroyDetector(detector);
  224. detector = IntPtr.Zero;
  225. }
  226. step = 5;
  227. string modelPath = $"{ConfMgr.Instance.SysConfigParams.AIModelPath}\\{task.modelName}";
  228. detector = CreateDetector(modelPath);
  229. if (detector == IntPtr.Zero)
  230. throw new Exception($"模型({modelPath})初始化失败!");
  231. step = 6;
  232. preModelName = task.modelName;
  233. }
  234. //源图
  235. //Bitmap bmp = yolo1.Read2Bmp(file_path);
  236. //切割图像,输入图像格式14208*10640
  237. stopwatch.Start();
  238. //task.resizeBmp = OpenCVUtil.resize( task.bmp.Clone(), task.resize.Width, task.resize.Height);//在外面已做了resize
  239. //Cv2.CvtColor(task.bmp, task.bmpBgr2rgb, ColorConversionCodes.BGR2RGB);
  240. //task.bmps_cut = OpenCVToCutsMat(task.bmpBgr2rgb, image_width, image_hight); //这里cut时之前加的clone
  241. step = 7;
  242. task.bmps_cut = OpenCVToCutsMat(task.bmp, image_width, image_hight); //这里cut时之前加的clone
  243. stopwatch.Stop();
  244. task.stopwatch[0] = stopwatch.ElapsedMilliseconds;
  245. //Resize图像
  246. //stopwatch.Restart();
  247. //task.bmps_resize = yolo1.OpenCVToResizesMat(task.bmps_cut, task.resize.Width, task.resize.Height);
  248. //stopwatch.Stop();
  249. //task.stopwatch[1] = stopwatch.ElapsedMilliseconds;
  250. //预处理模型
  251. //stopwatch.Restart();
  252. //task.tensors = yolo1.PreprocessImageMat(task.bmps_resize);
  253. //stopwatch.Stop();
  254. //task.stopwatch[2] = stopwatch.ElapsedMilliseconds;
  255. step = 8;
  256. lock (taskOperationList)
  257. {
  258. taskOperationList.Add(task);
  259. QueueCountEvent?.BeginInvoke(1, taskOperationList.Count, null, null);
  260. }
  261. step = 9;
  262. }
  263. }
  264. catch (Exception ex)
  265. {
  266. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib task1 err({step}):" + ex.Message);
  267. task.isSucceed = false;
  268. task.resultInfo = ex.Message;
  269. callback(task);
  270. }
  271. Thread.Sleep(5);
  272. }
  273. }
  274. //推理
  275. private void run2()
  276. {
  277. QualifiedLimit qualifiedLimit;
  278. while (IsInit)
  279. {
  280. if (taskOperationList.Count < 1)
  281. {
  282. Thread.Sleep(25);
  283. continue;
  284. }
  285. //
  286. var task = pop2();
  287. int cut_count = 0, step = 0;
  288. try
  289. {
  290. if (task != null && task.bmps_cut.Count() > 0)
  291. {
  292. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, "DefectLib tasks 运行推理...");
  293. cut_count = task.bmps_cut.Count();
  294. Stopwatch stopwatch = Stopwatch.StartNew();
  295. //====推理(必需单队列)
  296. stopwatch.Start();
  297. // 把数据转为byte数组,【h, w, c】的bgr格式,第一张在前,第二张在后
  298. byte[] imgData = new byte[image_bytes * cut_count];
  299. for (int i = 0; i < cut_count; i++)
  300. Marshal.Copy(task.bmps_cut[i].Data, imgData, image_bytes * i, image_bytes);
  301. step = 1;
  302. stopwatch.Stop();
  303. task.stopwatch[1] = stopwatch.ElapsedMilliseconds;
  304. stopwatch.Restart();
  305. task.output = new float[cut_count * detect_elem_size * detect_max_object_num];
  306. task.output_num = new int[cut_count];
  307. //执行推理
  308. step = 2;
  309. bool ok = Detect(detector, ref imgData[0], cut_count, image_width, image_hight, image_channels,
  310. 0.25f, 0.45f, ref task.output[0], task.output.Length, ref task.output_num[0], task.expand_pixel);
  311. //bool ok = Detect(_detector, ref imgData[0], imgs.Count, ImageWidth, image_hight, image_channels,
  312. // 0.25f, 0.45f, ref output[0], output.Length, ref output_num[0]);
  313. step = 3;
  314. stopwatch.Stop();
  315. task.stopwatch[2] = stopwatch.ElapsedMilliseconds;
  316. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"DefectLib tasks 结果推理={ok}");
  317. for (int i = 0; i < cut_count; i++)
  318. task.bmps_cut[i].Dispose();
  319. if (ok == false)
  320. throw new Exception($"推理失败或者输入数组太小({cut_count})");
  321. //
  322. lock (taskMakeTagList)
  323. {
  324. taskMakeTagList.Add(task);
  325. QueueCountEvent?.BeginInvoke(2, taskMakeTagList.Count, null, null);
  326. }
  327. }
  328. }
  329. catch (Exception ex)
  330. {
  331. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib task2 err({step}):({cut_count}){ex.Message}");
  332. task.isSucceed = false;
  333. task.resultInfo = ex.Message;
  334. callback(task);
  335. }
  336. Thread.Sleep(5);
  337. }
  338. }
  339. //打标
  340. private void run3()
  341. {
  342. QualifiedLimit qualifiedLimit;
  343. while (IsInit)
  344. {
  345. if (taskMakeTagList.Count < 1)
  346. {
  347. Thread.Sleep(25);
  348. continue;
  349. }
  350. //
  351. var task = pop3();
  352. int liStep = 0;
  353. try
  354. {
  355. Stopwatch stopwatch = Stopwatch.StartNew();
  356. stopwatch.Restart();
  357. int cut_count = task.bmps_cut.Count();//上面bmps_cut已销毁
  358. int colNum = task.bmp.Width / image_width;
  359. int rowNum = task.bmp.Height / image_hight;
  360. int count = 0;
  361. liStep = 3;
  362. //车用革去除接头处横档误判
  363. bool haveJieTou = false;
  364. List<DefectLabelInfo> DefectLabelInfoList = new List<DefectLabelInfo>();
  365. for (int i = 0; i < cut_count; i++)
  366. {
  367. liStep = i * 100;
  368. task.resultInfo += $"第 {i}/{cut_count} 张小图(大图索引{task.photoIndex}): 缺陷数 = {task.output_num[i]}-{task.output.Length}\n";
  369. //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";
  370. #region 检测信息汇总
  371. for (int j = 0; j < task.output_num[i]; j++)//缺陷数
  372. {
  373. liStep += j + 10000;//0
  374. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"-------");
  375. int index = count * detect_elem_size;
  376. // 打印输出信息(示例代码,根据实际情况进行修改和格式化)
  377. // 获取输出信息
  378. int x = (int)task.output[index];
  379. int y = (int)task.output[index + 1];
  380. int w = (int)task.output[index + 2];
  381. int h = (int)task.output[index + 3];
  382. int classId = (int)task.output[index + 4];
  383. double confidence = Math.Round(task.output[index + 5], 2); //置信度
  384. double contrast = Math.Round(task.output[index + 6], 3);//对比度
  385. //y = image_hight-y-h;//转到右下角为原点
  386. count++;
  387. liStep+= 10000;//0
  388. //var cmW = Math.Round(w * task.widthRatio / task.cm2px_x, 2);
  389. //var cmH = Math.Round(h * task.widthRatio / task.cm2px_y, 2);
  390. // 打印输出信息
  391. //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";
  392. DefectLabelInfoList.Add(new DefectLabelInfo()
  393. {
  394. x = (int)task.output[index],
  395. y = (int)task.output[index + 1],
  396. w = (int)task.output[index + 2],
  397. h = (int)task.output[index + 3],
  398. classId = (int)task.output[index + 4],
  399. confidence = Math.Round(task.output[index + 5], 2), //置信度
  400. contrast = Math.Round(task.output[index + 6], 3),//对比度
  401. cmW = Math.Round(w * task.widthRatio / task.cm2px_x, 2),
  402. cmH = Math.Round(h * task.widthRatio / task.cm2px_y, 2),
  403. i = i,
  404. j = j,
  405. });
  406. }
  407. #endregion
  408. }
  409. liStep = 7777;
  410. #region 合并接头横档
  411. if (DefectLabelInfoList.Count > 0)
  412. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "jietou", DefectLabelInfoList);
  413. if (DefectLabelInfoList.Count > 0)
  414. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "hengdang", DefectLabelInfoList);
  415. if (DefectLabelInfoList.Count > 0)
  416. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "jt", DefectLabelInfoList);
  417. if (DefectLabelInfoList.Count > 0)
  418. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "hd", DefectLabelInfoList);
  419. if (DefectLabelInfoList.Count > 0)
  420. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "bj", DefectLabelInfoList);
  421. if (DefectLabelInfoList.Count > 0)
  422. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "zj", DefectLabelInfoList);
  423. #endregion
  424. //结果过滤
  425. #region 结果过滤
  426. liStep = 8888;
  427. if (DefectLabelInfoList.Count > 0)
  428. {
  429. //降序排序,先得到是否有接头检出
  430. List<DefectLabelInfo> DefectLabelInfoListByClassID = DefectLabelInfoList.OrderByDescending(t => t.classId).ToList();//降序
  431. for (int q = 0; q < DefectLabelInfoList.Count; q++)
  432. {
  433. //是否满足此产品标准
  434. if (task.qualifiedLimitList != null && task.qualifiedLimitList.Count > 0)
  435. {
  436. qualifiedLimit = task.qualifiedLimitList.FirstOrDefault(m => m.Code == task.labelDic[DefectLabelInfoList[q].classId]);
  437. if (qualifiedLimit != null)
  438. {
  439. //if ((qualifiedLimit.ZXD > 0 && qualifiedLimit.ZXD > confidence)
  440. // || (qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower > 0 && x> qualifiedLimit.ContrastLower && x < qualifiedLimit.ContrastTop)
  441. // || (qualifiedLimit.Area > 0 && qualifiedLimit.Area > cmW * cmH))
  442. if (DefectLabelInfoList[q].confidence <= qualifiedLimit.ZXD)//confidence > qualifiedLimit.ZXD 是瑕疵 才继续判断下面的两个条件
  443. {
  444. task.resultInfo += $" 置信度不满足此产品瑕疵标准,跳过! \n";
  445. continue;
  446. }
  447. //下限<对比度<上限:不是瑕疵
  448. var ContrastTotal = qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower;
  449. if (qualifiedLimit.IsOR)
  450. {
  451. if (!(
  452. (qualifiedLimit.Area <= 0 || DefectLabelInfoList[q].cmW * DefectLabelInfoList[q].cmH >= (qualifiedLimit.Area / 100)) ||
  453. (ContrastTotal <= 0 || (DefectLabelInfoList[q].contrast < qualifiedLimit.ContrastLower || DefectLabelInfoList[q].contrast > qualifiedLimit.ContrastTop))))
  454. {
  455. task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n";
  456. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  457. continue;
  458. }
  459. }
  460. else
  461. {
  462. if (!(
  463. (qualifiedLimit.Area <= 0 || DefectLabelInfoList[q].cmW * DefectLabelInfoList[q].cmH >= (qualifiedLimit.Area / 100)) &&
  464. (ContrastTotal <= 0 || (DefectLabelInfoList[q].contrast < qualifiedLimit.ContrastLower || DefectLabelInfoList[q].contrast > qualifiedLimit.ContrastTop))))
  465. {
  466. task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n";
  467. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  468. continue;
  469. }
  470. }
  471. if (task.labelDic[DefectLabelInfoList[q].classId] == "jietou")
  472. haveJieTou = true;
  473. if (haveJieTou && (task.labelDic[DefectLabelInfoList[q].classId] == "hengdang"))
  474. {
  475. task.resultInfo += $" 判断为接头处横档,跳过! \n";
  476. continue;
  477. }
  478. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  479. }
  480. }
  481. liStep++;
  482. //1
  483. int penLine = 20;
  484. //打标
  485. var point1 = new OpenCvSharp.Point((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x - penLine/2, (DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y - penLine / 2);
  486. var point2 = new OpenCvSharp.Point(point1.X + DefectLabelInfoList[q].w + penLine / 2, point1.Y + DefectLabelInfoList[q].h + penLine / 2);
  487. liStep++;//2
  488. task.resultInfo += $" 转换到大图坐标(px):p1={point1.X},{point1.Y}; p2={point2.X},{point2.Y}\n";
  489. Cv2.Rectangle(task.bmpTag, point1, point2, new Scalar(0.0, 0.0, 255.0), penLine);//画打标点
  490. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 行缺陷信息;");
  491. int px = (point1.X - task.xw) > 0 ? (point1.X - task.xw) : 0;
  492. var cmX = Math.Round(px * task.widthRatio / task.cm2px_x, 2);
  493. var cmY = Math.Round((task.bmp.Height - point1.Y - DefectLabelInfoList[q].h) * task.widthRatio / task.cm2px_y, 2);//外面计Y从右下角为原点
  494. liStep++;//3
  495. task.resultInfo += $" 转换到大图坐标(cm)[widthRatio={task.widthRatio}]:x={cmX},y={cmY}; w={DefectLabelInfoList[q].cmW},h={DefectLabelInfoList[q].cmH}\n";
  496. task.excelTable.Rows.Add($"{task.photoIndex}", cmX, cmY, DefectLabelInfoList[q].cmW, DefectLabelInfoList[q].cmH, DefectLabelInfoList[q].j + 1, DefectLabelInfoList[q].classId, DefectLabelInfoList[q].confidence, Utils.ContrastToPercent(DefectLabelInfoList[q].contrast));
  497. liStep++;//4
  498. //切缺陷小图
  499. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 个缺陷小图;");
  500. int left, top, decX, decY;
  501. //decX = (DefectLabelInfoList[q].w > 236 ? 20 : 256 - DefectLabelInfoList[q].w) / 2;
  502. //decY = (DefectLabelInfoList[q].h > 236 ? 20 : 256 - DefectLabelInfoList[q].h) / 2;
  503. int tdecX = (DefectLabelInfoList[q].w /2 ) / 2;
  504. int tdecY = DefectLabelInfoList[q].w/ DefectLabelInfoList[q].h > 4 ? DefectLabelInfoList[q].w /8 : (DefectLabelInfoList[q].h /1 ) / 2;
  505. decX = (DefectLabelInfoList[q].w > 236 ? tdecX : 256 - DefectLabelInfoList[q].w) / 2;
  506. decY = (DefectLabelInfoList[q].h > 236 ? tdecY : 256 - DefectLabelInfoList[q].h) / 2;
  507. left = point1.X - decX;
  508. top = point1.Y - decY;
  509. if (left < 0) left = 0;
  510. if (top < 0) top = 0;
  511. int width = DefectLabelInfoList[q].w + decX * 2;
  512. int height = DefectLabelInfoList[q].h + decY * 2;
  513. if (left + width > task.bmp.Width - 1) width = task.bmp.Width - left - 1;
  514. if (top + height > task.bmp.Height - 1) height = task.bmp.Height - top - 1;
  515. liStep++;//5
  516. Rect roi = new Rect(left, top, width, height);
  517. liStep++;//6
  518. if (height < 1 || width < 1)
  519. {
  520. task.resultInfo += $" 打标到大图坐标Rect(px):left={left},top={top}; width={width},height={height}\n";
  521. task.resultInfo += $" test point1.Y={point1.Y},h={DefectLabelInfoList[q].h}; top={top},mat.Height={task.bmp.Height}\n================\n";
  522. WarningEvent?.Invoke(WarningEnum.Normal, task.resultInfo);
  523. }
  524. //保存
  525. //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";
  526. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(new Mat(task.bmp, roi)).Save(filename, ImageFormat.Jpeg);
  527. task.lstDefectBmp.Add(new Mat(task.bmpTag, roi).Clone());
  528. liStep++;//7
  529. }
  530. }
  531. #endregion
  532. liStep = 99;
  533. stopwatch.Stop();
  534. task.stopwatch[3] = stopwatch.ElapsedMilliseconds;
  535. task.isSucceed = true;
  536. //lock (taskDefectOverList)
  537. //{
  538. // taskDefectOverList.Add(task);
  539. // QueueCountEvent?.BeginInvoke(3, taskDefectOverList.Count, null, null);
  540. //}
  541. callback(task);
  542. Thread.Sleep(5);
  543. }
  544. catch (Exception ex)
  545. {
  546. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib task3 err({liStep}):" + ex.Message + $"-{task.resultInfo}");
  547. task.isSucceed = false;
  548. task.resultInfo = ex.Message;
  549. callback(task);
  550. }
  551. }
  552. }
  553. //最终处理
  554. private void run()
  555. {
  556. int step = 0;
  557. QualifiedLimit qualifiedLimit;
  558. while (IsInit)
  559. {
  560. if (taskList.Count < 1)
  561. {
  562. Thread.Sleep(5);
  563. continue;
  564. }
  565. step = 1;
  566. var task = pop();
  567. try
  568. {
  569. if (task != null)
  570. {
  571. Stopwatch stopwatch = Stopwatch.StartNew();
  572. step = 2;
  573. if (preModelName != task.modelName)
  574. {
  575. step = 3;
  576. //先释放模型
  577. if (detector != IntPtr.Zero)
  578. {
  579. step = 4;
  580. DestroyDetector(detector);
  581. detector = IntPtr.Zero;
  582. }
  583. step = 5;
  584. string modelPath = $"{ConfMgr.Instance.SysConfigParams.AIModelPath}\\{task.modelName}";
  585. detector = CreateDetector(modelPath);
  586. if (detector == IntPtr.Zero)
  587. throw new Exception($"模型({modelPath})初始化失败!");
  588. step = 6;
  589. preModelName = task.modelName;
  590. }
  591. //源图
  592. stopwatch.Start();
  593. step = 7;
  594. //裁切
  595. task.bmps_cut = OpenCVToCutsMat(task.bmp, image_width, image_hight); //这里cut时之前加的clone
  596. stopwatch.Stop();
  597. task.stopwatch[0] = stopwatch.ElapsedMilliseconds;
  598. step = 8;
  599. int cut_count = task.bmps_cut.Count();
  600. //====推理(必需单队列)
  601. stopwatch.Restart();
  602. // 把数据转为byte数组,【h, w, c】的bgr格式,第一张在前,第二张在后
  603. byte[] imgData = new byte[image_bytes * cut_count];
  604. for (int i = 0; i < cut_count; i++)
  605. Marshal.Copy(task.bmps_cut[i].Data, imgData, image_bytes * i, image_bytes);
  606. step = 9;
  607. stopwatch.Stop();
  608. task.stopwatch[1] = stopwatch.ElapsedMilliseconds;
  609. stopwatch.Restart();
  610. task.output = new float[cut_count * detect_elem_size * detect_max_object_num];
  611. task.output_num = new int[cut_count];
  612. //执行推理
  613. step = 10;
  614. bool ok = Detect(detector, ref imgData[0], cut_count, image_width, image_hight, image_channels,
  615. 0.25f, 0.45f, ref task.output[0], task.output.Length, ref task.output_num[0], task.expand_pixel);
  616. step = 11;
  617. stopwatch.Stop();
  618. task.stopwatch[2] = stopwatch.ElapsedMilliseconds;
  619. stopwatch.Restart();
  620. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"DefectLib tasks 结果推理={ok}");
  621. for (int i = 0; i < cut_count; i++)
  622. task.bmps_cut[i].Dispose();
  623. if (ok == false)
  624. throw new Exception($"推理失败或者输入数组太小({cut_count})");
  625. step = 12;
  626. //打标
  627. cut_count = task.bmps_cut.Count();//上面bmps_cut已销毁
  628. int colNum = task.bmp.Width / image_width;
  629. int rowNum = task.bmp.Height / image_hight;
  630. int count = 0;
  631. step = 13;
  632. //车用革去除接头处横档误判
  633. bool haveJieTou = false;
  634. List<DefectLabelInfo> DefectLabelInfoList = new List<DefectLabelInfo>();
  635. for (int i = 0; i < cut_count; i++)
  636. {
  637. step = i * 100;
  638. task.resultInfo += $"第 {i}/{cut_count} 张小图(大图索引{task.photoIndex}): 缺陷数 = {task.output_num[i]}-{task.output.Length}\n";
  639. //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";
  640. #region 检测信息汇总
  641. for (int j = 0; j < task.output_num[i]; j++)//缺陷数
  642. {
  643. step += j + 10000;//0
  644. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"-------");
  645. int index = count * detect_elem_size;
  646. // 打印输出信息(示例代码,根据实际情况进行修改和格式化)
  647. // 获取输出信息
  648. int x = (int)task.output[index];
  649. int y = (int)task.output[index + 1];
  650. int w = (int)task.output[index + 2];
  651. int h = (int)task.output[index + 3];
  652. int classId = (int)task.output[index + 4];
  653. double confidence = Math.Round(task.output[index + 5], 2); //置信度
  654. double contrast = Math.Round(task.output[index + 6], 3);//对比度
  655. //y = image_hight-y-h;//转到右下角为原点
  656. count++;
  657. step += 10000;//0
  658. DefectLabelInfoList.Add(new DefectLabelInfo()
  659. {
  660. x = (int)task.output[index],
  661. y = (int)task.output[index + 1],
  662. w = (int)task.output[index + 2],
  663. h = (int)task.output[index + 3],
  664. classId = (int)task.output[index + 4],
  665. confidence = Math.Round(task.output[index + 5], 2), //置信度
  666. contrast = Math.Round(task.output[index + 6], 3),//对比度
  667. cmW = Math.Round(w * task.widthRatio / task.cm2px_x, 2),
  668. cmH = Math.Round(h * task.widthRatio / task.cm2px_y, 2),
  669. i = i,
  670. j = j,
  671. });
  672. }
  673. #endregion
  674. }
  675. step = 7777;
  676. #region 合并接头横档
  677. if (DefectLabelInfoList.Count > 0)
  678. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "jietou", DefectLabelInfoList);
  679. if (DefectLabelInfoList.Count > 0)
  680. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "hengdang", DefectLabelInfoList);
  681. if (DefectLabelInfoList.Count > 0)
  682. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "jt", DefectLabelInfoList);
  683. if (DefectLabelInfoList.Count > 0)
  684. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "hd", DefectLabelInfoList);
  685. if (DefectLabelInfoList.Count > 0)
  686. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "bj", DefectLabelInfoList);
  687. #endregion
  688. //结果过滤
  689. #region 结果过滤
  690. step = 8888;
  691. if (DefectLabelInfoList.Count > 0)
  692. {
  693. //降序排序,先得到是否有接头检出
  694. List<DefectLabelInfo> DefectLabelInfoListByClassID = DefectLabelInfoList.OrderByDescending(t => t.classId).ToList();//降序
  695. for (int q = 0; q < DefectLabelInfoList.Count; q++)
  696. {
  697. //是否满足此产品标准
  698. if (task.qualifiedLimitList != null && task.qualifiedLimitList.Count > 0)
  699. {
  700. qualifiedLimit = task.qualifiedLimitList.FirstOrDefault(m => m.Code == task.labelDic[DefectLabelInfoList[q].classId]);
  701. if (qualifiedLimit != null)
  702. {
  703. //if ((qualifiedLimit.ZXD > 0 && qualifiedLimit.ZXD > confidence)
  704. // || (qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower > 0 && x> qualifiedLimit.ContrastLower && x < qualifiedLimit.ContrastTop)
  705. // || (qualifiedLimit.Area > 0 && qualifiedLimit.Area > cmW * cmH))
  706. if (DefectLabelInfoList[q].confidence <= qualifiedLimit.ZXD)//confidence > qualifiedLimit.ZXD 是瑕疵 才继续判断下面的两个条件
  707. {
  708. task.resultInfo += $" 置信度不满足此产品瑕疵标准,跳过! \n";
  709. continue;
  710. }
  711. //下限<对比度<上限:不是瑕疵
  712. var ContrastTotal = qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower;
  713. if (qualifiedLimit.IsOR)
  714. {
  715. if (!(
  716. (qualifiedLimit.Area <= 0 || DefectLabelInfoList[q].cmW * DefectLabelInfoList[q].cmH >= (qualifiedLimit.Area / 100)) ||
  717. (ContrastTotal <= 0 || (DefectLabelInfoList[q].contrast < qualifiedLimit.ContrastLower || DefectLabelInfoList[q].contrast > qualifiedLimit.ContrastTop))))
  718. {
  719. task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n";
  720. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  721. continue;
  722. }
  723. }
  724. else
  725. {
  726. if (!(
  727. (qualifiedLimit.Area <= 0 || DefectLabelInfoList[q].cmW * DefectLabelInfoList[q].cmH >= qualifiedLimit.Area / 100) &&
  728. (ContrastTotal <= 0 || (DefectLabelInfoList[q].contrast < qualifiedLimit.ContrastLower || DefectLabelInfoList[q].contrast > qualifiedLimit.ContrastTop))))
  729. {
  730. task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n";
  731. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  732. continue;
  733. }
  734. }
  735. if (task.labelDic[DefectLabelInfoList[q].classId] == "jietou")
  736. haveJieTou = true;
  737. if (haveJieTou && (task.labelDic[DefectLabelInfoList[q].classId] == "hengdang"))
  738. {
  739. task.resultInfo += $" 判断为接头处横档,跳过! \n";
  740. continue;
  741. }
  742. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  743. }
  744. }
  745. step++;
  746. //1
  747. int penLine = 20;
  748. //打标
  749. var point1 = new OpenCvSharp.Point((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x - penLine / 2, (DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y - penLine / 2);
  750. var point2 = new OpenCvSharp.Point(point1.X + DefectLabelInfoList[q].w + penLine / 2, point1.Y + DefectLabelInfoList[q].h + penLine / 2);
  751. step++;//2
  752. task.resultInfo += $" 转换到大图坐标(px):p1={point1.X},{point1.Y}; p2={point2.X},{point2.Y}\n";
  753. Cv2.Rectangle(task.bmpTag, point1, point2, new Scalar(0.0, 0.0, 255.0), penLine);//画打标点
  754. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 行缺陷信息;");
  755. int px = (point1.X - task.xw) > 0 ? (point1.X - task.xw) : 0;
  756. var cmX = Math.Round(px * task.widthRatio / task.cm2px_x, 2);
  757. var cmY = Math.Round((task.bmp.Height - point1.Y - DefectLabelInfoList[q].h) * task.widthRatio / task.cm2px_y, 2);//外面计Y从右下角为原点
  758. step++;//3
  759. task.resultInfo += $" 转换到大图坐标(cm)[widthRatio={task.widthRatio}]:x={cmX},y={cmY}; w={DefectLabelInfoList[q].cmW},h={DefectLabelInfoList[q].cmH}\n";
  760. task.excelTable.Rows.Add($"{task.photoIndex}", cmX, cmY, DefectLabelInfoList[q].cmW, DefectLabelInfoList[q].cmH, DefectLabelInfoList[q].j + 1, DefectLabelInfoList[q].classId, DefectLabelInfoList[q].confidence, Utils.ContrastToPercent(DefectLabelInfoList[q].contrast));
  761. step++;//4
  762. //切缺陷小图
  763. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 个缺陷小图;");
  764. int left, top, decX, decY;
  765. //decX = (DefectLabelInfoList[q].w > 236 ? 20 : 256 - DefectLabelInfoList[q].w) / 2;
  766. //decY = (DefectLabelInfoList[q].h > 236 ? 20 : 256 - DefectLabelInfoList[q].h) / 2;
  767. int tdecX = (DefectLabelInfoList[q].w / 2) / 2;
  768. int tdecY = DefectLabelInfoList[q].w / DefectLabelInfoList[q].h > 4 ? DefectLabelInfoList[q].w / 8 : (DefectLabelInfoList[q].h / 1) / 2;
  769. decX = (DefectLabelInfoList[q].w > 236 ? tdecX : 256 - DefectLabelInfoList[q].w) / 2;
  770. decY = (DefectLabelInfoList[q].h > 236 ? tdecY : 256 - DefectLabelInfoList[q].h) / 2;
  771. left = point1.X - decX;
  772. top = point1.Y - decY;
  773. if (left < 0) left = 0;
  774. if (top < 0) top = 0;
  775. int width = DefectLabelInfoList[q].w + decX * 2;
  776. int height = DefectLabelInfoList[q].h + decY * 2;
  777. if (left + width > task.bmp.Width - 1) width = task.bmp.Width - left - 1;
  778. if (top + height > task.bmp.Height - 1) height = task.bmp.Height - top - 1;
  779. step++;//5
  780. Rect roi = new Rect(left, top, width, height);
  781. step++;//6
  782. if (height < 1 || width < 1)
  783. {
  784. task.resultInfo += $" 打标到大图坐标Rect(px):left={left},top={top}; width={width},height={height}\n";
  785. task.resultInfo += $" test point1.Y={point1.Y},h={DefectLabelInfoList[q].h}; top={top},mat.Height={task.bmp.Height}\n================\n";
  786. WarningEvent?.Invoke(WarningEnum.Normal, task.resultInfo);
  787. }
  788. //保存
  789. //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";
  790. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(new Mat(task.bmp, roi)).Save(filename, ImageFormat.Jpeg);
  791. task.lstDefectBmp.Add(new Mat(task.bmpTag, roi).Clone());
  792. step++;//7
  793. }
  794. }
  795. #endregion
  796. step = 99;
  797. stopwatch.Stop();
  798. task.stopwatch[3] = stopwatch.ElapsedMilliseconds;
  799. task.isSucceed = true;
  800. //lock (taskDefectOverList)
  801. //{
  802. // taskDefectOverList.Add(task);
  803. // QueueCountEvent?.BeginInvoke(3, taskDefectOverList.Count, null, null);
  804. //}
  805. callback(task);
  806. }
  807. }
  808. catch (Exception ex)
  809. {
  810. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib taskRun err({step}):" + ex.Message);
  811. task.isSucceed = false;
  812. task.resultInfo = ex.Message;
  813. callback(task);
  814. }
  815. Thread.Sleep(5);
  816. }
  817. }
  818. #region 词条合并
  819. private List<DefectLabelInfo> HeBingDefect(int Width, string label, List<DefectLabelInfo> DefectLabelInfoList)
  820. {
  821. int fw = 2000;
  822. List<DefectLabelInfo> outList = new List<DefectLabelInfo>();
  823. List<DefectLabelInfo> HeBingList = new List<DefectLabelInfo>();
  824. List<DefectLabelInfo> XcHeBingList = new List<DefectLabelInfo>();
  825. List<int> xPos = new List<int>();
  826. List<int> yPos = new List<int>();
  827. List<double> xZXD = new List<double>();
  828. List<double> xDBD = new List<double>();
  829. DefectLabelInfo stpoint = DefectLabelInfoList[0];
  830. int colNum = Width / image_width;
  831. //寻找在一条线上
  832. for (int q = 0; q < DefectLabelInfoList.Count; q++)
  833. {
  834. if (SysMgr.Instance.GetDefectCode()[DefectLabelInfoList[q].classId] == label)
  835. {
  836. int max = stpoint.y + fw;
  837. int min = stpoint.y - fw > 0 ? stpoint.y - fw : 0;
  838. if (DefectLabelInfoList[q].y >= min && DefectLabelInfoList[q].y <= max)
  839. {
  840. HeBingList.Add(DefectLabelInfoList[q]);
  841. xPos.Add((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x);
  842. yPos.Add((DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y);
  843. xZXD.Add(DefectLabelInfoList[q].confidence);
  844. xDBD.Add(DefectLabelInfoList[q].contrast);
  845. }
  846. else
  847. XcHeBingList.Add(DefectLabelInfoList[q]);
  848. }
  849. else
  850. outList.Add(DefectLabelInfoList[q]);
  851. }
  852. //递归下次合并数据
  853. List<DefectLabelInfo> dg1 = new List<DefectLabelInfo>();
  854. if (XcHeBingList.Count > 0)
  855. dg1 = HeBingDefect(Width, label, XcHeBingList);
  856. //多个jietou合并
  857. if (HeBingList.Count > 0)
  858. {
  859. var stIt = HeBingList.Find(x => ((x.i % colNum) * image_width + x.x) == xPos.Min());
  860. var edIt = HeBingList.Find(x => ((x.i % colNum) * image_width + x.x) == xPos.Max());
  861. var stIty = HeBingList.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos.Min());
  862. var edIty = HeBingList.Find(x => ((x.i / colNum) * image_hight + x.y) == yPos.Max());
  863. var eZXD = HeBingList.Find(x => x.confidence == xZXD.Max());
  864. double eDBD = 0;
  865. double DBD = 0;
  866. for (int i = 0; i < xDBD.Count; i++)
  867. {
  868. if (Math.Abs(xDBD[i] - 1) >= eDBD)
  869. {
  870. eDBD = Math.Abs(xDBD[i] - 1);
  871. DBD = xDBD[i];
  872. }
  873. }
  874. int newW = Math.Abs(((edIt.i % colNum) * image_width + edIt.x) - ((stIt.i % colNum) * image_width + stIt.x)) + edIt.w;
  875. int newh = Math.Abs(((edIt.i / colNum) * image_hight + edIt.y) - ((stIt.i / colNum) * image_hight + stIt.y)) + edIt.h;
  876. outList.Add(new DefectLabelInfo()
  877. {
  878. x = stIt.x,
  879. y = edIt.y,
  880. w = newW, //多图叠加
  881. h = newh, //多图叠加
  882. classId = eZXD.classId,
  883. confidence = eZXD.confidence,
  884. contrast = DBD,
  885. cmH = Math.Round(edIt.h * 1.0 / ConfMgr.Instance.SysConfigParams.Cm2px_y, 2),
  886. cmW = Math.Round(newW * 1.0 / ConfMgr.Instance.SysConfigParams.Cm2px_x, 2),
  887. i = stIt.i,
  888. j = stIt.j,
  889. });
  890. }
  891. outList = outList.Concat(dg1).ToList<DefectLabelInfo>();//保留重复项
  892. return outList;
  893. }
  894. #endregion
  895. #region 结果回调
  896. private void callback(DefectTask task)
  897. {
  898. //返回成功/失败,异步调用
  899. if (task.finishEvent != null || (task.finishEvent = finishEvent) != null)
  900. //task.finishEvent.BeginInvoke(result, errInfo, res => task.finishEvent.EndInvoke(res), null);
  901. System.Threading.ThreadPool.QueueUserWorkItem(waitCallback, task);
  902. }
  903. //异步回调
  904. WaitCallback waitCallback = new WaitCallback(o =>
  905. {
  906. var task = (DefectTask)o;
  907. task.finishEvent(task);
  908. });
  909. #endregion
  910. #region 处理队列
  911. public string GetDefectInfo()
  912. {
  913. string str = "";
  914. int cnt1, cnt2, cnt3;
  915. lock (taskList)
  916. {
  917. cnt1 = taskList.Count;
  918. }
  919. lock (taskOperationList)
  920. {
  921. cnt2 = taskOperationList.Count;
  922. }
  923. lock (taskMakeTagList)
  924. {
  925. cnt3 = taskMakeTagList.Count;
  926. }
  927. str = $"预处理:{cnt1},推理:{cnt2},打标:{cnt3}";
  928. return str; ;
  929. }
  930. public void add(DefectTask task)
  931. {
  932. lock (taskList)
  933. {
  934. taskList.Add(task);
  935. QueueCountEvent?.BeginInvoke(0, taskList.Count, null, null);
  936. }
  937. }
  938. private DefectTask pop()
  939. {
  940. lock (taskList)
  941. {
  942. if (taskList.Count < 1)
  943. return null;
  944. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  945. //if (index < 0) index = 0;
  946. var task = taskList[0];
  947. taskList.RemoveAt(0);
  948. QueueCountEvent?.BeginInvoke(0, taskList.Count, null, null);
  949. return task;
  950. }
  951. }
  952. private DefectTask pop2()
  953. {
  954. lock (taskOperationList)
  955. {
  956. if (taskOperationList.Count < 1)
  957. return null;
  958. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  959. //if (index < 0) index = 0;
  960. var task = taskOperationList[0];
  961. taskOperationList.RemoveAt(0);
  962. QueueCountEvent?.BeginInvoke(1, taskOperationList.Count, null, null);
  963. return task;
  964. }
  965. }
  966. private DefectTask pop3()
  967. {
  968. lock (taskMakeTagList)
  969. {
  970. if (taskMakeTagList.Count < 1)
  971. return null;
  972. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  973. //if (index < 0) index = 0;
  974. var task = taskMakeTagList[0];
  975. taskMakeTagList.RemoveAt(0);
  976. QueueCountEvent?.BeginInvoke(2, taskMakeTagList.Count, null, null);
  977. return task;
  978. }
  979. }
  980. private DefectTask pop4()
  981. {
  982. lock (taskDefectOverList)
  983. {
  984. if (taskDefectOverList.Count < 1)
  985. return null;
  986. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  987. //if (index < 0) index = 0;
  988. var task = taskDefectOverList[0];
  989. taskDefectOverList.RemoveAt(0);
  990. QueueCountEvent?.BeginInvoke(3, taskDefectOverList.Count, null, null);
  991. return task;
  992. }
  993. }
  994. #endregion
  995. public void Dispose()
  996. {
  997. stop();
  998. }
  999. private class DefectLabelInfo
  1000. {
  1001. public int x { get; set; }
  1002. public int y { get; set; }
  1003. public int w { get; set; }
  1004. public int h { get; set; }
  1005. public int classId { get; set; }
  1006. public double confidence { get; set; } //置信度
  1007. public double contrast { get; set; }//对比度
  1008. public double cmW { get; set; }
  1009. public double cmH { get; set; }
  1010. public int i { get; set; }//小图index
  1011. public int j { get; set; }//缺陷index
  1012. }
  1013. }
  1014. public class DefectTask
  1015. {
  1016. public DefectTask()
  1017. {
  1018. // 创建一个 DataTable 对象来存储数据
  1019. excelTable = new DataTable("MyData");
  1020. // 添加列到 DataTable
  1021. excelTable.Columns.Add("FileName", typeof(string));
  1022. excelTable.Columns.Add("X", typeof(decimal));
  1023. excelTable.Columns.Add("Y", typeof(decimal));
  1024. excelTable.Columns.Add("W", typeof(decimal));
  1025. excelTable.Columns.Add("H", typeof(decimal));
  1026. excelTable.Columns.Add("目标", typeof(int));
  1027. excelTable.Columns.Add("类别", typeof(int));
  1028. excelTable.Columns.Add("置信度", typeof(decimal));
  1029. excelTable.Columns.Add("对比度", typeof(decimal));
  1030. // 向 DataTable 中添加数据行
  1031. //excelTable.Rows.Add("John Doe", 30);
  1032. //excelTable.Rows.Add("Jane Smith", 25);
  1033. }
  1034. /// <summary>
  1035. /// 处理参数
  1036. /// </summary>
  1037. public int expand_pixel;
  1038. public int cm2px_x;
  1039. public int cm2px_y;
  1040. public Dictionary<int, string> labelDic;
  1041. /// <summary>
  1042. /// 模型名字
  1043. /// </summary>
  1044. public string modelName;
  1045. public Models.Records record;
  1046. //public string bmpPath;//源图路径(仅目录)
  1047. /// <summary>
  1048. /// 源图(resize后的)
  1049. /// </summary>
  1050. public Mat bmp;
  1051. //public Mat bmpBgr2rgb=new Mat();
  1052. public System.Drawing.Size resize = new System.Drawing.Size(224, 224);
  1053. //public Mat resizeBmp;//resize后 BGR2RGB图,只用于识别
  1054. public Mat bmpTag;
  1055. /// <summary>
  1056. /// 图片索引0-n
  1057. /// </summary>
  1058. public int photoIndex;//excel中对应的图像路径标识
  1059. public float widthRatio;//宽度比例,resize前/resize后
  1060. //切割后
  1061. public Mat[] bmps_cut;
  1062. //用于比对参数 }//置信度 面积 对比度
  1063. public List<QualifiedLimit> qualifiedLimitList;
  1064. //推理后结果用于打标
  1065. public float[] output;
  1066. public int[] output_num;
  1067. //
  1068. /// <summary>
  1069. /// 完成后回调
  1070. /// </summary>
  1071. public Action<DefectTask> finishEvent;
  1072. //==结果返回
  1073. public bool isSucceed;//转换是否成功
  1074. public string resultInfo = "";//成功或失败信息
  1075. public List<Mat> lstDefectBmp = new List<Mat>();
  1076. /// <summary>
  1077. /// fileIndex,x_mm,y_mm,w_mm,h_mm,目标,类别ID,置信度
  1078. /// </summary>
  1079. public DataTable excelTable = new DataTable();
  1080. public long[] stopwatch = new long[6];
  1081. /// <summary>
  1082. /// 等比例填充的宽度
  1083. /// </summary>
  1084. public int xw;
  1085. /// <summary>
  1086. /// 当前图像计米器位置
  1087. /// </summary>
  1088. public double CurrDis;
  1089. }
  1090. }