FaRun.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. using MeterVision.Config;
  2. using MeterVision.model;
  3. using MeterVision.Util;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.Drawing;
  8. using System.Drawing.Imaging;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Runtime.InteropServices;
  12. using System.Text;
  13. using System.Threading.Tasks;
  14. using static MeterVision.FreeAi.FaImport;
  15. namespace MeterVision.FreeAi
  16. {
  17. //识别主程序
  18. public class FaRun
  19. {
  20. //private FaLog faLog; //设备运行日志类
  21. private StringBuilder mRunLog = new StringBuilder();
  22. public event EventHandler<AiRealLogEventArgs> OnAiRealLogInfo;
  23. //ai输出的日志回调函数
  24. private void PrintfCallbackMethod(string message)
  25. {
  26. //Debug.Write(message);
  27. //faLog.Append_aiLog(message);
  28. mRunLog.Append(message);
  29. //发送消息给主程序控件
  30. OnAiRealLogInfo?.Invoke(this, new AiRealLogEventArgs(message));
  31. }
  32. //增加MCU的日志
  33. private void AddMCULog(string message)
  34. {
  35. mRunLog.Append(message + "\n");
  36. OnAiRealLogInfo?.Invoke(this, new AiRealLogEventArgs(message));
  37. }
  38. //开始识别
  39. //public bool StartRecognition(string jpgFile)
  40. //{
  41. // faLog = new FaLog();
  42. // FaImport.PrintfCallback callback = PrintfCallbackMethod;
  43. // short[] rgb565 = FaImageHelper.getRGB565Array_from_jpgfile(jpgFile,faLog);
  44. // FaImport.BeforeAI beforeAI = FaBefore.getBeforeAI(); //new FreeAiImport.BeforeAI();
  45. // FaImport.AfterAI afterAI = new FaImport.AfterAI();
  46. // FaImport.SmallImage smallJpg = new FaImport.SmallImage();
  47. // FaImport.BigImage bigJpg = new FaImport.BigImage();
  48. // string onnxPath = ConfigItem.GetConfigItem().OnnxPath;
  49. // //FaConfig.get_onnxPath();
  50. // //判断onnxPath的路径是否存在
  51. // if (!File.Exists(onnxPath))
  52. // {
  53. // faLog.Appendln_mcuLog("onnxPath error");
  54. // return false;
  55. // }
  56. // //调用识别
  57. // //开始调用c_dll的识别函数
  58. // int result = FaImport.recognition(rgb565, ref beforeAI, ref afterAI, ref smallJpg, ref bigJpg, onnxPath, callback);
  59. // string bigJpg_filePath = @"C:\test_image\result\" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".jpg";
  60. // FaImage.saveBigJpg(bigJpg, bigJpg_filePath);
  61. // return true;
  62. //}
  63. public ResultModel StartRecognition(string jpgFile)
  64. {
  65. //PrintfCallback callback = PrintfCallbackMethod;
  66. ////string jpgFile = resultModel.SrcImage;
  67. ////判断图像尺寸是否合规
  68. //if (!ThisApp.IsImageDimensionsValid(jpgFile))
  69. //{
  70. // Console.WriteLine($"{jpgFile}图像尺寸不合规!");
  71. // return null;
  72. //}
  73. //short[] rgb565 = GetRGB565Array(jpgFile);
  74. //if (rgb565.Length != (320 * 240))
  75. //{
  76. // throw new InvalidOperationException("无效的图像大小。");
  77. //}
  78. //BeforeAI beforeAI = FaBefore.getBeforeAI();
  79. //AfterAI afterAI = new AfterAI();
  80. //SmallImage smallJpg = new SmallImage();
  81. //BigImage bigJpg = new BigImage();
  82. ////string onnxPath = ConfigItem.GetConfigItem().OnnxPath;
  83. //string onnxPath = CfginiItem.GetConfigItem().OnnxPath;
  84. //onnxPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, onnxPath);
  85. ////判断onnxPath的路径是否存在
  86. //if (!File.Exists(onnxPath))
  87. //{
  88. // throw new InvalidOperationException($"onnx文件{onnxPath}不存在!");
  89. //}
  90. ////调用识别
  91. ////开始调用c_dll的识别函数
  92. ////int result;
  93. ////try
  94. ////{
  95. //// result = recognition(rgb565, ref beforeAI, ref afterAI, ref smallJpg, ref bigJpg, onnxPath, callback);
  96. ////}
  97. ////catch(AccessViolationException ex)
  98. ////{
  99. //// // 处理异常,例如记录日志
  100. //// Console.WriteLine("Access violation: " + ex.Message);
  101. ////}
  102. ////调用动态加载的方式
  103. ////初始化加载动态库,
  104. ////string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigItem.GetConfigItem().AiDll);
  105. //string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, CfginiItem.GetConfigItem().AiDll);
  106. //if (!File.Exists(dllPath))
  107. //{
  108. // throw new InvalidOperationException($"AI动态库文件{dllPath}不存在!");
  109. //}
  110. //int result = -1;
  111. //if (DynamicFaImport.Initialize(dllPath))
  112. //{
  113. // try
  114. // {
  115. // result = DynamicFaImport.Recognition(rgb565, ref beforeAI, ref afterAI, ref smallJpg, ref bigJpg, onnxPath, callback);
  116. // }
  117. // catch (AccessViolationException ex)
  118. // {
  119. // // 处理异常,例如记录日志
  120. // Console.WriteLine("Access violation: " + ex.Message);
  121. // }
  122. // catch (Exception ex)
  123. // {
  124. // Console.WriteLine("Exeception: " + ex.Message);
  125. // }
  126. //}
  127. //else
  128. //{
  129. // throw new InvalidOperationException($"初始化AI动态库{dllPath}失败!");
  130. //}
  131. //DynamicFaImport.Unload();
  132. ////存储图像
  133. //string dstImagPath = CfginiItem.GetConfigItem().DstImgPath;
  134. //dstImagPath = Path.Combine(dstImagPath, ThisApp.GetNowTime_yyyyMMdd());
  135. //if (!Directory.Exists(dstImagPath))
  136. //{
  137. // Directory.CreateDirectory(dstImagPath);
  138. //}
  139. //dstImagPath = Path.Combine(dstImagPath, Guid.NewGuid().ToString() + ".jpg");
  140. //SaveBigJpg(bigJpg, dstImagPath);
  141. ////存储日志
  142. //string aiLogPath = CfginiItem.GetConfigItem().AiLogPath;
  143. //aiLogPath = Path.Combine(aiLogPath, ThisApp.GetNowTime_yyyyMMdd());
  144. //if (!Directory.Exists(aiLogPath))
  145. //{
  146. // Directory.CreateDirectory(aiLogPath);
  147. //}
  148. //aiLogPath = Path.Combine(aiLogPath, Guid.NewGuid().ToString() + ".txt");
  149. //try
  150. //{
  151. // if (LicenseMana.mLicenseModel != null && LicenseMana.mLicenseModel.IsPermanent)
  152. // {
  153. // File.WriteAllText(aiLogPath, mRunLog.ToString());
  154. // }
  155. // else
  156. // {
  157. // File.WriteAllText(aiLogPath, "");
  158. // }
  159. //}
  160. //catch(Exception ex)
  161. //{
  162. // throw new InvalidOperationException($"保存文件{aiLogPath}失败:{ex.Message}");
  163. //}
  164. ////结果对象赋值
  165. //ResultModel resultModel = new ResultModel();
  166. //resultModel.SrcImage = jpgFile;
  167. //resultModel.DstImage = dstImagPath;
  168. //resultModel.LogPath = aiLogPath;
  169. //resultModel.MeterType = afterAI.meter_type;
  170. //if(afterAI.meter_type == 1)
  171. //{
  172. // //数字水表: 数字+指针
  173. // resultModel.DigitCount = afterAI.NUM_DETECTED;
  174. // resultModel.PointerCount = afterAI.IND_DETECTED;
  175. //}
  176. //else if(afterAI.meter_type == 2)
  177. //{
  178. // //全指针
  179. // resultModel.DigitCount = 0;
  180. // resultModel.PointerCount = afterAI.NUM_DETECTED;
  181. //}else if(afterAI.meter_type == 3)
  182. //{
  183. // //全数字
  184. // resultModel.DigitCount = afterAI.NUM_DETECTED;
  185. // resultModel.PointerCount = 0;
  186. //}
  187. //else
  188. //{
  189. // resultModel.MeterType = 0;
  190. // resultModel.DigitCount = 0;
  191. // resultModel.PointerCount = 0;
  192. //}
  193. ////1,2,7,8
  194. //resultModel.ResultType = afterAI.AI_result_array[11];
  195. //resultModel.RawValue = afterAI.init_AI_result;
  196. //resultModel.FinalValue = afterAI.AI_result;
  197. //resultModel.LastUnit = afterAI.UNIT_OF_THE_LAST_NUMBER;
  198. //resultModel.AiVer = BitConverter.ToString(afterAI.AI_ver).Replace("-", "");
  199. //resultModel.DebugInfoBytes = afterAI.AI_result_array;
  200. //return resultModel;
  201. return null;
  202. }
  203. public ResultModel StartRecognition(SingleDetailItem detailItem)
  204. {
  205. PrintfCallback callback = PrintfCallbackMethod;
  206. //string jpgFile = resultModel.SrcImage;
  207. //判断图像尺寸是否合规
  208. if (!ThisApp.IsImageDimensionsValid(detailItem.SrcImage))
  209. {
  210. Console.WriteLine($"{detailItem.SrcImage}图像尺寸不合规!");
  211. return null;
  212. }
  213. short[] rgb565 = GetRGB565Array(detailItem.SrcImage);
  214. if (rgb565.Length != (320 * 240))
  215. {
  216. throw new InvalidOperationException("无效的图像大小。");
  217. }
  218. BeforeAI beforeAI = FaBefore.getBeforeAI();
  219. AfterAI afterAI = new AfterAI();
  220. SmallImage smallJpg = new SmallImage();
  221. BigImage bigJpg = new BigImage();
  222. //string onnxPath = ConfigItem.GetConfigItem().OnnxPath;
  223. string onnxPath = CfginiItem.GetConfigItem().OnnxPath;
  224. onnxPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, onnxPath);
  225. //判断onnxPath的路径是否存在
  226. if (!File.Exists(onnxPath))
  227. {
  228. throw new InvalidOperationException($"onnx文件{onnxPath}不存在!");
  229. }
  230. //调用识别
  231. //开始调用c_dll的识别函数
  232. //int result;
  233. //try
  234. //{
  235. // result = recognition(rgb565, ref beforeAI, ref afterAI, ref smallJpg, ref bigJpg, onnxPath, callback);
  236. //}
  237. //catch(AccessViolationException ex)
  238. //{
  239. // // 处理异常,例如记录日志
  240. // Console.WriteLine("Access violation: " + ex.Message);
  241. //}
  242. //调用动态加载的方式
  243. //初始化加载动态库,
  244. //string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigItem.GetConfigItem().AiDll);
  245. string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, CfginiItem.GetConfigItem().AiDll);
  246. if (!File.Exists(dllPath))
  247. {
  248. throw new InvalidOperationException($"AI动态库文件{dllPath}不存在!");
  249. }
  250. int result = -1;
  251. if (DynamicFaImport.Initialize(dllPath))
  252. {
  253. try
  254. {
  255. result = DynamicFaImport.Recognition(rgb565, ref beforeAI, ref afterAI, ref smallJpg, ref bigJpg, onnxPath, callback);
  256. }
  257. catch (AccessViolationException ex)
  258. {
  259. // 处理异常,例如记录日志
  260. Console.WriteLine("Access violation: " + ex.Message);
  261. }
  262. catch (Exception ex)
  263. {
  264. Console.WriteLine("Exeception: " + ex.Message);
  265. }
  266. }
  267. else
  268. {
  269. throw new InvalidOperationException($"初始化AI动态库{dllPath}失败!");
  270. }
  271. DynamicFaImport.Unload();
  272. //存储图像
  273. string dstImagPath = CfginiItem.GetConfigItem().DstImgPath;
  274. dstImagPath = Path.Combine(dstImagPath, ThisApp.GetNowTime_yyyyMMdd());
  275. if (!Directory.Exists(dstImagPath))
  276. {
  277. Directory.CreateDirectory(dstImagPath);
  278. }
  279. dstImagPath = Path.Combine(dstImagPath, Guid.NewGuid().ToString() + ".jpg");
  280. SaveBigJpg(bigJpg, dstImagPath);
  281. //存储日志
  282. string aiLogPath = CfginiItem.GetConfigItem().AiLogPath;
  283. aiLogPath = Path.Combine(aiLogPath, ThisApp.GetNowTime_yyyyMMdd());
  284. if (!Directory.Exists(aiLogPath))
  285. {
  286. Directory.CreateDirectory(aiLogPath);
  287. }
  288. aiLogPath = Path.Combine(aiLogPath, Guid.NewGuid().ToString() + ".txt");
  289. try
  290. {
  291. if (LicenseMana.mLicenseModel != null && LicenseMana.mLicenseModel.IsPermanent)
  292. {
  293. File.WriteAllText(aiLogPath, mRunLog.ToString());
  294. }
  295. else
  296. {
  297. File.WriteAllText(aiLogPath, "");
  298. }
  299. }
  300. catch (Exception ex)
  301. {
  302. throw new InvalidOperationException($"保存文件{aiLogPath}失败:{ex.Message}");
  303. }
  304. //结果对象赋值
  305. ResultModel resultModel = new ResultModel();
  306. resultModel.SrcImage = detailItem.SrcImage;
  307. resultModel.DstImage = dstImagPath;
  308. resultModel.LogPath = aiLogPath;
  309. resultModel.MeterType = afterAI.METER_TYPE;
  310. //1,2,7,8
  311. resultModel.ResultType = afterAI.AI_RESULT_ARRAY[11];
  312. resultModel.RawValue = afterAI.INIT_AI_RESULT;
  313. resultModel.FinalValue = afterAI.AI_RESULT;
  314. if (detailItem.MeterType == 1 || detailItem.MeterType == 3) {
  315. resultModel.LastUnit = beforeAI.UNIT_OF_THE_LAST_NUMBER;
  316. }
  317. else if(detailItem.MeterType == 2)
  318. {
  319. resultModel.LastUnit = beforeAI.UNIT_OF_THE_LAST_INDICATOR;
  320. }
  321. resultModel.AiVer = BitConverter.ToString(afterAI.AI_VER).Replace("-", "");
  322. resultModel.DebugInfoBytes = afterAI.AI_RESULT_ARRAY;
  323. return resultModel;
  324. }
  325. private short[] GetRGB565Array(string jpgFilePath)
  326. {
  327. using (Bitmap bmp = new Bitmap(jpgFilePath))
  328. {
  329. int width = bmp.Width;
  330. int height = bmp.Height;
  331. //string message = string.Format("width = %d,height = %d", width, height);
  332. string message = $"width = {width}, height = {height}";
  333. AddMCULog(message);
  334. //创建数组存储RGB565数据
  335. short[] rgb565Data = new short[width * height];
  336. //给它多分配1倍的内存
  337. //short[] rgb565Data = new short[width * height*2];
  338. //锁定位图内存
  339. BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
  340. IntPtr ptr = bmpData.Scan0;
  341. //创建数据存储RGB888数据
  342. byte[] rgb888Data = new byte[Math.Abs(bmpData.Stride) * height];
  343. //将像素数据拷贝到字节数组中
  344. Marshal.Copy(ptr, rgb888Data, 0, rgb888Data.Length);
  345. // 逐个像素转换为 RGB565 格式,并进行上下颠倒处理
  346. for (int y = 0; y < height; y++)
  347. {
  348. for (int x = 0; x < width; x++)
  349. {
  350. // 颠倒行的顺序
  351. int invertedY = height - 1 - y;
  352. //int index = y * bmpData.Stride + x * 3;
  353. int index = invertedY * bmpData.Stride + x * 3;
  354. byte r = rgb888Data[index + 2]; // R 通道
  355. byte g = rgb888Data[index + 1]; // G 通道
  356. byte b = rgb888Data[index]; // B 通道
  357. // 将 RGB888 转换为 RGB565
  358. short rgb565 = (short)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3));
  359. rgb565Data[y * width + x] = rgb565;
  360. }
  361. }
  362. //解锁位图
  363. bmp.UnlockBits(bmpData);
  364. bmp.Dispose();
  365. return rgb565Data;
  366. }//using Bitmap
  367. }
  368. private bool SaveBigJpg(BigImage bigJpg, string fileName)
  369. {
  370. if (bigJpg.size_of_JPEG_data == 0)
  371. {
  372. //Debug.Write("bigJpg dataSize error!");
  373. AddMCULog("bigJpg dataSize error!");
  374. return false;
  375. }
  376. bool saveResult = false;
  377. try
  378. {
  379. //获取文件夹路径
  380. string directoryPath = Path.GetDirectoryName(fileName);
  381. //如果文件夹不存在,创建文件夹
  382. if (!Directory.Exists(directoryPath))
  383. {
  384. Directory.CreateDirectory(directoryPath);
  385. }
  386. //保存文件
  387. //File.WriteAllBytes(fileName, bigJpg.JPEG_data);
  388. using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
  389. {
  390. fs.Write(bigJpg.JPEG_data, 0, bigJpg.size_of_JPEG_data);
  391. }
  392. saveResult = true;
  393. }
  394. catch (Exception e)
  395. {
  396. AddMCULog(e.Message);
  397. //Debug.Write(e.Message);
  398. }
  399. string strResult = string.Format("save {0} {1}", fileName, saveResult ? "success" : "fail");
  400. //Debug.Write(strResult);
  401. AddMCULog(strResult);
  402. return saveResult;
  403. }
  404. //-------------------------------------------------------------------
  405. }
  406. //日志信息事件
  407. public class AiRealLogEventArgs : EventArgs
  408. {
  409. public string mLogInfo { get; }
  410. public AiRealLogEventArgs(string logInfo)
  411. {
  412. mLogInfo = logInfo;
  413. }
  414. }
  415. //---------------------------------------------------
  416. }