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
}
}