革博士程序V1仓库
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

1148 wiersze
61 KiB

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