CarotidPlaqueAutoDetection.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. using System.Collections.Generic;
  2. using Emgu.CV;
  3. using Emgu.CV.Structure;
  4. using System.Drawing;
  5. using System;
  6. using Emgu.CV.Util;
  7. using System.Linq;
  8. using WingServerCommon.Log;
  9. using System.Runtime.InteropServices;
  10. namespace WingAIDiagnosisService.Carotid.Utilities.DetectPlaque
  11. {
  12. public class CarotidPlaqueAutoDetection
  13. {
  14. private static CarotidPlaqueAutoDetection _instance;
  15. public static CarotidPlaqueAutoDetection Instance
  16. {
  17. get => _instance ?? (_instance = new CarotidPlaqueAutoDetection());
  18. }
  19. public ModelSize _modelSize;
  20. public string _plaqueImagePath;
  21. /// <summary>
  22. /// 斑块自动检测
  23. /// </summary>
  24. /// <param name="image">颈动脉图像</param>
  25. /// <param name="physicalPerPixel">每个像素代表实际长度</param>
  26. /// <returns>斑块位置</returns>
  27. public DetectPlaqueResult GetPlaqueImage(byte[][] model, ModelSize modelSize, string plaqueImagePath, float physicalPerPixel)
  28. {
  29. _modelSize = modelSize;
  30. _plaqueImagePath = plaqueImagePath;
  31. var allPlaque = GetModelVesselAndPlaque.Instance.GetAllPlaqueContours();
  32. if (allPlaque.Count == 0)
  33. {
  34. return new DetectPlaqueResult(false);
  35. }
  36. var maxPlaque = GetMaxPlaque(allPlaque);
  37. if (maxPlaque.RealRect.Size.Width < 15 || maxPlaque.RealRect.Size.Height < 15)
  38. {
  39. var detectPlaqueResult1 = new DetectPlaqueResult(true,
  40. PlaqueCountType.NoPlaque,
  41. PlaqueType.SoftPlaque,
  42. 0,
  43. 0,
  44. 0);
  45. return detectPlaqueResult1;
  46. }
  47. using var image = new Image<Gray, byte>(_modelSize.ModelLengthX, _modelSize.ModelLengthY);
  48. Marshal.Copy(model[maxPlaque.SerialNumber], 0, image.Mat.DataPointer, _modelSize.OneFacePixelsNum);
  49. //计算是否是亮斑
  50. var isBright = IsBrightPlaque(image, maxPlaque.PlaqueContour);
  51. //调整图像亮度
  52. ImageTools.Adjust(image.Mat);
  53. using var imageBgr = image.Convert<Bgr, byte>();
  54. var realPlaqueContours = new Point[maxPlaque.PlaqueContour.Length];
  55. var plaqueContours = maxPlaque.PlaqueContour;
  56. var left = maxPlaque.ImageRect.Left;
  57. var top = maxPlaque.ImageRect.Top;
  58. for (var i = 0; i < plaqueContours.Length; ++i)
  59. {
  60. realPlaqueContours[i] = new Point(plaqueContours[i].X, plaqueContours[i].Y);
  61. }
  62. imageBgr.Draw(realPlaqueContours, new Bgr(0, 0, 255), 2);
  63. imageBgr.Save(plaqueImagePath);
  64. //计算斑块的参数
  65. var width = maxPlaque.RealRect.Size.Width * physicalPerPixel;
  66. var height = maxPlaque.RealRect.Size.Height * physicalPerPixel;
  67. width = (float)Math.Round(width, 2, MidpointRounding.AwayFromZero);
  68. height = (float)Math.Round(height, 2, MidpointRounding.AwayFromZero);
  69. var detectPlaqueResult = new DetectPlaqueResult(true,
  70. PlaqueCountType.MultiPlaque,
  71. isBright ? PlaqueType.HardPlaque : PlaqueType.SoftPlaque,
  72. width,
  73. height,
  74. maxPlaque.Ratio);
  75. return detectPlaqueResult;
  76. }
  77. private List<OnePlaqueContours> GetPlaqueInArtery(IList<OnePlaqueContours> allPlaque)
  78. {
  79. var plaqueList = new List<OnePlaqueContours>();
  80. foreach (OnePlaqueContours plaque in allPlaque)
  81. {
  82. var count = plaque.PlaqueContour.Length;
  83. var num = 0;
  84. var arterConter = new VectorOfPoint(plaque.ArteryContour);
  85. for (var i = 0; i < count; ++i)
  86. {
  87. if (CvInvoke.PointPolygonTest(arterConter, plaque.PlaqueContour[i], false) >= 0)
  88. {
  89. num++;
  90. }
  91. }
  92. if (num > count * 3 / 4)
  93. {
  94. plaqueList.Add(plaque);
  95. }
  96. }
  97. return plaqueList;
  98. }
  99. private OnePlaqueContours GetMaxPlaque(IList<OnePlaqueContours> allPlaqueSrc)
  100. {
  101. if (allPlaqueSrc.Count < 1)
  102. {
  103. return new OnePlaqueContours();
  104. }
  105. var allPlaque = GetPlaqueInArtery(allPlaqueSrc);
  106. if (allPlaque.Count < 1)
  107. {
  108. return new OnePlaqueContours();
  109. }
  110. allPlaque = allPlaque.OrderByDescending(o => o.PlaqueArea).ToList();
  111. var maxPlaque = allPlaque[0];
  112. //计算中心点
  113. var centerPoint = Get2DContoursCenterPoints(maxPlaque.PlaqueContour);
  114. //计算动脉轮廓上距离斑块中心最远的点
  115. var maxDistancePoint = GetMaxDisPointInOutContour(centerPoint, maxPlaque.ArteryContour);
  116. //计算狭窄率
  117. var ratio = GetRatio(maxPlaque.ArteryContour, maxPlaque.PlaqueContour);
  118. ratio = (float)Math.Round(ratio, 2, MidpointRounding.AwayFromZero);
  119. maxPlaque.Ratio = (float)ratio;
  120. //斑块外接矩阵
  121. //var plaqueRect = CvInvoke.BoundingRectangle(new VectorOfPoint(maxPlaque.PlaqueContour));
  122. var plaqueRect = CvInvoke.MinAreaRect(new VectorOfPoint(maxPlaque.PlaqueContour));
  123. //计算实际位置
  124. maxPlaque.RealRect = new RotatedRect(new PointF(maxPlaque.ImageRect.Left + plaqueRect.Center.X,
  125. maxPlaque.ImageRect.Top + plaqueRect.Center.Y),
  126. plaqueRect.Size, plaqueRect.Angle);
  127. //计算实际的中心点
  128. maxPlaque.RealCenterPoint = new Point(centerPoint.X + maxPlaque.ImageRect.Left, centerPoint.Y + maxPlaque.ImageRect.Top);
  129. return maxPlaque;
  130. }
  131. /// <summary>
  132. /// 计算狭窄率,面积法
  133. /// </summary>
  134. /// <param name="centerPoint"></param>
  135. /// <param name="maxDistancePoint"></param>
  136. /// <param name="contourPoint"></param>
  137. /// <returns></returns>
  138. private double GetRatio(Point[] arteryContour, Point[] contourPoint)
  139. {
  140. VectorOfPoint vect1 = new VectorOfPoint(arteryContour);
  141. VectorOfPoint vect2 = new VectorOfPoint(contourPoint);
  142. var areaArtery = Math.Max(CvInvoke.ContourArea(vect1), 0);
  143. var areaPlaque = Math.Max(CvInvoke.ContourArea(vect2), 0);
  144. if (areaPlaque <= areaArtery)
  145. {
  146. return (areaPlaque / areaArtery) * 100;
  147. }
  148. else
  149. {
  150. return 100;
  151. }
  152. }
  153. private Point GetMaxDisPointInOutContour(Point centerPoint, Point[] outContourPoint)
  154. {
  155. var maxPoint = new Point();
  156. double distance = 0;
  157. for (var i = 0; i < outContourPoint.Length; ++i)
  158. {
  159. var disX = centerPoint.X - outContourPoint[i].X;
  160. var disY = centerPoint.Y - outContourPoint[i].Y;
  161. var temp = Math.Sqrt(disX * disX + disY * disY);
  162. if (temp > distance)
  163. {
  164. distance = temp;
  165. maxPoint = outContourPoint[i];
  166. }
  167. }
  168. return maxPoint;
  169. }
  170. private Point Get2DContoursCenterPoints(Point[] contourPoints)
  171. {
  172. //计算轮廓的中心点
  173. var len = contourPoints.Length;
  174. var sumX = 0;
  175. var sumY = 0;
  176. for (var i = 0; i < len; ++i)
  177. {
  178. sumX += contourPoints[i].X;
  179. sumY += contourPoints[i].Y;
  180. }
  181. var centerX = sumX / (float)len;
  182. var centerY = sumY / (float)len;
  183. //加上离最远点最远的点
  184. return new Point((int)Math.Round(centerX, 0, MidpointRounding.AwayFromZero), (int)Math.Round(centerY, 0, MidpointRounding.AwayFromZero));
  185. }
  186. /// <summary>
  187. /// 判断斑块是量斑还是暗斑
  188. /// </summary>
  189. /// <param name="imageGray"></param>
  190. /// <param name="plaqueContours"></param>
  191. /// <returns></returns>
  192. private bool IsBrightPlaque(Image<Gray, byte> imageGray, Point[] plaqueContours)
  193. {
  194. try
  195. {
  196. if (plaqueContours.Length < 5)
  197. {
  198. return false;
  199. }
  200. var count = plaqueContours.Length;
  201. var pointList = plaqueContours.OrderBy(o => o.X).ThenBy(o => o.Y).ToList();
  202. var xMin = pointList[0].X;
  203. var xMax = pointList.Last().X;
  204. var index = 0;
  205. var minY = 0;
  206. var maxY = 0;
  207. var brightPointNum = 0;
  208. var brightPointThreshold = 200;
  209. for (var i = xMin; i < xMax; ++i)
  210. {
  211. minY = pointList[index].Y;
  212. for (var j = index; j < count; ++j)
  213. {
  214. if (pointList[j].X != i)
  215. {
  216. maxY = pointList[j - 1].Y;
  217. index = j;
  218. break;
  219. }
  220. }
  221. for (var z = minY; z < maxY; z++)
  222. {
  223. if (imageGray.Data[z, i, 0] > brightPointThreshold)
  224. {
  225. brightPointNum++;
  226. }
  227. }
  228. }
  229. if (brightPointNum > 30)
  230. {
  231. return true;
  232. }
  233. else
  234. {
  235. return false;
  236. }
  237. }
  238. catch (Exception e)
  239. {
  240. Logger.WriteLineError($"Resample Model have an error{e}");
  241. return false;
  242. }
  243. }
  244. }
  245. }