123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- 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
- {
- /// <summary>
- /// 可能是血管的边缘线
- /// </summary>
- public struct EdgeLines
- {
- public List<Point> UpperLinePoints;
- public List<Point> LowerLinePoints;
- }
- //检测血管
- public class DetectVessel
- {
- //相邻血管边缘差
- private const int DiffHeight = 5;
- //候选血管面积差
- private const int DiffArea = 200;
- /// <summary>
- /// 边缘点
- /// </summary>
- private struct EdgePoints
- {
- public Point StartPoint;
- public Point EndPoint;
- }
- /// <summary>
- /// 可能是血管的边缘线
- /// </summary>
- private struct VesselEdgeLines
- {
- public List<Point> StartLine;
- public List<Point> EndLine;
- //血管外接矩阵
- public Rectangle VesselRectangle;
- //血管高度方差
- public float HeightStd;
- //血管平均高度
- public float AvgHeight;
- //血管宽度
- public int VesselWidth;
- //血管面积
- public int Area;
- }
- /// <summary>
- /// 获得血管所在区域rect
- /// </summary>
- /// <param name="imgGray"></param>
- /// <returns></returns>
- public EdgeLines GetVessel(Image<Gray, byte> 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<Point>(),
- LowerLinePoints = new List<Point>()
- };
- }
- 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<VesselEdgeLines> FilterVesselByAiResult(IEnumerable<VesselEdgeLines> 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;
- }
- /// <summary>
- /// 图像预处理
- /// </summary>
- /// <param name="imgGray"></param>
- /// <returns></returns>
- private Image<Gray, byte> ImagePreprocessing(Image<Gray, byte> imgGray, int minVesselH)
- {
- var imageBri = new Image<Gray, byte>(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;
- }
- }
-
- /// <summary>
- /// 计算血管线的属性
- /// </summary>
- /// <param name="allVesselLines"></param>
- private void CalculationVesselLinesAttributes(List<VesselEdgeLines> 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))
- };
- }
- }
- /// <summary>
- /// 获得所有的边缘点
- /// </summary>
- /// <param name="imageGray"></param>
- /// <returns></returns>
- private List<EdgePoints>[] GetAllEdgePoints(Image<Gray, byte> imageGray)
- {
- try
- {
- var parallelOption = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
- var width = imageGray.Width;
- var height = imageGray.Height;
- var allEdgePoints = new List<EdgePoints>[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<EdgePoints>[0];
- }
- }
- /// <summary>
- /// 获得一列图像的开始点和结束点
- /// </summary>
- /// <param name="dataArray"></param>
- /// <param name="w"></param>
- /// <returns></returns>
- private List<EdgePoints> GetOneRowEdgePoints(byte[] dataArray, int w)
- {
- var startPoint = new Point();
- var start = false;
- var height = dataArray.Length;
- var edgeList = new List<EdgePoints>();
- 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;
- }
- /// <summary>
- /// 获得所有血管边缘
- /// </summary>
- /// <param name="allEdgePoints"></param>
- /// <param name="width"></param>
- /// <returns></returns>
- private List<VesselEdgeLines> GetAllVesselEdgeLines(List<EdgePoints>[] allEdgePoints, int width, int minVesselH)
- {
- try
- {
- var minH = minVesselH / 3;
- //生成边缘线-----
- var lineList = new List<VesselEdgeLines>();
- 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<Point> { edgePoints.StartPoint },
- EndLine = new List<Point> { 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<VesselEdgeLines>();
- }
- }
- //寻找合适的points轮廓
- private int GetTheClosestContours(List<VesselEdgeLines> 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;
- }
- }
- /// <summary>
- /// 再次去除杂质
- /// </summary>
- /// <param name="image"></param>
- private void RemoveNonVessel(Image<Gray, byte> 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<Gray, byte> image, Func<Rectangle, bool> 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);
- }
- }
- }
- }
- }
- }
|