using System; using System.IO; using System.Windows; using System.Drawing; using System.Threading; using Microsoft.Win32; using System.Windows.Threading; using System.Collections.Generic; using Accord.Video.FFMPEG; using AI.DiagSystem.Workers; using AI.DiagSystem.Workers.WorkerInputs; using ImageShowUtilsLib; using AI.Common; using AI.Common.Log; using AI.DiagSystem; namespace AIMultiInferWorkDemo { /// /// 图像相关信息 /// public class ImageSourceFileInfo { private VideoFileReader _videoReader; public string OrigPath { get; protected set; } public bool IsVideo { get; protected set; } public int ImageCount { get; protected set; } public Bitmap GetOrigImage(int index = 0) { if (!File.Exists(OrigPath)) { return null; } if (IsVideo) { if (index >= ImageCount) { return null; } var img = _videoReader.ReadVideoFrame(index); return img; } else { var img = new Bitmap(OrigPath); return img; } } public ImageSourceFileInfo(string origImagePath) { OrigPath = origImagePath; // 是否为视频 FileInfo fileInfo = new FileInfo(origImagePath); IsVideo = false; if ((fileInfo.Extension == ".mp4") || (fileInfo.Extension == ".avi") || (fileInfo.Extension == ".wmv") || (fileInfo.Extension == ".MP4") || (fileInfo.Extension == ".AVI") || (fileInfo.Extension == ".WMV")) { IsVideo = true; } // 如果是视频,需要_videoReader打开它 if (IsVideo) { _videoReader = new VideoFileReader(); _videoReader.Open(origImagePath); if (_videoReader.CodecName == ".wmv2") { int count = 0; while (_videoReader.ReadVideoFrame(count) != null) { count += 1; } ImageCount = count; } else { ImageCount = (int)_videoReader.FrameCount; } } else { ImageCount = 1; } } public void Dispose() { if (_videoReader != null) { _videoReader.Close(); _videoReader.Dispose(); _videoReader = null; } } } /// /// MainWindow.xaml 的交互逻辑 /// public partial class MainWindow : Window { #region private variables private WorkerManager _workManager = null; private AI.DiagSystem.ResultsAggregator _resultAggregator = null; private const int _numWorker = 2; private const int _modelCPU = 2; private const int _calCPU = 1; private const int _sleepTime = 500; private const bool _isCropped = false; private volatile bool _disposing = false; private volatile bool _loaded = false; private volatile EnumInferWorkName _inferWorkName1; private volatile EnumInferWorkName _inferWorkName2; private volatile ImageSourceFileInfo _imageSource1 = null; private volatile int _index1 = 0; private Thread _videoPlayThread1 = null; private volatile bool _videoPlaying1 = false; private volatile bool _stopVideoPlay1 = false; private volatile bool _reuse1 = false; private volatile bool _enableLesionSeg1 = false; private volatile bool _enableDescription1 = false; private volatile ImageSourceFileInfo _imageSource2 = null; private volatile int _index2 = 0; private Thread _videoPlayThread2 = null; private volatile bool _videoPlaying2 = false; private volatile bool _stopVideoPlay2 = false; private volatile bool _reuse2 = false; private volatile bool _enableLesionSeg2 = false; private volatile bool _enableDescription2 = false; private volatile bool _errorMsgShowing = false; #endregion #region 用户界面响应 public MainWindow() { InitializeComponent(); ComboBoxInferNames1.SelectionChanged -= OnInferNames1Changed; ComboBoxInferNames2.SelectionChanged -= OnInferNames2Changed; ComboBoxInferNames1.Items.Clear(); ComboBoxInferNames2.Items.Clear(); foreach (var inferName in Enum.GetValues(typeof(EnumInferWorkName))) { if ((EnumInferWorkName)inferName != EnumInferWorkName.Default && (EnumInferWorkName)inferName != EnumInferWorkName.BreastDSOD && (EnumInferWorkName)inferName != EnumInferWorkName.BreastDSOD_LiverYOLO && (EnumInferWorkName)inferName != EnumInferWorkName.BreastDSOD_LiverKerasSeg && (EnumInferWorkName)inferName != EnumInferWorkName.UserDefine2 && (EnumInferWorkName)inferName != EnumInferWorkName.UserDefine3) { ComboBoxInferNames1.Items.Add(inferName); ComboBoxInferNames2.Items.Add(inferName); } } ComboBoxInferNames1.SelectionChanged += OnInferNames1Changed; ComboBoxInferNames2.SelectionChanged += OnInferNames2Changed; ComboBoxInferNames1.SelectedIndex = 0; ComboBoxInferNames2.SelectedIndex = 1; InitWorkManager(); } private void OnBtnLoadImage1Click(object sender, RoutedEventArgs e) { if (!_loaded) { MessageBox.Show("请先加载模型."); return; } OpenFileDialog openFileDialog = new OpenFileDialog { Filter = "图片或视频|*.png;*.PNG;*.bmp;*.BMP;*.jpg;*.JPG;*.jpeg;*.JPEG;*.mp4;*.MP4;*.avi;*.AVI;*.wmv;*.WMV", Multiselect = false, Title = "选择一个图像或视频" }; if (openFileDialog.ShowDialog() ?? false) { if (_imageSource1 != null) { if (_imageSource1.IsVideo && _videoPlaying1) { _stopVideoPlay1 = true; while (_videoPlaying1) { Thread.Sleep(5); } } _imageSource1.Dispose(); } _imageSource1 = new ImageSourceFileInfo(openFileDialog.FileName); _index1 = 0; if (_imageSource1.IsVideo) { _videoPlaying1 = true; BtnStop1.Visibility = Visibility.Visible; BtnStop1.Content = "暂停"; CheckBoxReuse1.Visibility = Visibility.Visible; if (_videoPlayThread1 == null || !_videoPlayThread1.IsAlive) { _videoPlayThread1 = new Thread(() => DoVideoPlay1()) { IsBackground = true, Name = "AI_VideoPlay_1" }; _videoPlayThread1.Start(); } } else { BtnStop1.Visibility = Visibility.Hidden; CheckBoxReuse1.Visibility = Visibility.Hidden; TestOneFrame1(); } } } private void OnBtnStop1Click(object sender, RoutedEventArgs e) { if (!_loaded) { MessageBox.Show("请先加载模型."); return; } if (_videoPlaying1) { BtnStop1.Content = "继续"; _videoPlaying1 = false; } else { BtnStop1.Content = "暂停"; _videoPlaying1 = true; if (_videoPlayThread1 == null || !_videoPlayThread1.IsAlive) { _videoPlayThread1 = new Thread(() => DoVideoPlay1()) { IsBackground = true, Name = "AI_VideoPlay_1" }; _videoPlayThread1.Start(); } } } private void OnUncheckedReuse1(object sender, RoutedEventArgs e) { _reuse1 = false; } private void OnCheckedReuse1(object sender, RoutedEventArgs e) { _reuse1 = true; } private void OnUncheckedEnabelLesionSeg1(object sender, RoutedEventArgs e) { _enableLesionSeg1 = false; } private void OnCheckedEnableLesionSeg1(object sender, RoutedEventArgs e) { _enableLesionSeg1 = true; } private void OnUncheckedEnableDescription1(object sender, RoutedEventArgs e) { _enableDescription1 = false; } private void OnCheckedEnableDescription1(object sender, RoutedEventArgs e) { _enableDescription1 = true; } private void OnBtnLoadImage2Click(object sender, RoutedEventArgs e) { if (!_loaded) { MessageBox.Show("请先加载模型."); return; } OpenFileDialog openFileDialog = new OpenFileDialog { Filter = "图片或视频|*.png;*.PNG;*.bmp;*.BMP;*.jpg;*.JPG;*.jpeg;*.JPEG;*.mp4;*.MP4;*.avi;*.AVI;*.wmv;*.WMV", Multiselect = false, Title = "选择一个图像或视频" }; if (openFileDialog.ShowDialog() ?? false) { if (_imageSource2 != null) { if (_imageSource2.IsVideo && _videoPlaying2) { _stopVideoPlay2 = true; while (_videoPlaying2) { Thread.Sleep(5); } } _imageSource2.Dispose(); } _imageSource2 = new ImageSourceFileInfo(openFileDialog.FileName); _index2 = 0; if (_imageSource2.IsVideo) { _videoPlaying2 = true; BtnStop2.Visibility = Visibility.Visible; BtnStop2.Content = "暂停"; CheckBoxReuse2.Visibility = Visibility.Visible; if (_videoPlayThread2 == null || !_videoPlayThread2.IsAlive) { _videoPlayThread2 = new Thread(() => DoVideoPlay2()) { IsBackground = true, Name = "AI_VideoPlay_2" }; _videoPlayThread2.Start(); } } else { BtnStop2.Visibility = Visibility.Hidden; CheckBoxReuse2.Visibility = Visibility.Hidden; TestOneFrame2(); } } } private void OnBtnStop2Click(object sender, RoutedEventArgs e) { if (!_loaded) { MessageBox.Show("请先加载模型."); return; } if (_videoPlaying2) { BtnStop2.Content = "继续"; _videoPlaying2 = false; } else { BtnStop2.Content = "暂停"; _videoPlaying2 = true; if (_videoPlayThread2 == null || !_videoPlayThread2.IsAlive) { _videoPlayThread2 = new Thread(() => DoVideoPlay2()) { IsBackground = true, Name = "AI_VideoPlay_2" }; _videoPlayThread2.Start(); } } } private void OnUncheckedReuse2(object sender, RoutedEventArgs e) { _reuse2 = false; } private void OnCheckedReuse2(object sender, RoutedEventArgs e) { _reuse2 = true; } private void OnUncheckedEnabelLesionSeg2(object sender, RoutedEventArgs e) { _enableLesionSeg2 = false; } private void OnCheckedEnableLesionSeg2(object sender, RoutedEventArgs e) { _enableLesionSeg2 = true; } private void OnUncheckedEnableDescription2(object sender, RoutedEventArgs e) { _enableDescription2 = false; } private void OnCheckedEnableDescription2(object sender, RoutedEventArgs e) { _enableDescription2 = true; } private void OnInferNames1Changed(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { _loaded = false; _inferWorkName1 = (EnumInferWorkName)ComboBoxInferNames1.SelectedItem; } private void OnInferNames2Changed(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { _loaded = false; _inferWorkName2 = (EnumInferWorkName)ComboBoxInferNames2.SelectedItem; } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { DoDispose(); } private void OnBtnDisposeClick(object sender, RoutedEventArgs e) { DoDispose(); } private void OnBtnLoadClick(object sender, RoutedEventArgs e) { InitWorkManager(); } #endregion #region private /// /// 初始化workmanager /// private void InitWorkManager() { // 初始化workManager _workManager = new WorkerManager(25, _numWorker, _modelCPU, _calCPU, "",new List { _inferWorkName1,_inferWorkName2}); _workManager.NotifyInferFinish += OnWorkerInferFinish; _workManager.NotifyError += OnErrorOccur; _workManager.NotifyLog += OnLogWrite; // 初始化resultAggregator _resultAggregator = new AI.DiagSystem.ResultsAggregator(false, -1); _resultAggregator.NotifyLog += OnLogWrite; _loaded = true; _disposing = false; _stopVideoPlay1 = false; _stopVideoPlay2 = false; } /// /// 收到workManager的推理结束通知 /// /// /// private void OnWorkerInferFinish(object sender, InferFinishEventArgs e) { if (!_disposing) { _resultAggregator.AddInferResult(e.WorkerResult); UpdateInferTime(e.TimeElapsed, e.InferSize); } } /// /// 收到发生错误的通知 /// /// /// private void OnErrorOccur(object sender, ErrorEventArgs e) { if (!_errorMsgShowing) { Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { _errorMsgShowing = true; MessageBox.Show("推理过程中发生错误!" + e.GetException()); _errorMsgShowing = false; })); } } /// /// 有log要记 /// /// /// private void OnLogWrite(object sender, LogEventArgs e) { Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { TextLog.Text += e.Msg +"\r\n"; })); } /// /// 播放视频1 /// private void DoVideoPlay1() { while (!_disposing) { if (_stopVideoPlay1) { _videoPlaying1 = false; _stopVideoPlay1 = false; } else { if (_videoPlaying1 && _imageSource1 != null) { if (!_imageSource1.IsVideo) { Thread.Sleep(5); continue; } if (_index1 <= -1) { Thread.Sleep(5); continue; } TestOneFrame1(); Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { ProgressBar1.Value = (int)((double)_index1 / _imageSource1.ImageCount * 100); })); // 更新index if (_index1 < _imageSource1.ImageCount - 1) { _index1 += 1; } else { if (_reuse1) { _index1 = 0; } else { _index1 = -1; } } Thread.Sleep(_sleepTime); } else { Thread.Sleep(5); } } } _videoPlaying1 = false; } /// /// 播放视频2 /// private void DoVideoPlay2() { while (!_disposing) { if (_stopVideoPlay2) { _videoPlaying2 = false; _stopVideoPlay2 = false; } else { if (_videoPlaying2 && _imageSource2 != null) { if (!_imageSource2.IsVideo) { Thread.Sleep(5); continue; } if (_index2 <= -1) { Thread.Sleep(5); continue; } TestOneFrame2(); Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { ProgressBar2.Value = (int)((double)_index2 / _imageSource2.ImageCount * 100); })); // 更新index if (_index2 < _imageSource2.ImageCount - 1) { _index2 += 1; } else { if (_reuse2) { _index2 = 0; } else { _index2 = -1; } } Thread.Sleep(_sleepTime); } else { Thread.Sleep(5); } } } _videoPlaying2 = false; } /// /// 评估单幅图像 /// 推理请求被塞入待处理队列后,等待诊断系统给出结果后再返回 /// /// /// /// /// private AIDiagResultPerImg EvaluateOneImage(RawImage image, bool isCropped, bool enableLesionSeg, bool enableDescription, EnumScanParts scanPart, EnumInferWorkName inferTaskName) { // 生成随机码,作为diagId和inferId string diagId = Guid.NewGuid().ToString(); WorkerInputBatchImages input = new WorkerInputBatchImages(diagId, diagId, new RawImage(image.DataBuffer, image.Width, image.Height, image.ColorType), isCropped,enableLesionSeg, enableDescription, scanPart,inferTaskName); _workManager.AddInferRequest(input); // 将相关信息塞入结果收集器 _resultAggregator.AddNewDiag(diagId, 1, isCropped,enableLesionSeg, enableDescription,scanPart, inferTaskName); _resultAggregator.AddNewInfer(diagId, diagId, 1); // 等待结果 AI.DiagSystem.AIDiagResultPerImg result = null; bool waiting = true; while (waiting && !_disposing) { if (!_resultAggregator.GetIsFinish(diagId)) { Thread.Sleep(5); } else { waiting = false; var ret = (AI.DiagSystem.AIDiagResultBatchImages)_resultAggregator.GetDiagResults(diagId); result = ret.DiagResult[0]; } } return result; } /// /// 将结果画到图上 /// /// /// /// private void DrawResultOnImage(Bitmap image, AI.DiagSystem.AIDiagResultPerImg diagResult) { try { ResultShowGrid.UpdateImage(image); ResultShowGrid.UpdateDiagResult(diagResult); } catch (Exception excep) { MessageBox.Show("出错了:" + excep); } } /// /// 将推理耗时显示到界面上 /// /// private void UpdateInferTime(Dictionary inferTime, int inferSize) { string inferTimePerTask = ""; foreach (var taskname in inferTime.Keys) { inferTimePerTask += "{'" + taskname + "':" + inferTime[taskname].ToString() + "}\r\n"; } string inferTimeStr = "InferSize:" + inferSize + ",\r\nInferTimePerTask:\r\n" + inferTimePerTask; Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { TextInferTime.Text = inferTimeStr; })); } private void DoDispose() { try { _disposing = true; _stopVideoPlay1 = true; while (_videoPlaying1) { Thread.Sleep(5); } _imageSource1?.Dispose(); _stopVideoPlay2 = true; while (_videoPlaying2) { Thread.Sleep(5); } _imageSource2?.Dispose(); _workManager?.Dispose(); _resultAggregator?.Dispose(); _loaded = false; } catch (Exception excep) { MessageBox.Show("释放时出错:" + excep); } } private void TestOneFrame1() { // 取出当前图像 Bitmap image = _imageSource1.GetOrigImage(_index1); // 测试 var rawImg = RawImageShowUtils.BitmapToRawImage(image); RawImage rawImage = new RawImage(rawImg.DataBuffer, rawImg.Width, rawImg.Height, rawImg.ColorType); EnumInferWorkName inferWorkName = _inferWorkName1; var result = EvaluateOneImage(rawImage, _isCropped, _enableLesionSeg1, _enableDescription1, EnumScanParts.NotSpecified, inferWorkName); rawImage.Dispose(); rawImg.Dispose(); if (result == null) { image.Dispose(); return; } // 更新显示 DrawResultOnImage(image, result); image.Dispose(); } private void TestOneFrame2() { // 取出当前图像 Bitmap image = _imageSource2.GetOrigImage(_index2); // 测试 var rawImg = RawImageShowUtils.BitmapToRawImage(image); RawImage rawImage = new RawImage(rawImg.DataBuffer, rawImg.Width, rawImg.Height, rawImg.ColorType); EnumInferWorkName inferWorkName = _inferWorkName2; var result = EvaluateOneImage(rawImage, _isCropped, _enableLesionSeg2, _enableDescription2, EnumScanParts.NotSpecified, inferWorkName); rawImage.Dispose(); rawImg.Dispose(); if (result == null) { image.Dispose(); return; } // 更新显示 DrawResultOnImage(image, result); image.Dispose(); } #endregion } }