123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- using System.Collections.Generic;
- using Emgu.CV;
- using Emgu.CV.Structure;
- using System.Drawing;
- using System;
- using Emgu.CV.Util;
- using System.Linq;
- using WingServerCommon.Log;
- using System.Runtime.InteropServices;
- namespace WingAIDiagnosisService.Carotid.Utilities.DetectPlaque
- {
- public class CarotidPlaqueAutoDetection
- {
- private static CarotidPlaqueAutoDetection _instance;
- public static CarotidPlaqueAutoDetection Instance
- {
- get => _instance ?? (_instance = new CarotidPlaqueAutoDetection());
- }
- public ModelSize _modelSize;
- public string _plaqueImagePath;
- /// <summary>
- /// 斑块自动检测
- /// </summary>
- /// <param name="image">颈动脉图像</param>
- /// <param name="physicalPerPixel">每个像素代表实际长度</param>
- /// <returns>斑块位置</returns>
- public DetectPlaqueResult GetPlaqueImage(byte[][] model, ModelSize modelSize, string plaqueImagePath, float physicalPerPixel)
- {
- _modelSize = modelSize;
- _plaqueImagePath = plaqueImagePath;
- var allPlaque = GetModelVesselAndPlaque.Instance.GetAllPlaqueContours();
- if (allPlaque.Count == 0)
- {
- return new DetectPlaqueResult(false);
- }
- var maxPlaque = GetMaxPlaque(allPlaque);
- if (maxPlaque.RealRect.Size.Width < 15 || maxPlaque.RealRect.Size.Height < 15)
- {
- var detectPlaqueResult1 = new DetectPlaqueResult(true,
- PlaqueCountType.NoPlaque,
- PlaqueType.SoftPlaque,
- 0,
- 0,
- 0);
- return detectPlaqueResult1;
- }
- using var image = new Image<Gray, byte>(_modelSize.ModelLengthX, _modelSize.ModelLengthY);
- Marshal.Copy(model[maxPlaque.SerialNumber], 0, image.Mat.DataPointer, _modelSize.OneFacePixelsNum);
- //计算是否是亮斑
- var isBright = IsBrightPlaque(image, maxPlaque.PlaqueContour);
- //调整图像亮度
- ImageTools.Adjust(image.Mat);
- using var imageBgr = image.Convert<Bgr, byte>();
- var realPlaqueContours = new Point[maxPlaque.PlaqueContour.Length];
- var plaqueContours = maxPlaque.PlaqueContour;
- var left = maxPlaque.ImageRect.Left;
- var top = maxPlaque.ImageRect.Top;
- for (var i = 0; i < plaqueContours.Length; ++i)
- {
- realPlaqueContours[i] = new Point(plaqueContours[i].X, plaqueContours[i].Y);
- }
- imageBgr.Draw(realPlaqueContours, new Bgr(0, 0, 255), 2);
- imageBgr.Save(plaqueImagePath);
-
- //计算斑块的参数
- var width = maxPlaque.RealRect.Size.Width * physicalPerPixel;
- var height = maxPlaque.RealRect.Size.Height * physicalPerPixel;
- width = (float)Math.Round(width, 2, MidpointRounding.AwayFromZero);
- height = (float)Math.Round(height, 2, MidpointRounding.AwayFromZero);
- var detectPlaqueResult = new DetectPlaqueResult(true,
- PlaqueCountType.MultiPlaque,
- isBright ? PlaqueType.HardPlaque : PlaqueType.SoftPlaque,
- width,
- height,
- maxPlaque.Ratio);
- return detectPlaqueResult;
- }
- private List<OnePlaqueContours> GetPlaqueInArtery(IList<OnePlaqueContours> allPlaque)
- {
- var plaqueList = new List<OnePlaqueContours>();
- foreach (OnePlaqueContours plaque in allPlaque)
- {
- var count = plaque.PlaqueContour.Length;
- var num = 0;
- var arterConter = new VectorOfPoint(plaque.ArteryContour);
- for (var i = 0; i < count; ++i)
- {
- if (CvInvoke.PointPolygonTest(arterConter, plaque.PlaqueContour[i], false) >= 0)
- {
- num++;
- }
- }
- if (num > count * 3 / 4)
- {
- plaqueList.Add(plaque);
- }
- }
- return plaqueList;
- }
- private OnePlaqueContours GetMaxPlaque(IList<OnePlaqueContours> allPlaqueSrc)
- {
- if (allPlaqueSrc.Count < 1)
- {
- return new OnePlaqueContours();
- }
- var allPlaque = GetPlaqueInArtery(allPlaqueSrc);
- if (allPlaque.Count < 1)
- {
- return new OnePlaqueContours();
- }
- allPlaque = allPlaque.OrderByDescending(o => o.PlaqueArea).ToList();
- var maxPlaque = allPlaque[0];
- //计算中心点
- var centerPoint = Get2DContoursCenterPoints(maxPlaque.PlaqueContour);
- //计算动脉轮廓上距离斑块中心最远的点
- var maxDistancePoint = GetMaxDisPointInOutContour(centerPoint, maxPlaque.ArteryContour);
- //计算狭窄率
- var ratio = GetRatio(maxPlaque.ArteryContour, maxPlaque.PlaqueContour);
- ratio = (float)Math.Round(ratio, 2, MidpointRounding.AwayFromZero);
- maxPlaque.Ratio = (float)ratio;
- //斑块外接矩阵
- //var plaqueRect = CvInvoke.BoundingRectangle(new VectorOfPoint(maxPlaque.PlaqueContour));
- var plaqueRect = CvInvoke.MinAreaRect(new VectorOfPoint(maxPlaque.PlaqueContour));
- //计算实际位置
- maxPlaque.RealRect = new RotatedRect(new PointF(maxPlaque.ImageRect.Left + plaqueRect.Center.X,
- maxPlaque.ImageRect.Top + plaqueRect.Center.Y),
- plaqueRect.Size, plaqueRect.Angle);
- //计算实际的中心点
- maxPlaque.RealCenterPoint = new Point(centerPoint.X + maxPlaque.ImageRect.Left, centerPoint.Y + maxPlaque.ImageRect.Top);
- return maxPlaque;
- }
- /// <summary>
- /// 计算狭窄率,面积法
- /// </summary>
- /// <param name="centerPoint"></param>
- /// <param name="maxDistancePoint"></param>
- /// <param name="contourPoint"></param>
- /// <returns></returns>
- private double GetRatio(Point[] arteryContour, Point[] contourPoint)
- {
- VectorOfPoint vect1 = new VectorOfPoint(arteryContour);
- VectorOfPoint vect2 = new VectorOfPoint(contourPoint);
- var areaArtery = Math.Max(CvInvoke.ContourArea(vect1), 0);
- var areaPlaque = Math.Max(CvInvoke.ContourArea(vect2), 0);
- if (areaPlaque <= areaArtery)
- {
- return (areaPlaque / areaArtery) * 100;
- }
- else
- {
- return 100;
- }
- }
-
- private Point GetMaxDisPointInOutContour(Point centerPoint, Point[] outContourPoint)
- {
- var maxPoint = new Point();
- double distance = 0;
- for (var i = 0; i < outContourPoint.Length; ++i)
- {
- var disX = centerPoint.X - outContourPoint[i].X;
- var disY = centerPoint.Y - outContourPoint[i].Y;
- var temp = Math.Sqrt(disX * disX + disY * disY);
- if (temp > distance)
- {
- distance = temp;
- maxPoint = outContourPoint[i];
- }
- }
- return maxPoint;
- }
- private Point Get2DContoursCenterPoints(Point[] contourPoints)
- {
- //计算轮廓的中心点
- var len = contourPoints.Length;
- var sumX = 0;
- var sumY = 0;
- for (var i = 0; i < len; ++i)
- {
- sumX += contourPoints[i].X;
- sumY += contourPoints[i].Y;
- }
- var centerX = sumX / (float)len;
- var centerY = sumY / (float)len;
- //加上离最远点最远的点
- return new Point((int)Math.Round(centerX, 0, MidpointRounding.AwayFromZero), (int)Math.Round(centerY, 0, MidpointRounding.AwayFromZero));
- }
- /// <summary>
- /// 判断斑块是量斑还是暗斑
- /// </summary>
- /// <param name="imageGray"></param>
- /// <param name="plaqueContours"></param>
- /// <returns></returns>
- private bool IsBrightPlaque(Image<Gray, byte> imageGray, Point[] plaqueContours)
- {
- try
- {
- if (plaqueContours.Length < 5)
- {
- return false;
- }
- var count = plaqueContours.Length;
- var pointList = plaqueContours.OrderBy(o => o.X).ThenBy(o => o.Y).ToList();
- var xMin = pointList[0].X;
- var xMax = pointList.Last().X;
- var index = 0;
- var minY = 0;
- var maxY = 0;
- var brightPointNum = 0;
- var brightPointThreshold = 200;
- for (var i = xMin; i < xMax; ++i)
- {
- minY = pointList[index].Y;
- for (var j = index; j < count; ++j)
- {
- if (pointList[j].X != i)
- {
- maxY = pointList[j - 1].Y;
- index = j;
- break;
- }
- }
- for (var z = minY; z < maxY; z++)
- {
- if (imageGray.Data[z, i, 0] > brightPointThreshold)
- {
- brightPointNum++;
- }
- }
- }
- if (brightPointNum > 30)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- catch (Exception e)
- {
- Logger.WriteLineError($"Resample Model have an error{e}");
- return false;
- }
-
- }
- }
- }
|