using System; using System.Collections.Generic; using System.Windows.Media.Imaging; using System.Windows.Threading; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Controls; using AI.Common; using Rectangle = System.Drawing.Rectangle; using RUSInferNet; using HumanOrganSegDemo; using RUSInferNet.PostProcess; using System.Xml.Linq; using System.Windows.Media; using System.Linq; namespace HumanOrganSegmentDemo { public class TestResults { /// /// 人体/人脸 /// public Dictionary BodyPartBoundBoxes; /// /// 一张图里目标对象的关键点 /// public BodyKeyPoints BodyKeyPoints { get; set; } /// /// 目标脏器的轮廓信息 /// public ContourPoints OrganContours; /// /// 像素坐标系下人体朝向的方向向量 /// public Point2D HumanOrientationInPCS { get; set; } public TestResults(Dictionary bodyBoundBoxes, BodyKeyPoints bodyKeyPoints, ContourPoints organContours, Point2D humanOrientationInPCS) { BodyPartBoundBoxes = bodyBoundBoxes; BodyKeyPoints = bodyKeyPoints; OrganContours = organContours; HumanOrientationInPCS = humanOrientationInPCS; } } 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); } } /// /// ImageInfo.xaml 的交互逻辑 /// public partial class ImageCanvas : UserControl { #region private private Bitmap _image; //private volatile bool _enableAI; private volatile bool _showContour; private volatile bool _showSize; private MyTransform _transform; private TestResults _testResult; #endregion #region properties public Bitmap Image { get => _image; } #endregion #region 用户界面响应 private void OcardialSizeChanged(object sender, System.Windows.SizeChangedEventArgs e) { UpdateTransforms(); } #endregion #region public public ImageCanvas() { InitializeComponent(); } public void UpdateImage(Bitmap image) { if (_image != null) { _image.Dispose(); } _image = image.Clone(new 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 UpdateHumanDetectResults(HumanDetectResultPerImage result) { _testResult = new TestResults(result.BodyPartBoundBoxesAll, result.ObjectKeyPoints, result.ObjectOrganContours, result.ObjectOrientationInPCS); UpdateTestResultShow(); } public void UpdateRoughPathResults(Point2D[] pathPts) { Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { DrawContoursInCanvas(pathPts, "path", System.Windows.Media.Brushes.Cyan); })); } public void Clear() { // 清空画布上的所有内容 TestResultCanvas.Children.Clear(); } #endregion #region private 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; } private void UpdateTransforms() { if (_image != null) { // 使图片保持长宽比例,居中显示,需要平移和缩放 var imgWidth = _image.Width; var imgHeight = _image.Height; var ocardialWidth = TestResultCanvas.ActualWidth; var ocardialHeight = TestResultCanvas.ActualHeight; var scaleX = ocardialWidth / imgWidth; var scaleY = ocardialHeight / 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 UpdateTestResultShow() { Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => { // 清空画布上的所有内容 TestResultCanvas.Children.Clear(); // 没有结果就直接返回 if (_testResult == null) { return; } if(_testResult.BodyPartBoundBoxes.Count==0) { return; } if (_testResult.BodyPartBoundBoxes.Count > 0) { // 更新所有框 foreach (var rcs in _testResult.BodyPartBoundBoxes.ToArray()) { if (rcs.Key == EnumHumanParts.Head) { DrawRectsInCanvas(rcs.Value, "head"); } if (rcs.Key == EnumHumanParts.Body) { DrawRectsInCanvas(rcs.Value, "body"); } } } // 更新人体关键点 DrawHumanInCanvas(_testResult.BodyKeyPoints, "keyPts"); // 更新轮廓 DrawContoursInCanvas(_testResult.OrganContours.Points, "contours", System.Windows.Media.Brushes.OrangeRed); // 更新人体朝向 //if (_testResult.HumanOrientationInPCS.X * _testResult.HumanOrientationInPCS.Y != 0) //{ // Point2D[] pts = new Point2D[2]; // pts[0] = new Point2D(_image.Width / 2, _image.Height / 2); // pts[1] = new Point2D(pts[0].X + _testResult.HumanOrientationInPCS.X, pts[0].Y + _testResult.HumanOrientationInPCS.Y); // DrawContoursInCanvas(pts, "Orientation", System.Windows.Media.Brushes.BlueViolet); //} })); } /// /// 从画布上移除矩形框 /// /// private void RemoveRectsCanvas(string roiName) { // 框 string textName = roiName; List rcsExist = TestResultCanvas.FindName(textName) as List; if (rcsExist != null) { foreach (var rcExist in rcsExist) { TestResultCanvas.Children.Remove(rcExist); } TestResultCanvas.UnregisterName(textName); } } /// /// 在画布上画出矩形框 /// /// /// private void DrawRectsInCanvas(Rect[] rcs, string rcName) { if (_transform == null) { return; } // 已有则删除 RemoveRectsCanvas(rcName); List rcRenders = new List { }; foreach (var rc in rcs) { System.Windows.Shapes.Rectangle rcRender = new System.Windows.Shapes.Rectangle(); rcRender.StrokeThickness = 3; rcRender.Stroke = System.Windows.Media.Brushes.AliceBlue; var transPtLeftTop = _transform.Transform(new System.Windows.Point(rc.Left, rc.Top)); var transPtRightDown = _transform.Transform(new System.Windows.Point(rc.Left + rc.Width, rc.Top + rc.Height)); Canvas.SetLeft(rcRender, transPtLeftTop.X); Canvas.SetTop(rcRender, transPtLeftTop.Y); rcRender.Width = transPtRightDown.X - transPtLeftTop.X; rcRender.Height = transPtRightDown.Y - transPtLeftTop.Y; TestResultCanvas.Children.Add(rcRender); //TestResultCanvas.RegisterName(rcName, rcRender); rcRenders.Add(rcRender); } TestResultCanvas.RegisterName(rcName, rcRenders); } /// /// 在画布上画出轮廓 /// /// /// private void DrawContoursInCanvas(Point2D[] pts, string registerName, System.Windows.Media.Brush color) { if (_transform == null) { return; } // 已有则删除 RemoveContoursInCanvas(registerName); if(pts== null) { return; } PointCollection contourPoints = new PointCollection(); foreach (var pt in pts) { var point = new System.Windows.Point(pt.X, pt.Y); var transPoint = _transform.Transform(point); contourPoints.Add(transPoint); } System.Windows.Shapes.Polyline contourDraw = new System.Windows.Shapes.Polyline(); contourDraw.Points = contourPoints; contourDraw.StrokeThickness = 3; contourDraw.Stroke = color; TestResultCanvas.Children.Add(contourDraw); TestResultCanvas.RegisterName(registerName, contourDraw); } /// /// 从画布上将轮廓移除 /// /// private void RemoveContoursInCanvas(string registerName) { System.Windows.Shapes.Polyline contourExist = TestResultCanvas.FindName(registerName) as System.Windows.Shapes.Polyline; if (contourExist != null) { TestResultCanvas.Children.Remove(contourExist); TestResultCanvas.UnregisterName(registerName); } } private void DrawHumanInCanvas(BodyKeyPoints humanKeyPts, string name) { if (_transform == null) { return; } // 已有则删除 RemoveHumanInCanvas(name); var neckPosition = _transform.Transform(new System.Windows.Point(humanKeyPts.Neck.X, humanKeyPts.Neck.Y)); var leftShoulderPosition = _transform.Transform(new System.Windows.Point(humanKeyPts.LeftShoulder.X, humanKeyPts.LeftShoulder.Y)); var rightShoulderPosition = _transform.Transform(new System.Windows.Point(humanKeyPts.RightShoulder.X, humanKeyPts.RightShoulder.Y)); // 脖子 if (humanKeyPts.Neck.X * humanKeyPts.Neck.Y > 0) { System.Windows.Shapes.Ellipse neck = new System.Windows.Shapes.Ellipse(); neck.StrokeThickness = 4; neck.Stroke = System.Windows.Media.Brushes.Orange; neck.Width = 6; Canvas.SetLeft(neck, neckPosition.X); Canvas.SetTop(neck, neckPosition.Y); TestResultCanvas.Children.Add(neck); string neckName = "Human_" + name + "_point_head"; TestResultCanvas.RegisterName(neckName, neck); } // 左肩 if (humanKeyPts.LeftShoulder.X * humanKeyPts.LeftShoulder.Y > 0) { System.Windows.Shapes.Ellipse leftShoulder = new System.Windows.Shapes.Ellipse(); leftShoulder.StrokeThickness = 3; leftShoulder.Stroke = System.Windows.Media.Brushes.AliceBlue; leftShoulder.Width = 6; Canvas.SetLeft(leftShoulder, leftShoulderPosition.X); Canvas.SetTop(leftShoulder, leftShoulderPosition.Y); TestResultCanvas.Children.Add(leftShoulder); string leftShoulderName = "Human_" + name + "_point_leftShoulder"; TestResultCanvas.RegisterName(leftShoulderName, leftShoulder); } // 右肩 if (humanKeyPts.RightShoulder.X * humanKeyPts.RightShoulder.Y > 0) { System.Windows.Shapes.Ellipse rightShoulder = new System.Windows.Shapes.Ellipse(); rightShoulder.StrokeThickness = 3; rightShoulder.Stroke = System.Windows.Media.Brushes.AliceBlue; rightShoulder.Width = 6; Canvas.SetLeft(rightShoulder, rightShoulderPosition.X); Canvas.SetTop(rightShoulder, rightShoulderPosition.Y); TestResultCanvas.Children.Add(rightShoulder); string rightShoulderName = "Human_" + name + "_point_rightShoulder"; TestResultCanvas.RegisterName(rightShoulderName, rightShoulder); } // 从脖子到左肩的线 if (humanKeyPts.Neck.X * humanKeyPts.Neck.Y > 0 && humanKeyPts.LeftShoulder.X * humanKeyPts.LeftShoulder.Y > 0) { System.Windows.Shapes.Line lineLeft = new System.Windows.Shapes.Line(); lineLeft.StrokeThickness = 2; lineLeft.Stroke = System.Windows.Media.Brushes.RosyBrown; lineLeft.X1 = neckPosition.X; lineLeft.Y1 = neckPosition.Y; lineLeft.X2 = leftShoulderPosition.X; lineLeft.Y2 = leftShoulderPosition.Y; TestResultCanvas.Children.Add(lineLeft); string lineLeftName = "Human_" + name + "_lineLeft"; TestResultCanvas.RegisterName(lineLeftName, lineLeft); } // 从脖子到右肩的线 if (humanKeyPts.Neck.X * humanKeyPts.Neck.Y > 0 && humanKeyPts.RightShoulder.X * humanKeyPts.RightShoulder.Y > 0) { System.Windows.Shapes.Line lineRight = new System.Windows.Shapes.Line(); lineRight.StrokeThickness = 2; lineRight.Stroke = System.Windows.Media.Brushes.DarkGray; lineRight.X1 = neckPosition.X; lineRight.Y1 = neckPosition.Y; lineRight.X2 = rightShoulderPosition.X; lineRight.Y2 = rightShoulderPosition.Y; TestResultCanvas.Children.Add(lineRight); string lineRightName = "Human_" + name + "_lineRight"; TestResultCanvas.RegisterName(lineRightName, lineRight); } } private void RemoveHumanInCanvas(string name) { // 脖子 string neckName = "Human_" + name + "_point_head"; System.Windows.Shapes.Ellipse neck = TestResultCanvas.FindName(neckName) as System.Windows.Shapes.Ellipse; if (neck != null) { TestResultCanvas.Children.Remove(neck); TestResultCanvas.UnregisterName(neckName); } // 左肩 string leftShoulderName = "Human_" + name + "_point_leftShoulder"; System.Windows.Shapes.Ellipse leftShoulder = TestResultCanvas.FindName(leftShoulderName) as System.Windows.Shapes.Ellipse; if (leftShoulder != null) { TestResultCanvas.Children.Remove(leftShoulder); TestResultCanvas.UnregisterName(leftShoulderName); } // 右肩 string rightShoulderName = "Human_" + name + "_point_rightShoulder"; System.Windows.Shapes.Ellipse rightShoulder = TestResultCanvas.FindName(rightShoulderName) as System.Windows.Shapes.Ellipse; if (rightShoulder != null) { TestResultCanvas.Children.Remove(rightShoulder); TestResultCanvas.UnregisterName(rightShoulderName); } // 从脖子到左肩的线 string lineLeftName = "Human_" + name + "_lineLeft"; System.Windows.Shapes.Line lineLeft = TestResultCanvas.FindName(lineLeftName) as System.Windows.Shapes.Line; if (lineLeft != null) { TestResultCanvas.Children.Remove(lineLeft); TestResultCanvas.UnregisterName(lineLeftName); } // 从脖子到右肩的线 string lineRightName = "Human_" + name + "_lineRight"; System.Windows.Shapes.Line lineRight = TestResultCanvas.FindName(lineRightName) as System.Windows.Shapes.Line; if (lineRight != null) { TestResultCanvas.Children.Remove(lineRight); TestResultCanvas.UnregisterName(lineRightName); } } #endregion } }