ImageCanvas.xaml.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Windows.Media.Imaging;
  4. using System.Windows.Threading;
  5. using System.Drawing;
  6. using System.Drawing.Imaging;
  7. using System.Windows.Controls;
  8. using AI.Common;
  9. using Rectangle = System.Drawing.Rectangle;
  10. using RUSInferNet;
  11. using HumanOrganSegDemo;
  12. using RUSInferNet.PostProcess;
  13. using System.Xml.Linq;
  14. using System.Windows.Media;
  15. using System.Linq;
  16. namespace HumanOrganSegmentDemo
  17. {
  18. public class TestResults
  19. {
  20. /// <summary>
  21. /// 人体/人脸
  22. /// </summary>
  23. public Dictionary<EnumHumanParts, Rect[]> BodyPartBoundBoxes;
  24. /// <summary>
  25. /// 一张图里目标对象的关键点
  26. /// </summary>
  27. public BodyKeyPoints BodyKeyPoints { get; set; }
  28. /// <summary>
  29. /// 目标脏器的轮廓信息
  30. /// </summary>
  31. public ContourPoints OrganContours;
  32. /// <summary>
  33. /// 像素坐标系下人体朝向的方向向量
  34. /// </summary>
  35. public Point2D HumanOrientationInPCS { get; set; }
  36. public TestResults(Dictionary<EnumHumanParts, Rect[]> bodyBoundBoxes, BodyKeyPoints bodyKeyPoints, ContourPoints organContours, Point2D humanOrientationInPCS)
  37. {
  38. BodyPartBoundBoxes = bodyBoundBoxes;
  39. BodyKeyPoints = bodyKeyPoints;
  40. OrganContours = organContours;
  41. HumanOrientationInPCS = humanOrientationInPCS;
  42. }
  43. }
  44. public class MyTransform
  45. {
  46. public double Scale { get; set; }
  47. public double OffsetX { get; set; }
  48. public double OffsetY { get; set; }
  49. public MyTransform(double scale, double offsetX, double offsetY)
  50. {
  51. Scale = scale;
  52. OffsetX = offsetX;
  53. OffsetY = offsetY;
  54. }
  55. public System.Windows.Point Transform(System.Windows.Point point)
  56. {
  57. double x = OffsetX + Scale * point.X;
  58. double y = OffsetY + Scale * point.Y;
  59. return new System.Windows.Point(x, y);
  60. }
  61. public System.Windows.Rect Transform(System.Windows.Rect rect)
  62. {
  63. double left = OffsetX + Scale * rect.Left;
  64. double top = OffsetY + Scale * rect.Top;
  65. double width = Scale * rect.Width;
  66. double height = Scale * rect.Height;
  67. return new System.Windows.Rect(left, top, width, height);
  68. }
  69. }
  70. /// <summary>
  71. /// ImageInfo.xaml 的交互逻辑
  72. /// </summary>
  73. public partial class ImageCanvas : UserControl
  74. {
  75. #region private
  76. private Bitmap _image;
  77. //private volatile bool _enableAI;
  78. private volatile bool _showContour;
  79. private volatile bool _showSize;
  80. private MyTransform _transform;
  81. private TestResults _testResult;
  82. #endregion
  83. #region properties
  84. public Bitmap Image { get => _image; }
  85. #endregion
  86. #region 用户界面响应
  87. private void OcardialSizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
  88. {
  89. UpdateTransforms();
  90. }
  91. #endregion
  92. #region public
  93. public ImageCanvas()
  94. {
  95. InitializeComponent();
  96. }
  97. public void UpdateImage(Bitmap image)
  98. {
  99. if (_image != null)
  100. {
  101. _image.Dispose();
  102. }
  103. _image = image.Clone(new Rectangle(0, 0, image.Width, image.Height), image.PixelFormat);
  104. // 更新缩放比例
  105. UpdateTransforms();
  106. // 更新图像显示
  107. var bitmapImage = BitmapToBitmapImage(image);
  108. Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
  109. {
  110. ImageShow.Source = bitmapImage;
  111. }));
  112. }
  113. public void UpdateHumanDetectResults(HumanDetectResultPerImage result)
  114. {
  115. _testResult = new TestResults(result.BodyPartBoundBoxesAll, result.ObjectKeyPoints, result.ObjectOrganContours, result.ObjectOrientationInPCS);
  116. UpdateTestResultShow();
  117. }
  118. public void UpdateRoughPathResults(Point2D[] pathPts)
  119. {
  120. Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
  121. {
  122. DrawContoursInCanvas(pathPts, "path", System.Windows.Media.Brushes.Cyan);
  123. }));
  124. }
  125. public void Clear()
  126. {
  127. // 清空画布上的所有内容
  128. TestResultCanvas.Children.Clear();
  129. }
  130. #endregion
  131. #region private
  132. private BitmapImage BitmapToBitmapImage(Bitmap img)
  133. {
  134. BitmapImage bmpimg = new BitmapImage();
  135. using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
  136. {
  137. img.Save(ms, ImageFormat.Png);
  138. bmpimg.BeginInit();
  139. bmpimg.StreamSource = ms;
  140. bmpimg.CacheOption = BitmapCacheOption.OnLoad;
  141. bmpimg.EndInit();
  142. bmpimg.Freeze();
  143. ms.Dispose();
  144. }
  145. return bmpimg;
  146. }
  147. private void UpdateTransforms()
  148. {
  149. if (_image != null)
  150. {
  151. // 使图片保持长宽比例,居中显示,需要平移和缩放
  152. var imgWidth = _image.Width;
  153. var imgHeight = _image.Height;
  154. var ocardialWidth = TestResultCanvas.ActualWidth;
  155. var ocardialHeight = TestResultCanvas.ActualHeight;
  156. var scaleX = ocardialWidth / imgWidth;
  157. var scaleY = ocardialHeight / imgHeight;
  158. var scale = scaleX < scaleY ? scaleX : scaleY;
  159. double offsetX, offsetY;
  160. if (Math.Abs(scale - scaleX) < 0.0001)
  161. {
  162. offsetY = 0.5 * (scaleY - scale) * imgHeight;
  163. offsetX = 0;
  164. }
  165. else
  166. {
  167. offsetX = 0.5 * (scaleX - scale) * imgWidth;
  168. offsetY = 0;
  169. }
  170. _transform = new MyTransform(scale, offsetX, offsetY);
  171. }
  172. }
  173. private void UpdateTestResultShow()
  174. {
  175. Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
  176. {
  177. // 清空画布上的所有内容
  178. TestResultCanvas.Children.Clear();
  179. // 没有结果就直接返回
  180. if (_testResult == null)
  181. {
  182. return;
  183. }
  184. if(_testResult.BodyPartBoundBoxes.Count==0)
  185. {
  186. return;
  187. }
  188. if (_testResult.BodyPartBoundBoxes.Count > 0)
  189. {
  190. // 更新所有框
  191. foreach (var rcs in _testResult.BodyPartBoundBoxes.ToArray())
  192. {
  193. if (rcs.Key == EnumHumanParts.Head)
  194. {
  195. DrawRectsInCanvas(rcs.Value, "head");
  196. }
  197. if (rcs.Key == EnumHumanParts.Body)
  198. {
  199. DrawRectsInCanvas(rcs.Value, "body");
  200. }
  201. }
  202. }
  203. // 更新人体关键点
  204. DrawHumanInCanvas(_testResult.BodyKeyPoints, "keyPts");
  205. // 更新轮廓
  206. DrawContoursInCanvas(_testResult.OrganContours.Points, "contours", System.Windows.Media.Brushes.OrangeRed);
  207. // 更新人体朝向
  208. //if (_testResult.HumanOrientationInPCS.X * _testResult.HumanOrientationInPCS.Y != 0)
  209. //{
  210. // Point2D[] pts = new Point2D[2];
  211. // pts[0] = new Point2D(_image.Width / 2, _image.Height / 2);
  212. // pts[1] = new Point2D(pts[0].X + _testResult.HumanOrientationInPCS.X, pts[0].Y + _testResult.HumanOrientationInPCS.Y);
  213. // DrawContoursInCanvas(pts, "Orientation", System.Windows.Media.Brushes.BlueViolet);
  214. //}
  215. }));
  216. }
  217. /// <summary>
  218. /// 从画布上移除矩形框
  219. /// </summary>
  220. /// <param name="roiName"></param>
  221. private void RemoveRectsCanvas(string roiName)
  222. {
  223. // 框
  224. string textName = roiName;
  225. List<System.Windows.Shapes.Rectangle> rcsExist = TestResultCanvas.FindName(textName) as List<System.Windows.Shapes.Rectangle>;
  226. if (rcsExist != null)
  227. {
  228. foreach (var rcExist in rcsExist)
  229. {
  230. TestResultCanvas.Children.Remove(rcExist);
  231. }
  232. TestResultCanvas.UnregisterName(textName);
  233. }
  234. }
  235. /// <summary>
  236. /// 在画布上画出矩形框
  237. /// </summary>
  238. /// <param name="rcs"></param>
  239. /// <param name="rcName"></param>
  240. private void DrawRectsInCanvas(Rect[] rcs, string rcName)
  241. {
  242. if (_transform == null)
  243. {
  244. return;
  245. }
  246. // 已有则删除
  247. RemoveRectsCanvas(rcName);
  248. List<System.Windows.Shapes.Rectangle> rcRenders = new List<System.Windows.Shapes.Rectangle> { };
  249. foreach (var rc in rcs)
  250. {
  251. System.Windows.Shapes.Rectangle rcRender = new System.Windows.Shapes.Rectangle();
  252. rcRender.StrokeThickness = 3;
  253. rcRender.Stroke = System.Windows.Media.Brushes.AliceBlue;
  254. var transPtLeftTop = _transform.Transform(new System.Windows.Point(rc.Left, rc.Top));
  255. var transPtRightDown = _transform.Transform(new System.Windows.Point(rc.Left + rc.Width, rc.Top + rc.Height));
  256. Canvas.SetLeft(rcRender, transPtLeftTop.X);
  257. Canvas.SetTop(rcRender, transPtLeftTop.Y);
  258. rcRender.Width = transPtRightDown.X - transPtLeftTop.X;
  259. rcRender.Height = transPtRightDown.Y - transPtLeftTop.Y;
  260. TestResultCanvas.Children.Add(rcRender);
  261. //TestResultCanvas.RegisterName(rcName, rcRender);
  262. rcRenders.Add(rcRender);
  263. }
  264. TestResultCanvas.RegisterName(rcName, rcRenders);
  265. }
  266. /// <summary>
  267. /// 在画布上画出轮廓
  268. /// </summary>
  269. /// <param name="pts"></param>
  270. /// <param name="registerName"></param>
  271. private void DrawContoursInCanvas(Point2D[] pts, string registerName, System.Windows.Media.Brush color)
  272. {
  273. if (_transform == null)
  274. {
  275. return;
  276. }
  277. // 已有则删除
  278. RemoveContoursInCanvas(registerName);
  279. if(pts== null)
  280. {
  281. return;
  282. }
  283. PointCollection contourPoints = new PointCollection();
  284. foreach (var pt in pts)
  285. {
  286. var point = new System.Windows.Point(pt.X, pt.Y);
  287. var transPoint = _transform.Transform(point);
  288. contourPoints.Add(transPoint);
  289. }
  290. System.Windows.Shapes.Polyline contourDraw = new System.Windows.Shapes.Polyline();
  291. contourDraw.Points = contourPoints;
  292. contourDraw.StrokeThickness = 3;
  293. contourDraw.Stroke = color;
  294. TestResultCanvas.Children.Add(contourDraw);
  295. TestResultCanvas.RegisterName(registerName, contourDraw);
  296. }
  297. /// <summary>
  298. /// 从画布上将轮廓移除
  299. /// </summary>
  300. /// <param name="registerName"></param>
  301. private void RemoveContoursInCanvas(string registerName)
  302. {
  303. System.Windows.Shapes.Polyline contourExist = TestResultCanvas.FindName(registerName) as System.Windows.Shapes.Polyline;
  304. if (contourExist != null)
  305. {
  306. TestResultCanvas.Children.Remove(contourExist);
  307. TestResultCanvas.UnregisterName(registerName);
  308. }
  309. }
  310. private void DrawHumanInCanvas(BodyKeyPoints humanKeyPts, string name)
  311. {
  312. if (_transform == null)
  313. {
  314. return;
  315. }
  316. // 已有则删除
  317. RemoveHumanInCanvas(name);
  318. var neckPosition = _transform.Transform(new System.Windows.Point(humanKeyPts.Neck.X, humanKeyPts.Neck.Y));
  319. var leftShoulderPosition = _transform.Transform(new System.Windows.Point(humanKeyPts.LeftShoulder.X, humanKeyPts.LeftShoulder.Y));
  320. var rightShoulderPosition = _transform.Transform(new System.Windows.Point(humanKeyPts.RightShoulder.X, humanKeyPts.RightShoulder.Y));
  321. // 脖子
  322. if (humanKeyPts.Neck.X * humanKeyPts.Neck.Y > 0)
  323. {
  324. System.Windows.Shapes.Ellipse neck = new System.Windows.Shapes.Ellipse();
  325. neck.StrokeThickness = 4;
  326. neck.Stroke = System.Windows.Media.Brushes.Orange;
  327. neck.Width = 6;
  328. Canvas.SetLeft(neck, neckPosition.X);
  329. Canvas.SetTop(neck, neckPosition.Y);
  330. TestResultCanvas.Children.Add(neck);
  331. string neckName = "Human_" + name + "_point_head";
  332. TestResultCanvas.RegisterName(neckName, neck);
  333. }
  334. // 左肩
  335. if (humanKeyPts.LeftShoulder.X * humanKeyPts.LeftShoulder.Y > 0)
  336. {
  337. System.Windows.Shapes.Ellipse leftShoulder = new System.Windows.Shapes.Ellipse();
  338. leftShoulder.StrokeThickness = 3;
  339. leftShoulder.Stroke = System.Windows.Media.Brushes.AliceBlue;
  340. leftShoulder.Width = 6;
  341. Canvas.SetLeft(leftShoulder, leftShoulderPosition.X);
  342. Canvas.SetTop(leftShoulder, leftShoulderPosition.Y);
  343. TestResultCanvas.Children.Add(leftShoulder);
  344. string leftShoulderName = "Human_" + name + "_point_leftShoulder";
  345. TestResultCanvas.RegisterName(leftShoulderName, leftShoulder);
  346. }
  347. // 右肩
  348. if (humanKeyPts.RightShoulder.X * humanKeyPts.RightShoulder.Y > 0)
  349. {
  350. System.Windows.Shapes.Ellipse rightShoulder = new System.Windows.Shapes.Ellipse();
  351. rightShoulder.StrokeThickness = 3;
  352. rightShoulder.Stroke = System.Windows.Media.Brushes.AliceBlue;
  353. rightShoulder.Width = 6;
  354. Canvas.SetLeft(rightShoulder, rightShoulderPosition.X);
  355. Canvas.SetTop(rightShoulder, rightShoulderPosition.Y);
  356. TestResultCanvas.Children.Add(rightShoulder);
  357. string rightShoulderName = "Human_" + name + "_point_rightShoulder";
  358. TestResultCanvas.RegisterName(rightShoulderName, rightShoulder);
  359. }
  360. // 从脖子到左肩的线
  361. if (humanKeyPts.Neck.X * humanKeyPts.Neck.Y > 0 && humanKeyPts.LeftShoulder.X * humanKeyPts.LeftShoulder.Y > 0)
  362. {
  363. System.Windows.Shapes.Line lineLeft = new System.Windows.Shapes.Line();
  364. lineLeft.StrokeThickness = 2;
  365. lineLeft.Stroke = System.Windows.Media.Brushes.RosyBrown;
  366. lineLeft.X1 = neckPosition.X;
  367. lineLeft.Y1 = neckPosition.Y;
  368. lineLeft.X2 = leftShoulderPosition.X;
  369. lineLeft.Y2 = leftShoulderPosition.Y;
  370. TestResultCanvas.Children.Add(lineLeft);
  371. string lineLeftName = "Human_" + name + "_lineLeft";
  372. TestResultCanvas.RegisterName(lineLeftName, lineLeft);
  373. }
  374. // 从脖子到右肩的线
  375. if (humanKeyPts.Neck.X * humanKeyPts.Neck.Y > 0 && humanKeyPts.RightShoulder.X * humanKeyPts.RightShoulder.Y > 0)
  376. {
  377. System.Windows.Shapes.Line lineRight = new System.Windows.Shapes.Line();
  378. lineRight.StrokeThickness = 2;
  379. lineRight.Stroke = System.Windows.Media.Brushes.DarkGray;
  380. lineRight.X1 = neckPosition.X;
  381. lineRight.Y1 = neckPosition.Y;
  382. lineRight.X2 = rightShoulderPosition.X;
  383. lineRight.Y2 = rightShoulderPosition.Y;
  384. TestResultCanvas.Children.Add(lineRight);
  385. string lineRightName = "Human_" + name + "_lineRight";
  386. TestResultCanvas.RegisterName(lineRightName, lineRight);
  387. }
  388. }
  389. private void RemoveHumanInCanvas(string name)
  390. {
  391. // 脖子
  392. string neckName = "Human_" + name + "_point_head";
  393. System.Windows.Shapes.Ellipse neck = TestResultCanvas.FindName(neckName) as System.Windows.Shapes.Ellipse;
  394. if (neck != null)
  395. {
  396. TestResultCanvas.Children.Remove(neck);
  397. TestResultCanvas.UnregisterName(neckName);
  398. }
  399. // 左肩
  400. string leftShoulderName = "Human_" + name + "_point_leftShoulder";
  401. System.Windows.Shapes.Ellipse leftShoulder = TestResultCanvas.FindName(leftShoulderName) as System.Windows.Shapes.Ellipse;
  402. if (leftShoulder != null)
  403. {
  404. TestResultCanvas.Children.Remove(leftShoulder);
  405. TestResultCanvas.UnregisterName(leftShoulderName);
  406. }
  407. // 右肩
  408. string rightShoulderName = "Human_" + name + "_point_rightShoulder";
  409. System.Windows.Shapes.Ellipse rightShoulder = TestResultCanvas.FindName(rightShoulderName) as System.Windows.Shapes.Ellipse;
  410. if (rightShoulder != null)
  411. {
  412. TestResultCanvas.Children.Remove(rightShoulder);
  413. TestResultCanvas.UnregisterName(rightShoulderName);
  414. }
  415. // 从脖子到左肩的线
  416. string lineLeftName = "Human_" + name + "_lineLeft";
  417. System.Windows.Shapes.Line lineLeft = TestResultCanvas.FindName(lineLeftName) as System.Windows.Shapes.Line;
  418. if (lineLeft != null)
  419. {
  420. TestResultCanvas.Children.Remove(lineLeft);
  421. TestResultCanvas.UnregisterName(lineLeftName);
  422. }
  423. // 从脖子到右肩的线
  424. string lineRightName = "Human_" + name + "_lineRight";
  425. System.Windows.Shapes.Line lineRight = TestResultCanvas.FindName(lineRightName) as System.Windows.Shapes.Line;
  426. if (lineRight != null)
  427. {
  428. TestResultCanvas.Children.Remove(lineRight);
  429. TestResultCanvas.UnregisterName(lineRightName);
  430. }
  431. }
  432. #endregion
  433. }
  434. }