Form1.cs 117 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217
  1. using System;
  2. using System.IO;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Data;
  6. using System.Drawing;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. using System.Windows.Forms;
  12. using System.Runtime.InteropServices;
  13. using System.Drawing.Imaging;
  14. using OpenCvSharp;
  15. namespace WinFormsApp_final
  16. {
  17. public partial class Form1 : Form
  18. {
  19. /**********************************************************************/
  20. /***************** 1.推理DLL导入实现 ****************/
  21. /**********************************************************************/
  22. // 加载推理相关方法
  23. [DllImport("model_infer.dll", EntryPoint = "InitModel")] // 模型统一初始化方法: 需要yml、pdmodel、pdiparams
  24. public static extern void InitModel(string model_type, string model_filename, string params_filename, string cfg_file, bool use_gpu, int gpu_id, ref byte paddlex_model_type);
  25. [DllImport("model_infer.dll", EntryPoint = "Det_ModelPredict")] // PaddleDetection模型推理方法
  26. public static extern void Det_ModelPredict(byte[] img, int W, int H, int C, IntPtr output, int[] BoxesNum, ref byte label);
  27. [DllImport("model_infer.dll", EntryPoint = "Seg_ModelPredict")] // PaddleSeg模型推理方法
  28. public static extern void Seg_ModelPredict(byte[] img, int W, int H, int C, ref byte output);
  29. [DllImport("model_infer.dll", EntryPoint = "Cls_ModelPredict")] // PaddleClas模型推理方法
  30. public static extern void Cls_ModelPredict(byte[] img, int W, int H, int C, ref float score, ref byte category, ref int category_id);
  31. [DllImport("model_infer.dll", EntryPoint = "Mask_ModelPredict")] // Paddlex的MaskRCNN模型推理方法
  32. public static extern void Mask_ModelPredict(byte[] img, int W, int H, int C, IntPtr output, ref byte Mask_output, int[] BoxesNum, ref byte label);
  33. [DllImport("model_infer.dll", EntryPoint = "DestructModel")] // 分割、检测、识别模型销毁方法
  34. public static extern void DestructModel();
  35. /**********************************************************************/
  36. /****************** 2.控制参数的声明 *****************/
  37. /**********************************************************************/
  38. // 模型基本参数
  39. string imgfile = null; // 推理的图片路径 -- 单张图片路径
  40. List<string> imgfiles = new List<string>(); // 推理的图片路径 -- 多张图片路径
  41. string videofile = null; // 推理的视频路径
  42. bool use_gpu = false; // 是否使用gpu
  43. int gpu_id = 0; // 默认GPU_ID为0
  44. float det_threshold = 0.5F; // 设置阈值 -- 默认0.5
  45. string model_type = "det"; // 模型类型 -- 检测: det / paddlex
  46. string model_filename = null; // *.pdmodel -- 模型文件
  47. string params_filename = null; // *.pdiparams == 参数文件
  48. string cfg_file = null; // *.yml -- 配置文件
  49. // paddlex模型下的实际模型类型
  50. byte[] paddlex_model_type = new byte[10]; // det/seg/clas + \0
  51. // 记录paddlex模式存在
  52. bool paddlex_doing = false;
  53. // 图片类型
  54. string[] img_type = {"jpg", "png", "JPEG", "jpeg"};
  55. // 模型已完成初始化的标志
  56. static int has_model_init = 0;
  57. // 是否正在进行推理预测
  58. static int is_infer = 0;
  59. // 是否中断推理
  60. static int isBreakInfer = 0;
  61. // 推理线程进行标志
  62. static int infer_one_img_flag = 0;
  63. static int infer_many_img_flag = 0;
  64. static int infer_video_img_flag = 0;
  65. // 连续推理的间隔ms
  66. int continue_infer_delay = 50;
  67. /**********************************************************************/
  68. /************** 3.窗体加载与关闭的实现 ***************/
  69. /**********************************************************************/
  70. public Form1()
  71. {
  72. InitializeComponent();
  73. }
  74. private void Form1_Load(object sender, EventArgs e)
  75. {
  76. comboBox1.SelectedIndex = 0; // 初始运行环境 -- cpu
  77. comboBox2.SelectedIndex = 0; // 初始模型 -- det
  78. comboBox3.SelectedIndex = 5; // 初始阈值 -- 0.5
  79. numericUpDown1.Value = 50; // 设置初始连续推理间隔为50ms
  80. label7.Text = "0.00"; // 默认推理耗时
  81. textBox1.Text = "0"; // 默认GPU_ID为0
  82. }
  83. private void Form1_FromClosing(object sender, EventArgs e)
  84. {
  85. while (is_infer != 0) // 有推理进程在运行
  86. {
  87. isBreakInfer = 1; // 关掉进程
  88. } // 等待推理进程完全结束
  89. if (has_model_init == 1) // 有初始化的模型存在,销毁模型后正常退出
  90. {
  91. DestructModel(); // 销毁模型
  92. }
  93. }
  94. /**********************************************************************/
  95. /***************** 4.细节参数选项实现 ***************/
  96. /**********************************************************************/
  97. int comboBox_clicked = 0;
  98. int comboBox1_last_index = 0;
  99. // 选择运行环境 - 是否使用GPU
  100. private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
  101. {
  102. // 推理过程中,不支持运行环境选择
  103. if (is_infer == 1 && comboBox_clicked == 0)
  104. {
  105. MessageBox.Show("正在推理中,请推理完成后再选择运行环境重新初始化!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
  106. comboBox_clicked = 1;
  107. comboBox1.SelectedIndex = comboBox1_last_index; // 使用上一次改变后得到的index
  108. return;
  109. }
  110. // 已经初始化,不支持运行环境选择
  111. if (has_model_init == 1 && comboBox_clicked == 0)
  112. {
  113. MessageBox.Show("模型已初始化,请销毁模型后再进行运行环境选择!\n(CPU,GPU)", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
  114. comboBox_clicked = 1;
  115. comboBox1.SelectedIndex = comboBox1_last_index; // 使用上一次改变后得到的index
  116. return;
  117. }
  118. // 对应两种运行环境
  119. if (comboBox1.SelectedItem.ToString() == "GPU") // 使用gpu
  120. {
  121. use_gpu = true;
  122. }
  123. else if (comboBox1.SelectedItem.ToString() == "CPU")
  124. {
  125. use_gpu = false;
  126. }
  127. comboBox1_last_index = comboBox1.SelectedIndex;
  128. comboBox_clicked = 0;
  129. }
  130. // 修改GPU_ID -- 指定gpu
  131. int last_gpu_id = 0;
  132. int gpu_id_done = 0;
  133. private void textBox1_TextChanged(object sender, EventArgs e)
  134. {
  135. // 推理过程中,不支持GPU指定 -- 未定义操作
  136. if (is_infer == 1 && gpu_id_done == 0)
  137. {
  138. MessageBox.Show("正在推理中,请推理完成后再选择指定GPU重新初始化!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
  139. gpu_id_done = 1;
  140. gpu_id = last_gpu_id;
  141. textBox1.Text = $"{gpu_id}";
  142. return;
  143. }
  144. // 已经初始化,不支持GPU指定 -- 未定义操作
  145. if (has_model_init == 1 && gpu_id_done == 0)
  146. {
  147. MessageBox.Show("模型已初始化,请销毁模型后再进行GPU指定!\n(GPU:x)", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
  148. gpu_id_done = 1;
  149. gpu_id = last_gpu_id;
  150. textBox1.Text = $"{gpu_id}";
  151. return;
  152. }
  153. if (gpu_id_done == 0) // 定义操作下的修改才会执行以下内容
  154. {
  155. string gpu_id_str = textBox1.Text.ToString();
  156. if (gpu_id_str.Length != 0)
  157. {
  158. last_gpu_id = gpu_id;
  159. try
  160. {
  161. gpu_id = Int32.Parse(gpu_id_str); // 获取新的GPU_id
  162. }
  163. catch (Exception ex)
  164. {
  165. gpu_id = last_gpu_id;
  166. textBox1.Text = $"{gpu_id}";
  167. MessageBox.Show("GPU_ID只能输入数字!");
  168. }
  169. }
  170. }
  171. gpu_id_done = 0; // 复原状态值
  172. }
  173. int comboBox2_last_index = 0;
  174. // 执行推理的模型的类型选择
  175. private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
  176. {
  177. // 推理过程中,不支持模型类型选择
  178. if (is_infer == 1 && comboBox_clicked == 0)
  179. {
  180. MessageBox.Show("正在推理中,请推理完成后再选择模型类型重新初始化!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
  181. comboBox_clicked = 1;
  182. comboBox2.SelectedIndex = comboBox2_last_index; // 使用上一次改变后得到的index
  183. return;
  184. }
  185. // 已经初始化,发出警告,提示重新初始化,模型类型的修改才会生效
  186. if (has_model_init == 1 && comboBox_clicked == 0)
  187. {
  188. MessageBox.Show("模型已初始化,请销毁模型后再进行模型类型选择!\n(det,seg,clas)", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
  189. comboBox_clicked = 1;
  190. comboBox2.SelectedIndex = comboBox2_last_index; // 使用上一次改变后得到的index
  191. return;
  192. }
  193. // 对应三种类型
  194. if (comboBox2.SelectedItem.ToString() == "det") // 加载检测模型 -- 推理已实现
  195. {
  196. model_type = comboBox2.SelectedItem.ToString();
  197. paddlex_doing = false; // 进入非paddlex模式 -- 检测
  198. }
  199. else if (comboBox2.SelectedItem.ToString() == "seg") // 加载分割模型 -- 推理已实现
  200. {
  201. model_type = comboBox2.SelectedItem.ToString();
  202. paddlex_doing = false; // 进入非paddlex模式 -- 分割
  203. }
  204. else if (comboBox2.SelectedItem.ToString() == "clas") // 加载识别模型 -- 推理已实现
  205. {
  206. model_type = comboBox2.SelectedItem.ToString();
  207. paddlex_doing = false; // 进入非paddlex模式 -- 识别
  208. }
  209. else if (comboBox2.SelectedItem.ToString() == "mask") // 加载实例分割MaskRCNN模型 -- 推理已实现
  210. {
  211. model_type = comboBox2.SelectedItem.ToString();
  212. paddlex_doing = false; // 进入非paddlex模式 -- 实则也为paddlex导出的模型
  213. }
  214. else if (comboBox2.SelectedItem.ToString() == "paddlex") // 加载识别模型 -- 推理已实现
  215. {
  216. model_type = comboBox2.SelectedItem.ToString();
  217. // 重复选中paddlex,不修改状态
  218. }
  219. comboBox2_last_index = comboBox2.SelectedIndex;
  220. comboBox_clicked = 0;
  221. }
  222. int comboBox3_last_index = 0;
  223. // 设置目标检测的检测阈值
  224. private void comboBox3_SelectedIndexChanged(object sender, EventArgs e)
  225. {
  226. // 推理过程中,不支持检测阈值选择
  227. if (is_infer == 1 && comboBox_clicked == 0)
  228. {
  229. MessageBox.Show("正在推理中,检测阈值修改将在本次模型推理完成后生效!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
  230. comboBox_clicked = 1;
  231. comboBox3.SelectedIndex = comboBox3_last_index; // 使用上一次改变后得到的index
  232. return;
  233. }
  234. // 修改检测阈值
  235. det_threshold = float.Parse(comboBox3.SelectedItem.ToString());
  236. comboBox3_last_index = comboBox3.SelectedIndex; // 保存本次的索引
  237. comboBox_clicked = 0;
  238. }
  239. // 连续推理的间隔时间长度 -- 图片文件夹推理
  240. private void numericUpDown1_ValueChanged(object sender, EventArgs e)
  241. {
  242. // 配置连续推理的延时
  243. continue_infer_delay = ((int)numericUpDown1.Value);
  244. }
  245. /**********************************************************************/
  246. /***************** 5.选择控制组件实现 ***************/
  247. /**********************************************************************/
  248. // 加载模型相关文件的文件夹 -- 测试完成
  249. private void button1_Click(object sender, EventArgs e)
  250. {
  251. // 推理过程中,不支持模型初始化
  252. if (is_infer == 1)
  253. {
  254. MessageBox.Show("正在推理中,请推理完成后再初始化加载模型!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  255. return;
  256. }
  257. // 先检查MaskRCNN启动状态
  258. if (!CheckMaskRCNN_workOnGpu(model_type, use_gpu)) // MaskRCNN环境不在GPU,则报错提醒
  259. {
  260. MessageBox.Show("MaskRCNN推理仅支持GPU环境,请重新选择启动环境!\n(因为CPU环境可能存在内存不足,导致推理失败。)", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  261. return;
  262. }
  263. int dir_load_flag = 0; // 文件夹选择的标志位
  264. string dir_path = null;
  265. folderBrowserDialog1.Description = "请选择模型文件夹";
  266. DialogResult folder = folderBrowserDialog1.ShowDialog();
  267. if (folder == DialogResult.OK || folder == DialogResult.Yes)
  268. {
  269. dir_path = folderBrowserDialog1.SelectedPath;
  270. if (string.IsNullOrEmpty(dir_path)) // 判断是否选择了模型文件
  271. {
  272. MessageBox.Show("请选择模型路径/模型路径为空!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  273. dir_load_flag = 0;
  274. }
  275. else
  276. {
  277. dir_load_flag = 1;
  278. }
  279. }
  280. if (dir_load_flag == 1) // 寻找模型文件
  281. {
  282. List<FileInfo> model_lst = new List<FileInfo>();
  283. List<FileInfo> params_lst = new List<FileInfo>();
  284. List<FileInfo> cfg_lst = new List<FileInfo>();
  285. model_lst = getFile(dir_path, ".pdmodel", model_lst); // 返回匹配的文件
  286. params_lst = getFile(dir_path, ".pdiparams", params_lst); // 返回匹配的文件
  287. cfg_lst = getFile(dir_path, ".yml", cfg_lst); // 返回匹配的文件
  288. if (cfg_lst.Count == 0)
  289. cfg_lst = getFile(dir_path, ".yaml", cfg_lst); // 返回匹配的文件
  290. if (model_lst.Count != 1 || params_lst.Count != 1)
  291. {
  292. MessageBox.Show("模型文件加载失败!\n请注意模型文件夹下应包含以下文件各一个:\n*.pdmodel, *.pdiparams", "提示");
  293. return;
  294. }
  295. model_filename = model_lst[0].FullName;
  296. params_filename = params_lst[0].FullName;
  297. if (cfg_lst.Count == 0) // 没有yml文件
  298. {
  299. MessageBox.Show("模型文件加载失败!\n请注意模型文件夹下应包含以下文件:\nmodel.yml/model.yaml", "提示");
  300. return;
  301. }
  302. else if (cfg_lst.Count > 2) // yml过多, > 2
  303. {
  304. MessageBox.Show("模型文件加载失败!\n请注意模型文件夹下应至多包含以下文件(yml文件个数不得超过2):\nmodel.yml/model.yaml,pipeline.yml/pipeline.yaml", "提示");
  305. return;
  306. }
  307. else if (cfg_lst.Count == 2) // 对于包含多个yml文件的情况的处理 , == 2, 及针对paddlex的处理
  308. {
  309. // 筛选yml文件 -- 只需要model.yml
  310. for (int i = 0; i < 2; i++)
  311. {
  312. if (cfg_lst[i].Name == "model.yml" || cfg_lst[i].Name == "model.yaml")
  313. {
  314. cfg_file = cfg_lst[i].FullName;
  315. break;
  316. }
  317. }
  318. }
  319. else if (cfg_lst.Count == 1) // 直接取出唯一的yml文件
  320. {
  321. cfg_file = cfg_lst[0].FullName;
  322. }
  323. int raise_ex_flag = 0; // 是否发生了异常
  324. int is_Mask = 0; // 当前初始化模型是否未MaskRCNN
  325. if (has_model_init == 1) // 已经初始化,再次初始化前要完成上一个模型的销毁
  326. {
  327. // 销毁模型
  328. DestructModel();
  329. // 初始化模型
  330. try
  331. {
  332. // 保持paddlex模式
  333. if (paddlex_doing == true) model_type = "paddlex";
  334. if (model_type == "mask")
  335. {
  336. model_type = "paddlex"; // 因为MaskRCNN来自paddlex训练,所以这里先转未paddlex
  337. is_Mask = 1;
  338. }
  339. InitModel(model_type, model_filename, params_filename, cfg_file, use_gpu, gpu_id, ref paddlex_model_type[0]);
  340. if (is_Mask == 1) // 初始化完成后还原model_type
  341. {
  342. model_type = "mask";
  343. }
  344. if (model_type == "paddlex") // 如果当前初始模型类型为paddlex,则初始化完成后,转为paddlex模型的实际类型
  345. {
  346. paddlex_doing = true; // 进入paddlex类型模式
  347. model_type = System.Text.Encoding.UTF8.GetString(paddlex_model_type).Split('\0')[0]; // 得到实际运行的模型类型 -- Split去掉多余的\0(原byte[]长度为10,有许多多余的\0)
  348. }
  349. }
  350. catch (Exception ex)
  351. {
  352. raise_ex_flag = 1; // 发生了异常
  353. MessageBox.Show("1.请确定文件中包含有效的模型文件(*.pdmodel, *.pdiparams, *.yml)!\n2.请检查模型文件与模型类型是否一致!\n3.其它原因:GPU号有误,yml中预处理有误...", "模型初始化失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  354. }
  355. }
  356. else
  357. {
  358. // 初始化模型
  359. try
  360. {
  361. // 保持paddlex模式
  362. if (paddlex_doing == true) model_type = "paddlex";
  363. if (model_type == "mask")
  364. {
  365. model_type = "paddlex"; // 因为MaskRCNN来自paddlex训练,所以这里先转未paddlex
  366. is_Mask = 1;
  367. }
  368. InitModel(model_type, model_filename, params_filename, cfg_file, use_gpu, gpu_id, ref paddlex_model_type[0]);
  369. if (is_Mask == 1) // 初始化完成后还原model_type
  370. {
  371. model_type = "mask";
  372. }
  373. if (model_type == "paddlex") // 如果当前初始模型类型为paddlex,则初始化完成后,转为paddlex模型的实际类型
  374. {
  375. paddlex_doing = true; // 进入paddlex类型模式
  376. model_type = System.Text.Encoding.UTF8.GetString(paddlex_model_type).Split('\0')[0]; // 得到实际运行的模型类型
  377. }
  378. }
  379. catch (Exception ex)
  380. {
  381. raise_ex_flag = 1; // 发生了异常
  382. MessageBox.Show("1.请确定文件中包含有效的模型文件(*.pdmodel, *.pdiparams, *.yml)!\n2.请检查模型文件与模型类型是否一致!\n3.其它原因:GPU号有误,yml中预处理有误...", "模型初始化失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  383. }
  384. }
  385. if (raise_ex_flag == 0) // 未发生异常时,才进行正常的运行提示
  386. {
  387. has_model_init = 1; // 已经完成初始化
  388. if (use_gpu)
  389. {
  390. MessageBox.Show($"模型文件已加载到GPU:{gpu_id}!\n(模型类型为: {model_type.Split('\0')[0]})", "提示");
  391. }
  392. else
  393. {
  394. MessageBox.Show($"模型类型为: {model_type.Split('\0')[0]}", "提示");
  395. }
  396. button1.Text = "模型已初始化"; // 更改按键提示信息
  397. }
  398. }
  399. }
  400. // 加载单张图片 -- 测试完成
  401. private void button2_Click(object sender, EventArgs e)
  402. {
  403. // 推理过程中,不支持推理数据集选择与加载
  404. if (is_infer == 1)
  405. {
  406. MessageBox.Show("正在推理中,请推理完成后再选择推理数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  407. return;
  408. }
  409. int has_load_img_file_flag = 1;
  410. openFileDialog1.Filter = "(*.png;*.jpg;*.JPEG;*.jpeg)|*.*"; // 设置打开的文件类型
  411. DialogResult dr = openFileDialog1.ShowDialog();
  412. //获取所打开文件的文件名
  413. string filename = openFileDialog1.FileName;
  414. if (dr != System.Windows.Forms.DialogResult.OK || string.IsNullOrEmpty(filename)) // 检验文件是否选择成功
  415. {
  416. has_load_img_file_flag = 0; // 没有读取到图片路径
  417. }
  418. if (has_load_img_file_flag==1) // 正确加载图片才有以下执行
  419. {
  420. // 划分文件,获取后缀
  421. string[] final_tag = filename.Split('.');
  422. int flag = 0;
  423. foreach (string type in img_type)
  424. {
  425. if (final_tag[1] == type)
  426. {
  427. flag = 1; // 类型满足预置图片类型时,flag为1
  428. imgfile = filename; // 单张图片
  429. // 显示加载的图片
  430. pictureBox1.Image = Image.FromFile(imgfile);
  431. pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
  432. // 清空其它推理数据的来源
  433. videofile = null;
  434. imgfiles.Clear(); // 加载单张图片,清空文件夹图片索引
  435. MessageBox.Show("图片加载完成!", "提示");
  436. button2.Text = "图片已加载"; // 更改按键提示信息
  437. button3.Text = "加载图片文件夹"; // 更改按键提示信息
  438. button4.Text = "加载视频流"; // 更改按键提示信息
  439. }
  440. }
  441. }
  442. }
  443. // 加载文件夹图片
  444. private void button3_Click(object sender, EventArgs e)
  445. {
  446. // 推理过程中,不支持推理数据集选择与加载
  447. if (is_infer == 1)
  448. {
  449. MessageBox.Show("正在推理中,请推理完成后再选择推理数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  450. return;
  451. }
  452. int img_dir_load_flag = 0;
  453. string img_dir_path = null;
  454. folderBrowserDialog1.Description = "请选择模型文件夹";
  455. DialogResult folder = folderBrowserDialog1.ShowDialog();
  456. if (folder == DialogResult.OK || folder == DialogResult.Yes)
  457. {
  458. img_dir_path = folderBrowserDialog1.SelectedPath;
  459. if (string.IsNullOrEmpty(img_dir_path)) // 判断是否选择了模型文件
  460. {
  461. MessageBox.Show("请选择图片文件夹路径/图片文件夹路径为空!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  462. img_dir_load_flag = 0;
  463. }
  464. else
  465. {
  466. img_dir_load_flag = 1;
  467. }
  468. }
  469. if (img_dir_load_flag == 1) // 读取文件夹中的指定图片文件
  470. {
  471. List<FileInfo> lst = new List<FileInfo>();
  472. lst = getFile(img_dir_path, ".jpg", lst); // 返回匹配的文件
  473. lst = getFile(img_dir_path, ".png", lst); // 返回匹配的文件
  474. lst = getFile(img_dir_path, ".JPEG", lst); // 返回匹配的文件
  475. foreach (FileInfo Image_File in lst) // 添加文件
  476. {
  477. imgfiles.Add(Image_File.FullName);
  478. }
  479. if (imgfiles.Count == 0)
  480. {
  481. MessageBox.Show("请输入选择非空/包含正确图片类型的图片文件夹!\n(*.png, *.jpg, *.JPEG)", "图片解析失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  482. return; // 提前终止该函数操作 -- 保留原有加载数据
  483. }
  484. // 展示第一张图片
  485. // 显示加载的图片
  486. pictureBox1.Image = Image.FromFile(imgfiles[0]);
  487. pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
  488. // 清空其它推理数据的来源
  489. imgfile = null; // 既然加载文件夹,则单张图片的索引应该清空
  490. videofile = null;
  491. MessageBox.Show("图片文件夹加载完成!", "提示");
  492. button3.Text = "图片文件夹已加载"; // 更改按键提示信息
  493. button2.Text = "加载图片"; // 更改按键提示信息
  494. button4.Text = "加载视频流"; // 更改按键提示信息
  495. }
  496. }
  497. // 加载视频流
  498. private void button4_Click(object sender, EventArgs e)
  499. {
  500. // 推理过程中,不支持模型初始化
  501. if (is_infer == 1)
  502. {
  503. MessageBox.Show("正在推理中,请推理完成后再选择推理数据!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  504. return;
  505. }
  506. int has_load_mp4_file_flag = 1;
  507. openFileDialog1.Filter = "(*.mp4)|*.*"; // 设置打开的文件类型
  508. DialogResult dr = openFileDialog1.ShowDialog();
  509. //获取所打开文件的文件名
  510. string filename = openFileDialog1.FileName;
  511. if (dr != System.Windows.Forms.DialogResult.OK || string.IsNullOrEmpty(filename)) // 检验文件是否选择成功
  512. {
  513. if (string.IsNullOrEmpty(filename)) MessageBox.Show("请选择视频(*.mp4)文件!", "视频路径为空", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  514. has_load_mp4_file_flag = 0;
  515. }
  516. if (has_load_mp4_file_flag==1) // 读取到视频mp4
  517. {
  518. // 划分文件,获取后缀
  519. string[] final_tag = filename.Split('.');
  520. if (final_tag[1] == "mp4")
  521. {
  522. videofile = filename; // mp4视频路径
  523. Bitmap image = null;
  524. Mat frame = new Mat();
  525. VideoCapture capture = new VideoCapture(); // 创建一个摄像头
  526. capture.Open(videofile);
  527. bool read_success = capture.Read(frame); // 帧是否读取成功
  528. if (!read_success)
  529. {
  530. MessageBox.Show("无法读取视频的帧!!!", "提示");
  531. }
  532. else
  533. {
  534. image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frame);
  535. // 显示加载的视频的第一帧
  536. pictureBox1.Image = image;
  537. pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
  538. capture = null; // 收回内存
  539. frame = null; // 收回内存
  540. image = null; // 收回内存
  541. // 清空其它推理数据的来源
  542. imgfile = null;
  543. imgfiles.Clear(); // 加载单张图片,清空文件夹图片索引
  544. MessageBox.Show("视频加载完成!", "提示");
  545. button4.Text = "视频流已加载"; // 更改按键提示信息
  546. button2.Text = "加载图片"; // 更改按键提示信息
  547. button3.Text = "加载图片文件夹"; // 更改按键提示信息
  548. }
  549. }
  550. else
  551. {
  552. // 保持原有数据加载情况,并发出错误警告
  553. MessageBox.Show("请选择mp4视频文件!", "视频资源加载失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  554. }
  555. }
  556. }
  557. // 执行推理
  558. private void button5_Click(object sender, EventArgs e)
  559. {
  560. // has_model_init: 确保模型已经初始化
  561. if (imgfile != null && is_infer==0 && has_model_init == 1) // 单张图片的预测 -- is_infer 等于 0, 表示没有任何进程在运行
  562. {
  563. Thread infer_one_img_thread = null;
  564. if (model_type == "det") infer_one_img_thread = new Thread(new ThreadStart(delegate { det_infer_one_img(); }));
  565. else if (model_type == "seg") infer_one_img_thread = new Thread(new ThreadStart(delegate { seg_infer_one_img(); }));
  566. else if (model_type == "clas") infer_one_img_thread = new Thread(new ThreadStart(delegate { cls_infer_one_img(); }));
  567. else if (model_type == "mask") infer_one_img_thread = new Thread(new ThreadStart(delegate { mask_infer_one_img(); }));
  568. MessageBox.Show("开始图片推理任务!", "提示");
  569. infer_one_img_thread.Start(); // 启动任务
  570. infer_one_img_flag = 1; // 标志着图片正在推理执行
  571. }
  572. else if (imgfiles.Count != 0 && is_infer == 0 && has_model_init == 1) // 图片文件夹的预测
  573. {
  574. Thread infer_many_img_thread = null;
  575. if (model_type == "det") infer_many_img_thread = new Thread(new ThreadStart(delegate { det_infer_many_img(); }));
  576. else if (model_type == "seg") infer_many_img_thread = new Thread(new ThreadStart(delegate { seg_infer_many_img(); }));
  577. else if (model_type == "clas") infer_many_img_thread = new Thread(new ThreadStart(delegate { cls_infer_many_img(); }));
  578. else if (model_type == "mask") infer_many_img_thread = new Thread(new ThreadStart(delegate { mask_infer_many_img(); }));
  579. MessageBox.Show("开始图片文件夹推理任务!", "提示");
  580. infer_many_img_thread.Start(); // 启动任务
  581. infer_many_img_flag = 1; // 标志着图片文件夹正在推理执行
  582. }
  583. else if (videofile != null && is_infer == 0 && has_model_init == 1)
  584. {
  585. Thread infer_video_img_thread = null;
  586. if (model_type == "det") infer_video_img_thread = new Thread(new ThreadStart(delegate { det_infer_video_img(); }));
  587. else if (model_type == "seg") infer_video_img_thread = new Thread(new ThreadStart(delegate { seg_infer_video_img(); }));
  588. else if (model_type == "clas") infer_video_img_thread = new Thread(new ThreadStart(delegate { cls_infer_video_img(); }));
  589. else if (model_type == "mask") infer_video_img_thread = new Thread(new ThreadStart(delegate { mask_infer_video_img(); }));
  590. MessageBox.Show("开始视频推理任务!", "提示");
  591. infer_video_img_thread.Start(); // 启动任务
  592. infer_video_img_flag = 1; // 标志着视频正在推理执行
  593. }
  594. else if (is_infer == 1 && has_model_init == 1)
  595. {
  596. if (infer_one_img_flag == 1) MessageBox.Show("正在进行推理任务!", "请勿再执行图片推理任务", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  597. if (infer_many_img_flag == 1) MessageBox.Show("正在进行推理任务!", "请勿再执行图片文件夹推理任务", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  598. if (infer_video_img_flag == 1) MessageBox.Show("正在进行推理任务!", "请勿再执行视频推理任务", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  599. }
  600. if (has_model_init == 0 && (imgfile == null && imgfiles.Count == 0 && videofile == null)) // 模型未初始化,数据未加载
  601. {
  602. MessageBox.Show("请先初始化模型,并选择加载的推理数据后,再点击模型推理!", "推理执行失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  603. }
  604. else if (has_model_init == 0 && (imgfile != null || imgfiles.Count != 0 || videofile != null)) // 模型未初始化,数据加载
  605. {
  606. MessageBox.Show("请初始化模型,再点击模型推理!", "推理执行失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  607. }
  608. else if (has_model_init != 0 && (imgfile == null && imgfiles.Count == 0 && videofile == null)) // 模型初始化,数据未加载
  609. {
  610. MessageBox.Show("请选择加载的推理数据,再点击模型推理!", "推理执行失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  611. }
  612. }
  613. // 终止推理
  614. private void button6_Click(object sender, EventArgs e)
  615. {
  616. isBreakInfer = 1; // 发出推理终止的信号 -- 线程会开始终止(非kill终止)
  617. }
  618. // 销毁已初始化好的模型
  619. private void button7_Click(object sender, EventArgs e)
  620. {
  621. if (is_infer == 0)
  622. {
  623. if (has_model_init == 1)
  624. {
  625. // 销毁模型
  626. try // 进行未定义的模型销毁时的异常处理
  627. {
  628. DestructModel();
  629. }
  630. catch (Exception ex)
  631. {
  632. MessageBox.Show("当前未初始化模型,无需销毁!", "模型销毁失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  633. }
  634. has_model_init = 0;
  635. }
  636. button1.Text = "初始化模型"; // 重置按键状态
  637. }
  638. else
  639. {
  640. MessageBox.Show("请先中断模型推理,再销毁已初始化的模型!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
  641. }
  642. }
  643. /***********************************************************************/
  644. /***************** 6.可视化推理实现部分 **************/
  645. /***********************************************************************/
  646. // 检测单张图片
  647. private void det_infer_one_img()
  648. {
  649. is_infer = 1; // 进入推理
  650. byte[] color_map = get_color_map_list(256);
  651. //Bitmap bmp = new Bitmap(imgfile);
  652. Bitmap bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(Cv2.ImRead(imgfile));
  653. byte[] inputData = GetBGRValues(bmp, out int stride);
  654. float[] resultlist = new float[600];
  655. IntPtr results = FloatToIntptr(resultlist);
  656. int[] boxesInfo = new int[1]; // 10 boundingbox
  657. byte[] labellist = new byte[1000]; //新建字节数组:label1_str label2_str
  658. int raise_ex_flag = 0; // 是否发生了异常
  659. try
  660. {
  661. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  662. // 第四个参数为输入图像的通道数
  663. Det_ModelPredict(inputData, bmp.Width, bmp.Height, 3, results, boxesInfo, ref labellist[0]);
  664. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  665. string strGet = System.Text.Encoding.Default.GetString(labellist, 0, labellist.Length); //将字节数组转换为字符串
  666. string[] predict_Label_List = strGet.Split(' '); // 预测的类别情况
  667. // MessageBox.Show($"Box_Number: {boxesInfo[0]}");
  668. using OpenCvSharp.Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);//用bitmap转换为mat
  669. for (int i = 0; i < boxesInfo[0]; i++) // 未绘制图像
  670. {
  671. int labelindex = Convert.ToInt32(resultlist[i * 6 + 0]);
  672. float score = resultlist[i * 6 + 1];
  673. float left = resultlist[i * 6 + 2];
  674. float top = resultlist[i * 6 + 3];
  675. float right = resultlist[i * 6 + 4];
  676. float down = resultlist[i * 6 + 5];
  677. if (score > det_threshold)
  678. {
  679. int[] color_ = { (int)(color_map[(labelindex%256)*3]),
  680. (int)(color_map[(labelindex % 256) * 3 + 1]),
  681. (int)(color_map[(labelindex % 256) * 3 + 2]) };
  682. // 获取文本区域的大小
  683. var text_size = Cv2.GetTextSize($"{predict_Label_List[i]}-{labelindex}-{score:f2}",
  684. HersheyFonts.HersheySimplex, 1, 2, out int baseline); // 1倍大小的HersheySimplex,高度为22
  685. // 获取文本区域的左下顶点 -- 右上角
  686. int left_down_x = (int)left + 22; // 小偏移调整量: (int)(text_size.Width/10)
  687. int left_down_y = (int)top + text_size.Height;
  688. // 绘制矩形,书写类别
  689. Cv2.Rectangle(mat, new OpenCvSharp.Rect((int)left, (int)top, (int)right, (int)down), new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.AntiAlias);//LineTypes.AntiAlias:反锯齿效果
  690. Cv2.PutText(mat, $"{predict_Label_List[i]}-{labelindex}-: {score:f2}", new OpenCvSharp.Point(left_down_x, left_down_y), HersheyFonts.HersheySimplex, 1, new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.Link4);
  691. }
  692. }
  693. // 转换回bitmap进行显示
  694. bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  695. // 反馈到另一个picturebox上
  696. if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
  697. pictureBox2.Image = bmp;
  698. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  699. // 展示推理耗时
  700. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  701. double cost_milliseconds = start2end_time.TotalMilliseconds;
  702. // 通过委托展示到label上
  703. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  704. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  705. }
  706. catch (Exception e)
  707. {
  708. raise_ex_flag = 1;
  709. // 默认耗时为0ms
  710. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  711. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  712. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  713. }
  714. isBreakInfer = 0; // 清空标志
  715. is_infer = 0; // 退出推理 -- 解除推理状态
  716. infer_one_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  717. if (raise_ex_flag == 0) MessageBox.Show("图片推理完成!"); // 未发生异常,正常显示推理完成提示
  718. }
  719. // 检测图片文件夹
  720. private void det_infer_many_img()
  721. {
  722. is_infer = 1; // 进入推理
  723. byte[] color_map = get_color_map_list(256);
  724. int raise_ex_flag = 0; // 是否发生了异常
  725. try
  726. {
  727. foreach (string img_file in imgfiles)
  728. {
  729. if (isBreakInfer == 1) break; // 中断推理
  730. Bitmap show_image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(Cv2.ImRead(img_file));
  731. Bitmap bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(Cv2.ImRead(img_file));
  732. byte[] inputData = GetBGRValues(bmp, out int stride);
  733. float[] resultlist = new float[600];
  734. IntPtr results = FloatToIntptr(resultlist);
  735. int[] boxesInfo = new int[1];
  736. byte[] labellist = new byte[1000]; //新建字节数组
  737. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  738. //第四个参数为输入图像的通道数
  739. Det_ModelPredict(inputData, bmp.Width, bmp.Height, 3, results, boxesInfo, ref labellist[0]);
  740. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  741. string strGet = System.Text.Encoding.Default.GetString(labellist, 0, labellist.Length); //将字节数组转换为字符串
  742. string[] predict_Label_List = strGet.Split(' '); // 预测的类别情况
  743. //MessageBox.Show($"Box_Number: {boxesInfo[0]}");
  744. //Console.WriteLine("labellist: {0}", strGet);
  745. // 转换为mat数据,方便opencv处理
  746. using OpenCvSharp.Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);//用bitmap转换为mat
  747. for (int i = 0; i < boxesInfo[0]; i++) // 未绘制图像
  748. {
  749. int labelindex = Convert.ToInt32(resultlist[i * 6 + 0]);
  750. float score = resultlist[i * 6 + 1];
  751. float left = resultlist[i * 6 + 2];
  752. float top = resultlist[i * 6 + 3];
  753. float right = resultlist[i * 6 + 4]; // det -- right down
  754. float down = resultlist[i * 6 + 5];
  755. if (score > det_threshold)
  756. {
  757. int[] color_ = { (int)(color_map[(labelindex%256)*3]),
  758. (int)(color_map[(labelindex % 256) * 3 + 1]),
  759. (int)(color_map[(labelindex % 256) * 3 + 2]) };
  760. // 获取文本区域的大小
  761. var text_size = Cv2.GetTextSize($"{predict_Label_List[i]}-{labelindex}-{score:f2}",
  762. HersheyFonts.HersheySimplex, 1, 2, out int baseline); // 1倍大小的HersheySimplex,高度为22
  763. // 获取文本区域的左下顶点 -- 右上角
  764. int left_down_x = (int)left + 22; // 小偏移调整量: (int)(text_size.Width/10)
  765. int left_down_y = (int)top + text_size.Height;
  766. // 绘制矩形,书写类别
  767. Cv2.Rectangle(mat, new OpenCvSharp.Rect((int)left, (int)top, (int)right, (int)down), new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.AntiAlias);//LineTypes.AntiAlias:反锯齿效果
  768. Cv2.PutText(mat, $"{predict_Label_List[i]}-{labelindex}-: {score:f2}", new OpenCvSharp.Point(left_down_x, left_down_y), HersheyFonts.HersheySimplex, 1, new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.Link4);
  769. }
  770. }
  771. // 转换回bitmap进行显示
  772. bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  773. // 显示图片
  774. if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
  775. pictureBox1.Image = show_image; //显示原始图片到box1
  776. pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; //显示原始图片到box1
  777. // 反馈到另一个picturebox上
  778. if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
  779. pictureBox2.Image = bmp;
  780. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  781. // 展示推理耗时
  782. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  783. double cost_milliseconds = start2end_time.TotalMilliseconds;
  784. // 通过委托展示到label上
  785. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  786. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  787. Thread.Sleep(continue_infer_delay); // 连续识别时,每张图片间隔continue_infer_delay毫秒
  788. }
  789. }
  790. catch (Exception e)
  791. {
  792. raise_ex_flag = 1;
  793. // 默认耗时为0ms
  794. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  795. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  796. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  797. }
  798. isBreakInfer = 0; // 清空标志
  799. // DestructModel(); // 销毁模型
  800. is_infer = 0; // 退出推理 -- 解除推理状态
  801. infer_many_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  802. if (raise_ex_flag == 0) MessageBox.Show("图片文件夹推理完成!"); // 未发生异常,正常显示推理完成提示
  803. }
  804. // 检测视频流
  805. private void det_infer_video_img()
  806. {
  807. is_infer = 1; // 进入推理
  808. byte[] color_map = get_color_map_list(256);
  809. VideoCapture capture = new VideoCapture();
  810. capture.Open(videofile); // 读取视频
  811. using Mat frame = new Mat();
  812. int raise_ex_flag = 0; // 是否发生了异常
  813. try
  814. {
  815. while (true)
  816. {
  817. if (isBreakInfer == 1) break;
  818. capture.Read(frame);//图像存储一帧数据
  819. if (frame.Empty()) break;
  820. // ------------- 原始图片 ----------
  821. Bitmap image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frame); //显示原始图片到box1
  822. if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
  823. pictureBox1.Image = image; //显示原始图片到box1
  824. pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; //显示原始图片到box1
  825. // ------------- 送入推理的图片以及数据 ----------
  826. image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frame);
  827. byte[] inputData = GetBGRValues(image, out int stride);
  828. float[] resultlist = new float[600];
  829. IntPtr results = FloatToIntptr(resultlist);
  830. int[] boxesInfo = new int[1];
  831. byte[] labellist = new byte[1000]; //新建字节数组
  832. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  833. //第四个参数为输入图像的通道数
  834. Det_ModelPredict(inputData, image.Width, image.Height, 3, results, boxesInfo, ref labellist[0]);
  835. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  836. string strGet = System.Text.Encoding.Default.GetString(labellist, 0, labellist.Length); //将字节数组转换为字符串
  837. string[] predict_Label_List = strGet.Split(' '); // 预测的类别情况
  838. //Console.WriteLine("labellist: {0}", strGet);
  839. // 转换为mat数据,方便opencv处理
  840. using OpenCvSharp.Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(image);//用bitmap转换为mat
  841. for (int i = 0; i < boxesInfo[0]; i++) // 未绘制图像
  842. {
  843. int labelindex = Convert.ToInt32(resultlist[i * 6 + 0]);
  844. float score = resultlist[i * 6 + 1];
  845. float left = resultlist[i * 6 + 2];
  846. float top = resultlist[i * 6 + 3];
  847. float right = resultlist[i * 6 + 4];
  848. float down = resultlist[i * 6 + 5];
  849. if (score > det_threshold)
  850. {
  851. int[] color_ = { (int)(color_map[(labelindex%256)*3]),
  852. (int)(color_map[(labelindex % 256) * 3 + 1]),
  853. (int)(color_map[(labelindex % 256) * 3 + 2]) };
  854. // 获取文本区域的大小
  855. var text_size = Cv2.GetTextSize($"{predict_Label_List[i]}-{labelindex}-{score:f2}",
  856. HersheyFonts.HersheySimplex, 1, 2, out int baseline); // 1倍大小的HersheySimplex,高度为22
  857. // 获取文本区域的左下顶点 -- 右上角
  858. int left_down_x = (int)left + 22; // 小偏移调整量: (int)(text_size.Width/10)
  859. int left_down_y = (int)top + text_size.Height;
  860. // 绘制矩形
  861. Cv2.Rectangle(mat, new OpenCvSharp.Rect((int)left, (int)top, (int)right, (int)down), new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.AntiAlias);//LineTypes.AntiAlias:反锯齿效果
  862. Cv2.PutText(mat, $"{predict_Label_List[i]}-{labelindex}-: {score:f2}", new OpenCvSharp.Point(left_down_x, left_down_y), HersheyFonts.HersheySimplex, 1, new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.Link4);
  863. }
  864. }
  865. // 转换回bitmap进行显示
  866. image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  867. // 反馈到另一个picturebox上
  868. if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
  869. pictureBox2.Image = image;
  870. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  871. // 展示推理耗时
  872. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  873. double cost_milliseconds = start2end_time.TotalMilliseconds;
  874. // 通过委托展示到label上
  875. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  876. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  877. }
  878. }
  879. catch (Exception e)
  880. {
  881. raise_ex_flag = 1; // 发生了异常
  882. // 默认耗时为0ms
  883. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  884. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  885. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  886. }
  887. isBreakInfer = 0; // 清空标志
  888. // DestructModel(); // 销毁模型
  889. is_infer = 0; // 退出推理 -- 解除推理状态
  890. infer_video_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  891. if (raise_ex_flag == 0) MessageBox.Show("视频推理完成!"); // 未发生异常,正常显示推理完成提示
  892. }
  893. // 识别单张图片 -- 固定大小展示:short_side: 512
  894. private void cls_infer_one_img()
  895. {
  896. is_infer = 1; // 进入推理
  897. byte[] color_map = get_color_map_list(256);
  898. //Bitmap bmp = new Bitmap(imgfile);
  899. Bitmap bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(Cv2.ImRead(imgfile));
  900. // resize()
  901. var short_side = bmp.Width > bmp.Height ? bmp.Height : bmp.Width;
  902. double resize_scale = 512.0 / short_side;
  903. OpenCvSharp.Mat input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);
  904. OpenCvSharp.Mat output_mat = new Mat();
  905. int new_height = (int)(bmp.Height * resize_scale);
  906. int new_width = (int)(bmp.Width * resize_scale);
  907. Cv2.Resize(input_mat, output_mat, new OpenCvSharp.Size(new_width, new_height));
  908. bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  909. byte[] inputData = GetBGRValues(bmp, out int stride);
  910. float[] pre_score = new float[1];
  911. int[] pre_category_id = new int[1];
  912. byte[] pre_category = new byte[200]; //新建字节数组
  913. int raise_ex_flag = 0; // 是否发生了异常
  914. try
  915. {
  916. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  917. //第四个参数为输入图像的通道数
  918. Cls_ModelPredict(inputData, bmp.Width, bmp.Height, 3, ref pre_score[0], ref pre_category[0], ref pre_category_id[0]);
  919. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  920. string category_strGet = System.Text.Encoding.Default.GetString(pre_category, 0, pre_category.Length).Split('\0')[0]; //将类别字节数组转换为字符串
  921. OpenCvSharp.Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);//用bitmap转换为mat
  922. // 对应类别的颜色
  923. int[] color_ = { (int)(color_map[(pre_category_id[0]%256)*3]),
  924. (int)(color_map[(pre_category_id[0] % 256) * 3 + 1]),
  925. (int)(color_map[(pre_category_id[0] % 256) * 3 + 2]) };
  926. // 获取文本区域的大小
  927. var text_size = Cv2.GetTextSize($"{category_strGet}-{pre_category_id[0]}-{pre_score[0]:f2}",
  928. HersheyFonts.HersheySimplex, 1, 2, out int baseline); // 1倍大小的HersheySimplex,高度为22
  929. // 获取文本区域的左下顶点 -- 右上角
  930. int left_down_x = bmp.Width - text_size.Width; // 小偏移调整量: (int)(text_size.Width/10)
  931. int left_down_y = text_size.Height;
  932. // 书写类别
  933. Cv2.PutText(mat, $"{category_strGet}-{pre_category_id[0]}-{pre_score[0]:f2}", new OpenCvSharp.Point(left_down_x, left_down_y), HersheyFonts.HersheySimplex, 1, new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.Link4);
  934. // 转换回bitmap进行显示
  935. bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  936. // 反馈到另一个picturebox上
  937. if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
  938. pictureBox2.Image = bmp;
  939. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  940. // 收回内存
  941. input_mat = null;
  942. output_mat = null;
  943. mat = null;
  944. inputData = null;
  945. pre_score = null;
  946. pre_category_id = null;
  947. pre_category = null;
  948. // 展示推理耗时
  949. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  950. double cost_milliseconds = start2end_time.TotalMilliseconds;
  951. // 通过委托展示到label上
  952. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  953. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  954. }
  955. catch (Exception e)
  956. {
  957. raise_ex_flag = 1;
  958. // 默认耗时为0ms
  959. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  960. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  961. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  962. }
  963. isBreakInfer = 0; // 清空标志
  964. is_infer = 0; // 退出推理 -- 解除推理状态
  965. infer_one_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  966. if (raise_ex_flag == 0) MessageBox.Show("图片推理完成!"); // 未发生异常,正常显示推理完成提示
  967. }
  968. // 识别图片文件夹 -- 固定大小展示:short_side: 512
  969. private void cls_infer_many_img()
  970. {
  971. is_infer = 1; // 进入推理
  972. byte[] color_map = get_color_map_list(256);
  973. int raise_ex_flag = 0; // 是否发生了异常
  974. try
  975. {
  976. foreach (string img_file in imgfiles)
  977. {
  978. if (isBreakInfer == 1) break; // 中断推理
  979. //Bitmap bmp = new Bitmap(img_file);
  980. Bitmap bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(Cv2.ImRead(img_file));
  981. // resize()
  982. var short_side = bmp.Width > bmp.Height ? bmp.Height : bmp.Width;
  983. double resize_scale = 512.0 / short_side;
  984. OpenCvSharp.Mat input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);
  985. OpenCvSharp.Mat output_mat = new Mat();
  986. int new_height = (int)(bmp.Height * resize_scale);
  987. int new_width = (int)(bmp.Width * resize_scale);
  988. Cv2.Resize(input_mat, output_mat, new OpenCvSharp.Size(new_width, new_height));
  989. bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  990. byte[] inputData = GetBGRValues(bmp, out int stride);
  991. float[] pre_score = new float[1];
  992. int[] pre_category_id = new int[1];
  993. byte[] pre_category = new byte[200]; //新建字节数组
  994. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  995. //第四个参数为输入图像的通道数
  996. Cls_ModelPredict(inputData, bmp.Width, bmp.Height, 3, ref pre_score[0], ref pre_category[0], ref pre_category_id[0]);
  997. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  998. string category_strGet = System.Text.Encoding.Default.GetString(pre_category, 0, pre_category.Length).Split('\0')[0]; //将类别字节数组转换为字符串
  999. OpenCvSharp.Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);//用bitmap转换为mat
  1000. // 对应类别的颜色
  1001. int[] color_ = { (int)(color_map[(pre_category_id[0]%256)*3]),
  1002. (int)(color_map[(pre_category_id[0] % 256) * 3 + 1]),
  1003. (int)(color_map[(pre_category_id[0] % 256) * 3 + 2]) };
  1004. // 获取文本区域的大小
  1005. var text_size = Cv2.GetTextSize($"{category_strGet}-{pre_category_id[0]}-:{pre_score[0]:f2}",
  1006. HersheyFonts.HersheySimplex, 1, 2, out int baseline);
  1007. // 获取文本区域的左下顶点 -- 右上角
  1008. int left_down_x = bmp.Width - text_size.Width; // 小偏移调整量: (int)(text_size.Width/10)
  1009. int left_down_y = text_size.Height;
  1010. // 书写类别
  1011. Cv2.PutText(mat, $"{category_strGet}-{pre_category_id[0]}-:{pre_score[0]:f2}", new OpenCvSharp.Point(left_down_x, left_down_y), HersheyFonts.HersheySimplex, 1, new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.Link4);
  1012. // 转换回bitmap进行显示
  1013. bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  1014. // 原图显示
  1015. Bitmap show_image = new Bitmap(img_file);
  1016. if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
  1017. pictureBox1.Image = show_image; //显示原始图片到box1
  1018. pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; //显示原始图片到box1
  1019. // 反馈到另一个picturebox上
  1020. if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
  1021. pictureBox2.Image = bmp;
  1022. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  1023. // 收回内存
  1024. mat = null;
  1025. inputData = null;
  1026. pre_score = null;
  1027. pre_category_id = null;
  1028. pre_category = null;
  1029. // 展示推理耗时
  1030. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  1031. double cost_milliseconds = start2end_time.TotalMilliseconds;
  1032. // 通过委托展示到label上
  1033. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1034. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  1035. Thread.Sleep(continue_infer_delay); // 连续识别时,每张图片间隔continue_infer_delay毫秒
  1036. }
  1037. }
  1038. catch (Exception e)
  1039. {
  1040. raise_ex_flag = 1;
  1041. // 默认耗时为0ms
  1042. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1043. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  1044. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  1045. }
  1046. isBreakInfer = 0; // 清空标志
  1047. is_infer = 0; // 退出推理 -- 解除推理状态
  1048. infer_many_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  1049. if (raise_ex_flag == 0) MessageBox.Show("图片文件夹推理完成!"); // 未发生异常,正常显示推理完成提示
  1050. }
  1051. // 识别视频 -- 固定大小展示:short_side: 512
  1052. private void cls_infer_video_img()
  1053. {
  1054. is_infer = 1; // 进入推理
  1055. byte[] color_map = get_color_map_list(256);
  1056. VideoCapture capture = new VideoCapture();
  1057. capture.Open(videofile); // 读取视频
  1058. using Mat frame = new Mat();
  1059. int raise_ex_flag = 0; // 是否发生了异常
  1060. try
  1061. {
  1062. while (true)
  1063. {
  1064. if (isBreakInfer == 1) break;
  1065. capture.Read(frame);//图像存储一帧数据
  1066. if (frame.Empty()) break;
  1067. // ------------- 原始图片 ----------
  1068. Bitmap image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frame); //显示原始图片到box1
  1069. if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
  1070. pictureBox1.Image = image; //显示原始图片到box1
  1071. pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; //显示原始图片到box1
  1072. // ------------- 送入推理的图片以及数据 ----------
  1073. image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frame);
  1074. // resize()
  1075. var short_side = image.Width > image.Height ? image.Height : image.Width;
  1076. double resize_scale = 512.0 / short_side;
  1077. OpenCvSharp.Mat input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(image);
  1078. OpenCvSharp.Mat output_mat = new Mat();
  1079. int new_height = (int)(image.Height * resize_scale);
  1080. int new_width = (int)(image.Width * resize_scale);
  1081. Cv2.Resize(input_mat, output_mat, new OpenCvSharp.Size(new_width, new_height));
  1082. image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1083. byte[] inputData = GetBGRValues(image, out int stride);
  1084. float[] pre_score = new float[1];
  1085. int[] pre_category_id = new int[1];
  1086. byte[] pre_category = new byte[200]; //新建字节数组
  1087. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  1088. //第四个参数为输入图像的通道数
  1089. Cls_ModelPredict(inputData, image.Width, image.Height, 3, ref pre_score[0], ref pre_category[0], ref pre_category_id[0]);
  1090. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  1091. string category_strGet = System.Text.Encoding.Default.GetString(pre_category, 0, pre_category.Length).Split('\0')[0]; //将类别字节数组转换为字符串
  1092. OpenCvSharp.Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(image);//用bitmap转换为mat
  1093. // 对应类别的颜色
  1094. int[] color_ = { (int)(color_map[(pre_category_id[0]%256)*3]),
  1095. (int)(color_map[(pre_category_id[0] % 256) * 3 + 1]),
  1096. (int)(color_map[(pre_category_id[0] % 256) * 3 + 2]) };
  1097. // 获取文本区域的大小
  1098. var text_size = Cv2.GetTextSize($"{category_strGet}-{pre_category_id[0]}-:{pre_score[0]:f2}",
  1099. HersheyFonts.HersheySimplex, 1, 2, out int baseline);
  1100. // 获取文本区域的左下顶点 -- 右上角
  1101. int left_down_x = image.Width - text_size.Width; // 小偏移调整量: (int)(text_size.Width/10)
  1102. int left_down_y = text_size.Height;
  1103. // 书写类别
  1104. Cv2.PutText(mat, $"{category_strGet}-{pre_category_id[0]}-:{pre_score[0]:f2}", new OpenCvSharp.Point(left_down_x, left_down_y), HersheyFonts.HersheySimplex, 1, new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.Link4);
  1105. // 转换回bitmap进行显示
  1106. image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  1107. // 反馈到另一个picturebox上
  1108. pictureBox2.Image = image;
  1109. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  1110. // 收回内存
  1111. mat = null;
  1112. inputData = null;
  1113. pre_score = null;
  1114. pre_category_id = null;
  1115. pre_category = null;
  1116. // 展示推理耗时
  1117. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  1118. double cost_milliseconds = start2end_time.TotalMilliseconds;
  1119. // 通过委托展示到label上
  1120. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1121. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  1122. }
  1123. }
  1124. catch (Exception e)
  1125. {
  1126. raise_ex_flag = 1; // 发生了异常
  1127. // 默认耗时为0ms
  1128. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1129. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  1130. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  1131. }
  1132. isBreakInfer = 0; // 清空标志
  1133. // DestructModel(); // 销毁模型
  1134. is_infer = 0; // 退出推理 -- 解除推理状态
  1135. infer_video_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  1136. if (raise_ex_flag == 0) MessageBox.Show("视频推理完成!"); // 未发生异常,正常显示推理完成提示
  1137. }
  1138. // 分割图片 -- 固定大小展示:512 X 512
  1139. private void seg_infer_one_img()
  1140. {
  1141. is_infer = 1; // 进入推理
  1142. byte[] color_map = get_color_map_list(256);
  1143. //Bitmap origin_bmp = new Bitmap(imgfile);
  1144. Bitmap origin_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(Cv2.ImRead(imgfile));
  1145. Bitmap input_bmp = null;
  1146. // resize()
  1147. OpenCvSharp.Mat input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1148. OpenCvSharp.Mat output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1149. Cv2.Resize(input_mat, output_mat, new OpenCvSharp.Size(512, 512));
  1150. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1151. input_mat = null;
  1152. output_mat = null;
  1153. byte[] inputData = GetBGRValues(input_bmp, out int stride);
  1154. byte[] output_map = new byte[input_bmp.Height * input_bmp.Width]; //新建字节数组
  1155. int raise_ex_flag = 0; // 是否发生了异常
  1156. try
  1157. {
  1158. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  1159. //第四个参数为输入图像的通道数
  1160. Seg_ModelPredict(inputData, input_bmp.Width, input_bmp.Height, 3, ref output_map[0]);
  1161. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  1162. // 还原原始图像大小
  1163. input_bmp = CreateBitmap(output_map, input_bmp.Width, input_bmp.Height, color_map); // 还原512的输入大小的图像
  1164. input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp);
  1165. output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp); // 获取处理后的图像
  1166. Cv2.Resize(input_mat, output_mat, new OpenCvSharp.Size(origin_bmp.Width, origin_bmp.Height)); // 还原到与输入一致的图像大小
  1167. input_mat = null; // 回收内存
  1168. input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp); // 获取原始图像
  1169. //OpenCvSharp.Mat add_mat = new Mat(); // 叠加后的图像
  1170. Cv2.AddWeighted(output_mat, 1.0, input_mat, 0.35, 1, output_mat); // 执行叠加
  1171. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1172. // 反馈到另一个picturebox上
  1173. if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
  1174. pictureBox2.Image = input_bmp;
  1175. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  1176. // 展示推理耗时
  1177. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  1178. double cost_milliseconds = start2end_time.TotalMilliseconds;
  1179. // 通过委托展示到label上
  1180. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1181. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  1182. }
  1183. catch (Exception e)
  1184. {
  1185. raise_ex_flag = 1;
  1186. // 默认耗时为0ms
  1187. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1188. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  1189. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  1190. }
  1191. isBreakInfer = 0; // 清空标志
  1192. is_infer = 0; // 退出推理 -- 解除推理状态
  1193. infer_one_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  1194. if (raise_ex_flag == 0) MessageBox.Show("图片推理完成!"); // 未发生异常,正常显示推理完成提示
  1195. }
  1196. // 分割图片文件夹 -- 固定大小展示:512 X 512
  1197. private void seg_infer_many_img()
  1198. {
  1199. is_infer = 1; // 进入推理
  1200. byte[] color_map = get_color_map_list(256);
  1201. int raise_ex_flag = 0; // 是否发生了异常
  1202. try
  1203. {
  1204. foreach (string img_file in imgfiles)
  1205. {
  1206. if (isBreakInfer == 1) break; // 中断推理
  1207. Bitmap origin_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(Cv2.ImRead(img_file));
  1208. Bitmap input_bmp = null;
  1209. // resize()
  1210. OpenCvSharp.Mat input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1211. OpenCvSharp.Mat output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1212. Cv2.Resize(input_mat, output_mat, new OpenCvSharp.Size(512, 512));
  1213. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1214. input_mat = null;
  1215. output_mat = null;
  1216. byte[] inputData = GetBGRValues(input_bmp, out int stride);
  1217. byte[] output_map = new byte[input_bmp.Height * input_bmp.Width]; //新建字节数组
  1218. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  1219. //第四个参数为输入图像的通道数
  1220. Seg_ModelPredict(inputData, input_bmp.Width, input_bmp.Height, 3, ref output_map[0]);
  1221. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  1222. // 还原原始图像大小
  1223. input_bmp = CreateBitmap(output_map, input_bmp.Width, input_bmp.Height, color_map); // 还原512的输入大小的图像
  1224. input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp);
  1225. output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp); // 获取处理后的图像
  1226. Cv2.Resize(input_mat, output_mat, new OpenCvSharp.Size(origin_bmp.Width, origin_bmp.Height)); // 还原到与输入一致的图像大小
  1227. input_mat = null; // 回收内存
  1228. input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp); // 获取原始图像
  1229. //OpenCvSharp.Mat add_mat = new Mat(); // 叠加后的图像
  1230. Cv2.AddWeighted(output_mat, 1.0, input_mat, 0.35, 1, output_mat); // 执行叠加
  1231. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1232. // 显示图片
  1233. if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
  1234. pictureBox1.Image = origin_bmp; //显示原始图片到box1
  1235. pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; //显示原始图片到box1
  1236. if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
  1237. pictureBox2.Image = input_bmp;
  1238. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  1239. // 展示推理耗时
  1240. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  1241. double cost_milliseconds = start2end_time.TotalMilliseconds;
  1242. // 通过委托展示到label上
  1243. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1244. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  1245. Thread.Sleep(continue_infer_delay); // 连续识别时,每张图片间隔continue_infer_delay毫秒
  1246. }
  1247. }
  1248. catch (Exception e)
  1249. {
  1250. raise_ex_flag = 1;
  1251. // 默认耗时为0ms
  1252. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1253. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  1254. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  1255. }
  1256. isBreakInfer = 0; // 清空标志
  1257. is_infer = 0; // 退出推理 -- 解除推理状态
  1258. infer_many_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  1259. if (raise_ex_flag == 0) MessageBox.Show("图片文件夹推理完成!"); // 未发生异常,正常显示推理完成提示
  1260. }
  1261. // 分割视频流 -- 固定大小展示:512 X 512
  1262. private void seg_infer_video_img()
  1263. {
  1264. is_infer = 1; // 进入推理
  1265. byte[] color_map = get_color_map_list(256);
  1266. VideoCapture capture = new VideoCapture();
  1267. capture.Open(videofile); // 读取视频
  1268. using Mat frame = new Mat();
  1269. int raise_ex_flag = 0; // 是否发生了异常
  1270. try
  1271. {
  1272. while (true)
  1273. {
  1274. if (isBreakInfer == 1) break;
  1275. capture.Read(frame);//图像存储一帧数据
  1276. if (frame.Empty()) break;
  1277. // ------------- 原始图片 ----------
  1278. Bitmap origin_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frame);
  1279. // ------------- 送入推理的图片以及数据 ----------
  1280. Bitmap input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frame);
  1281. // resize()
  1282. OpenCvSharp.Mat input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1283. OpenCvSharp.Mat output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1284. Cv2.Resize(input_mat, output_mat, new OpenCvSharp.Size(512, 512));
  1285. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1286. input_mat = null;
  1287. output_mat = null;
  1288. byte[] inputData = GetBGRValues(input_bmp, out int stride);
  1289. byte[] output_map = new byte[input_bmp.Height * input_bmp.Width]; //新建字节数组
  1290. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  1291. //第四个参数为输入图像的通道数
  1292. Seg_ModelPredict(inputData, input_bmp.Width, input_bmp.Height, 3, ref output_map[0]);
  1293. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  1294. // 还原原始图像大小
  1295. input_bmp = CreateBitmap(output_map, input_bmp.Width, input_bmp.Height, color_map); // 还原512的输入大小的图像
  1296. input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp);
  1297. output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp); // 获取处理后的图像
  1298. Cv2.Resize(input_mat, output_mat, new OpenCvSharp.Size(origin_bmp.Width, origin_bmp.Height)); // 还原到与输入一致的图像大小
  1299. input_mat = null; // 回收内存
  1300. input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp); // 获取原始图像
  1301. //OpenCvSharp.Mat add_mat = new Mat(); // 叠加后的图像
  1302. Cv2.AddWeighted(output_mat, 1.0, input_mat, 0.35, 1, output_mat); // 执行叠加
  1303. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1304. // 显示图片
  1305. if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
  1306. pictureBox1.Image = origin_bmp; //显示原始图片到box1
  1307. pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; //显示原始图片到box1
  1308. if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
  1309. pictureBox2.Image = input_bmp;
  1310. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  1311. // 展示推理耗时
  1312. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  1313. double cost_milliseconds = start2end_time.TotalMilliseconds;
  1314. // 通过委托展示到label上
  1315. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1316. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  1317. }
  1318. }
  1319. catch (Exception e)
  1320. {
  1321. raise_ex_flag = 1; // 发生了异常
  1322. // 默认耗时为0ms
  1323. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1324. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  1325. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  1326. }
  1327. isBreakInfer = 0; // 清空标志
  1328. // DestructModel(); // 销毁模型
  1329. is_infer = 0; // 退出推理 -- 解除推理状态
  1330. infer_video_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  1331. if (raise_ex_flag == 0) MessageBox.Show("视频推理完成!"); // 未发生异常,正常显示推理完成提示
  1332. }
  1333. // MaskRCNN检测单张图片 -- GPU推理正常
  1334. private void mask_infer_one_img()
  1335. {
  1336. is_infer = 1; // 进入推理
  1337. byte[] color_map = get_color_map_list(256);
  1338. Bitmap origin_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(Cv2.ImRead(imgfile));
  1339. Bitmap input_bmp = null;
  1340. // resize()
  1341. OpenCvSharp.Mat input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1342. OpenCvSharp.Mat output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1343. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1344. byte[] inputData = GetBGRValues(origin_bmp, out int stride);
  1345. float[] resultlist = new float[600];
  1346. IntPtr results = FloatToIntptr(resultlist);
  1347. byte[] mask_results = new byte[input_bmp.Height * input_bmp.Width]; //新建字节数组
  1348. int[] boxesInfo = new int[1]; // 10 boundingbox
  1349. byte[] labellist = new byte[1000]; //新建字节数组:label1_str label2_str
  1350. int raise_ex_flag = 0; // 是否发生了异常
  1351. try
  1352. {
  1353. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  1354. Mask_ModelPredict(inputData, input_bmp.Width, input_bmp.Height, 3, results, ref mask_results[0], boxesInfo, ref labellist[0]);
  1355. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  1356. input_bmp = CreateBitmap(mask_results, input_bmp.Width, input_bmp.Height, color_map);
  1357. output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp); // 获取处理后的图像
  1358. input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp); // 获取原始图像
  1359. //OpenCvSharp.Mat add_mat = new Mat(); // 叠加后的图像
  1360. Cv2.AddWeighted(output_mat, 0.65, input_mat, 0.35, 1, output_mat); // 执行叠加
  1361. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1362. string strGet = System.Text.Encoding.Default.GetString(labellist, 0, labellist.Length); //将字节数组转换为字符串
  1363. string[] predict_Label_List = strGet.Split(' '); // 预测的类别情况
  1364. // MessageBox.Show($"Box_Number: {boxesInfo[0]}");
  1365. using OpenCvSharp.Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp);//用bitmap转换为mat
  1366. for (int i = 0; i < boxesInfo[0]; i++) // 未绘制图像
  1367. {
  1368. int labelindex = Convert.ToInt32(resultlist[i * 6 + 0]);
  1369. float score = resultlist[i * 6 + 1];
  1370. float left = resultlist[i * 6 + 2];
  1371. float top = resultlist[i * 6 + 3];
  1372. float right = resultlist[i * 6 + 4];
  1373. float down = resultlist[i * 6 + 5];
  1374. if (score > det_threshold)
  1375. {
  1376. labelindex += 1; // Mask RCNN包含背景,故而加1
  1377. int[] color_ = { (int)(color_map[(labelindex%256)*3]),
  1378. (int)(color_map[(labelindex % 256) * 3 + 1]),
  1379. (int)(color_map[(labelindex % 256) * 3 + 2]) };
  1380. labelindex -= 1; // 还原类别
  1381. // 获取文本区域的大小
  1382. var text_size = Cv2.GetTextSize($"{predict_Label_List[i]}-{labelindex}-{score:f2}",
  1383. HersheyFonts.HersheySimplex, 1, 2, out int baseline); // 1倍大小的HersheySimplex,高度为22
  1384. // 获取文本区域的左下顶点 -- 右上角
  1385. int left_down_x = (int)left + 22; // 小偏移调整量: (int)(text_size.Width/10)
  1386. int left_down_y = (int)top + text_size.Height;
  1387. // 绘制矩形,书写类别
  1388. Cv2.Rectangle(mat, new OpenCvSharp.Rect((int)left, (int)top, (int)right, (int)down), new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.AntiAlias);//LineTypes.AntiAlias:反锯齿效果
  1389. Cv2.PutText(mat, $"{predict_Label_List[i]}-{labelindex}-: {score:f2}", new OpenCvSharp.Point(left_down_x, left_down_y), HersheyFonts.HersheySimplex, 1, new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.Link4);
  1390. }
  1391. }
  1392. // 转换回bitmap进行显示
  1393. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  1394. if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
  1395. pictureBox2.Image = input_bmp;
  1396. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  1397. // 展示推理耗时
  1398. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  1399. double cost_milliseconds = start2end_time.TotalMilliseconds;
  1400. // 通过委托展示到label上
  1401. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1402. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  1403. }
  1404. catch (Exception e)
  1405. {
  1406. raise_ex_flag = 1;
  1407. // 默认耗时为0ms
  1408. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1409. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  1410. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  1411. }
  1412. isBreakInfer = 0; // 清空标志
  1413. is_infer = 0; // 退出推理 -- 解除推理状态
  1414. infer_one_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  1415. if (raise_ex_flag == 0) MessageBox.Show("图片推理完成!"); // 未发生异常,正常显示推理完成提示
  1416. }
  1417. // MaskRCNN检测图片文件夹
  1418. private void mask_infer_many_img()
  1419. {
  1420. is_infer = 1; // 进入推理
  1421. byte[] color_map = get_color_map_list(256);
  1422. int raise_ex_flag = 0; // 是否发生了异常
  1423. try
  1424. {
  1425. foreach (string img_file in imgfiles)
  1426. {
  1427. if (isBreakInfer == 1) break; // 中断推理
  1428. Bitmap origin_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(Cv2.ImRead(img_file));
  1429. Bitmap input_bmp = null;
  1430. // resize()
  1431. OpenCvSharp.Mat input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1432. OpenCvSharp.Mat output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1433. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1434. byte[] inputData = GetBGRValues(origin_bmp, out int stride);
  1435. float[] resultlist = new float[600];
  1436. IntPtr results = FloatToIntptr(resultlist);
  1437. byte[] mask_results = new byte[input_bmp.Height * input_bmp.Width]; //新建字节数组
  1438. int[] boxesInfo = new int[1]; // 10 boundingbox
  1439. byte[] labellist = new byte[1000]; //新建字节数组:label1_str label2_str
  1440. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  1441. //第四个参数为输入图像的通道数
  1442. Mask_ModelPredict(inputData, input_bmp.Width, input_bmp.Height, 3, results, ref mask_results[0], boxesInfo, ref labellist[0]);
  1443. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  1444. input_bmp = CreateBitmap(mask_results, input_bmp.Width, input_bmp.Height, color_map);
  1445. output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp); // 获取处理后的图像
  1446. input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp); // 获取原始图像
  1447. //OpenCvSharp.Mat add_mat = new Mat(); // 叠加后的图像
  1448. Cv2.AddWeighted(output_mat, 1.0, input_mat, 0.35, 1, output_mat); // 执行叠加
  1449. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1450. string strGet = System.Text.Encoding.Default.GetString(labellist, 0, labellist.Length); //将字节数组转换为字符串
  1451. string[] predict_Label_List = strGet.Split(' '); // 预测的类别情况
  1452. // MessageBox.Show($"Box_Number: {boxesInfo[0]}");
  1453. using OpenCvSharp.Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp);//用bitmap转换为mat
  1454. for (int i = 0; i < boxesInfo[0]; i++) // 未绘制图像
  1455. {
  1456. int labelindex = Convert.ToInt32(resultlist[i * 6 + 0]);
  1457. float score = resultlist[i * 6 + 1];
  1458. float left = resultlist[i * 6 + 2];
  1459. float top = resultlist[i * 6 + 3];
  1460. float right = resultlist[i * 6 + 4];
  1461. float down = resultlist[i * 6 + 5];
  1462. if (score > det_threshold)
  1463. {
  1464. labelindex += 1; // Mask RCNN包含背景,故而加1
  1465. int[] color_ = { (int)(color_map[(labelindex%256)*3]),
  1466. (int)(color_map[(labelindex % 256) * 3 + 1]),
  1467. (int)(color_map[(labelindex % 256) * 3 + 2]) };
  1468. labelindex -= 1; // 还原类别
  1469. // 获取文本区域的大小
  1470. var text_size = Cv2.GetTextSize($"{predict_Label_List[i]}-{labelindex}-{score:f2}",
  1471. HersheyFonts.HersheySimplex, 1, 2, out int baseline); // 1倍大小的HersheySimplex,高度为22
  1472. // 获取文本区域的左下顶点 -- 右上角
  1473. int left_down_x = (int)left + 22; // 小偏移调整量: (int)(text_size.Width/10)
  1474. int left_down_y = (int)top + text_size.Height;
  1475. // 绘制矩形,书写类别
  1476. Cv2.Rectangle(mat, new OpenCvSharp.Rect((int)left, (int)top, (int)right, (int)down), new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.AntiAlias);//LineTypes.AntiAlias:反锯齿效果
  1477. Cv2.PutText(mat, $"{predict_Label_List[i]}-{labelindex}-: {score:f2}", new OpenCvSharp.Point(left_down_x, left_down_y), HersheyFonts.HersheySimplex, 1, new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.Link4);
  1478. }
  1479. }
  1480. // 显示图片
  1481. if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
  1482. pictureBox1.Image = origin_bmp; //显示原始图片到box1
  1483. pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; //显示原始图片到box1
  1484. // 转换回bitmap进行显示
  1485. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  1486. if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
  1487. pictureBox2.Image = input_bmp;
  1488. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  1489. // 展示推理耗时
  1490. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  1491. double cost_milliseconds = start2end_time.TotalMilliseconds;
  1492. // 通过委托展示到label上
  1493. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1494. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  1495. Thread.Sleep(continue_infer_delay); // 连续识别时,每张图片间隔continue_infer_delay毫秒
  1496. }
  1497. }
  1498. catch (Exception e)
  1499. {
  1500. raise_ex_flag = 1;
  1501. // 默认耗时为0ms
  1502. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1503. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  1504. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  1505. }
  1506. isBreakInfer = 0; // 清空标志
  1507. is_infer = 0; // 退出推理 -- 解除推理状态
  1508. infer_many_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  1509. if (raise_ex_flag == 0) MessageBox.Show("图片文件夹推理完成!"); // 未发生异常,正常显示推理完成提示
  1510. }
  1511. // MaskRCNN检测视频流
  1512. private void mask_infer_video_img()
  1513. {
  1514. is_infer = 1; // 进入推理
  1515. byte[] color_map = get_color_map_list(256);
  1516. VideoCapture capture = new VideoCapture();
  1517. capture.Open(videofile); // 读取视频
  1518. using Mat frame = new Mat();
  1519. int raise_ex_flag = 0; // 是否发生了异常
  1520. try
  1521. {
  1522. while (true)
  1523. {
  1524. if (isBreakInfer == 1) break;
  1525. capture.Read(frame);//图像存储一帧数据
  1526. if (frame.Empty()) break;
  1527. // ------------- 原始图片 ----------
  1528. Bitmap origin_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(frame);
  1529. // ------------- 送入推理的图片以及数据 ----------
  1530. Bitmap input_bmp = null;
  1531. // resize()
  1532. OpenCvSharp.Mat input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1533. OpenCvSharp.Mat output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp);
  1534. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1535. byte[] inputData = GetBGRValues(origin_bmp, out int stride);
  1536. float[] resultlist = new float[600];
  1537. IntPtr results = FloatToIntptr(resultlist);
  1538. byte[] mask_results = new byte[input_bmp.Height * input_bmp.Width]; //新建字节数组
  1539. int[] boxesInfo = new int[1]; // 10 boundingbox
  1540. byte[] labellist = new byte[1000]; //新建字节数组:label1_str label2_str
  1541. TimeSpan infer_start_time = new TimeSpan(DateTime.Now.Ticks);
  1542. //第四个参数为输入图像的通道数
  1543. Mask_ModelPredict(inputData, input_bmp.Width, input_bmp.Height, 3, results, ref mask_results[0], boxesInfo, ref labellist[0]);
  1544. TimeSpan infer_end_time = new TimeSpan(DateTime.Now.Ticks);
  1545. input_bmp = CreateBitmap(mask_results, input_bmp.Width, input_bmp.Height, color_map);
  1546. output_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp); // 获取处理后的图像
  1547. input_mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(origin_bmp); // 获取原始图像
  1548. //OpenCvSharp.Mat add_mat = new Mat(); // 叠加后的图像
  1549. Cv2.AddWeighted(output_mat, 1.0, input_mat, 0.35, 1, output_mat); // 执行叠加
  1550. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(output_mat);
  1551. string strGet = System.Text.Encoding.Default.GetString(labellist, 0, labellist.Length); //将字节数组转换为字符串
  1552. string[] predict_Label_List = strGet.Split(' '); // 预测的类别情况
  1553. // MessageBox.Show($"Box_Number: {boxesInfo[0]}");
  1554. using OpenCvSharp.Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(input_bmp);//用bitmap转换为mat
  1555. for (int i = 0; i < boxesInfo[0]; i++) // 未绘制图像
  1556. {
  1557. int labelindex = Convert.ToInt32(resultlist[i * 6 + 0]);
  1558. float score = resultlist[i * 6 + 1];
  1559. float left = resultlist[i * 6 + 2];
  1560. float top = resultlist[i * 6 + 3];
  1561. float right = resultlist[i * 6 + 4];
  1562. float down = resultlist[i * 6 + 5];
  1563. if (score > det_threshold)
  1564. {
  1565. labelindex += 1; // Mask RCNN包含背景,故而加1
  1566. int[] color_ = { (int)(color_map[(labelindex%256)*3]),
  1567. (int)(color_map[(labelindex % 256) * 3 + 1]),
  1568. (int)(color_map[(labelindex % 256) * 3 + 2]) };
  1569. labelindex -= 1; // 还原类别
  1570. // 获取文本区域的大小
  1571. var text_size = Cv2.GetTextSize($"{predict_Label_List[i]}-{labelindex}-{score:f2}",
  1572. HersheyFonts.HersheySimplex, 1, 2, out int baseline); // 1倍大小的HersheySimplex,高度为22
  1573. // 获取文本区域的左下顶点 -- 右上角
  1574. int left_down_x = (int)left + 22; // 小偏移调整量: (int)(text_size.Width/10)
  1575. int left_down_y = (int)top + text_size.Height;
  1576. // 绘制矩形,书写类别
  1577. Cv2.Rectangle(mat, new OpenCvSharp.Rect((int)left, (int)top, (int)right, (int)down), new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.AntiAlias);//LineTypes.AntiAlias:反锯齿效果
  1578. Cv2.PutText(mat, $"{predict_Label_List[i]}-{labelindex}-: {score:f2}", new OpenCvSharp.Point(left_down_x, left_down_y), HersheyFonts.HersheySimplex, 1, new OpenCvSharp.Scalar(color_[0], color_[1], color_[2]), 2, LineTypes.Link4);
  1579. }
  1580. }
  1581. // 显示图片
  1582. if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
  1583. pictureBox1.Image = origin_bmp; //显示原始图片到box1
  1584. pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; //显示原始图片到box1
  1585. // 转换回bitmap进行显示
  1586. input_bmp = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  1587. if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
  1588. pictureBox2.Image = input_bmp;
  1589. pictureBox2.SizeMode = PictureBoxSizeMode.Zoom;
  1590. // 展示推理耗时
  1591. TimeSpan start2end_time = infer_end_time.Subtract(infer_start_time).Duration();
  1592. double cost_milliseconds = start2end_time.TotalMilliseconds;
  1593. // 通过委托展示到label上
  1594. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1595. label7.Invoke(AsyncUIDelegate, new object[] { $"{cost_milliseconds:f2}" });
  1596. }
  1597. }
  1598. catch (Exception e)
  1599. {
  1600. raise_ex_flag = 1; // 发生了异常
  1601. // 默认耗时为0ms
  1602. Action<String> AsyncUIDelegate = delegate (string n) { label7.Text = n; };//定义一个委托
  1603. label7.Invoke(AsyncUIDelegate, new object[] { "0.00" });
  1604. MessageBox.Show("1.请检查模型文件与模型类型是否一致!\n2.内存溢出,yml预处理有误,图片格式确保为1/3通道...", "模型运行失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
  1605. }
  1606. isBreakInfer = 0; // 清空标志
  1607. is_infer = 0; // 退出推理 -- 解除推理状态
  1608. infer_video_img_flag = 0; // 重置当前推理状态 -- 解除图片推理状态
  1609. if (raise_ex_flag == 0) MessageBox.Show("视频推理完成!"); // 未发生异常,正常显示推理完成提示
  1610. }
  1611. /**********************************************************************/
  1612. /***************** 7.部分推理组件函数 ***************/
  1613. /**********************************************************************/
  1614. /// <summary>
  1615. /// 从内存流中指定位置,读取数据
  1616. /// </summary>
  1617. /// <param name="curStream"></param>
  1618. /// <param name="startPosition"></param>
  1619. /// <param name="length"></param>
  1620. /// <returns></returns>
  1621. public static int ReadData(MemoryStream curStream, int startPosition, int length)
  1622. {
  1623. int result = -1;
  1624. byte[] tempData = new byte[length];
  1625. curStream.Position = startPosition;
  1626. curStream.Read(tempData, 0, length);
  1627. result = BitConverter.ToInt32(tempData, 0);
  1628. return result;
  1629. }
  1630. /// <summary>
  1631. /// 使用byte[]数据,生成三通道 BMP 位图
  1632. /// </summary>
  1633. /// <param name="originalImageData"></param>
  1634. /// <param name="originalWidth"></param>
  1635. /// <param name="originalHeight"></param>
  1636. /// <returns></returns>
  1637. public static Bitmap CreateBitmap(byte[] originalImageData, int originalWidth, int originalHeight, byte[] color_map)
  1638. {
  1639. // 指定8位格式,即256色
  1640. Bitmap resultBitmap = new Bitmap(originalWidth, originalHeight, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
  1641. // 将该位图存入内存中
  1642. MemoryStream curImageStream = new MemoryStream();
  1643. resultBitmap.Save(curImageStream, System.Drawing.Imaging.ImageFormat.Bmp);
  1644. curImageStream.Flush();
  1645. // 由于位图数据需要DWORD对齐(4byte倍数),计算需要补位的个数
  1646. int curPadNum = ((originalWidth * 8 + 31) / 32 * 4) - originalWidth;
  1647. // 最终生成的位图数据大小
  1648. int bitmapDataSize = ((originalWidth * 8 + 31) / 32 * 4) * originalHeight;
  1649. // 数据部分相对文件开始偏移,具体可以参考位图文件格式
  1650. int dataOffset = ReadData(curImageStream, 10, 4);
  1651. // 改变调色板,因为默认的调色板是32位彩色的,需要修改为256色的调色板
  1652. int paletteStart = 54;
  1653. int paletteEnd = dataOffset;
  1654. int color = 0;
  1655. for (int i = paletteStart; i < paletteEnd; i += 4)
  1656. {
  1657. byte[] tempColor = new byte[4];
  1658. tempColor[0] = (byte)color;
  1659. tempColor[1] = (byte)color;
  1660. tempColor[2] = (byte)color;
  1661. tempColor[3] = (byte)0;
  1662. color++;
  1663. curImageStream.Position = i;
  1664. curImageStream.Write(tempColor, 0, 4);
  1665. }
  1666. // 最终生成的位图数据,以及大小,高度没有变,宽度需要调整
  1667. byte[] destImageData = new byte[bitmapDataSize];
  1668. int destWidth = originalWidth + curPadNum;
  1669. // 生成最终的位图数据,注意的是,位图数据 从左到右,从下到上,所以需要颠倒
  1670. for (int originalRowIndex = originalHeight - 1; originalRowIndex >= 0; originalRowIndex--)
  1671. {
  1672. int destRowIndex = originalHeight - originalRowIndex - 1;
  1673. for (int dataIndex = 0; dataIndex < originalWidth; dataIndex++)
  1674. {
  1675. // 同时还要注意,新的位图数据的宽度已经变化destWidth,否则会产生错位
  1676. destImageData[destRowIndex * destWidth + dataIndex] = originalImageData[originalRowIndex * originalWidth + dataIndex];
  1677. }
  1678. }
  1679. // 将流的Position移到数据段
  1680. curImageStream.Position = dataOffset;
  1681. // 将新位图数据写入内存中
  1682. curImageStream.Write(destImageData, 0, bitmapDataSize);
  1683. curImageStream.Flush();
  1684. // 将内存中的位图写入Bitmap对象
  1685. resultBitmap = new Bitmap(curImageStream);
  1686. resultBitmap = transForm8to24(resultBitmap, color_map); // 转为3通道图像
  1687. return resultBitmap;
  1688. }
  1689. // 实现bitmap单通道到三通道(分割生成掩码图像(单通道) ==> RGB图像)
  1690. public static Bitmap transForm8to24(Bitmap bmp, byte[] color_map)
  1691. {
  1692. System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
  1693. System.Drawing.Imaging.BitmapData bitmapData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
  1694. //计算实际8位图容量
  1695. int size8 = bitmapData.Stride * bmp.Height;
  1696. byte[] grayValues = new byte[size8];
  1697. //// 申请目标位图的变量,并将其内存区域锁定
  1698. Bitmap TempBmp = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format24bppRgb);
  1699. BitmapData TempBmpData = TempBmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
  1700. //// 获取图像参数以及设置24位图信息
  1701. int stride = TempBmpData.Stride; // 扫描线的宽度
  1702. int offset = stride - TempBmp.Width; // 显示宽度与扫描线宽度的间隙
  1703. IntPtr iptr = TempBmpData.Scan0; // 获取bmpData的内存起始位置
  1704. int scanBytes = stride * TempBmp.Height;// 用stride宽度,表示这是内存区域的大小
  1705. //// 下面把原始的显示大小字节数组转换为内存中实际存放的字节数组
  1706. byte[] pixelValues = new byte[scanBytes]; //为目标数组分配内存
  1707. System.Runtime.InteropServices.Marshal.Copy(bitmapData.Scan0, grayValues, 0, size8);
  1708. for (int i = 0; i < bmp.Height; i++)
  1709. {
  1710. for (int j = 0; j < bitmapData.Stride; j++)
  1711. {
  1712. if (j >= bmp.Width)
  1713. continue;
  1714. int indexSrc = i * bitmapData.Stride + j;
  1715. int realIndex = i * TempBmpData.Stride + j * 3;
  1716. // color_id:就是预测出来的结果
  1717. int color_id = (int)grayValues[indexSrc] % 256;
  1718. if (color_id == 0) // 分割中类别1对应值1,而背景往往为0,因此这里就将背景置为[0, 0, 0]
  1719. {
  1720. // 空白
  1721. pixelValues[realIndex] = 0;
  1722. pixelValues[realIndex + 1] = 0;
  1723. pixelValues[realIndex + 2] = 0;
  1724. }
  1725. else
  1726. {
  1727. // 替换为color_map中的颜色值
  1728. pixelValues[realIndex] = color_map[color_id * 3];
  1729. pixelValues[realIndex + 1] = color_map[color_id * 3 + 1];
  1730. pixelValues[realIndex + 2] = color_map[color_id * 3 + 2];
  1731. }
  1732. }
  1733. }
  1734. //// 用Marshal的Copy方法,将刚才得到的内存字节数组复制到BitmapData中
  1735. System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, iptr, scanBytes);
  1736. TempBmp.UnlockBits(TempBmpData); // 解锁内存区域
  1737. bmp.UnlockBits(bitmapData);
  1738. return TempBmp;
  1739. }
  1740. // 生成伪彩色图的RGB值集合(color_map) -- 同时也是适用于检测框分类颜色
  1741. private byte[] get_color_map_list(int num_classes = 256)
  1742. {
  1743. num_classes += 1;
  1744. byte[] color_map = new byte[num_classes * 3];
  1745. for (int i = 0; i < num_classes; i++)
  1746. {
  1747. int j = 0;
  1748. int lab = i;
  1749. while (lab != 0)
  1750. {
  1751. color_map[i * 3] |= (byte)(((lab >> 0) & 1) << (7 - j));
  1752. color_map[i * 3 + 1] |= (byte)(((lab >> 1) & 1) << (7 - j));
  1753. color_map[i * 3 + 2] |= (byte)(((lab >> 2) & 1) << (7 - j));
  1754. j += 1;
  1755. lab >>= 3;
  1756. }
  1757. }
  1758. // 去掉底色
  1759. color_map = color_map.Skip(3).ToArray();
  1760. return color_map;
  1761. }
  1762. /// <summary>
  1763. /// 获得目录下所有文件或指定文件类型文件(包含所有子文件夹)
  1764. /// </summary>
  1765. /// <param name="path">文件夹路径</param>
  1766. /// <param name="extName">扩展名可以多个 例如 .mp3.wma.rm</param>
  1767. /// <returns>List<FileInfo></returns>
  1768. public static List<FileInfo> getFile(string path, string extName, List<FileInfo> lst)
  1769. {
  1770. try
  1771. {
  1772. DirectoryInfo fdir = new DirectoryInfo(path);
  1773. FileInfo[] file = fdir.GetFiles();
  1774. //FileInfo[] file = Directory.GetFiles(path); //文件列表
  1775. if (file.Length != 0) //当前目录文件或文件夹不为空
  1776. {
  1777. foreach (FileInfo f in file) //显示当前目录所有文件
  1778. {
  1779. if (extName.ToLower().IndexOf(f.Extension.ToLower()) >= 0)
  1780. {
  1781. lst.Add(f);
  1782. }
  1783. }
  1784. }
  1785. return lst;
  1786. }
  1787. catch (Exception ex)
  1788. {
  1789. throw ex;
  1790. }
  1791. }
  1792. // 将Btimap类转换为byte[]类函数
  1793. public static byte[] GetBGRValues(Bitmap bmp, out int stride)
  1794. {
  1795. var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
  1796. var bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
  1797. stride = bmpData.Stride;
  1798. var rowBytes = bmpData.Width * Image.GetPixelFormatSize(bmp.PixelFormat) / 8;
  1799. var imgBytes = bmp.Height * rowBytes;
  1800. byte[] rgbValues = new byte[imgBytes];
  1801. IntPtr ptr = bmpData.Scan0;
  1802. for (var i = 0; i < bmp.Height; i++)
  1803. {
  1804. Marshal.Copy(ptr, rgbValues, i * rowBytes, rowBytes);
  1805. ptr += bmpData.Stride;
  1806. }
  1807. bmp.UnlockBits(bmpData);
  1808. return rgbValues;
  1809. }
  1810. // 创建指向float数组类型的IntPtr指针
  1811. public static IntPtr FloatToIntptr(float[] bytes)
  1812. {
  1813. GCHandle hObject = GCHandle.Alloc(bytes, GCHandleType.Pinned);
  1814. return hObject.AddrOfPinnedObject();
  1815. }
  1816. // 检查MaskRCNN模型是否启动在GPU上 -- 只支持GPU推理,因为内存占用较大,CPU可能溢出,导致无法连续推理
  1817. public static bool CheckMaskRCNN_workOnGpu(string model_type, bool use_gpu)
  1818. {
  1819. if (model_type == "mask")
  1820. {
  1821. if (use_gpu == false) // 当且仅当为MaskRCNN时,没有使用GPU会返回false
  1822. return false;
  1823. }
  1824. return true;
  1825. }
  1826. }
  1827. }