MainWindow.xaml.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. using System;
  2. using System.Windows;
  3. using System.Windows.Threading;
  4. using System.Windows.Media.Imaging;
  5. using System.Collections.Generic;
  6. using System.Collections.Concurrent;
  7. using System.Threading.Tasks;
  8. using System.Drawing;
  9. using System.Drawing.Imaging;
  10. using Microsoft.Win32;
  11. using System.Threading;
  12. using System.Diagnostics;
  13. using Accord.Video.FFMPEG;
  14. using System.IO;
  15. using System.Runtime.InteropServices;
  16. using YOLODetectProcessLib;
  17. using Accord.Video.DirectShow;
  18. using Accord.Video;
  19. using System.Windows.Controls;
  20. namespace YOLODetectDemo
  21. {
  22. /// <summary>
  23. /// MainWindow.xaml 的交互逻辑
  24. /// </summary>
  25. public partial class MainWindow : Window
  26. {
  27. private IInferenceNetwork _inferNet = null;
  28. private BitmapImage _origImg = null;
  29. private BitmapImage _dstImg = null;
  30. private int _doneImageNum = 0;
  31. private volatile bool _isCropped = false;
  32. private Stopwatch _stopWatch = new Stopwatch();
  33. //private BreastLesionDetectImg _doBreastLesionDetect;
  34. private LiverLesionDetectImg _doLiverLesionDetect;
  35. int coreCount = Environment.ProcessorCount * 2;
  36. int numCPU;
  37. private volatile bool _enableAI = true;
  38. private volatile bool _continuouslyDetecting = false;
  39. List<DetectedBreastLesionResult> inferResult = new List<DetectedBreastLesionResult>();
  40. int oriWidth = 0;
  41. int oriHeight = 0;
  42. private readonly object _videoReaderLocker = new object();
  43. private VideoFileReader _videoReader;
  44. private volatile int _displayCount = 0;
  45. private ManualResetEvent _playEvent = new ManualResetEvent(false);
  46. private VideoCaptureDevice _videoCapture;
  47. public MainWindow()
  48. {
  49. InitializeComponent();
  50. try
  51. {
  52. numCPU = Convert.ToInt32(TextBoxCPU.Text);
  53. if (numCPU <= 0 || numCPU > coreCount)
  54. throw new Exception("CPU数目设置错误");
  55. }
  56. catch (Exception excep)
  57. {
  58. MessageBox.Show("CPU数目设置错误,只能为正整数且小于本机CPU线程总数!");
  59. return;
  60. }
  61. try
  62. {
  63. string netDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Networks");
  64. //_doBreastLesionDetect = new BreastLesionDetectImg(numCPU, netDir);
  65. _doLiverLesionDetect = new LiverLesionDetectImg(numCPU, netDir);
  66. }
  67. catch (Exception excep)
  68. {
  69. MessageBox.Show("doMyocardialSegment失败!");
  70. return;
  71. }
  72. }
  73. private void OnBtnTestClicked(object sender, RoutedEventArgs e)
  74. {
  75. StopPlay();
  76. try
  77. {
  78. OpenFileDialog openFileDialog = new OpenFileDialog
  79. {
  80. Filter = "图片文件|*.png;*.bmp;*.jpg;*.jpeg;*.avi;*.mp4",
  81. Multiselect = false,
  82. Title = "选择一幅或多幅图",
  83. };
  84. if (openFileDialog.ShowDialog() == true)
  85. {
  86. var fileName = openFileDialog.FileName;
  87. var fileExtension = Path.GetExtension(fileName);
  88. if (fileExtension == ".png" || fileExtension == ".jpg" || fileExtension == ".bmp" || fileExtension == ".jpeg")
  89. {
  90. var bitmap = new Bitmap(fileName);
  91. if (_enableAI)
  92. {
  93. DoImgTest(bitmap);
  94. }
  95. MyImageCanvas.UpdateImage(bitmap);
  96. bitmap.Dispose();
  97. }
  98. else
  99. {
  100. long frameCount;
  101. lock (_videoReaderLocker)
  102. {
  103. _videoReader = new VideoFileReader();
  104. _videoReader.Open(fileName);
  105. frameCount = _videoReader.FrameCount;
  106. }
  107. _displayCount = 0;
  108. _playEvent.Reset();
  109. Task.Run(() =>
  110. {
  111. _continuouslyDetecting = true;
  112. bool breakFlag = false;
  113. while (!_playEvent.WaitOne(1) && !breakFlag)
  114. {
  115. for (var ni = 0; ni < frameCount; ni++)
  116. {
  117. if (_playEvent.WaitOne(1))
  118. {
  119. breakFlag = true;
  120. break;
  121. }
  122. Bitmap bitmap;
  123. lock (_videoReaderLocker)
  124. {
  125. bitmap = _videoReader.ReadVideoFrame(ni);
  126. }
  127. _displayCount++;
  128. if (_enableAI)
  129. {
  130. DoImgTest(bitmap);
  131. }
  132. // 更新显示图像
  133. MyImageCanvas.UpdateImage(bitmap);
  134. bitmap.Dispose();
  135. if (_playEvent.WaitOne(0))
  136. {
  137. breakFlag = true;
  138. break;
  139. }
  140. }
  141. }
  142. _continuouslyDetecting = false;
  143. });
  144. VideoFileReader videoReader = new VideoFileReader();
  145. videoReader.Open(fileName);
  146. int totalCount = (int)videoReader.FrameCount;
  147. videoReader.Close();
  148. for (int ni = 0; ni < totalCount; ni++)
  149. {
  150. videoReader.Open(fileName);
  151. videoReader.Close();
  152. }
  153. videoReader.Dispose();
  154. }
  155. }
  156. }
  157. catch (Exception excep)
  158. {
  159. MessageBox.Show("加载测试图片时出错:" + excep);
  160. }
  161. }
  162. private void DoImgTest(Bitmap bmp)
  163. {
  164. try
  165. {
  166. RawImage rawImg = BitmapToRawImage(bmp);
  167. _stopWatch.Restart();
  168. //inferResult = _doBreastLesionDetect.ProcessBreastLesionImg(rawImg, _isCropped);
  169. inferResult = _doLiverLesionDetect.ProcessLiverLesionImg(rawImg, _isCropped);
  170. long inferTime = _stopWatch.ElapsedMilliseconds;
  171. _stopWatch.Stop();
  172. Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
  173. {
  174. ForwardTime.Text = inferTime.ToString();
  175. }));
  176. using (var g = Graphics.FromImage(bmp))
  177. {
  178. Brush brush = Brushes.Red;
  179. if (inferResult.Count > 0)
  180. {
  181. int len = inferResult.Count;
  182. for (int nj = 0; nj < len; nj++)
  183. {
  184. string labels = "";
  185. //if (inferResult[nj].Label == 1)
  186. //{
  187. // labels = "脂肪瘤";
  188. //}
  189. //if (inferResult[nj].Label == 2)
  190. //{
  191. // labels = "2类";
  192. //}
  193. //if (inferResult[nj].Label == 3)
  194. //{
  195. // labels = "3类";
  196. //}
  197. //if (inferResult[nj].Label == 4)
  198. //{
  199. // labels = "4a类";
  200. //}
  201. //if (inferResult[nj].Label == 5)
  202. //{
  203. // labels = "4b类";
  204. //}
  205. //if (inferResult[nj].Label == 6)
  206. //{
  207. // labels = "4c类";
  208. //}
  209. //if (inferResult[nj].Label == 7)
  210. //{
  211. // labels = "5类";
  212. //}
  213. if (inferResult[nj].Label == 1)
  214. {
  215. labels = "肝内强回声灶";
  216. }
  217. if (inferResult[nj].Label == 2)
  218. {
  219. labels = "肝血管瘤";
  220. }
  221. if (inferResult[nj].Label == 3)
  222. {
  223. labels = "肝囊肿";
  224. }
  225. if (inferResult[nj].Label == 4)
  226. {
  227. labels = "肝癌可能";
  228. }
  229. g.DrawString(labels + ":" + inferResult[nj].Confidence.ToString("0.0" + "%"), new Font("Arial", 10),
  230. brush, inferResult[nj].BoundingBox.Left + 10, inferResult[nj].BoundingBox.Top + 10);
  231. System.Drawing.Rectangle rect2 = new Rectangle(inferResult[nj].BoundingBox.Left,
  232. inferResult[nj].BoundingBox.Top, inferResult[nj].BoundingBox.Width,
  233. inferResult[nj].BoundingBox.Height);
  234. g.DrawRectangle(new Pen(brush, 2), rect2);
  235. }
  236. }
  237. }
  238. _doneImageNum += 1;
  239. }
  240. catch (Exception excep)
  241. {
  242. MessageBox.Show("测试图像时出错:" + excep);
  243. }
  244. }
  245. private void OnUncheckedEnableAI(object sender, RoutedEventArgs e)
  246. {
  247. _enableAI = false;
  248. MyImageCanvas.SetShowParams(_enableAI);
  249. }
  250. private void OnCheckedEnableAI(object sender, RoutedEventArgs e)
  251. {
  252. _enableAI = true;
  253. MyImageCanvas.SetShowParams(_enableAI);
  254. if (!_continuouslyDetecting && MyImageCanvas.Image != null)
  255. {
  256. DoImgTest(MyImageCanvas.Image);
  257. }
  258. }
  259. public static void SaveBitmapImageIntoFile(BitmapImage bitmapImage, string filePath)
  260. {
  261. BitmapEncoder encoder = new PngBitmapEncoder();
  262. encoder.Frames.Add(BitmapFrame.Create(bitmapImage));
  263. using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
  264. {
  265. encoder.Save(fileStream);
  266. }
  267. }
  268. public static RawImage BitmapToRawImage(Bitmap image, bool keepChannel = false)
  269. {
  270. int width = image.Width;
  271. int height = image.Height;
  272. PixelFormat pixelFormat = image.PixelFormat;
  273. if (pixelFormat != PixelFormat.Format24bppRgb && pixelFormat != PixelFormat.Format32bppArgb &&
  274. pixelFormat != PixelFormat.Format32bppPArgb && pixelFormat != PixelFormat.Format32bppRgb &&
  275. pixelFormat != PixelFormat.Format8bppIndexed)
  276. {
  277. throw new Exception("Unexpected image pixel format:" + pixelFormat);
  278. }
  279. int origChannel;
  280. if (pixelFormat == PixelFormat.Format24bppRgb)
  281. {
  282. origChannel = 3;
  283. }
  284. else if (pixelFormat == PixelFormat.Format8bppIndexed)
  285. {
  286. origChannel = 1;
  287. }
  288. else
  289. {
  290. origChannel = 4;
  291. }
  292. int dstChannel = 3;
  293. if (keepChannel)
  294. {
  295. dstChannel = origChannel;
  296. }
  297. var bmData = image.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, pixelFormat);
  298. byte[] dstDataArray = new byte[width * height * dstChannel];
  299. {
  300. int stride = bmData.Stride;
  301. int dstStride = width * dstChannel;
  302. IntPtr ptr = bmData.Scan0;
  303. IntPtr ptrH, ptrW;
  304. for (int nh = 0; nh < height; nh++)
  305. {
  306. ptrH = IntPtr.Add(ptr, nh * stride);
  307. if (origChannel == dstChannel)
  308. {
  309. Marshal.Copy(ptrH, dstDataArray, nh * dstStride, dstStride);
  310. }
  311. else if (origChannel > dstChannel)
  312. {
  313. for (int nw = 0; nw < width; nw++)
  314. {
  315. ptrW = IntPtr.Add(ptrH, nw * origChannel);
  316. Marshal.Copy(ptrW, dstDataArray, nh * dstStride + nw * dstChannel, dstChannel);
  317. }
  318. }
  319. else
  320. {
  321. for (int nw = 0; nw < width; nw++)
  322. {
  323. ptrW = IntPtr.Add(ptrH, nw * origChannel);
  324. for (int nc = 0; nc < dstChannel; nc++)
  325. {
  326. Marshal.Copy(ptrW, dstDataArray, nh * dstStride + nw * dstChannel + nc, 1);
  327. }
  328. }
  329. }
  330. }
  331. }
  332. image.UnlockBits(bmData);
  333. return new RawImage(dstDataArray, width, height, dstChannel, width * dstChannel);
  334. }
  335. public static Bitmap RawImageToBitmap(RawImage image)
  336. {
  337. int width = image.Width;
  338. int height = image.Height;
  339. int channel = image.Channel;
  340. PixelFormat pixelFormat;
  341. switch (channel)
  342. {
  343. case 1:
  344. pixelFormat = PixelFormat.Format8bppIndexed;
  345. break;
  346. case 3:
  347. pixelFormat = PixelFormat.Format24bppRgb;
  348. break;
  349. case 4:
  350. pixelFormat = PixelFormat.Format32bppArgb;
  351. break;
  352. default:
  353. throw new ArgumentOutOfRangeException("The expected image.channel is 1,3,4 but got:" + channel + ".");
  354. }
  355. Bitmap dstBmp = new Bitmap(width, height, pixelFormat);
  356. var bmData = dstBmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, pixelFormat);
  357. {
  358. int stride = bmData.Stride;
  359. IntPtr ptr = bmData.Scan0;
  360. byte[] dataBuffer = image.DataBuffer;
  361. if (stride == width * channel)
  362. {
  363. Marshal.Copy(dataBuffer, 0, ptr, width * height * channel);
  364. }
  365. else
  366. {
  367. IntPtr ptrDst;
  368. for (int ni = 0; ni < height; ni++)
  369. {
  370. ptrDst = IntPtr.Add(ptr, ni * stride);
  371. Marshal.Copy(dataBuffer, ni * width * channel, ptrDst, width * channel);
  372. }
  373. }
  374. }
  375. dstBmp.UnlockBits(bmData);
  376. return dstBmp;
  377. }
  378. private BitmapImage BitmapToBitmapImage(Bitmap img)
  379. {
  380. BitmapImage bmpimg = new BitmapImage();
  381. using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
  382. {
  383. img.Save(ms, ImageFormat.Png);
  384. bmpimg.BeginInit();
  385. bmpimg.StreamSource = ms;
  386. bmpimg.CacheOption = BitmapCacheOption.OnLoad;
  387. bmpimg.EndInit();
  388. bmpimg.Freeze();
  389. ms.Dispose();
  390. }
  391. return bmpimg;
  392. }
  393. private void StopPlay()
  394. {
  395. _playEvent.Set();
  396. lock (_videoReaderLocker)
  397. {
  398. if (_videoReader != null)
  399. {
  400. _videoReader.Close();
  401. _videoReader.Dispose();
  402. _videoReader = null;
  403. }
  404. }
  405. if (_videoCapture != null)
  406. {
  407. _videoCapture.NewFrame -= OnVideoCaptureNewFrame;
  408. _videoCapture.SignalToStop();
  409. _videoCapture = null;
  410. }
  411. _continuouslyDetecting = false;
  412. }
  413. private void OnVideoCaptureNewFrame(object sender, NewFrameEventArgs e)
  414. {
  415. var bitmap = e.Frame;
  416. // 更新显示图像
  417. MyImageCanvas.UpdateImage(bitmap);
  418. _displayCount++;
  419. if (_enableAI)
  420. {
  421. DoImgTest(bitmap);
  422. }
  423. MyImageCanvas.UpdateImage(bitmap);
  424. bitmap.Dispose();
  425. }
  426. private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
  427. {
  428. _inferNet?.Dispose();
  429. }
  430. private void OnCheckedIsCropped(object sender, RoutedEventArgs e)
  431. {
  432. _isCropped = true;
  433. }
  434. private void OnUncheckedIsCropped(object sender, RoutedEventArgs e)
  435. {
  436. _isCropped = false;
  437. }
  438. }
  439. }