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;
}
///
/// 图像信息
///
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
{
///
/// 斑块数量 无、单发、多发
///
public PlaqueCountType PlaqueCountType { get; }
///
/// 斑块特性 软斑、硬斑
///
public PlaqueType PlaqueType { get; }
///
/// 最大斑块宽度
///
public float PlaqueWidth { get; }
///
/// 最大斑块高度
///
public float PlaqueHeight { get; }
///
/// 狭窄率
///
public float Stenosis { get; }
///
/// 斑块位置,上内膜/下内膜
///
public PlaquePostionType PlaquePostion;
///
/// 检测切面的三维点
///
public List ClipPoints { get; }
///
/// 是否识别成功
///
public bool IsSuccess { get; }
///
/// 斑块的轮廓
///
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 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);
///
/// 斑块自动检测
///
/// 颈动脉图像
/// 每个像素代表实际长度
/// 斑块位置
public PlaqueResult CalcPlaqueProperty(byte[][] model, ModelSize modelSize, float physicalPerPixel, Dictionary 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 { }, 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 clipPoints = new List {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;
}
///
/// 判断斑块是否在血管内
///
///
///
private List GetPlaqueInArtery(IList allPlaque)
{
var plaqueList = new List();
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;
}
///
/// 计算最大斑块的属性
///
///
///
private PlaqueProperty GetMaxPlaque(IList 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;
}
///
/// 计算轮廓的中心点
///
///
///
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));
}
///
/// 获取AI预测结果中所有斑块的轮廓点、外接矩形等尺寸
///
///
///
private List GetAllPlaqueContours(Dictionary modelResults)
{
List allPlaqueContours = new List();
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;
}
}
}