革博士程序V1仓库
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

799 lignes
37 KiB

  1. using CCWin.Win32.Const;
  2. using GeBoShi.SysCtrl;
  3. using HZH_Controls.Controls;
  4. using MaiMuControl.Device;
  5. using Models;
  6. using OpenCvSharp;
  7. using S7.Net.Types;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Data;
  11. using System.Diagnostics;
  12. using System.Linq;
  13. using System.Reflection;
  14. using System.Runtime.InteropServices;
  15. using System.Text;
  16. using System.Threading;
  17. using System.Threading.Tasks;
  18. using static System.ComponentModel.Design.ObjectSelectorEditor;
  19. namespace GeBoShi.ImageDefect
  20. {
  21. public class DefectLib
  22. {
  23. #region C++dll
  24. private const string dll_path = "yolo_trt.dll";
  25. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
  26. static extern IntPtr CreateDetector(string model_path);
  27. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
  28. extern static bool DestroyDetector(IntPtr detector);
  29. /// <summary>
  30. /// 非0值表示成功,0表示失败 返回小图张数
  31. /// </summary>
  32. /// <param name="detector"></param>
  33. /// <returns></returns>
  34. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
  35. static extern int GetBatchSize(IntPtr detector);
  36. [DllImport(dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
  37. static extern bool Detect(IntPtr detector, ref byte bgrs_data,
  38. int image_num, int width, int height, int channels,
  39. float conf_threshold, float iou_threshold,
  40. ref float output, int output_size, ref int object_num,
  41. int expand_pixel);
  42. #endregion
  43. public Action<WarningEnum, string> WarningEvent;
  44. /// <summary>
  45. /// 检测结果JSON(原图,结果)
  46. /// </summary>
  47. public Action<DefectTask> finishEvent;
  48. /// <summary>
  49. /// 是否打开设备成功
  50. /// </summary>
  51. public bool IsInit { get; private set; } = false;
  52. private IntPtr detector = IntPtr.Zero;
  53. private Thread t_task, t_task_operation, t_task_maketag;
  54. //=======task list
  55. private List<DefectTask> taskList = new List<DefectTask>();
  56. private List<DefectTask> taskOperationList = new List<DefectTask>();
  57. private List<DefectTask> taskMakeTagList = new List<DefectTask>();
  58. private string preModelName = "";
  59. #region 图片处理参数
  60. private readonly int image_width = 2048;
  61. private readonly int image_hight = 2048;
  62. private readonly int image_channels = 3;
  63. private readonly int image_bytes = 2048 * 2048 * 3;
  64. private readonly int detect_elem_size = 7; //维度数据结果,x y w h conf classid
  65. private readonly int detect_max_object_num = 20;//这个指的是一张子图可能最多给你返回的目标个球
  66. public Action<int, int> QueueCountEvent;//0/1/2, 数量
  67. #endregion
  68. public DefectLib()
  69. {
  70. }
  71. public bool start()
  72. {
  73. try
  74. {
  75. //detector = CreateDetector(Config.model_path, Config.labels_path, true, 6);
  76. //if (detector == IntPtr.Zero)
  77. // throw new Exception("模型初始化失败!");
  78. preModelName = "";
  79. IsInit = true;
  80. taskList.Clear();
  81. taskOperationList.Clear();
  82. taskMakeTagList.Clear();
  83. t_task = new System.Threading.Thread(runStep);
  84. t_task.IsBackground = true;
  85. t_task.Start();
  86. t_task_operation = new System.Threading.Thread(run2);
  87. t_task_operation.IsBackground = true;
  88. t_task_operation.Start();
  89. t_task_maketag = new System.Threading.Thread(run3);
  90. t_task_maketag.IsBackground = true;
  91. t_task_maketag.Start();
  92. return true;
  93. }
  94. catch (Exception ex)
  95. {
  96. WarningEvent?.Invoke(WarningEnum.High, ex.Message);
  97. return false;
  98. }
  99. }
  100. public void stop()
  101. {
  102. if (!IsInit) return;
  103. try
  104. {
  105. IsInit = false;
  106. //timer.Elapsed -= Timer_Elapsed;
  107. preModelName = "";
  108. //释放模型
  109. if (detector != IntPtr.Zero)
  110. {
  111. DestroyDetector(detector);
  112. detector = IntPtr.Zero;
  113. }
  114. if (t_task != null)
  115. {
  116. bool b = t_task.Join(5000);
  117. if (!b) t_task.Abort();
  118. t_task = null;
  119. }
  120. if (t_task_operation != null)
  121. {
  122. bool b = t_task_operation.Join(5000);
  123. if (!b) t_task_operation.Abort();
  124. t_task_operation = null;
  125. }
  126. if (t_task_maketag != null)
  127. {
  128. bool b = t_task_maketag.Join(5000);
  129. if (!b) t_task_maketag.Abort();
  130. t_task_maketag = null;
  131. }
  132. taskList.Clear();
  133. taskOperationList.Clear();
  134. taskMakeTagList.Clear();
  135. }
  136. catch { }
  137. }
  138. /// <summary>
  139. /// 切割(先左右,后上下)
  140. /// </summary>
  141. /// <param name="mat"></param>
  142. /// <param name="width"></param>
  143. /// <param name="height"></param>
  144. /// <returns></returns>
  145. private Mat[] OpenCVToCutsMat(Mat mat, int width, int height)
  146. {
  147. Mat[] array = new Mat[mat.Width / width * mat.Height / height];
  148. int num = 0;
  149. for (int i = 0; i < mat.Height / height; i++)
  150. {
  151. for (int j = 0; j < mat.Width / width; j++)
  152. {
  153. int x = j * width;
  154. int y = i * height;
  155. System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(x, y, width, height);
  156. Rect roi = new Rect(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
  157. array[num] = new Mat(mat, roi).Clone();
  158. num++;
  159. }
  160. }
  161. return array;
  162. }
  163. public static string ToGB2312(int codepage, string str)
  164. {
  165. try
  166. {
  167. Encoding cp850 = Encoding.GetEncoding(codepage);
  168. Encoding gb2312 = Encoding.GetEncoding("gb2312");//Encoding.Default ,936
  169. byte[] temp = cp850.GetBytes(str);
  170. return Encoding.GetEncoding("gb2312").GetString(temp, 0, temp.Length);
  171. }
  172. catch (Exception ex)//(UnsupportedEncodingException ex)
  173. {
  174. Console.Write(ex.Message);
  175. return null;
  176. }
  177. }
  178. private void runStep()
  179. {
  180. int step = 0;
  181. while (IsInit)
  182. {
  183. if (taskList.Count < 1)
  184. {
  185. Thread.Sleep(0);
  186. continue;
  187. }
  188. //
  189. step = 1;
  190. var task = pop();
  191. try
  192. {
  193. if (task != null)
  194. {
  195. Stopwatch stopwatch = Stopwatch.StartNew();
  196. step = 2;
  197. if (preModelName != task.modelName)
  198. {
  199. step = 3;
  200. //先释放模型
  201. if (detector != IntPtr.Zero)
  202. {
  203. step = 4;
  204. DestroyDetector(detector);
  205. detector = IntPtr.Zero;
  206. }
  207. step = 5;
  208. string modelPath = $"{ConfMgr.Instance.SysConfigParams.AIModelPath}\\{task.modelName}";
  209. detector = CreateDetector(modelPath);
  210. if (detector == IntPtr.Zero)
  211. throw new Exception($"模型({modelPath})初始化失败!");
  212. step = 6;
  213. preModelName = task.modelName;
  214. }
  215. //源图
  216. //Bitmap bmp = yolo1.Read2Bmp(file_path);
  217. //切割图像,输入图像格式14208*10640
  218. stopwatch.Start();
  219. //task.resizeBmp = OpenCVUtil.resize( task.bmp.Clone(), task.resize.Width, task.resize.Height);//在外面已做了resize
  220. //Cv2.CvtColor(task.bmp, task.bmpBgr2rgb, ColorConversionCodes.BGR2RGB);
  221. //task.bmps_cut = OpenCVToCutsMat(task.bmpBgr2rgb, image_width, image_hight); //这里cut时之前加的clone
  222. step = 7;
  223. task.bmps_cut = OpenCVToCutsMat(task.bmp, image_width, image_hight); //这里cut时之前加的clone
  224. stopwatch.Stop();
  225. task.stopwatch[0] = stopwatch.ElapsedMilliseconds;
  226. //Resize图像
  227. //stopwatch.Restart();
  228. //task.bmps_resize = yolo1.OpenCVToResizesMat(task.bmps_cut, task.resize.Width, task.resize.Height);
  229. //stopwatch.Stop();
  230. //task.stopwatch[1] = stopwatch.ElapsedMilliseconds;
  231. //预处理模型
  232. //stopwatch.Restart();
  233. //task.tensors = yolo1.PreprocessImageMat(task.bmps_resize);
  234. //stopwatch.Stop();
  235. //task.stopwatch[2] = stopwatch.ElapsedMilliseconds;
  236. step = 8;
  237. lock (taskOperationList)
  238. {
  239. taskOperationList.Add(task);
  240. QueueCountEvent?.BeginInvoke(1, taskOperationList.Count, null, null);
  241. }
  242. step = 9;
  243. }
  244. }
  245. catch (Exception ex)
  246. {
  247. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib task1 err({step}):" + ex.Message);
  248. task.isSucceed = false;
  249. task.resultInfo = ex.Message;
  250. callback(task);
  251. }
  252. }
  253. }
  254. //推理
  255. private void run2()
  256. {
  257. QualifiedLimit qualifiedLimit;
  258. while (IsInit)
  259. {
  260. if (taskOperationList.Count < 1)
  261. {
  262. Thread.Sleep(0);
  263. continue;
  264. }
  265. //
  266. var task = pop2();
  267. int cut_count = 0, step = 0;
  268. try
  269. {
  270. if (task != null && task.bmps_cut.Count() > 0)
  271. {
  272. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, "DefectLib tasks 运行推理...");
  273. cut_count = task.bmps_cut.Count();
  274. Stopwatch stopwatch = Stopwatch.StartNew();
  275. //====推理(必需单队列)
  276. stopwatch.Start();
  277. // 把数据转为byte数组,【h, w, c】的bgr格式,第一张在前,第二张在后
  278. byte[] imgData = new byte[image_bytes * cut_count];
  279. for (int i = 0; i < cut_count; i++)
  280. Marshal.Copy(task.bmps_cut[i].Data, imgData, image_bytes * i, image_bytes);
  281. step = 1;
  282. stopwatch.Stop();
  283. task.stopwatch[1] = stopwatch.ElapsedMilliseconds;
  284. stopwatch.Restart();
  285. task.output = new float[cut_count * detect_elem_size * detect_max_object_num];
  286. task.output_num = new int[cut_count];
  287. //执行推理
  288. step = 2;
  289. bool ok = Detect(detector, ref imgData[0], cut_count, image_width, image_hight, image_channels,
  290. 0.25f, 0.45f, ref task.output[0], task.output.Length, ref task.output_num[0], task.expand_pixel);
  291. //bool ok = Detect(_detector, ref imgData[0], imgs.Count, ImageWidth, image_hight, image_channels,
  292. // 0.25f, 0.45f, ref output[0], output.Length, ref output_num[0]);
  293. step = 3;
  294. stopwatch.Stop();
  295. task.stopwatch[2] = stopwatch.ElapsedMilliseconds;
  296. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"DefectLib tasks 结果推理={ok}");
  297. for (int i = 0; i < cut_count; i++)
  298. task.bmps_cut[i].Dispose();
  299. if (ok == false)
  300. throw new Exception($"推理失败或者输入数组太小({cut_count})");
  301. //
  302. lock (taskMakeTagList)
  303. {
  304. taskMakeTagList.Add(task);
  305. QueueCountEvent?.BeginInvoke(2, taskMakeTagList.Count, null, null);
  306. }
  307. }
  308. }
  309. catch (Exception ex)
  310. {
  311. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib task2 err({step}):({cut_count}){ex.Message}");
  312. task.isSucceed = false;
  313. task.resultInfo = ex.Message;
  314. callback(task);
  315. }
  316. }
  317. }
  318. //打标
  319. private void run3()
  320. {
  321. QualifiedLimit qualifiedLimit;
  322. while (IsInit)
  323. {
  324. if (taskMakeTagList.Count < 1)
  325. {
  326. Thread.Sleep(0);
  327. continue;
  328. }
  329. //
  330. var task = pop3();
  331. int liStep = 0;
  332. try
  333. {
  334. Stopwatch stopwatch = Stopwatch.StartNew();
  335. stopwatch.Restart();
  336. int cut_count = task.bmps_cut.Count();//上面bmps_cut已销毁
  337. int colNum = task.bmp.Width / image_width;
  338. int rowNum = task.bmp.Height / image_hight;
  339. int count = 0;
  340. liStep = 3;
  341. //车用革去除接头处横档误判
  342. bool haveJieTou = false;
  343. List<DefectLabelInfo> DefectLabelInfoList = new List<DefectLabelInfo>();
  344. for (int i = 0; i < cut_count; i++)
  345. {
  346. liStep = i * 100;
  347. task.resultInfo += $"第 {i}/{cut_count} 张小图(大图索引{task.photoIndex}): 缺陷数 = {task.output_num[i]}\n";
  348. //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";
  349. #region 检测信息汇总
  350. for (int j = 0; j < task.output_num[i]; j++)//缺陷数
  351. {
  352. liStep += j;//0
  353. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"-------");
  354. int index = count * detect_elem_size;
  355. // 打印输出信息(示例代码,根据实际情况进行修改和格式化)
  356. // 获取输出信息
  357. int x = (int)task.output[index];
  358. int y = (int)task.output[index + 1];
  359. int w = (int)task.output[index + 2];
  360. int h = (int)task.output[index + 3];
  361. int classId = (int)task.output[index + 4];
  362. double confidence = Math.Round(task.output[index + 5], 2); //置信度
  363. double contrast = Math.Round(task.output[index + 6], 3);//对比度
  364. //y = image_hight-y-h;//转到右下角为原点
  365. count++;
  366. //var cmW = Math.Round(w * task.widthRatio / task.cm2px_x, 2);
  367. //var cmH = Math.Round(h * task.widthRatio / task.cm2px_y, 2);
  368. // 打印输出信息
  369. 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";
  370. DefectLabelInfoList.Add(new DefectLabelInfo()
  371. {
  372. x = (int)task.output[index],
  373. y = (int)task.output[index + 1],
  374. w = (int)task.output[index + 2],
  375. h = (int)task.output[index + 3],
  376. classId = (int)task.output[index + 4],
  377. confidence = Math.Round(task.output[index + 5], 2), //置信度
  378. contrast = Math.Round(task.output[index + 6], 3),//对比度
  379. cmW = Math.Round(w * task.widthRatio / task.cm2px_x, 2),
  380. cmH = Math.Round(h * task.widthRatio / task.cm2px_y, 2),
  381. i = i,
  382. j = j,
  383. });
  384. }
  385. #endregion
  386. }
  387. #region 合并接头横档
  388. if(DefectLabelInfoList.Count >0)
  389. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "jietou", DefectLabelInfoList);
  390. if (DefectLabelInfoList.Count > 0)
  391. DefectLabelInfoList = HeBingDefect(task.bmp.Width, "hengdang", DefectLabelInfoList);
  392. #endregion
  393. //结果过滤
  394. #region 结果过滤
  395. //降序排序,先得到是否有接头检出
  396. List<DefectLabelInfo> DefectLabelInfoListByClassID = DefectLabelInfoList.OrderByDescending(t => t.classId).ToList();//降序
  397. for (int q = 0; q < DefectLabelInfoList.Count; q++)
  398. {
  399. //是否满足此产品标准
  400. if (task.qualifiedLimitList != null && task.qualifiedLimitList.Count > 0)
  401. {
  402. qualifiedLimit = task.qualifiedLimitList.FirstOrDefault(m => m.Code == task.labelDic[DefectLabelInfoList[q].classId]);
  403. if (qualifiedLimit != null)
  404. {
  405. //if ((qualifiedLimit.ZXD > 0 && qualifiedLimit.ZXD > confidence)
  406. // || (qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower > 0 && x> qualifiedLimit.ContrastLower && x < qualifiedLimit.ContrastTop)
  407. // || (qualifiedLimit.Area > 0 && qualifiedLimit.Area > cmW * cmH))
  408. if (DefectLabelInfoList[q].confidence <= qualifiedLimit.ZXD)//confidence > qualifiedLimit.ZXD 是瑕疵 才继续判断下面的两个条件
  409. {
  410. task.resultInfo += $" 置信度不满足此产品瑕疵标准,跳过! \n";
  411. continue;
  412. }
  413. //下限<对比度<上限:不是瑕疵
  414. var ContrastTotal = qualifiedLimit.ContrastTop + qualifiedLimit.ContrastLower;
  415. if (qualifiedLimit.IsOR)
  416. {
  417. if (!(
  418. (qualifiedLimit.Area <= 0 || DefectLabelInfoList[q].cmW * DefectLabelInfoList[q].cmH >= qualifiedLimit.Area) ||
  419. (ContrastTotal <= 0 || (DefectLabelInfoList[q].contrast < qualifiedLimit.ContrastLower || DefectLabelInfoList[q].contrast > qualifiedLimit.ContrastTop))))
  420. {
  421. task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n";
  422. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  423. continue;
  424. }
  425. }
  426. else
  427. {
  428. if (!(
  429. (qualifiedLimit.Area <= 0 || DefectLabelInfoList[q].cmW * DefectLabelInfoList[q].cmH >= qualifiedLimit.Area) &&
  430. (ContrastTotal <= 0 || (DefectLabelInfoList[q].contrast < qualifiedLimit.ContrastLower || DefectLabelInfoList[q].contrast > qualifiedLimit.ContrastTop))))
  431. {
  432. task.resultInfo += $" 不满足此产品瑕疵标准,跳过! \n";
  433. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断不是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  434. continue;
  435. }
  436. }
  437. if (task.labelDic[DefectLabelInfoList[q].classId] == "jietou")
  438. haveJieTou = true;
  439. if (haveJieTou && (task.labelDic[DefectLabelInfoList[q].classId] == "hengdang"))
  440. {
  441. task.resultInfo += $" 判断为接头处横档,跳过! \n";
  442. continue;
  443. }
  444. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"判断是瑕疵:类别ID:{classId}; 置信度({confidence},[{qualifiedLimit.ZXD}]); isOr({qualifiedLimit.IsOR}); 面积({cmW * cmH},[{ qualifiedLimit.Area}]); 对比度({contrast},[{qualifiedLimit.ContrastLower}-{qualifiedLimit.ContrastTop}])");
  445. }
  446. }
  447. liStep++;//1
  448. //打标
  449. var point1 = new OpenCvSharp.Point((DefectLabelInfoList[q].i % colNum) * image_width + DefectLabelInfoList[q].x, (DefectLabelInfoList[q].i / colNum) * image_hight + DefectLabelInfoList[q].y);
  450. var point2 = new OpenCvSharp.Point(point1.X + DefectLabelInfoList[q].w, point1.Y + DefectLabelInfoList[q].h);
  451. liStep++;//2
  452. task.resultInfo += $" 转换到大图坐标(px):p1={point1.X},{point1.Y}; p2={point2.X},{point2.Y}\n";
  453. Cv2.Rectangle(task.bmpTag, point1, point2, new Scalar(0.0, 0.0, 255.0), 1);//画打标点
  454. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 行缺陷信息;");
  455. int px = (point1.X - task.xw) > 0 ? (point1.X - task.xw) : 0;
  456. var cmX = Math.Round(px * task.widthRatio / task.cm2px_x, 2);
  457. var cmY = Math.Round((task.bmp.Height - point1.Y - DefectLabelInfoList[q].h) * task.widthRatio / task.cm2px_y, 2);//外面计Y从右下角为原点
  458. liStep++;//3
  459. task.resultInfo += $" 转换到大图坐标(cm)[widthRatio={task.widthRatio}]:x={cmX},y={cmY}; w={DefectLabelInfoList[q].cmW},h={DefectLabelInfoList[q].cmH}\n";
  460. 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));
  461. liStep++;//4
  462. //切缺陷小图
  463. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"保存第 {count} 个缺陷小图;");
  464. int left, top, decX, decY;
  465. decX = (DefectLabelInfoList[q].w > 236 ? 20 : 256 - DefectLabelInfoList[q].w) / 2;
  466. decY = (DefectLabelInfoList[q].h > 236 ? 20 : 256 - DefectLabelInfoList[q].h) / 2;
  467. left = point1.X - decX;
  468. top = point1.Y - decY;
  469. if (left < 0) left = 0;
  470. if (top < 0) top = 0;
  471. int width = DefectLabelInfoList[q].w + decX * 2;
  472. int height = DefectLabelInfoList[q].h + decY * 2;
  473. if (left + width > task.bmp.Width - 1) width = task.bmp.Width - left - 1;
  474. if (top + height > task.bmp.Height - 1) height = task.bmp.Height - top - 1;
  475. liStep++;//5
  476. Rect roi = new Rect(left, top, width, height);
  477. liStep++;//6
  478. if (height < 1 || width < 1)
  479. {
  480. task.resultInfo += $" 打标到大图坐标Rect(px):left={left},top={top}; width={width},height={height}\n";
  481. task.resultInfo += $" test point1.Y={point1.Y},h={DefectLabelInfoList[q].h}; top={top},mat.Height={task.bmp.Height}\n================\n";
  482. WarningEvent?.Invoke(WarningEnum.Normal, task.resultInfo);
  483. }
  484. //保存
  485. //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";
  486. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(new Mat(task.bmp, roi)).Save(filename, ImageFormat.Jpeg);
  487. task.lstDefectBmp.Add(new Mat(task.bmpTag, roi).Clone());
  488. liStep++;//7
  489. }
  490. #endregion
  491. liStep = 99;
  492. stopwatch.Stop();
  493. task.stopwatch[3] = stopwatch.ElapsedMilliseconds;
  494. task.isSucceed = true;
  495. callback(task);
  496. }
  497. catch (Exception ex)
  498. {
  499. WarningEvent?.Invoke(WarningEnum.Low, $"DefectLib task3 err({liStep}):" + ex.Message);
  500. task.isSucceed = false;
  501. task.resultInfo = ex.Message;
  502. callback(task);
  503. }
  504. }
  505. }
  506. #region 词条合并
  507. private List<DefectLabelInfo> HeBingDefect(int Width, string label, List<DefectLabelInfo> DefectLabelInfoList)
  508. {
  509. int fw = 500;
  510. List<DefectLabelInfo> outList = new List<DefectLabelInfo>();
  511. List<DefectLabelInfo> HeBingList = new List<DefectLabelInfo>();
  512. List<DefectLabelInfo> XcHeBingList = new List<DefectLabelInfo>();
  513. List<int> xPos = new List<int>();
  514. List<double> xZXD = new List<double>();
  515. DefectLabelInfo stpoint = DefectLabelInfoList[0];
  516. int colNum = Width / image_width;
  517. //寻找在一条线上
  518. for (int q = 0; q < DefectLabelInfoList.Count; q++)
  519. {
  520. if (SysMgr.Instance.GetDefectCode()[DefectLabelInfoList[q].classId] == label)
  521. {
  522. int max = stpoint.y + fw;
  523. int min = stpoint.y - fw > 0 ? stpoint.y - fw : 0;
  524. if (DefectLabelInfoList[q].y >= min && DefectLabelInfoList[q].y <= max)
  525. {
  526. HeBingList.Add(DefectLabelInfoList[q]);
  527. xPos.Add(DefectLabelInfoList[q].x);
  528. xZXD.Add(DefectLabelInfoList[q].confidence);
  529. }
  530. else
  531. XcHeBingList.Add(DefectLabelInfoList[q]);
  532. }
  533. else
  534. outList.Add(DefectLabelInfoList[q]);
  535. }
  536. //递归下次合并数据
  537. List<DefectLabelInfo> dg1 = new List<DefectLabelInfo>();
  538. if (XcHeBingList.Count > 0)
  539. dg1 = HeBingDefect(Width, label, XcHeBingList);
  540. //多个jietou合并
  541. if (HeBingList.Count > 0)
  542. {
  543. var stIt = HeBingList.Find(x => x.x == xPos.Min());
  544. var edIt = HeBingList.Find(x => x.x == xPos.Max());
  545. var eZXD = HeBingList.Find(x => x.confidence == xZXD.Max());
  546. int newW = Math.Abs((edIt.i % colNum) * image_width + edIt.x) - ((stIt.i % colNum) * image_width + stIt.x) + edIt.w;
  547. outList.Add(new DefectLabelInfo()
  548. {
  549. x = stIt.x,
  550. y = edIt.y,
  551. w = newW, //多图叠加
  552. h = edIt.h,
  553. classId = eZXD.classId,
  554. confidence = eZXD.confidence,
  555. contrast = eZXD.contrast,
  556. cmH = Math.Round(edIt.h * 1.0 / ConfMgr.Instance.SysConfigParams.Cm2px_y, 2),
  557. cmW = Math.Round(newW * 1.0 / ConfMgr.Instance.SysConfigParams.Cm2px_x, 2),
  558. i = stIt.i,
  559. j = stIt.j,
  560. });
  561. }
  562. outList = outList.Concat(dg1).ToList<DefectLabelInfo>();//保留重复项
  563. return outList;
  564. }
  565. #endregion
  566. #region 结果回调
  567. private void callback(DefectTask task)
  568. {
  569. //返回成功/失败,异步调用
  570. if (task.finishEvent != null || (task.finishEvent = finishEvent) != null)
  571. //task.finishEvent.BeginInvoke(result, errInfo, res => task.finishEvent.EndInvoke(res), null);
  572. System.Threading.ThreadPool.QueueUserWorkItem(waitCallback, task);
  573. }
  574. //异步回调
  575. WaitCallback waitCallback = new WaitCallback(o =>
  576. {
  577. var task = (DefectTask)o;
  578. task.finishEvent(task);
  579. });
  580. #endregion
  581. #region 处理队列
  582. public void add(DefectTask task)
  583. {
  584. lock (taskList)
  585. {
  586. taskList.Add(task);
  587. QueueCountEvent?.BeginInvoke(0, taskList.Count, null, null);
  588. }
  589. }
  590. private DefectTask pop()
  591. {
  592. lock (taskList)
  593. {
  594. if (taskList.Count < 1)
  595. return null;
  596. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  597. //if (index < 0) index = 0;
  598. var task = taskList[0];
  599. taskList.RemoveAt(0);
  600. QueueCountEvent?.BeginInvoke(0, taskList.Count, null, null);
  601. return task;
  602. }
  603. }
  604. private DefectTask pop2()
  605. {
  606. lock (taskOperationList)
  607. {
  608. if (taskOperationList.Count < 1)
  609. return null;
  610. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  611. //if (index < 0) index = 0;
  612. var task = taskOperationList[0];
  613. taskOperationList.RemoveAt(0);
  614. QueueCountEvent?.BeginInvoke(1, taskOperationList.Count, null, null);
  615. return task;
  616. }
  617. }
  618. private DefectTask pop3()
  619. {
  620. lock (taskMakeTagList)
  621. {
  622. if (taskMakeTagList.Count < 1)
  623. return null;
  624. //int index = 0;// taskList.FindIndex(p => { return p.isSync; });
  625. //if (index < 0) index = 0;
  626. var task = taskMakeTagList[0];
  627. taskMakeTagList.RemoveAt(0);
  628. QueueCountEvent?.BeginInvoke(2, taskMakeTagList.Count, null, null);
  629. return task;
  630. }
  631. }
  632. #endregion
  633. public void Dispose()
  634. {
  635. stop();
  636. }
  637. private class DefectLabelInfo
  638. {
  639. public int x { get; set; }
  640. public int y { get; set; }
  641. public int w { get; set; }
  642. public int h { get; set; }
  643. public int classId { get; set; }
  644. public double confidence { get; set; } //置信度
  645. public double contrast { get; set; }//对比度
  646. public double cmW { get; set; }
  647. public double cmH { get; set; }
  648. public int i { get; set; }//小图index
  649. public int j { get; set; }//缺陷index
  650. }
  651. }
  652. public class DefectTask
  653. {
  654. public DefectTask()
  655. {
  656. // 创建一个 DataTable 对象来存储数据
  657. excelTable = new DataTable("MyData");
  658. // 添加列到 DataTable
  659. excelTable.Columns.Add("FileName", typeof(string));
  660. excelTable.Columns.Add("X", typeof(decimal));
  661. excelTable.Columns.Add("Y", typeof(decimal));
  662. excelTable.Columns.Add("W", typeof(decimal));
  663. excelTable.Columns.Add("H", typeof(decimal));
  664. excelTable.Columns.Add("目标", typeof(int));
  665. excelTable.Columns.Add("类别", typeof(int));
  666. excelTable.Columns.Add("置信度", typeof(decimal));
  667. excelTable.Columns.Add("对比度", typeof(decimal));
  668. // 向 DataTable 中添加数据行
  669. //excelTable.Rows.Add("John Doe", 30);
  670. //excelTable.Rows.Add("Jane Smith", 25);
  671. }
  672. /// <summary>
  673. /// 处理参数
  674. /// </summary>
  675. public int expand_pixel;
  676. public int cm2px_x;
  677. public int cm2px_y;
  678. public Dictionary<int, string> labelDic;
  679. /// <summary>
  680. /// 模型名字
  681. /// </summary>
  682. public string modelName;
  683. public Models.Records record;
  684. //public string bmpPath;//源图路径(仅目录)
  685. /// <summary>
  686. /// 源图(resize后的)
  687. /// </summary>
  688. public Mat bmp;
  689. //public Mat bmpBgr2rgb=new Mat();
  690. public System.Drawing.Size resize = new System.Drawing.Size(224, 224);
  691. //public Mat resizeBmp;//resize后 BGR2RGB图,只用于识别
  692. public Mat bmpTag;
  693. /// <summary>
  694. /// 图片索引0-n
  695. /// </summary>
  696. public int photoIndex;//excel中对应的图像路径标识
  697. public float widthRatio;//宽度比例,resize前/resize后
  698. //切割后
  699. public Mat[] bmps_cut;
  700. //用于比对参数 }//置信度 面积 对比度
  701. public List<QualifiedLimit> qualifiedLimitList;
  702. //推理后结果用于打标
  703. public float[] output;
  704. public int[] output_num;
  705. //
  706. /// <summary>
  707. /// 完成后回调
  708. /// </summary>
  709. public Action<DefectTask> finishEvent;
  710. //==结果返回
  711. public bool isSucceed;//转换是否成功
  712. public string resultInfo = "";//成功或失败信息
  713. public List<Mat> lstDefectBmp = new List<Mat>();
  714. /// <summary>
  715. /// fileIndex,x_mm,y_mm,w_mm,h_mm,目标,类别ID,置信度
  716. /// </summary>
  717. public DataTable excelTable = new DataTable();
  718. public long[] stopwatch = new long[4];
  719. /// <summary>
  720. /// 等比例填充的宽度
  721. /// </summary>
  722. public int xw;
  723. }
  724. }