123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- using AI.Reconstruction;
- using System;
- using System.Collections.Generic;
- using System.Drawing;
- using System.Linq;
- using System.Runtime.InteropServices;
- using AI.DiagSystem;
- namespace Reconstruction3DHelper
- {
- [StructLayout(LayoutKind.Sequential)]
- public struct PlaqueProperty
- {
- public int SerialNumber;
- public Rectangle ImageRect;
- public Point[] ArteryContour;
- public Point[] PlaqueContour;
- public double PlaqueArea;
- //狭窄率
- public float Ratio;
- //在原图中的斑块外界矩形
- public RotatedRectangle RealRect;
- //在原图中的斑块中心
- public Point RealCenterPoint;
- public float Credibility;
- }
- [StructLayout(LayoutKind.Sequential)]
- public struct RotatedRectangle
- {
- public float Angle;
- public float Cx;
- public float Cy;
- public float Height;
- public float Width;
- }
- /// <summary>
- /// 图像信息
- /// </summary>
- public struct StructImageInfo
- {
- private int _width;
- private int _height;
- private AI.Common.EnumColorType _colorType;
- private IntPtr _dataPointer;
- public int Width
- {
- get => _width;
- set => _width = value;
- }
- public int Height
- {
- get => _height;
- set => _height = value;
- }
- public AI.Common.EnumColorType ColorType
- {
- get => _colorType;
- set => _colorType = value;
- }
- public IntPtr DataPointer
- {
- get => _dataPointer;
- set => _dataPointer = value;
- }
- public StructImageInfo(int width, int height, AI.Common.EnumColorType colorType, IntPtr dataPointer)
- {
- _width = width;
- _height = height;
- _colorType = colorType;
- _dataPointer = dataPointer;
- }
- }
- public enum PlaqueType
- {
- SoftPlaque,
- HardPlaque
- }
- public enum PlaquePostionType
- {
- UpperIntima,
- LowerIntima
- }
- public enum PlaqueCountType
- {
- NoPlaque,
- OnePlaque,
- MultiPlaque
- }
- public class PlaqueResult
- {
- /// <summary>
- /// 斑块数量 无、单发、多发
- /// </summary>
- public PlaqueCountType PlaqueCountType { get; }
- /// <summary>
- /// 斑块特性 软斑、硬斑
- /// </summary>
- public PlaqueType PlaqueType { get; }
- /// <summary>
- /// 最大斑块宽度
- /// </summary>
- public float PlaqueWidth { get; }
- /// <summary>
- /// 最大斑块高度
- /// </summary>
- public float PlaqueHeight { get; }
- /// <summary>
- /// 狭窄率
- /// </summary>
- public float Stenosis { get; }
- /// <summary>
- /// 斑块位置,上内膜/下内膜
- /// </summary>
- public PlaquePostionType PlaquePostion;
- /// <summary>
- /// 检测切面的三维点
- /// </summary>
- public List<Point3DF> ClipPoints { get; }
- /// <summary>
- /// 是否识别成功
- /// </summary>
- public bool IsSuccess { get; }
- /// <summary>
- /// 斑块的轮廓
- /// </summary>
- public Point[] PlaqueContour { get; }
- public PlaqueResult() { }
- public PlaqueResult(bool isSuccess)
- {
- IsSuccess = isSuccess;
- }
- public PlaqueResult(bool isSuccess, PlaqueCountType plaqueCountType)
- {
- IsSuccess = isSuccess;
- PlaqueCountType = plaqueCountType;
- }
- public PlaqueResult(bool isSuccess, PlaqueCountType plaqueCountType, PlaqueType plaqueType, float plaqueWidth,
- float plaqueHeight, float stenosis, List<Point3DF> clipPoints, Point[] plaqueContour)
- {
- IsSuccess = isSuccess;
- PlaqueCountType = plaqueCountType;
- PlaqueType = plaqueType;
- PlaqueWidth = plaqueWidth;
- PlaqueHeight = plaqueHeight;
- Stenosis = stenosis;
- ClipPoints = clipPoints;
- PlaqueContour = plaqueContour;
- }
- }
- public class PlaquePostProcessHelper
- {
- public ModelSize _modelSize;
- public string _plaqueImagePath;
- [DllImport(@"PlaqueProcessingCpp.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern bool PointInPolygon(IntPtr contours, int pointCount, IntPtr point);
- [DllImport(@"PlaqueProcessingCpp.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern bool CalcMaxPlaque(IntPtr arteryContour, IntPtr plaqueContour,
- int arteryCount, int plaqueCount, int left, int top, ref float ratio, ref RotatedRectangle RealRect);
- [DllImport(@"PlaqueProcessingCpp.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern bool IsBrightPlaque(StructImageInfo srcImgInfo, IntPtr contours, int pointCount);
- /// <summary>
- /// 斑块自动检测
- /// </summary>
- /// <param name="image">颈动脉图像</param>
- /// <param name="physicalPerPixel">每个像素代表实际长度</param>
- /// <returns>斑块位置</returns>
- public PlaqueResult CalcPlaqueProperty(byte[][] model, ModelSize modelSize, float physicalPerPixel, Dictionary<int, AIDiagResultPerImg> vesselsAndPlaques)
- {
- _modelSize = modelSize;
- var allPlaque = GetAllPlaqueContours(vesselsAndPlaques);
- if (allPlaque.Count == 0)
- {
- return new PlaqueResult(false);
- }
- var maxPlaque = GetMaxPlaque(allPlaque);
-
- if (maxPlaque.RealRect.Width < 15 || maxPlaque.RealRect.Height < 15)
- {
- var detectPlaqueResult1 = new PlaqueResult(true, PlaqueCountType.NoPlaque, PlaqueType.SoftPlaque,
- 0, 0, 0, new List<Point3DF> { }, new Point[] { });
- return detectPlaqueResult1;
- }
- var decodedPointer = Marshal.UnsafeAddrOfPinnedArrayElement(model[maxPlaque.SerialNumber], 0);
- StructImageInfo imageInfo = new StructImageInfo(_modelSize.ModelLengthX, _modelSize.ModelLengthY, AI.Common.EnumColorType.Gray8, decodedPointer);
- GCHandle hObject1 = GCHandle.Alloc(maxPlaque.PlaqueContour, GCHandleType.Pinned);
- IntPtr plaqueContour = hObject1.AddrOfPinnedObject();
- var isBright = IsBrightPlaque(imageInfo, plaqueContour, maxPlaque.PlaqueContour.Length);
- List<Point3DF> clipPoints = new List<Point3DF> {new Point3DF(0, _modelSize.ModelLengthX, maxPlaque.SerialNumber),
- new Point3DF(_modelSize.ModelLengthY, 0, maxPlaque.SerialNumber),
- new Point3DF(0, 0, maxPlaque.SerialNumber)};
- //计算斑块的参数
- var width = maxPlaque.RealRect.Width * physicalPerPixel;
- var height = maxPlaque.RealRect.Height * physicalPerPixel;
- width = (float)Math.Round(width, 2, MidpointRounding.AwayFromZero);
- height = (float)Math.Round(height, 2, MidpointRounding.AwayFromZero);
- var plaqueResult = new PlaqueResult(true,
- PlaqueCountType.MultiPlaque,
- isBright ? PlaqueType.HardPlaque : PlaqueType.SoftPlaque,
- width,
- height,
- maxPlaque.Ratio,
- clipPoints,
- maxPlaque.PlaqueContour);
- return plaqueResult;
- }
- /// <summary>
- /// 判断斑块是否在血管内
- /// </summary>
- /// <param name="allPlaque"></param>
- /// <returns></returns>
- private List<PlaqueProperty> GetPlaqueInArtery(IList<PlaqueProperty> allPlaque)
- {
- var plaqueList = new List<PlaqueProperty>();
- foreach (PlaqueProperty plaque in allPlaque)
- {
- var count = plaque.PlaqueContour.Length;
- var num = 0;
- GCHandle hObject = GCHandle.Alloc(plaque.ArteryContour, GCHandleType.Pinned);
- IntPtr pObject = hObject.AddrOfPinnedObject();
- for (var i = 0; i < count; ++i)
- {
- GCHandle hObject2 = GCHandle.Alloc(plaque.PlaqueContour[i], GCHandleType.Pinned);
- IntPtr pObject2 = hObject2.AddrOfPinnedObject();
- if (PointInPolygon(pObject, plaque.ArteryContour.Length, pObject2))
- {
- num++;
- }
- }
- if (num > count * 3 / 4)
- {
- plaqueList.Add(plaque);
- }
- }
- return plaqueList;
- }
- /// <summary>
- /// 计算最大斑块的属性
- /// </summary>
- /// <param name="allPlaqueSrc"></param>
- /// <returns></returns>
- private PlaqueProperty GetMaxPlaque(IList<PlaqueProperty> allPlaqueSrc)
- {
- if (allPlaqueSrc.Count < 1)
- {
- return new PlaqueProperty();
- }
- var allPlaque = GetPlaqueInArtery(allPlaqueSrc); //判断斑块是否在血管内
- if (allPlaque.Count < 1)
- {
- return new PlaqueProperty();
- }
- allPlaque = allPlaque.OrderByDescending(o => o.PlaqueArea).ToList();
- var maxPlaque = allPlaque[0];
- //计算中心点
- var centerPoint = Get2DContoursCenterPoints(maxPlaque.PlaqueContour);
- //计算动脉轮廓上距离斑块中心最远的点
- GCHandle hObject1 = GCHandle.Alloc(maxPlaque.ArteryContour, GCHandleType.Pinned);
- IntPtr arteryIntPtr = hObject1.AddrOfPinnedObject();
- GCHandle hObject2 = GCHandle.Alloc(maxPlaque.PlaqueContour, GCHandleType.Pinned);
- IntPtr plaqueIntPtr = hObject2.AddrOfPinnedObject();
- float ratio = 0.0F;
- RotatedRectangle rotatedRectangle = new RotatedRectangle();
- var result = CalcMaxPlaque(arteryIntPtr, plaqueIntPtr, maxPlaque.ArteryContour.Length,
- maxPlaque.PlaqueContour.Length, maxPlaque.ImageRect.Left, maxPlaque.ImageRect.Top, ref ratio, ref rotatedRectangle);
- maxPlaque.RealRect = rotatedRectangle;
- //计算实际的中心点
- maxPlaque.RealCenterPoint = new Point(centerPoint.X + maxPlaque.ImageRect.Left, centerPoint.Y + maxPlaque.ImageRect.Top);
- maxPlaque.Ratio = ratio;
- return maxPlaque;
- }
- /// <summary>
- /// 计算轮廓的中心点
- /// </summary>
- /// <param name="contourPoints"></param>
- /// <returns></returns>
- 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>
- /// 获取AI预测结果中所有斑块的轮廓点、外接矩形等尺寸
- /// </summary>
- /// <param name="modelResults"></param>
- /// <returns></returns>
- private List<PlaqueProperty> GetAllPlaqueContours(Dictionary<int, AIDiagResultPerImg> modelResults)
- {
- List<PlaqueProperty> allPlaqueContours = new List<PlaqueProperty>();
- foreach (var modelResult in modelResults)
- {
- if (modelResult.Value.DiagResultsForEachOrgan[0].DetectedObjects.Length > 0)
- {
- if (modelResult.Value.DiagResultsForEachOrgan[0].DetectedObjects[0].Label == 0)
- {
- continue;
- }
- ///modelResults赋值给_allPlaqueContours
- var plaqueContours = new PlaqueProperty();
- AI.Common.Point2D[] contour1 = modelResult.Value.DiagResultsForEachOrgan[0].OrganContours[0];
- Point[] arteryPoints = new Point[contour1.Length];
- for (int i = 0; i < contour1.Length; i++)
- {
- arteryPoints[i].X = contour1[i].X;
- arteryPoints[i].Y = contour1[i].Y;
- }
- plaqueContours.ArteryContour = arteryPoints;
- AI.Common.Point2D[] contour2 = modelResult.Value.DiagResultsForEachOrgan[0].DetectedObjects[0].Contours[0];
- Point[] plaquePoints = new Point[contour2.Length];
- for (int i = 0; i < contour2.Length; i++)
- {
- plaquePoints[i].X = contour2[i].X;
- plaquePoints[i].Y = contour2[i].Y;
- }
- plaqueContours.PlaqueContour = plaquePoints;
- AI.Common.Rect rect2 = modelResult.Value.DiagResultsForEachOrgan[0].DetectedObjects[0].BoundingBox;
- plaqueContours.ImageRect = new Rectangle(rect2.Left, rect2.Top, rect2.Width, rect2.Height);
- plaqueContours.SerialNumber = modelResult.Key;
- plaqueContours.PlaqueArea = modelResult.Value.DiagResultsForEachOrgan[0].DetectedObjects[0].BoundingBox.Area;
- plaqueContours.Credibility = modelResult.Value.DiagResultsForEachOrgan[0].DetectedObjects[0].Confidence;
- allPlaqueContours.Add(plaqueContours);
- }
- }
- return allPlaqueContours;
- }
- }
- }
|