using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using WingServerCommon.Log;
namespace WingAIDiagnosisService.Carotid.Utilities
{
///
/// 可能是血管的边缘线
///
public struct EdgeLines
{
public List UpperLinePoints;
public List LowerLinePoints;
}
//检测血管
public class DetectVessel
{
//相邻血管边缘差
private const int DiffHeight = 5;
//候选血管面积差
private const int DiffArea = 200;
///
/// 边缘点
///
private struct EdgePoints
{
public Point StartPoint;
public Point EndPoint;
}
///
/// 可能是血管的边缘线
///
private struct VesselEdgeLines
{
public List StartLine;
public List EndLine;
//血管外接矩阵
public Rectangle VesselRectangle;
//血管高度方差
public float HeightStd;
//血管平均高度
public float AvgHeight;
//血管宽度
public int VesselWidth;
//血管面积
public int Area;
}
///
/// 获得血管所在区域rect
///
///
///
public EdgeLines GetVessel(Image imgGray)
{
try
{
//血管最小高度 399 * 0.08
var minVesselH = (int)(imgGray.Height * VesselConstParameter.MinVesslHeightRatio);
//血管最小位置 399 * 0.1
var minVesselPositionY = (int)(imgGray.Height * VesselConstParameter.MinVesselPositionRatio);
//血管最小宽度 813 * 0.025
var minVesselW = (int)(imgGray.Width * VesselConstParameter.MinVesselWidthRatio);
using (var imageBri = ImagePreprocessing(imgGray, minVesselH))
{
//所有可能的上下血管端点
var allEdgePoints = GetAllEdgePoints(imageBri);
//寻找可能的血管边缘
var allVesselLines = GetAllVesselEdgeLines(allEdgePoints, imageBri.Width, minVesselH);
//计算相邻连通域间的黑色区域高度的方差和均值
CalculationVesselLinesAttributes(allVesselLines);
//血管筛选
var vesselLineList = allVesselLines.Where(m =>
m.VesselWidth > minVesselW && m.AvgHeight > minVesselH &&
m.VesselRectangle.Top > minVesselPositionY).ToList();
if (vesselLineList.Count == 0)
{
return new EdgeLines
{
UpperLinePoints = new List(),
LowerLinePoints = new List()
};
}
vesselLineList = FilterVesselByAiResult(vesselLineList).ToList();
//得到最符合条件的血管边缘
vesselLineList =vesselLineList.OrderByDescending(o => o.Area).ToList();
//如果有两个以上候选
if (vesselLineList.Count > 1)
{
//如果两个面积相差不大
if (vesselLineList[0].Area - vesselLineList[1].Area < DiffArea)
{
//如果面积大的比面积小的血管高度方差大很多,则选第二个候选项作为血管
if (vesselLineList[0].HeightStd - vesselLineList[1].HeightStd > VesselConstParameter.DiffStd)
{
return new EdgeLines
{
UpperLinePoints = vesselLineList[1].StartLine,
LowerLinePoints = vesselLineList[1].EndLine
};
}
}
}
return new EdgeLines
{
UpperLinePoints = vesselLineList[0].StartLine,
LowerLinePoints = vesselLineList[0].EndLine
};
}
}
catch (Exception e)
{
Logger.WriteLineError("DetectVessel GetVessel error," + e.Message + "," + e.StackTrace);
return new EdgeLines();
}
}
private IEnumerable FilterVesselByAiResult(IEnumerable inputLines)
{
var vesselYEdge = GetModelVesselAndPlaque.Instance.GetVesselYEdge();
var filteredVessel = inputLines.Where(m => m.VesselRectangle.Bottom > vesselYEdge.AvgTop && m.VesselRectangle.Top < vesselYEdge.AvgBottom).ToList();
if (filteredVessel.Count > 0)
{
return filteredVessel;
}
return inputLines;
}
///
/// 图像预处理
///
///
///
private Image ImagePreprocessing(Image imgGray, int minVesselH)
{
var imageBri = new Image(imgGray.Width, imgGray.Height);
try
{
//图像增强
CvInvoke.EqualizeHist(imgGray, imgGray);
//二值化
var threshold = ImageTools.GetThreshold(imgGray);
CvInvoke.Threshold(imgGray, imageBri, threshold, 255, ThresholdType.Binary);
//中值滤波去噪点
CvInvoke.MedianBlur(imageBri, imageBri, 3);
//反转二值化图像
CvInvoke.Threshold(imageBri, imageBri, 100, 255, ThresholdType.BinaryInv);
//去除杂质
RemoveNonVessel(imageBri, false, minVesselH);
//反转二值化图像
CvInvoke.Threshold(imageBri, imageBri, 100, 255, ThresholdType.BinaryInv);
//去掉边缘周围的杂质
RemoveNonVessel(imageBri, true, minVesselH);
return imageBri;
}
catch (Exception e)
{
Logger.WriteLineError("DetectVessel ImagePreprocessing error," + e.Message + "," + e.StackTrace);
return imageBri;
}
}
///
/// 计算血管线的属性
///
///
private void CalculationVesselLinesAttributes(List allVesselLines)
{
var count1 = allVesselLines.Count;
for (var j = 0; j < count1; ++j)
{
var startLine = allVesselLines[j].StartLine;
var endLine = allVesselLines[j].EndLine;
var count = startLine.Count;
var vesselHeight = new int[count];
var sumHeight = 0;
var minY = int.MaxValue;
var maxY = 0;
for (var i = 0; i < count; ++i)
{
var startY = startLine[i].Y;
var endY = endLine[i].Y;
if (startY < minY)
{
minY = startY;
}
if (endY > maxY)
{
maxY = endY;
}
vesselHeight[i] = endY - startY;
sumHeight += vesselHeight[i];
}
var avgHeight = sumHeight / (float)count;
float sumStd = 0;
for (var i = 0; i < count; ++i)
{
var diff = vesselHeight[i] - avgHeight;
sumStd += diff * diff;
}
sumStd = (float)Math.Sqrt(sumStd / count);
allVesselLines[j] = new VesselEdgeLines
{
StartLine = startLine,
EndLine = endLine,
AvgHeight = avgHeight,
HeightStd = sumStd,
Area = sumHeight,
VesselWidth = count,
VesselRectangle = new Rectangle(new Point(startLine[0].X, minY), new Size(startLine.Last().X - startLine[0].X, maxY - minY))
};
}
}
///
/// 获得所有的边缘点
///
///
///
private List[] GetAllEdgePoints(Image imageGray)
{
try
{
var parallelOption = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
var width = imageGray.Width;
var height = imageGray.Height;
var allEdgePoints = new List[width];
var dataArray = new byte[width][];
Parallel.For(0, width, parallelOption, w =>
{
dataArray[w] = new byte[height];
for (var h = 1; h != height; ++h)
{
dataArray[w][h] = imageGray.Data[h, w, 0];
}
allEdgePoints[w] = GetOneRowEdgePoints(dataArray[w], w);
});
return allEdgePoints;
}
catch (Exception e)
{
Logger.WriteLineError("DetectVessel GetAllEdgePoints error," + e.Message + "," + e.StackTrace);
return new List[0];
}
}
///
/// 获得一列图像的开始点和结束点
///
///
///
///
private List GetOneRowEdgePoints(byte[] dataArray, int w)
{
var startPoint = new Point();
var start = false;
var height = dataArray.Length;
var edgeList = new List();
var threshold = 100;
for (var h = 1; h < height - 1; ++h)
{
var data = dataArray[h];
if (data > threshold)
{
if (!start)
{
start = true;
}
}
else
{
if (start)
{
var dataLast = dataArray[h - 1];
var dataNext = dataArray[h + 1];
if (dataLast > threshold)
{
startPoint = new Point(w, h);
}
if (dataNext > threshold)
{
edgeList.Add(new EdgePoints
{
StartPoint = startPoint,
EndPoint = new Point(w, h)
});
start = false;
}
}
}
}
return edgeList;
}
///
/// 获得所有血管边缘
///
///
///
///
private List GetAllVesselEdgeLines(List[] allEdgePoints, int width, int minVesselH)
{
try
{
var minH = minVesselH / 3;
//生成边缘线-----
var lineList = new List();
for (var w = 0; w < width; ++w)
{
foreach (var edgePoints in allEdgePoints[w])
{
var h = edgePoints.EndPoint.Y - edgePoints.StartPoint.Y;
if (h < minH)
{
continue;
}
var index = GetTheClosestContours(lineList, edgePoints);
if (index == -1)
{
lineList.Add(new VesselEdgeLines
{
StartLine = new List { edgePoints.StartPoint },
EndLine = new List { edgePoints.EndPoint }
});
}
else
{
lineList[index].StartLine.Add(edgePoints.StartPoint);
lineList[index].EndLine.Add(edgePoints.EndPoint);
}
}
}
return lineList;
}
catch (Exception e)
{
Logger.WriteLineError("DetectVessel GetAllVesselEdgeLines error," + e.Message + "," + e.StackTrace);
return new List();
}
}
//寻找合适的points轮廓
private int GetTheClosestContours(List linePoints, EdgePoints edgePoints)
{
try
{
var count = linePoints.Count;
if (count == 0)
{
return -1;
}
var maxClosePointsNum = -1;
var maxIndex = -1;
for (var i = 0; i < count; ++i)
{
var startPoint = linePoints[i].StartLine.Last();
var endPoint = linePoints[i].EndLine.Last();
var maxStart = Math.Max(startPoint.Y, edgePoints.StartPoint.Y);
var minEnd = Math.Min(endPoint.Y, edgePoints.EndPoint.Y);
if (maxStart < minEnd && edgePoints.StartPoint.X == startPoint.X + 1)
{
var height1 = endPoint.Y - startPoint.Y;
var height2 = edgePoints.EndPoint.Y - edgePoints.StartPoint.Y;
//如果两段的高都小于5,则不考虑2倍的情况
if (height2 < DiffHeight && height1 < DiffHeight)
{
var closePointNum = minEnd - maxStart;
if (closePointNum > maxClosePointsNum)
{
maxClosePointsNum = closePointNum;
maxIndex = i;
}
}
else
{
//血管高度差不超过2倍
if (height1 / height2 < 2 && height2 / height1 < 2)
{
var closePointNum = minEnd - maxStart;
if (closePointNum > maxClosePointsNum)
{
maxClosePointsNum = closePointNum;
maxIndex = i;
}
}
}
}
}
return maxIndex;
}
catch (Exception e)
{
Logger.WriteLineError("DetectVessel GetTheClosestContours error," + e.Message + "," + e.StackTrace);
return -1;
}
}
///
/// 再次去除杂质
///
///
private void RemoveNonVessel(Image image, bool isRemoveImpurity, int minVesselH)
{
try
{
//去掉边缘周围的杂质---
//求连通域
var contours = ImageTools.FindContours(image);
var minWidth = image.Width / 5;
if (isRemoveImpurity)
{
//去掉宽度较小的连通域
FillSmallArea(contours, image, rect => rect.Width < minWidth);
}
else
{
//去掉宽度或高度较小的连通域
FillSmallArea(contours, image, rect => rect.Width < minWidth || rect.Height < minVesselH);
}
}
catch (Exception e)
{
Logger.WriteLineError("DetectVessel RemoveNonVessel error," + e.Message + "," + e.StackTrace);
}
}
private void FillSmallArea(VectorOfVectorOfPoint contours, Image image, Func condition)
{
for (var i = 0; i < contours.Size; ++i)
{
var contour = contours[i];
var rect = CvInvoke.BoundingRectangle(contour);
if (condition(rect))
{
var points = contour.ToArray();
if (rect.Height > rect.Width)
{
ImageTools.ChangeImageH(image, points, rect);
}
else
{
ImageTools.ChangeImageW(image, points, rect);
}
}
}
}
}
}