using AI.Common; using UsHepatoRenalRatioDetectLib; using UsHepatoRenalRatioDetectLib.OrganSegProcessModule; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; using static System.Net.Mime.MediaTypeNames; using Rect = AI.Common.Rect; namespace HepatoRenalEchoContrastDemo { //public class TestResults //{ // public Point2D[][] Countours { get; set; } // public Rect[] Rois { get; set; } // public double EchoContastValue { get; set; } // public TestResults(Point2D[][] countours, Rect[] rois, double echoContastValue) // { // Countours = countours; // Rois = rois; // EchoContastValue = echoContastValue; // } //} public class RoiInfo { public Rect RoiRect { get; set; } public System.Windows.Media.Brush Color { get; set; } public RoiInfo(Rect roi, System.Windows.Media.Brush color) { RoiRect = roi; Color = color; } } public class OrganInfo { public string OrganName { get; set; } public Rect BoundingBox { get; set; } public Point2D[][] Contours { get; set; } public System.Windows.Media.Brush Color => System.Windows.Media.Brushes.Green; public OrganInfo(string organName, Rect boundingBox, Point2D[][] contours) { OrganName = organName; BoundingBox = boundingBox; Contours = contours; } } public class MyTransform { public double Scale { get; set; } public double OffsetX { get; set; } public double OffsetY { get; set; } public MyTransform(double scale, double offsetX, double offsetY) { Scale = scale; OffsetX = offsetX; OffsetY = offsetY; } public System.Windows.Point Transform(System.Windows.Point point) { double x = OffsetX + Scale * point.X; double y = OffsetY + Scale * point.Y; return new System.Windows.Point(x, y); } public System.Windows.Rect Transform(System.Windows.Rect rect) { double left = OffsetX + Scale * rect.Left; double top = OffsetY + Scale * rect.Top; double width = Scale * rect.Width; double height = Scale * rect.Height; return new System.Windows.Rect(left, top, width, height); } } /// /// ImageCanvas.xaml 的交互逻辑 /// public partial class ImageCanvas : UserControl { #region private variables private Bitmap _image; private List _rois; private List _organs; private volatile bool _showOrgan; private volatile bool _showRois; private volatile bool _showEchoContastValue; private MyTransform _transform; private double _echoContrastRatio; #endregion #region 用户界面响应 private void CanvasSizeChanged(object sender, System.Windows.SizeChangedEventArgs e) { UpdateTransforms(); } #endregion #region public funcs public ImageCanvas() { InitializeComponent(); } /// /// 设置显示参数 /// /// /// /// public void SetShowParams(bool showCountours, bool showRois, bool showeEchoContastValue) { _showOrgan = showCountours; _showRois = showRois; _showEchoContastValue = showeEchoContastValue; if (_rois != null) { UpdateRois(); } if (_organs != null) { UpdateOrgans(); } } public void UpdateImage(Bitmap image) { if (_image != null) { _image.Dispose(); } _image = image.Clone(new System.Drawing.Rectangle(0, 0, image.Width, image.Height), image.PixelFormat); // 更新缩放比例 UpdateTransforms(); // 更新图像显示 var bitmapImage = BitmapToBitmapImage(image); Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { ImageShow.Source = bitmapImage; })); } public void UpdateTestResults(HRRDetectResultPerImg detectedResult) { List organs = new List(); List rois = new List(); foreach (var organ in detectedResult.SegResults) { organs.Add(new OrganInfo(organ.Organ.ToString(), organ.BoundingBox, organ.Contours)); } foreach (var roiDict in detectedResult.Rois) { rois.Add(new RoiInfo(roiDict.Value, System.Windows.Media.Brushes.Yellow)); } // 删掉旧的Roi和Organ RemoveRois(); RemoveOrgans(); RemoveText(); _organs = organs; _rois = rois; _echoContrastRatio = detectedResult.HepatoRenalRatio; // 更新画布上显示的Roi和Organ //////////////////////////////// double ratio = Math.Round(_echoContrastRatio, 4); if (ratio > 0) { UpdateRois(); } /////////////////////////////// UpdateOrgans(); UpdateText(); } public void ClearTestResult() { // 删掉旧的Roi和Organ RemoveRois(); RemoveOrgans(); RemoveText(); // 设置 _rois = null; _organs = null; } /// /// 将画布上的点转到图像坐标系下 /// /// /// public Point2D TransBack(System.Windows.Point point) { int x = Convert.ToInt32((point.X - _transform.OffsetX) / _transform.Scale); int y = Convert.ToInt32((point.Y - _transform.OffsetY) / _transform.Scale); return new Point2D(x, y); } #endregion #region private funcs private BitmapImage BitmapToBitmapImage(Bitmap img) { BitmapImage bmpimg = new BitmapImage(); using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { img.Save(ms, ImageFormat.Png); bmpimg.BeginInit(); bmpimg.StreamSource = ms; bmpimg.CacheOption = BitmapCacheOption.OnLoad; bmpimg.EndInit(); bmpimg.Freeze(); ms.Dispose(); } return bmpimg; } public void RemoveRoiInCanvas(string roiName) { // 框 string rectName = "ROI_Rect_" + roiName; System.Windows.Shapes.Rectangle rectExist = TestResultCanvas.FindName(rectName) as System.Windows.Shapes.Rectangle; if (rectExist != null) { TestResultCanvas.Children.Remove(rectExist); TestResultCanvas.UnregisterName(rectName); } // 文字 string textName = "ROI_Text_" + roiName; System.Windows.Controls.TextBlock textExist = TestResultCanvas.FindName(textName) as System.Windows.Controls.TextBlock; if (textExist != null) { TestResultCanvas.Children.Remove(textExist); TestResultCanvas.UnregisterName(textName); } } private void RemoveOrganInCanvas(OrganInfo organ) { string organName = organ.OrganName; // 框 string rectName = "Organ_Rect_" + organName; System.Windows.Shapes.Rectangle rectExist = TestResultCanvas.FindName(rectName) as System.Windows.Shapes.Rectangle; if (rectExist != null) { TestResultCanvas.Children.Remove(rectExist); TestResultCanvas.UnregisterName(rectName); } // 轮廓 int count = organ.Contours.Length; for (int ni = 0; ni < count; ni++) { string contourName = "Organ_Contour_" + organName + "_" + ni; System.Windows.Shapes.Polygon contourExist = TestResultCanvas.FindName(contourName) as System.Windows.Shapes.Polygon; if (contourExist != null) { TestResultCanvas.Children.Remove(contourExist); TestResultCanvas.UnregisterName(contourName); } } // 文字 string textName = "Organ_Text_" + organName; System.Windows.Controls.TextBlock textExist = TestResultCanvas.FindName(textName) as System.Windows.Controls.TextBlock; if (textExist != null) { TestResultCanvas.Children.Remove(textExist); TestResultCanvas.UnregisterName(textName); } } public void DrawRoiInCanvas(RoiInfo roi, string roiName) { if (_transform == null) { return; } // 已有则删除 RemoveRoiInCanvas(roiName); // 不显示ROI,则直接退出 if (!_showRois) { return; } // 画框 var rect = new System.Windows.Rect(roi.RoiRect.Left, roi.RoiRect.Top, roi.RoiRect.Width, roi.RoiRect.Height); var transRect = _transform.Transform(rect); System.Windows.Shapes.Rectangle rectDraw = new System.Windows.Shapes.Rectangle(); rectDraw.StrokeThickness = 3; rectDraw.Stroke = roi.Color; rectDraw.Width = transRect.Width; rectDraw.Height = transRect.Height; Canvas.SetLeft(rectDraw, transRect.Left); Canvas.SetTop(rectDraw, transRect.Top); TestResultCanvas.Children.Add(rectDraw); string rectName = "ROI_Rect_" + roiName; TestResultCanvas.RegisterName(rectName, rectDraw); // 将Roi的序号写在左上角 var pointLT = new System.Windows.Point(roi.RoiRect.Left, roi.RoiRect.Top); var transPointLT = _transform.Transform(pointLT); var textLeft = transPointLT.X - 16; var textTop = transPointLT.Y; TextBlock text = new TextBlock(); text.Text = roiName; text.FontSize = 16; text.FontWeight = System.Windows.FontWeights.Bold; text.Foreground = roi.Color; text.VerticalAlignment = System.Windows.VerticalAlignment.Top; Canvas.SetLeft(text, textLeft); Canvas.SetTop(text, textTop); TestResultCanvas.Children.Add(text); string textName = "ROI_Text_" + roiName; TestResultCanvas.RegisterName(textName, text); } private void DrawOrganInCanvas(OrganInfo organ) { if (_transform == null) { return; } // 已有则删除 RemoveOrganInCanvas(organ); // 是否显示Organ if (!_showOrgan) { return; } // 有轮廓就显示轮廓,没有轮廓就显示方框 string organName = organ.OrganName; if (organ.Contours.Length > 0) { int count = organ.Contours.Length; for (int ni = 0; ni < count; ni++) { Point2D[] contour = organ.Contours[ni]; PointCollection contourPoints = new PointCollection(); for (int nj = 0; nj < contour.Length; nj++) { var point = new System.Windows.Point(contour[nj].X, contour[nj].Y); var transPoint = _transform.Transform(point); contourPoints.Add(transPoint); } System.Windows.Shapes.Polygon contourDraw = new System.Windows.Shapes.Polygon(); contourDraw.Points = contourPoints; contourDraw.StrokeThickness = 3; contourDraw.Stroke = organ.Color; TestResultCanvas.Children.Add(contourDraw); string contourName = "Organ_Contour_" + organName + "_" + ni; TestResultCanvas.RegisterName(contourName, contourDraw); } } else { var rect = new System.Windows.Rect(organ.BoundingBox.Left, organ.BoundingBox.Top, organ.BoundingBox.Width, organ.BoundingBox.Height); var transRect = _transform.Transform(rect); System.Windows.Shapes.Rectangle rectDraw = new System.Windows.Shapes.Rectangle(); rectDraw.StrokeThickness = 3; rectDraw.Stroke = organ.Color; rectDraw.Width = transRect.Width; rectDraw.Height = transRect.Height; Canvas.SetLeft(rectDraw, transRect.Left); Canvas.SetTop(rectDraw, transRect.Top); TestResultCanvas.Children.Add(rectDraw); string rectName = "Organ_Rect_" + organName; TestResultCanvas.RegisterName(rectName, rectDraw); } // 将Organ的序号写在左上角 var pointLT = new System.Windows.Point(organ.BoundingBox.Left, organ.BoundingBox.Top); var transPointLT = _transform.Transform(pointLT); var textLeft = transPointLT.X + 16; var textTop = transPointLT.Y; TextBlock text = new TextBlock(); text.Text = organName; text.FontSize = 16; text.FontWeight = System.Windows.FontWeights.Bold; text.Foreground = organ.Color; text.VerticalAlignment = System.Windows.VerticalAlignment.Top; Canvas.SetLeft(text, textLeft); Canvas.SetTop(text, textTop); TestResultCanvas.Children.Add(text); string textName = "Organ_Text_" + organName; TestResultCanvas.RegisterName(textName, text); } private void UpdateTransforms() { if (_image != null) { // 使图片保持长宽比例,居中显示,需要平移和缩放 var imgWidth = _image.Width; var imgHeight = _image.Height; var canvasWidth = TestResultCanvas.ActualWidth; var canvasHeight = TestResultCanvas.ActualHeight; var scaleX = canvasWidth / imgWidth; var scaleY = canvasHeight / imgHeight; var scale = scaleX < scaleY ? scaleX : scaleY; double offsetX, offsetY; if (Math.Abs(scale - scaleX) < 0.0001) { offsetY = 0.5 * (scaleY - scale) * imgHeight; offsetX = 0; } else { offsetX = 0.5 * (scaleX - scale) * imgWidth; offsetY = 0; } _transform = new MyTransform(scale, offsetX, offsetY); } } private void RemoveRois() { Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { // 移除所有旧的ROI if (_rois != null) { for (int ni = 0; ni < _rois.Count; ni++) { RemoveRoiInCanvas(ni.ToString()); } } })); } private void RemoveOrgans() { Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { // 移除所有旧的Organ if (_organs != null) { for (int ni = 0; ni < _organs.Count; ni++) { RemoveOrganInCanvas(_organs[ni]); } } })); } private void RemoveText() { Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { // 文字 string textName = "Ratio"; System.Windows.Controls.TextBlock textExist = TestResultCanvas.FindName(textName) as System.Windows.Controls.TextBlock; if (textExist != null) { TestResultCanvas.Children.Remove(textExist); TestResultCanvas.UnregisterName(textName); } })); } private void UpdateRois() { Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { if (_rois != null) { for (int ni = 0; ni < _rois.Count; ni++) { DrawRoiInCanvas(_rois[ni], ni.ToString()); } } })); } private void UpdateOrgans() { Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { if (_organs != null) { for (int ni = 0; ni < _organs.Count; ni++) { DrawOrganInCanvas(_organs[ni]); } } })); } private void UpdateText() { Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { if (_transform == null) { return; } // 已有则删除 RemoveText(); // 不显示ROI,则直接退出 if (!_showRois) { return; } var pointLT = new System.Windows.Point(50, 50); var transPointLT = _transform.Transform(pointLT); var textLeft = transPointLT.X - 16; var textTop = transPointLT.Y; TextBlock text = new TextBlock(); double ratio = Math.Round(_echoContrastRatio, 4); text.Text = ratio.ToString(); if (ratio<=0) { text.Text = "Invalid !"; } text.FontSize = 30; text.FontWeight = System.Windows.FontWeights.Bold; text.Foreground = System.Windows.Media.Brushes.Yellow; text.VerticalAlignment = System.Windows.VerticalAlignment.Top; Canvas.SetLeft(text, textLeft); Canvas.SetTop(text, textTop); TestResultCanvas.Children.Add(text); string textName = "Ratio"; TestResultCanvas.RegisterName(textName, text); })); } #endregion } }