147 lines
5.6 KiB
C#
147 lines
5.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
using System.Windows.Media;
|
|
using Yztob.AiSports.Inferences.Things;
|
|
|
|
namespace Wpf_AiSportsMicrospace.Common
|
|
{
|
|
/// <summary>
|
|
/// 基于WPF的人体骨骼绘制器
|
|
/// </summary>
|
|
internal class HumanGraphicsRenderer
|
|
{
|
|
private readonly Typeface _typeface;
|
|
private IList<Human> _humans;
|
|
private IList<BoundingBox> _objects;
|
|
private readonly object _mutex = new object();
|
|
|
|
public HumanGraphicsRenderer()
|
|
{
|
|
_typeface = new Typeface(new FontFamily("Microsoft YaHei UI"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
|
|
}
|
|
|
|
#region 公共属性
|
|
public float ScaleRatio { get; set; } = 1f;
|
|
public float OffsetX { get; set; }
|
|
public float OffsetY { get; set; }
|
|
|
|
public System.Windows.Media.Color NoseColor { get; set; } = (System.Windows.Media.Color)ColorConverter.ConvertFromString("#FF8000");
|
|
public System.Windows.Media.Color LeftColor { get; set; } = (System.Windows.Media.Color)ColorConverter.ConvertFromString("#0075f2");
|
|
public System.Windows.Media.Color RightColor { get; set; } = (System.Windows.Media.Color)ColorConverter.ConvertFromString("#00AA00");
|
|
public float BonedWidth { get; set; } = 4;
|
|
public bool DrawLabel { get; set; } = true;
|
|
|
|
public IList<Human> Humans
|
|
{
|
|
get => _humans;
|
|
set { lock (_mutex) { _humans = value; } }
|
|
}
|
|
public IList<BoundingBox> Objects
|
|
{
|
|
get => _objects;
|
|
set { lock (_mutex) { _objects = value; } }
|
|
}
|
|
#endregion
|
|
|
|
#region 私有方法
|
|
private void DrawLine(DrawingContext dc, Keypoint begin, Keypoint end, System.Windows.Media.Color color)
|
|
{
|
|
var pen = new Pen(new SolidColorBrush(color), BonedWidth);
|
|
dc.DrawLine(pen,
|
|
new Point(begin.X * ScaleRatio + OffsetX, begin.Y * ScaleRatio + OffsetY),
|
|
new Point(end.X * ScaleRatio + OffsetX, end.Y * ScaleRatio + OffsetY));
|
|
}
|
|
|
|
private void DrawPoints(DrawingContext dc, IList<Keypoint> points)
|
|
{
|
|
foreach (var kp in points)
|
|
{
|
|
var x = kp.X * ScaleRatio + OffsetX;
|
|
var y = kp.Y * ScaleRatio + OffsetY;
|
|
|
|
// 绘制阴影点
|
|
dc.DrawEllipse(new SolidColorBrush(System.Windows.Media.Color.FromRgb(255, 255, 238)), null, new Point(x, y), 5, 5);
|
|
|
|
// 左右和鼻子颜色
|
|
var brush = new SolidColorBrush(LeftColor);
|
|
if (kp.Name == "nose")
|
|
brush = new SolidColorBrush(NoseColor);
|
|
else if (kp.Name.StartsWith("right_"))
|
|
brush = new SolidColorBrush(RightColor);
|
|
|
|
dc.DrawEllipse(brush, null, new Point(x, y), 4, 4);
|
|
}
|
|
}
|
|
|
|
private void DrawSkeleton(DrawingContext dc, IList<Keypoint> points)
|
|
{
|
|
var pointDict = points.ToDictionary(p => p.Name, p => p);
|
|
|
|
// 简单骨架连线示例
|
|
DrawLine(dc, pointDict["right_wrist"], pointDict["right_elbow"], System.Windows.Media.Colors.White);
|
|
DrawLine(dc, pointDict["right_elbow"], pointDict["right_shoulder"], System.Windows.Media.Colors.White);
|
|
DrawLine(dc, pointDict["right_shoulder"], pointDict["left_shoulder"], System.Windows.Media.Colors.White);
|
|
DrawLine(dc, pointDict["left_shoulder"], pointDict["left_elbow"], System.Windows.Media.Colors.White);
|
|
DrawLine(dc, pointDict["left_elbow"], pointDict["left_wrist"], System.Windows.Media.Colors.White);
|
|
|
|
// 头部
|
|
DrawLine(dc, pointDict["nose"], pointDict["left_eye"], System.Windows.Media.Colors.White);
|
|
DrawLine(dc, pointDict["nose"], pointDict["right_eye"], System.Windows.Media.Colors.White);
|
|
}
|
|
|
|
private void DrawBoxes(DrawingContext dc, IList<BoundingBox> boxes)
|
|
{
|
|
foreach (var box in boxes)
|
|
{
|
|
var color = System.Windows.Media.Colors.Red; // 这里可根据box.Label.Color转换
|
|
var pen = new Pen(new SolidColorBrush(color), 2);
|
|
|
|
var rect = new Rect(
|
|
box.X * ScaleRatio + OffsetX,
|
|
box.Y * ScaleRatio + OffsetY,
|
|
(box.RightX - box.X) * ScaleRatio,
|
|
(box.BottomY - box.Y) * ScaleRatio);
|
|
|
|
dc.DrawRectangle(null, pen, rect);
|
|
|
|
if (DrawLabel)
|
|
{
|
|
var formattedText = new FormattedText(
|
|
box.Label.Name + $" {box.Confidence:N6}",
|
|
System.Globalization.CultureInfo.CurrentCulture,
|
|
FlowDirection.LeftToRight,
|
|
_typeface,
|
|
12,
|
|
new SolidColorBrush(color),
|
|
1.0);
|
|
|
|
dc.DrawText(formattedText, new Point(rect.Left + 5, rect.Top + 5));
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region 公共方法
|
|
public void Drawing(DrawingContext dc)
|
|
{
|
|
lock (_mutex)
|
|
{
|
|
if (Humans?.Any() == true)
|
|
{
|
|
foreach (var human in Humans)
|
|
{
|
|
DrawSkeleton(dc, human.Keypoints);
|
|
DrawPoints(dc, human.Keypoints);
|
|
}
|
|
}
|
|
|
|
if (Objects?.Any() == true)
|
|
DrawBoxes(dc, Objects);
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|