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); } } } } } }