using OpenCvSharp; using PaintDotNet.Adjust.BaseImage; using PaintDotNet.Base; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; namespace PaintDotNet.Adjust { public unsafe class Battery { /// /// 全局中间变量 /// 不带视场的时候就是原图/二值图 /// 带视场的时候就是原图/二值图 /// public static Mat temp, temp_view; /// /// 用来存储透明图 /// public static Mat alpha; /// /// 1个颜色区间还是2个 /// public static int colorInterval; /// /// 1个颜色区间时的起始值 /// public static int colorOneStart; /// /// 1个颜色区间时的结止值 /// public static int colorOneEnd; /// /// 2个颜色区间时的第1个区间的起始值 /// public static int colorTwoStart = 0; /// /// 2个颜色区间时的第1个区间的结止值 /// public static int colorTwoEnd = 0; /// /// 2个颜色区间时的第2个区间的起始值 /// public static int colorThreeStart = 0; /// /// 2个颜色区间时的第2个区间的起始值 /// public static int colorThreeEnd = 0; //碎屑删除面积起 public static int debrisAreaStart = 0; //图片类型,1同心圆孔隙2单晶3二次球与单晶 public static int imageType = 1; //碎屑删除面积止 public static int debrisAreaEnd = 0; /// /// 默认相颜色 /// public static Vec4b vec4B = new Vec4b(255, 0, 0, 255); /// /// 默认相颜色 /// public static Vec4b vec4Bw = new Vec4b(0, 0, 0, 0); /// /// 新增的参数,用于FloodFill方法 /// public static Rect rect; /// /// 各个连通域的代表点 /// public static List points; /// /// 用来记录需要删除的连通区域的编号 /// public static Dictionary keyValuePairs = new Dictionary(); /// /// 用来记录选择的连通区域的编号 /// public static Dictionary keyValueSel = new Dictionary(); public static Mat rgb_ap; public static Mat temp_ap; //碎屑删除面积止 public static int poArea = 0; //孔隙同心圆面积 public static List poAreaList = new List() { }; //孔隙信息,孔隙的x,y,width,height,area,id public static List> poList = new List> { }; //开裂球历史记录 public static List> poListHis = new List> { }; //同心圆数 public static int circleCount = 0; //最大轮廓 public static OpenCvSharp.Point[] maxContour = new OpenCvSharp.Point[] { }; //同心圆半径 public static int CircleR = 0; //同心圆半径 public static OpenCvSharp.Point center = new OpenCvSharp.Point(); //删除孔隙 public static List delPointFs = new List(); //选择孔隙 public static int selPointFs = -1; //记录联通区域 public static Mat labelMatForSel = new Mat(); //记录新增联通区域 public static OpenCvSharp.Point[][] labelMatForSelAdd; //记录联通区域数量 public static int fieldsCount = 0; //处理后的mat public static Mat retMat = new Mat(); //同心圆颜色列表 public static List colorList = new List() { new Scalar(0, 0, 255, 255), new Scalar(0, 255, 0, 255), new Scalar(0, 0, 139, 255), new Scalar(128, 0, 128, 255), new Scalar(255, 160, 122, 255) }; public static List vec4BList = new List() { new Vec4b(0, 0, 255, 255), new Vec4b(0, 255, 0, 255), new Vec4b(0, 0, 139, 255), new Vec4b(128, 0, 128, 255), new Vec4b(255, 160, 122, 255) }; //所有点 public static Dictionary> particlePixles = new Dictionary>(); //轮廓面积 public static int maxArea = 0; //图像高度 public static int imageHight = 0; //图像高度 public static int imageWidth = 0; //二次球点 public static List BallPointFs = new List(); //二次球单晶点 public static List CrystalPointFs = new List(); //二次球轮廓 public static List> CrystalLunkuo = new List>(); //二次球模糊系数 public static int BlurSiaze = 15; //二次球阈值 public static int param2 = 24; //二次球最小半径 public static int minRadius = 33; //二次球最大半径 public static int maxRadius = 52; //去边界 public static int boundary = 0; //去底边 public static double borderBottom = 0; //忽略开裂球 public static List CreackBallPointFs = new List(); //设为开裂球 public static List CreackBallPointFsK = new List(); //设为普通球 public static List CreackBallPointFsP = new List(); //小颗粒 public static double pointsize = 0.1; //标尺 public static double Micron = 0.01; //边缘 public static int border = 1; //长宽比 public static double HW = 1; //面积率 public static double AreaRatio = 1; //添加单晶 public static List> AddPontins = new List>(); //连通域集合 static List> AllFields = new List>(); //二次球测量区域 public static List Contour = new List(); //手动画同心圆半径和颜色 public static Dictionary ListRadiusColor = new Dictionary(); //是否画测距 public static bool isDis = false; //是否画矩形 public static bool isJu = false; #region 无视场 二值提取 /// /// 二值操作-二值提取-无视场 /// /// 源图像 /// 参数集合 /// public static Mat ImageBinaryExtraction(Mat src, List lists, bool findContours = false) { //以下是参数信息--------------------- ///1个颜色区间还是2个 colorInterval = 1; //第一个二值区间 colorOneStart = 0; colorOneEnd = 0; //第二个二值区间 colorTwoStart = 0; colorTwoEnd = 0; //第三个二值区间 colorThreeStart = 0; colorThreeEnd = 0; //处理细节 //删除边界对象 bool deleteBoundaryObject = false; //孔洞填充 bool holeFilling = false; //碎屑删除 bool debrisRemoval = false; //碎屑删除面积起 debrisAreaStart = 0; //碎屑删除面积止 debrisAreaEnd = 0; //二值样式 //1实心 2边线 int binaryStyle = 0; //相颜色 Color phaseColor = Color.Red; //目标选择 int targetSelection = 1; for (int i = 0; i < lists.Count; i++) { Args args = lists[i]; switch (args.Key) { case "colorInterval": { if (args.Value is Boolean) colorInterval = (Boolean)args.Value ? 2 : 1; else colorInterval = (int)args.Value; } break; case "scope1": colorOneStart = (int)((List)args.Value)[0]; colorOneEnd = (int)((List)args.Value)[1]; break; case "scope2": colorTwoStart = (int)((List)args.Value)[0]; colorTwoEnd = (int)((List)args.Value)[1]; break; case "scope3": colorThreeStart = (int)((List)args.Value)[0]; colorThreeEnd = (int)((List)args.Value)[1]; break; case "deleteBoundaryObject": deleteBoundaryObject = (bool)args.Value; break; case "holeFilling": holeFilling = (bool)args.Value; break; case "debrisRemoval": debrisRemoval = (bool)args.Value; break; case "binaryStyle": binaryStyle = (int)args.Value; break; case "phaseColor": phaseColor = Color.FromArgb((int)args.Value); break; case "targetSelection": targetSelection = (int)args.Value; break; case "scope4": debrisAreaStart = (int)((List)args.Value)[0]; debrisAreaEnd = (int)((List)args.Value)[1]; findContours = true; break; case "imageType": imageType = (int)args.Value; break; default: break; } } if (phaseColor.A < 1)//#21321 phaseColor = Color.FromArgb(1, phaseColor.R, phaseColor.G, phaseColor.B); vec4B.Item0 = phaseColor.B; vec4B.Item1 = phaseColor.G; vec4B.Item2 = phaseColor.R; vec4B.Item3 = phaseColor.A; //中值滤波 //Cv2.MedianBlur(src, src, 3); //二值提取 src = Binarization(src); //碎屑删除,参考冈萨雷斯,414,9.5.3,连通分量提取 // if (debrisRemoval && debrisAreaEnd > 0) src = DebrisRemoval_New(src); //实心/边线,参考冈萨雷斯,412,9.5.1,边界提取 Cv2.Erode(src, temp, null); src = src - temp; src = BaseTools.MergeMatFromMatArr(src, vec4B); return src; } /// /// 前驱截面 /// /// 源图像 /// 参数集合 /// public static Mat ImageBinaryExtraction(Mat src, List lists, out List> data, bool findContours = false) { //以下是参数信息--------------------- ///1个颜色区间还是2个 colorInterval = 1; //第一个二值区间 colorOneStart = 0; colorOneEnd = 0; //第二个二值区间 colorTwoStart = 0; colorTwoEnd = 0; //第三个二值区间 colorThreeStart = 0; colorThreeEnd = 0; boundary = 0; //处理细节 //删除边界对象 bool deleteBoundaryObject = false; //孔洞填充 bool holeFilling = false; //碎屑删除 bool debrisRemoval = false; //碎屑删除面积起 debrisAreaStart = 0; //碎屑删除面积止 debrisAreaEnd = 0; //二值样式 //1实心 2边线 int binaryStyle = 0; //相颜色 Color phaseColor = Color.Red; //目标选择 int targetSelection = 1; for (int i = 0; i < lists.Count; i++) { Args args = lists[i]; switch (args.Key) { case "colorInterval": { if (args.Value is Boolean) colorInterval = (Boolean)args.Value ? 2 : 1; else colorInterval = (int)args.Value; } break; case "scope1": colorOneStart = (int)((List)args.Value)[0]; colorOneEnd = (int)((List)args.Value)[1]; break; case "scope2": colorTwoStart = (int)((List)args.Value)[0]; colorTwoEnd = (int)((List)args.Value)[1]; break; case "scope3": colorThreeStart = (int)((List)args.Value)[0]; colorThreeEnd = (int)((List)args.Value)[1]; break; case "deleteBoundaryObject": deleteBoundaryObject = (bool)args.Value; break; case "holeFilling": holeFilling = (bool)args.Value; break; case "debrisRemoval": debrisRemoval = (bool)args.Value; break; case "binaryStyle": binaryStyle = (int)args.Value; break; case "phaseColor": phaseColor = Color.FromArgb((int)args.Value); break; case "targetSelection": targetSelection = (int)args.Value; break; case "scope4": debrisAreaStart = (int)((List)args.Value)[0]; debrisAreaEnd = (int)((List)args.Value)[1]; findContours = true; break; case "CircleCount": circleCount = (int)args.Value; break; case "maxContour": maxContour = (OpenCvSharp.Point[])args.Value; break; case "CircleR": CircleR = (int)args.Value; break; case "Center": center = (OpenCvSharp.Point)args.Value; break; case "DelPointFs": delPointFs = (List)args.Value; break; case "imageType": imageType = (int)args.Value; break; case "SelPointFs": selPointFs = (int)args.Value; break; case "imageTypes": imageType = (int)args.Value; break; case "BlurSiaze": BlurSiaze = (int)args.Value; break; case "param2": param2 = (int)args.Value; break; case "minRadius": minRadius = (int)args.Value; break; case "maxRadius": maxRadius = (int)args.Value; break; case "boundary": boundary = (int)args.Value; break; case "BallPointFs": BallPointFs = (List)args.Value; break; case "CrystalPointFs": CrystalPointFs = (List)args.Value; break; case "CrystalLunkuo": CrystalLunkuo = (List>)args.Value; break; case "AddPontins": AddPontins = (List>)args.Value; break; case "pointsize": pointsize = (double)args.Value; break; case "Micron": Micron = (double)args.Value; break; case "border": border = (int)args.Value; break; case "HW": HW = (double)args.Value; break; case "AreaRatio": AreaRatio = (double)args.Value; break; case "Contour": Contour = (List)args.Value; break; case "ListRadiusColor": ListRadiusColor = (Dictionary)args.Value; break; case "isDis": isDis = (bool)args.Value; break; case "isJu": isJu = (bool)args.Value; break; case "borderBottom": borderBottom = (int)args.Value; break; default: break; } } if (phaseColor.A < 1)//#21321 phaseColor = Color.FromArgb(1, phaseColor.R, phaseColor.G, phaseColor.B); temp_view = src.Clone(); vec4B.Item0 = phaseColor.B; vec4B.Item1 = phaseColor.G; vec4B.Item2 = phaseColor.R; vec4B.Item3 = phaseColor.A; poArea = 0; maxArea = 0; poList.Clear(); poAreaList = new List() { }; data = poList; imageHight = src.Rows; imageWidth = src.Cols; if (imageType == 1) { if (selPointFs != -1 && retMat != null) { Mat used = retMat.Clone(); keyValueSel.Add(selPointFs, 1); src = SelectPoint(used); } else { if (ListRadiusColor.Count > 0) { for (int i = 0; i < ListRadiusColor.Count; i++) { poAreaList.Add(0); } ListRadiusColor = ListRadiusColor.OrderByDescending(c => c.Key).ToDictionary(pair => pair.Key, pair => pair.Value); } else if (circleCount > 0) { for (int i = 0; i < circleCount; i++) { poAreaList.Add(0); } } //二值提取 src = Binarization(src); //using (new Window("InputImage", WindowMode.Normal, src)) //{ // Cv2.WaitKey(0); //} //去掉过小孔隙,计算孔隙面积 src = DebrisRemoval_New(src); //using (new Window("InputImage1", WindowMode.Normal, src)) //{ // Cv2.WaitKey(0); //} OpenCvSharp.Point[][] contours = new OpenCvSharp.Point[][] { maxContour }; Cv2.DrawContours(src, contours, 0, new Scalar(255, 144, 30, 255), 2); if (circleCount > 1) { for (int i = 0; i < circleCount; i++) { Cv2.Circle(src, center, Convert.ToInt32(CircleR * (i + 1)), colorList[i], 2); } } poAreaList.Add(poArea); poAreaList.Add(maxArea); data.Insert(0, poAreaList); retMat = src.Clone(); ListRadiusColor.Clear(); } keyValueSel.Clear(); selPointFs = -1; } else if (imageType == 2) { if (selPointFs != -1 && retMat != null) { Mat used = retMat.Clone(); keyValueSel.Add(selPointFs, 1); src = SelectPoint(used); keyValueSel.Clear(); selPointFs = -1; } else { src = WhirtBinarization(src); Mat srcGray = src.CvtColor(ColorConversionCodes.BGRA2BGR); Mat dst = new Mat(); //双边滤波 Cv2.BilateralFilter(srcGray, dst, 21, 132, 181); Mat canny = new Mat(); Mat gray = new Mat(); Mat andmet = new Mat(); Cv2.GaussianBlur(dst, canny, new OpenCvSharp.Size(3, 3), 40); Cv2.CvtColor(canny, gray, ColorConversionCodes.BGR2GRAY); andmet = gray.Clone(); Cv2.Canny(gray, gray, 100, 100); Cv2.Dilate(gray, gray, null); Cv2.Dilate(gray, gray, null); Cv2.Erode(gray, gray, null); Cv2.GaussianBlur(gray, gray, new OpenCvSharp.Size(3, 3), 10); gray = DebrisRemoval_CrystCanny(gray); Mat notmet = gray.Clone(); Cv2.BitwiseNot(notmet, notmet); Cv2.Threshold(andmet, andmet, colorOneStart, colorOneEnd, ThresholdTypes.Binary); for (int i = 0; i < 4; i++) { Cv2.Dilate(andmet, andmet, null); } for (int i = 0; i < 4; i++) { Cv2.Erode(andmet, andmet, null); } Cv2.BitwiseAnd(notmet, andmet, andmet); Cv2.MedianBlur(andmet, andmet, 9); //二值提取 src = Binarization(andmet); } } else if (imageType == 12) { if (selPointFs != -1 && retMat != null) { Mat used = retMat.Clone(); if (selPointFs >= fieldsCount) { Cv2.DrawContours(used, labelMatForSelAdd, selPointFs- fieldsCount, new Scalar(255, 255, vec4B.Item2, vec4B.Item3), -1); src= used.Clone(); } else { keyValueSel.Add(selPointFs, 1); src = SelectPoint(used); keyValueSel.Clear(); } selPointFs = -1; } else { src = DebrisRemoval_Cryst(src); retMat = src.Clone(); } } else if (imageType == 3) { src = WhirtBinarization(src); List circleList = new List(); List circleAreaList = new List(); Mat dst = new Mat(); Mat m1 = new Mat(); Cv2.MedianBlur(src, m1, BlurSiaze); // ksize必须大于1且是奇数 //2:转为灰度图像 Mat hb = new Mat(src.Rows, src.Cols, MatType.CV_8UC1); Mat m2 = m1.Clone(); Cv2.CvtColor(m1, m2, ColorConversionCodes.BGR2GRAY); //3:霍夫圆检测:使用霍夫变换查找灰度图像中的圆。 /* * 参数: * 1:输入参数: 8位、单通道、灰度输入图像 * 2:实现方法:目前,唯一的实现方法是HoughCirclesMethod.Gradient * 3: dp :累加器分辨率与图像分辨率的反比。默认=1 * 4:minDist: 检测到的圆的中心之间的最小距离。(最短距离-可以分辨是两个圆的,否则认为是同心圆- src_gray.rows/8) * 5:param1: 第一个方法特定的参数。[默认值是100] canny边缘检测阈值低 * 6:param2: 第二个方法特定于参数。[默认值是100] 中心点累加器阈值 – 候选圆心 * 7:minRadius: 最小半径 * 8:maxRadius: 最大半径 * */ CircleSegment[] cs = Cv2.HoughCircles(m2, HoughMethods.Gradient, 1, 80, 70, param2, minRadius, maxRadius); src.CopyTo(dst); int one = 0; int two = 0; int three = 0; int four = 0; double oneA = 0; double twoA = 0; double threeA = 0; double fourA = 0; int helfx = src.Cols / 2; int helfy = (src.Rows - 70) / 2; List delKey = new List(); List> trmpList = new List>(); CrystalLunkuo.ForEach(s => trmpList.Add(s)); //大圆 for (int i = 0; i < cs.Length; i++) { if (CrystalPointFs.Count > 0) { int isCrystal = 0; foreach (var item in CrystalPointFs) { Point2f pin = new Point2f(item.X, item.Y); double distanc = pin.DistanceTo(cs[i].Center); if (distanc < cs[i].Radius) { isCrystal = 1; break; } } if (isCrystal == 1) { delKey.Add(i); continue; } } //手画圆轮廓 if (trmpList.Count > 0) { int del = -1; for (int lk = 0; lk < trmpList.Count; lk++) { List pl = new List(); trmpList[lk].ForEach(pp => pl.Add(new OpenCvSharp.Point(pp.X, pp.Y))); Point2f newcenter = new Point2f(); float newR = 0; Cv2.MinEnclosingCircle(pl, out newcenter, out newR); if (newcenter.DistanceTo(cs[i].Center) < cs[i].Radius) { cs[i].Center = newcenter; cs[i].Radius = newR; del = lk; break; } } if (del >= 0) { trmpList.RemoveAt(del); } } double area = Math.PI * cs[i].Radius * cs[i].Radius; if ((int)cs[i].Center.X < helfx && (int)cs[i].Center.Y < helfy) { one++; oneA = oneA + area; } if ((int)cs[i].Center.X < helfx && (int)cs[i].Center.Y > helfy) { two++; twoA = twoA + area; } if ((int)cs[i].Center.X > helfx && (int)cs[i].Center.Y < helfy) { three++; threeA = threeA + area; } if ((int)cs[i].Center.X > helfx && (int)cs[i].Center.Y > helfy) { four++; fourA = fourA + area; } //画圆 Cv2.Circle(dst, (int)cs[i].Center.X, (int)cs[i].Center.Y, (int)cs[i].Radius, new Scalar(0, 0, 0), -1, LineTypes.AntiAlias); //加强圆心显示 Cv2.Circle(dst, (int)cs[i].Center.X, (int)cs[i].Center.Y, 3, new Scalar(0, 0, 0), 2, LineTypes.AntiAlias); //画圆 Cv2.Circle(hb, (int)cs[i].Center.X, (int)cs[i].Center.Y, (int)cs[i].Radius, new Scalar(255), -1, LineTypes.AntiAlias); } //手画圆轮廓 if (trmpList.Count > 0) { for (int lk = 0; lk < trmpList.Count; lk++) { List pl = new List(); trmpList[lk].ForEach(pp => pl.Add(new OpenCvSharp.Point(pp.X, pp.Y))); Point2f newcenter = new Point2f(); float newR = 0; Cv2.MinEnclosingCircle(pl, out newcenter, out newR); Cv2.Circle(dst, (int)newcenter.X, (int)newcenter.Y, 3, colorList[0], 2, LineTypes.AntiAlias); //加强圆心显示 Cv2.Circle(dst, (int)newcenter.X, (int)newcenter.Y, (int)newR, new Scalar(0, 0, 0), -1, LineTypes.AntiAlias); //画圆 Cv2.Circle(hb, (int)newcenter.X, (int)newcenter.Y, (int)newR, new Scalar(255), -1, LineTypes.AntiAlias); double CircleArea = Math.PI * newR * newR; if ((int)newcenter.X < helfx && newcenter.Y < helfy) { one++; oneA = oneA + CircleArea; } if ((int)newcenter.X < helfx && (int)newcenter.Y > helfy) { two++; twoA = twoA + CircleArea; } if ((int)newcenter.X > helfx && (int)newcenter.Y < helfy) { three++; threeA = threeA + CircleArea; } if ((int)newcenter.X > helfx && (int)newcenter.Y > helfy) { four++; fourA = fourA + CircleArea; } } } Mat oldDst = dst.Clone(); if (boundary > 0) { //去边界 dst = BallCutBottor(dst); //左上 Rect rectL1 = new Rect(0, 0, helfx, helfy); Mat MatL1 = new Mat(hb, rectL1); int areaAllL1 = MatL1.CountNonZero(); Rect rectL1Cut = new Rect(boundary, boundary, helfx - boundary, helfy - boundary); Mat MatL1Cut = new Mat(hb, rectL1Cut); int areaCut = MatL1Cut.CountNonZero(); int oneCut = areaAllL1 - areaCut; oneA = oneA - oneCut; //左下 Rect rectL2 = new Rect(0, helfy, helfx, helfy); Mat MatL2 = new Mat(hb, rectL2); int areaAllL2 = MatL2.CountNonZero(); Rect rectL2Cut = new Rect(boundary, helfy, helfx - boundary, helfy - boundary); Mat MatL2Cut = new Mat(hb, rectL2Cut); int areaCutL2 = MatL2Cut.CountNonZero(); int oneCutL2 = areaAllL2 - areaCutL2; twoA = twoA - oneCutL2; //右上 Rect rectR1 = new Rect(helfx, 0, helfx, helfy); Mat MatR1 = new Mat(hb, rectR1); int areaAllR1 = MatR1.CountNonZero(); Rect rectR1Cut = new Rect(helfx, boundary, helfx - boundary, helfy - boundary); Mat MatR1Cut = new Mat(hb, rectR1Cut); int areaCutR1 = MatR1Cut.CountNonZero(); int oneCutR1 = areaAllR1 - areaCutR1; threeA = threeA - oneCutR1; //右下 Rect rectR2 = new Rect(helfx, helfy, helfx, helfy); Mat MatR2 = new Mat(hb, rectR2); int areaAllR2 = MatR2.CountNonZero(); Rect rectR2Cut = new Rect(helfx, helfy, helfx - boundary, helfy - boundary); Mat MatR2Cut = new Mat(hb, rectR2Cut); int areaCutR2 = MatR2Cut.CountNonZero(); int oneCutR2 = areaAllR2 - areaCutR2; fourA = fourA - oneCutR2; Rect cut = new Rect(boundary, boundary, src.Cols - boundary * 2, src.Rows - 70 - boundary * 2); Cv2.Rectangle(src, cut, colorList[1]); //using (new Window("MatR2Cut", WindowMode.Normal, MatR2Cut)) //{ // Cv2.WaitKey(0); //} } OpenCvSharp.Point[][] contours = new OpenCvSharp.Point[][] { }; HierarchyIndex[] hierarchy; Cv2.GaussianBlur(dst, dst, new OpenCvSharp.Size(25, 25), 0, 0, BorderTypes.Default); dst = Binarization(dst); List crystalList = new List() { 0, 0, 0, 0 }; List crystalListi = new List() { 0, 0, 0, 0 }; int xx = 0; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { //定义截取矩形 Rect m_select = new Rect(i * helfx, j * helfy, helfx, helfy); //进行裁剪 Mat imgRect = new Mat(dst, m_select); Cv2.CvtColor(imgRect, imgRect, ColorConversionCodes.BGR2GRAY); Cv2.FindContours(imgRect, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone, null); for (int t = 0; t < contours.Length; t++) { RotatedRect rectR = Cv2.MinAreaRect(contours[t]); //计算每个轮廓最小外接矩形 float width = rectR.Size.Width; float height = rectR.Size.Height; bool isjoin = false; for (int p = 0; p < cs.Count(); p++) { if (delKey.Contains(p)) continue; Point2f center = new Point2f(cs[p].Center.X, cs[p].Center.Y); double distanc = 0; for (int k = 0; k < contours[t].Length; k++) { Point2f pin = new Point2f(contours[t][k].X, contours[t][k].Y); distanc += pin.DistanceTo(center); } double dev = distanc / contours[t].Length; float mvg = width / height; if (dev < cs[p].Radius + 20) { isjoin = true; break; } } if (isjoin) { continue; } double area = Cv2.ContourArea(contours[t]); crystalList[xx] = crystalList[xx] + area; } crystalListi[xx] = Convert.ToInt32(crystalList[xx]); xx++; } } Rect m_select1 = new Rect(0, 0, dst.Cols, dst.Rows - 70); //进行裁剪 Mat imgRect1 = new Mat(dst, m_select1); Cv2.CvtColor(imgRect1, imgRect1, ColorConversionCodes.BGR2GRAY); for (int i = 0; i < 6; i++) { Cv2.Erode(imgRect1, imgRect1, null); } Cv2.FindContours(imgRect1, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone, null); for (int t = 0; t < contours.Length; t++) { Rect CraRect = Cv2.BoundingRect(contours[t]); double s = Cv2.ContourArea(contours[t]);//轮廓面积 double c = Cv2.ArcLength(contours[t], true); //轮廓周长 //设为二次球 if (BallPointFs.Count > 0) { int iscr = 0; foreach (var item in BallPointFs) { OpenCvSharp.Point repoint = new OpenCvSharp.Point(item.X, item.Y); double isball = Cv2.PointPolygonTest(contours[t], repoint, false); if (isball > -1) { OpenCvSharp.Point pcenter = new OpenCvSharp.Point(CraRect.X + CraRect.Width / 2, CraRect.Y + CraRect.Height / 2); //加强圆心显示 Cv2.Circle(src, (int)pcenter.X, (int)pcenter.Y, 3, colorList[0], 2, LineTypes.AntiAlias); double area = s; if ((int)pcenter.X < helfx && (int)pcenter.Y < helfy) { one++; oneA = oneA + area; crystalListi[0] = crystalListi[0] - Convert.ToInt32(area); } if ((int)pcenter.X < helfx && (int)pcenter.Y > helfy) { two++; twoA = twoA + area; crystalListi[1] = crystalListi[1] - Convert.ToInt32(area); } if ((int)pcenter.X > helfx && (int)pcenter.Y < helfy) { three++; threeA = threeA + area; crystalListi[2] = crystalListi[2] - Convert.ToInt32(area); } if ((int)pcenter.X > helfx && (int)pcenter.Y > helfy) { four++; fourA = fourA + area; crystalListi[3] = crystalListi[3] - Convert.ToInt32(area); } iscr = 1; break; } } if (iscr == 1) { continue; } } RotatedRect rectR = Cv2.MinAreaRect(contours[t]); //计算每个轮廓最小外接矩形 float width = rectR.Size.Width; float height = rectR.Size.Height; //如果离圆心很近算作圆的部分 bool isjoin = false; for (int p = 0; p < cs.Count(); p++) { if (delKey.Contains(p)) continue; Point2f center = new Point2f(cs[p].Center.X, cs[p].Center.Y); double distanc = 0; for (int k = 0; k < contours[t].Length; k++) { Point2f pin = new Point2f(contours[t][k].X, contours[t][k].Y); distanc += pin.DistanceTo(center); } double dev = distanc / contours[t].Length; float mvg = width / height; if ((dev < cs[p].Radius + 20)) { isjoin = true; break; } } if (isjoin) { continue; } #region 如果球度在范围内判定为球 //List plist = new List(); //int rx = CraRect.X; //int ry = CraRect.Y; //int rw = CraRect.Width; //int rh = CraRect.Height; ////top //if (ry == 0) //{ // int rmx = rx + rw; // int rmxh = rw / 2 + rx; // plist = contours[t].OrderByDescending(g => g.Y).ToList(); // int rmy = plist[0].Y; // List qli = new List() {new OpenCvSharp.Point(rx,0), // new OpenCvSharp.Point(rx+ rw/4, rmy/2), // new OpenCvSharp.Point(rmx,0), // new OpenCvSharp.Point(rx+ rw*3/4, rmy/2), // new OpenCvSharp.Point(rmxh, rmy) }; // Point2f newcenter1 = new Point2f(); // float newR1 = 0; // Cv2.MinEnclosingCircle(qli, out newcenter1, out newR1); // int pcou = 0; // List newl = new List(); // OpenCvSharp.Point pv = new OpenCvSharp.Point((int)newcenter1.X, (int)newcenter1.Y); // foreach (var item in plist) // { // if (item.DistanceTo(pv) > newR1) // { // pcou++; // contours[t] = contours[t].Where(val => val.X != item.X && val.Y != item.Y).ToArray(); // } // else // { // newl.Add(item); // } // } // double t1 = (double)pcou; // double s1 = Cv2.ContourArea(qli); // if (s1 / s >0.9 && t1 / s < 0.1) // { // //加强圆心显示 // Cv2.Circle(src, (int)pv.X, (int)pv.Y, 3, colorList[0], 2, LineTypes.AntiAlias); // continue; // } //} /*********************** //如果球度在范围内判定为球 //afa参考代码 //double afa = 4 * Math.PI * s / (c * c); //afa计算 //afa = Math.Abs(afa - 1); //if (afa < 0.2&& s>4000) //{ // OpenCvSharp.Point pcenter = new OpenCvSharp.Point(CraRect.X+ CraRect.Width/2, CraRect.Y+ CraRect.Height/2); // //加强圆心显示 // Cv2.Circle(src, (int)pcenter.X, (int)pcenter.Y, 3, colorList[0], 2, LineTypes.AntiAlias); // double area = s; // if ((int)pcenter.X < helfx && (int)pcenter.Y < helfy) // { // one++; // oneA = oneA + area; // } // if ((int)pcenter.X < helfx && (int)pcenter.Y > helfy) // { // two++; // twoA = twoA + area; // } // if ((int)pcenter.X > helfx && (int)pcenter.Y < helfy) // { // three++; // threeA = threeA + area; // } // if ((int)pcenter.X > helfx && (int)pcenter.Y > helfy) // { // four++; // fourA = fourA + area; // } // continue; //} #endregion #region 如果是边界半圆算作圆 //如果是边界半圆算作圆 List plist = new List(); int rx = CraRect.X; int ry = CraRect.Y; int rw = CraRect.Width; int rh = CraRect.Height; //top if (ry == 0) { int minx = contours[t][0].X; int maxx = contours[t][0].X; for (int k = 0; k < contours[t].Length; k++) { if (contours[t][k].Y > 0) { plist.Add(contours[t][k]); if (minx > contours[t][k].X) minx = contours[t][k].X; if (maxx < contours[t][k].X) maxx = contours[t][k].X; } } plist.Sort((x, y) => x.X.CompareTo(y.X)); //for (int i = 0; i < maxx - minx; i++) //{ // int curx = i + minx; // if (plist[i].X > curx&&i>0) // { // int y = (plist[i - 1].Y + plist[i].Y) / 2; // plist.Insert(i, new OpenCvSharp.Point(curx, y)); // } //} if (plist.Count > 10) { int len = plist.Count / 8; int midx = (maxx - minx) / 2 + minx; int a = Math.Abs(plist[len].Y - plist[7 * len].Y); int b = Math.Abs(plist[2 * len].Y - plist[6 * len].Y); int d = Math.Abs(plist[3 * len].Y - plist[5 * len].Y); int l1 = plist[len].Y; int l2 = plist[2 * len].Y; int l3 = plist[3 * len].Y; int l5 = plist[5 * len].Y; int l6 = plist[6 * len].Y; int l7 = plist[7 * len].Y; if (l2 > l1 && l3 > l2 && l5 > l6 && l6 > l7) { OpenCvSharp.Point pcenter = new OpenCvSharp.Point(plist[len * 4].X, plist[len * 4].Y + 4); //加强圆心显示 Cv2.Circle(src, (int)pcenter.X, (int)pcenter.Y, 3, colorList[0], 2, LineTypes.AntiAlias); double area = s; if ((int)pcenter.X < helfx && (int)pcenter.Y < helfy) { one++; oneA = oneA + area; } if ((int)pcenter.X < helfx && (int)pcenter.Y > helfy) { two++; twoA = twoA + area; } if ((int)pcenter.X > helfx && (int)pcenter.Y < helfy) { three++; threeA = threeA + area; } if ((int)pcenter.X > helfx && (int)pcenter.Y > helfy) { four++; fourA = fourA + area; } continue; } } } //bottom if (ry + rh > src.Rows - 155) { int minx = contours[t][0].X; int maxx = contours[t][0].X; for (int k = 0; k < contours[t].Length; k++) { if (contours[t][k].Y < src.Rows - 155) { plist.Add(contours[t][k]); if (minx > contours[t][k].X) minx = contours[t][k].X; if (maxx < contours[t][k].X) maxx = contours[t][k].X; } } plist.Sort((x, y) => x.X.CompareTo(y.X)); //for (int i = 0; i < maxx - minx; i++) //{ // int curx = i + minx; // if (plist[i].X > curx && i > 0) // { // int y = (plist[i - 1].Y + plist[i].Y) / 2; // plist.Insert(i, new OpenCvSharp.Point(curx, y)); // } //} if (plist.Count > 10) { int len = plist.Count / 8; int midx = (maxx - minx) / 2 + minx; int a = Math.Abs(plist[len].Y - plist[7 * len].Y); int b = Math.Abs(plist[2 * len].Y - plist[6 * len].Y); int d = Math.Abs(plist[3 * len].Y - plist[5 * len].Y); int l1 = plist[len].Y; int l2 = plist[2 * len].Y; int l3 = plist[3 * len].Y; int l5 = plist[5 * len].Y; int l6 = plist[6 * len].Y; int l7 = plist[7 * len].Y; if (l2 < l1 && l3 < l2 && l5 < l6 && l6 < l7) { OpenCvSharp.Point pcenter = new OpenCvSharp.Point(plist[len * 4].X, plist[len * 4].Y + 4); //加强圆心显示 Cv2.Circle(src, (int)pcenter.X, (int)pcenter.Y, 3, colorList[0], 2, LineTypes.AntiAlias); double area = s; if ((int)pcenter.X < helfx && (int)pcenter.Y < helfy) { one++; oneA = oneA + area; } if ((int)pcenter.X < helfx && (int)pcenter.Y > helfy) { two++; twoA = twoA + area; } if ((int)pcenter.X > helfx && (int)pcenter.Y < helfy) { three++; threeA = threeA + area; } if ((int)pcenter.X > helfx && (int)pcenter.Y > helfy) { four++; fourA = fourA + area; } continue; } } } //left if (rx == 0) { int minx = contours[t][0].Y; int maxx = contours[t][0].Y; for (int k = 0; k < contours[t].Length; k++) { if (contours[t][k].X > 0) { plist.Add(contours[t][k]); if (minx > contours[t][k].Y) minx = contours[t][k].Y; if (maxx < contours[t][k].Y) maxx = contours[t][k].Y; } } plist.Sort((x, y) => x.Y.CompareTo(y.Y)); //for (int i = 0; i < maxx - minx; i++) //{ // int curx = i + minx; // if (plist[i].Y > curx && i > 0) // { // int y = (plist[i - 1].X + plist[i].X) / 2; // plist.Insert(i, new OpenCvSharp.Point(y, curx)); // } //} if (plist.Count > 10) { int len = plist.Count / 8; int midx = (maxx - minx) / 2 + minx; int a = Math.Abs(plist[len].X - plist[7 * len].X); int b = Math.Abs(plist[2 * len].X - plist[6 * len].X); int d = Math.Abs(plist[3 * len].X - plist[5 * len].X); int l1 = plist[len].X; int l2 = plist[2 * len].X; int l3 = plist[3 * len].X; int l5 = plist[5 * len].X; int l6 = plist[6 * len].X; int l7 = plist[7 * len].X; if (l2 > l1 && l3 > l2 && l5 > l6 && l6 > l7) { OpenCvSharp.Point pcenter = new OpenCvSharp.Point(plist[len * 4].X + 4, plist[len * 4].Y); //加强圆心显示 Cv2.Circle(src, (int)pcenter.X, (int)pcenter.Y, 3, colorList[0], 2, LineTypes.AntiAlias); double area = s; if ((int)pcenter.X < helfx && (int)pcenter.Y < helfy) { one++; oneA = oneA + area; } if ((int)pcenter.X < helfx && (int)pcenter.Y > helfy) { two++; twoA = twoA + area; } if ((int)pcenter.X > helfx && (int)pcenter.Y < helfy) { three++; threeA = threeA + area; } if ((int)pcenter.X > helfx && (int)pcenter.Y > helfy) { four++; fourA = fourA + area; } continue; } } } //rght if (rx + rw > src.Cols - 3) { int minx = contours[t][0].Y; int maxx = contours[t][0].Y; for (int k = 0; k < contours[t].Length; k++) { if (contours[t][k].X < src.Cols - 3) { plist.Add(contours[t][k]); if (minx > contours[t][k].Y) minx = contours[t][k].Y; if (maxx < contours[t][k].Y) maxx = contours[t][k].Y; } } plist.Sort((x, y) => x.Y.CompareTo(y.Y)); //for (int i = 0; i < maxx - minx; i++) //{ // int curx = i + minx; // if (plist[i].Y > curx && i > 0) // { // int y = (plist[i - 1].X + plist[i].X) / 2; // plist.Insert(i, new OpenCvSharp.Point(y, curx)); // } //} if (plist.Count > 10) { int len = plist.Count / 8; int midx = (maxx - minx) / 2 + minx; int a = Math.Abs(plist[len].X - plist[7 * len].X); int b = Math.Abs(plist[2 * len].X - plist[6 * len].X); int d = Math.Abs(plist[3 * len].X - plist[5 * len].X); int l1 = plist[len].X; int l2 = plist[2 * len].X; int l3 = plist[3 * len].X; int l5 = plist[5 * len].X; int l6 = plist[6 * len].X; int l7 = plist[7 * len].X; if (l2 < l1 && l3 < l2 && l5 < l6 && l6 < l7) { OpenCvSharp.Point pcenter = new OpenCvSharp.Point(plist[len * 4].X + 4, plist[len * 4].Y); //加强圆心显示 Cv2.Circle(src, (int)pcenter.X, (int)pcenter.Y, 3, colorList[0], 2, LineTypes.AntiAlias); double area = s; if ((int)pcenter.X < helfx && (int)pcenter.Y < helfy) { one++; oneA = oneA + area; } if ((int)pcenter.X < helfx && (int)pcenter.Y > helfy) { two++; twoA = twoA + area; } if ((int)pcenter.X > helfx && (int)pcenter.Y < helfy) { three++; threeA = threeA + area; } if ((int)pcenter.X > helfx && (int)pcenter.Y > helfy) { four++; fourA = fourA + area; } continue; } } } **************/ #endregion Mat temp_empt = Mat.Zeros(src.Size(), MatType.CV_8UC1); Cv2.DrawContours(temp_empt, contours, t, new Scalar(255), -1, LineTypes.Link8, hierarchy, 4, new OpenCvSharp.Point(0, 0)); for (int i = 0; i < 6; i++) { Cv2.Dilate(temp_empt, temp_empt, null); } OpenCvSharp.Point[][] contours1 = new OpenCvSharp.Point[][] { }; Cv2.FindContours(temp_empt, out contours1, out HierarchyIndex[] hierarchy1, RetrievalModes.External, ContourApproximationModes.ApproxNone, null); Cv2.DrawContours(src, contours1, 0, new Scalar(vec4B.Item0, vec4B.Item1, vec4B.Item2, vec4B.Item3), -1, LineTypes.Link8, hierarchy1, 4, new OpenCvSharp.Point(0, 0)); } for (int i = 0; i < cs.Length; i++) { if (delKey.Contains(i)) { continue; } //加强圆心显示 Cv2.Circle(src, (int)cs[i].Center.X, (int)cs[i].Center.Y, 3, colorList[0], 2, LineTypes.AntiAlias); } // if (CrystalLunkuo.Count > 0) { for (int lk = 0; lk < CrystalLunkuo.Count; lk++) { List pl = new List(); CrystalLunkuo[lk].ForEach(pp => pl.Add(new OpenCvSharp.Point(pp.X, pp.Y))); Point2f newcenter = new Point2f(); float newR = 0; Cv2.MinEnclosingCircle(pl, out newcenter, out newR); Cv2.Circle(src, (int)newcenter.X, (int)newcenter.Y, 3, colorList[0], 2, LineTypes.AntiAlias); //Rect lkRect = Cv2.BoundingRect(pl); ////加强圆心显示 //Cv2.Circle(dst, (int)(lkRect.X + lkRect.Width / 2), (int)(lkRect.Y + lkRect.Height / 2), 3, colorList[0], 2, LineTypes.AntiAlias); } } Cv2.Line(src, new OpenCvSharp.Point() { X = 0, Y = helfy }, new OpenCvSharp.Point() { X = src.Cols, Y = helfy }, colorList[1]); Cv2.Line(src, new OpenCvSharp.Point() { X = helfx, Y = 0 }, new OpenCvSharp.Point() { X = helfx, Y = src.Rows - 70 }, colorList[1]); circleList.Add(one); circleList.Add(two); circleList.Add(three); circleList.Add(four); circleAreaList.Add((int)oneA); circleAreaList.Add((int)twoA); circleAreaList.Add((int)threeA); circleAreaList.Add((int)fourA); data.Add(circleList); data.Add(crystalListi); data.Add(circleAreaList); } else if (imageType == 4) { if (selPointFs != -1 && retMat != null) { Mat used = retMat.Clone(); keyValueSel.Add(selPointFs, 1); List sel = poListHis[selPointFs]; //src = SelectBall(used, sel[0], sel[1], sel[2]); src = SelectBallInt(used, selPointFs); } else { //src = WhirtBinarization(src); Cv2.CvtColor(src, src, ColorConversionCodes.BGRA2BGR); Mat dst = new Mat(); //Cv2.PyrMeanShiftFiltering(src, src, 21, 51); Cv2.GaussianBlur(src, src, new OpenCvSharp.Size(17, 17), 0); Cv2.MedianBlur(src, src, 15); // Cv2.BilateralFilter(dst, src, 21, 132, 181); src = BinarizationBall(src); InputArray kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3), new OpenCvSharp.Point(-1, -1)); // 开操作,也可省落变量前缀名 // Cv2.MorphologyEx(src, src, MorphTypes.Dilate, kernel, new OpenCvSharp.Point(-1, -1)); //双边滤波 //Cv2.MorphologyEx(src, src, MorphTypes.Close, null, null, 4, BorderTypes.Constant); //src = WhirtBinarization(src); //src = DrwCrackBall(src); //retMat = src.Clone(); //poListHis.Clear(); //poList.ForEach(i => poListHis.Add(i)); } keyValueSel.Clear(); selPointFs = -1; } else if (imageType == 14) { if (selPointFs != -1 && retMat != null) { Mat used = retMat.Clone(); keyValueSel.Add(selPointFs, 1); List sel = poListHis[selPointFs]; src = SelectBallInt(used, selPointFs); } else { src = DrwCrackBall(src); retMat = src.Clone(); poListHis.Clear(); poList.ForEach(i => poListHis.Add(i)); } keyValueSel.Clear(); selPointFs = -1; } else if (imageType == 5) { if (selPointFs != -1 && retMat != null) { Mat used = retMat.Clone(); keyValueSel.Add(selPointFs, 1); src = SelectPoint(used); } else { //二值提取 src = BinarizationForM(src); //去掉过小孔隙,计算孔隙面积 src = DebrisRemoval_New(src); data.Add(poAreaList); retMat = src.Clone(); } keyValueSel.Clear(); selPointFs = -1; } return src; } /// /// 开裂球 /// /// 源图像 /// 参数集合 /// public static Mat ImageBinaryExtraction(Mat src, Mat source, List lists, out List> data, bool findContours = false) { //以下是参数信息--------------------- ///1个颜色区间还是2个 colorInterval = 1; //第一个二值区间 colorOneStart = 0; colorOneEnd = 0; //第二个二值区间 colorTwoStart = 0; colorTwoEnd = 0; //第三个二值区间 colorThreeStart = 0; colorThreeEnd = 0; //处理细节 //删除边界对象 bool deleteBoundaryObject = false; //孔洞填充 bool holeFilling = false; //碎屑删除 bool debrisRemoval = false; //碎屑删除面积起 debrisAreaStart = 0; //碎屑删除面积止 debrisAreaEnd = 0; //二值样式 //1实心 2边线 int binaryStyle = 0; //相颜色 Color phaseColor = Color.Red; //目标选择 int targetSelection = 1; for (int i = 0; i < lists.Count; i++) { Args args = lists[i]; switch (args.Key) { case "colorInterval": { if (args.Value is Boolean) colorInterval = (Boolean)args.Value ? 2 : 1; else colorInterval = (int)args.Value; } break; case "scope1": colorOneStart = (int)((List)args.Value)[0]; colorOneEnd = (int)((List)args.Value)[1]; break; case "scope2": colorTwoStart = (int)((List)args.Value)[0]; colorTwoEnd = (int)((List)args.Value)[1]; break; case "scope3": colorThreeStart = (int)((List)args.Value)[0]; colorThreeEnd = (int)((List)args.Value)[1]; break; case "deleteBoundaryObject": deleteBoundaryObject = (bool)args.Value; break; case "holeFilling": holeFilling = (bool)args.Value; break; case "debrisRemoval": debrisRemoval = (bool)args.Value; break; case "binaryStyle": binaryStyle = (int)args.Value; break; case "phaseColor": phaseColor = Color.FromArgb((int)args.Value); break; case "targetSelection": targetSelection = (int)args.Value; break; case "scope4": debrisAreaStart = (int)((List)args.Value)[0]; debrisAreaEnd = (int)((List)args.Value)[1]; findContours = true; break; case "CircleCount": circleCount = (int)args.Value; break; case "maxContour": maxContour = (OpenCvSharp.Point[])args.Value; break; case "CircleR": CircleR = (int)args.Value; break; case "Center": center = (OpenCvSharp.Point)args.Value; break; case "DelPointFs": delPointFs = (List)args.Value; break; case "imageType": imageType = (int)args.Value; break; case "SelPointFs": selPointFs = (int)args.Value; break; case "imageTypes": imageType = (int)args.Value; break; case "CreackBallPointFs": CreackBallPointFs = (List)args.Value; break; case "CreackBallPointFsK": CreackBallPointFsK = (List)args.Value; break; case "CreackBallPointFsP": CreackBallPointFsP = (List)args.Value; break; default: break; } } if (phaseColor.A < 1)//#21321 phaseColor = Color.FromArgb(1, phaseColor.R, phaseColor.G, phaseColor.B); vec4B.Item0 = phaseColor.B; vec4B.Item1 = phaseColor.G; vec4B.Item2 = phaseColor.R; vec4B.Item3 = phaseColor.A; poArea = 0; maxArea = 0; poList.Clear(); poAreaList = new List() { }; data = poList; imageHight = src.Rows; if (imageType == 14) { if (selPointFs != -1 && retMat != null) { Mat used = retMat.Clone(); keyValueSel.Add(selPointFs, 1); List sel = poListHis[selPointFs]; src = SelectBallInt(used, selPointFs); } else { src = DrwCrackBall_New(src, source); retMat = src.Clone(); poListHis.Clear(); poList.ForEach(i => poListHis.Add(i)); } keyValueSel.Clear(); selPointFs = -1; } return src; } /// /// 二次球与单晶去底条 /// /// /// private static Mat RemoveBottm(Mat source) { Mat srcGray; if (source.Type() == MatType.CV_8UC1) { srcGray = source; } else { srcGray = source.CvtColor(ColorConversionCodes.BGR2GRAY); } temp = new Mat(source.Rows, source.Cols, MatType.CV_8UC4, new Scalar(0, 0, 0, 0)); srcGray.ForEachAsByte(RemoveBottmForEachAsByte); return temp.Clone(); } /// /// 并行循环 /// /// /// private static void RemoveBottmForEachAsByte(byte* value, int* position) { int y = position[0]; int x = position[1]; byte v = *value; if (y > imageHight - 140) { temp.Set(y, x, vec4Bw); } } /// /// 二值提取 /// /// 源 /// 1个或2个颜色区间 /// /// /// /// /// /// /// private static Mat Binarization(Mat source) { Mat srcGray; if (source.Type() == MatType.CV_8UC1) { srcGray = source; } else { srcGray = source.CvtColor(ColorConversionCodes.BGR2GRAY); } temp = new Mat(source.Rows, source.Cols, MatType.CV_8UC4, new Scalar(0, 0, 0, 0)); try { srcGray.ForEachAsByte(GrayForEachAsByte); } catch (Exception e) { throw; } return temp.Clone(); } /// /// 并行循环 /// /// /// private static void GrayForEachAsByte(byte* value, int* position) { int y = position[0]; int x = position[1]; byte v = *value; if (colorInterval == 1) { if (v >= colorOneStart && v <= colorOneEnd) { temp.Set(y, x, vec4B); //手动画圆 if (ListRadiusColor.Count > 0) { int d = Convert.ToInt32(Math.Sqrt((x - center.X) * (x - center.X) + (y - center.Y) * (y - center.Y))); Color co = ListRadiusColor.First().Value; Vec4b colorMax = new Vec4b(co.B, co.G, co.R, 255); temp.Set(y, x, colorMax); foreach (var item in ListRadiusColor) { int r = item.Key; if (d < r) { Vec4b vb4 = new Vec4b(item.Value.B, item.Value.G, item.Value.R, 255); temp.Set(y, x, vb4); } } if (ListRadiusColor.Count > 1) { for (int i = 0; i < ListRadiusColor.Count - 1; i++) { int r = i == 0 ? 0 : ListRadiusColor.ElementAt(ListRadiusColor.Count - i).Key; int r2 = ListRadiusColor.ElementAt(ListRadiusColor.Count - 1 - i).Key; if (r < d && d <= r2) { poAreaList[i]++; break; } } } } else if (circleCount > 1) //同心圆数量大于一时染色 { temp.Set(y, x, vec4BList[circleCount - 1]); int d = Convert.ToInt32(Math.Sqrt((x - center.X) * (x - center.X) + (y - center.Y) * (y - center.Y))); for (int i = circleCount - 1; i >= 0; i--) { int r = Convert.ToInt32(CircleR * (i + 1)); if (d < r) { temp.Set(y, x, vec4BList[i]); } } for (int i = 0; i < circleCount; i++) { int r = Convert.ToInt32(CircleR * (i)); int r2 = Convert.ToInt32(CircleR * (i + 1)); if (r < d && d <= r2) { poAreaList[i]++; break; } } } } } else { if ((v >= colorTwoStart && v <= colorTwoEnd) || (v >= colorThreeStart && v <= colorThreeEnd)) { temp.Set(y, x, vec4B); } } } /// /// 开裂球分水岭二值提取 /// /// 源 /// 1个或2个颜色区间 /// /// /// /// /// /// /// private static Mat BinarizationBall(Mat source) { Mat srcGray; if (source.Type() == MatType.CV_8UC1) { srcGray = source; } else { srcGray = source.CvtColor(ColorConversionCodes.BGR2GRAY); } temp = new Mat(source.Rows, source.Cols, MatType.CV_8UC4, new Scalar(0, 0, 0, 0)); srcGray.ForEachAsByte(GrayForEachAsByteBall); return temp.Clone(); } /// /// 并行循环 /// /// /// private static void GrayForEachAsByteBall(byte* value, int* position) { int y = position[0]; int x = position[1]; byte v = *value; if (colorInterval == 1) { if (v >= colorOneStart && v <= colorOneEnd) { temp.Set(y, x, vec4B); } } else { if ((v >= colorTwoStart && v <= colorTwoEnd) || (v >= colorThreeStart && v <= colorThreeEnd)) { temp.Set(y, x, vec4B); } } } private static Mat WhirtBinarization(Mat source) { Mat srcGray; if (source.Type() == MatType.CV_8UC1) { srcGray = source; } else { srcGray = source.CvtColor(ColorConversionCodes.BGR2GRAY); } temp = source.Clone(); srcGray.ForEachAsByte(WhirtForEachAsByte); return temp.Clone(); } /// /// 并行循环 /// /// /// private static void WhirtForEachAsByte(byte* value, int* position) { int y = position[0]; int x = position[1]; byte v = *value; if (v > 240 || y > imageHight - 70) { temp.Set(y, x, vec4Bw); } //if (x < 50 || y < 50 || x > imageWidth - 50 || y > imageHight - 190) //{ // temp.Set(y, x, vec4Bw); //} } //二次球去边 private static Mat BallCutBottor(Mat source) { Mat srcGray; if (source.Type() == MatType.CV_8UC1) { srcGray = source; } else { srcGray = source.CvtColor(ColorConversionCodes.BGR2GRAY); } temp = source.Clone(); srcGray.ForEachAsByte(BallCutBottorForEachAsByte); return temp.Clone(); } /// /// 并行循环 /// /// /// private static void BallCutBottorForEachAsByte(byte* value, int* position) { int y = position[0]; int x = position[1]; byte v = *value; if (x < boundary || y < boundary || x > imageWidth - boundary || y > imageHight - boundary - 140) { temp.Set(y, x, vec4Bw); } } /// /// 新版本删除边界 /// /// /// private static Mat DeleteContours_New(Mat src) { Mat[] arr = src.Split(); Mat rgb = BaseTools.MergeMatFromMatArr(arr); Mat temp_1 = arr[3].Clone(); for (int h = 0; h < temp_1.Width; h++) { byte vec4B_top = temp_1.At(0, h); if (vec4B_top > 0) { Cv2.FloodFill(rgb, new OpenCvSharp.Point(h, 0), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); Cv2.FloodFill(temp_1, new OpenCvSharp.Point(h, 0), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); } } for (int h = 0; h < temp_1.Width; h++) { byte vec4B_bottom = temp_1.At(temp_1.Height - 1, h); if (vec4B_bottom > 0) { Cv2.FloodFill(rgb, new OpenCvSharp.Point(h, temp_1.Height - 1), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); Cv2.FloodFill(temp_1, new OpenCvSharp.Point(h, temp_1.Height - 1), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); } } for (int y = 0; y < temp_1.Height; y++) { Vec4b vec4B_top = temp_1.At(y, 0); if (vec4B_top.Item3 > 0) { Cv2.FloodFill(rgb, new OpenCvSharp.Point(0, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); Cv2.FloodFill(temp_1, new OpenCvSharp.Point(0, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); } } for (int y = 0; y < temp_1.Height; y++) { byte vec4B_top = temp_1.At(y, temp_1.Width - 1); if (vec4B_top > 0) { Cv2.FloodFill(rgb, new OpenCvSharp.Point(temp_1.Width - 1, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); Cv2.FloodFill(temp_1, new OpenCvSharp.Point(temp_1.Width - 1, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); } } Mat[] mats = rgb.Split(); arr[0] = mats[0]; arr[1] = mats[1]; arr[2] = mats[2]; arr[3] = temp_1; Cv2.Merge(arr, src); return src; } /// /// 新孔洞填充,采用形态学填充 /// /// /// private static Mat HoleFilling_New(Mat src) { Mat[] arr2 = src.Split(); Mat matc = arr2[3]; //去掉透明层 Mat mat = src.CvtColor(ColorConversionCodes.BGRA2BGR); //填充孔洞 mat = BaseTools.FillHole(mat, new Scalar(255 - vec4B.Item0, 255 - vec4B.Item1, 255 - vec4B.Item2)); matc = BaseTools.FillHole(matc, new Scalar(255)); //循环处理 mat.ForEachAsVec3b(RGBForEachAsByteForHoleFillingNew); Mat[] arr1 = mat.Split(); arr2[0] = arr1[0]; arr2[1] = arr1[1]; arr2[2] = arr1[2]; arr2[3] = matc; Cv2.Merge(arr2, src); return src; } private static void RGBForEachAsByteForHoleFillingNew(Vec3b* value, int* position) { int y = position[0]; int x = position[1]; if (value->Item0 == 255 && value->Item1 == 255 && value->Item2 == 255) { value->Item0 = vec4B.Item0; value->Item1 = vec4B.Item1; value->Item2 = vec4B.Item2; } } /// /// 选择颗粒处理 /// /// /// private static Mat SelectPoint(Mat src) { Mat[] arr = src.Split(); rgb_ap = BaseTools.MergeMatFromMatArr(arr); temp_ap = arr[3].Clone(); labelMatForSel.ForEachAsInt32(CommonForEachForSel); //合并rgb和透明度 Mat[] mats = rgb_ap.Split(); arr[0] = mats[0]; arr[1] = mats[1]; arr[2] = mats[2]; arr[3] = temp_ap; Cv2.Merge(arr, src); return src; } /// /// 新碎屑删除,使用连通分量找寻碎屑截面孔隙 /// /// /// private static Mat DebrisRemoval_New(Mat src) { Mat[] arr = src.Split(); rgb_ap = BaseTools.MergeMatFromMatArr(arr); temp_ap = arr[3].Clone(); //寻找连通分量 Mat labelMat = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat(); int nonenum = Cv2.ConnectedComponentsWithStats(temp_ap, labelMat, stats, centroids, PixelConnectivity.Connectivity8); Mat oo = temp_ap.Clone(); Cv2.Dilate(oo, oo, null); Mat respend = new Mat(); temp_view.ConvertTo(respend, MatType.CV_8UC3); OpenCvSharp.Point[][] contours = new OpenCvSharp.Point[][] { }; HierarchyIndex[] hierarchyIndex = new HierarchyIndex[] { }; Cv2.FindContours(oo, out contours, out hierarchyIndex, RetrievalModes.External, ContourApproximationModes.ApproxNone); for (int i = 0; i < contours.Length; i++) { double art = Cv2.ContourArea(contours[i]); if (art < 50) continue; respend.DrawContours(contours, i, Scalar.RandomColor(), -1); } //using (new Window("s", WindowMode.Normal, respend)) //{ // Cv2.WaitKey(0); //} //Cv2.ImWrite("E://tt.jpg", respend); //寻找在范围内需要删除的碎屑 keyValuePairs.Clear(); keyValueSel.Clear(); for (int h = 1; h < centroids.Height; h++) { int areaField1 = stats.At(h, 4); int x = stats.At(h, 0); int y = stats.At(h, 1); int width = stats.At(h, 2); int height = stats.At(h, 3); //面积小于30的孔隙删除 if (debrisAreaStart <= areaField1 && areaField1 <= 3) { keyValuePairs.Add(h, 1); } else if (areaField1 > src.Rows * src.Cols * 0.3)//面积最大的是轮廓,这里算大于整体面积的0.3 { keyValuePairs.Add(h, 1); maxArea = areaField1; } else { int qud = 0; if (delPointFs != null && delPointFs.Count > 0) { for (int i = 0; i < delPointFs.Count; i++) { double px = delPointFs[i].X; double py = delPointFs[i].Y; if (px > x && px < (x + width) && py > y && py < (y + height)) { keyValuePairs.Add(h, 1); qud = 1; break; } } } if (qud == 1) { continue; } poArea += areaField1; List po = new List() { x, y, width, height, areaField1, h }; poList.Add(po); } } labelMatForSel = labelMat; labelMat.ForEachAsInt32(CommonForEachForInt32); labelMat.ForEachAsInt32(CommonForEachForSel); //合并rgb和透明度 Mat[] mats = rgb_ap.Split(); arr[0] = mats[0]; arr[1] = mats[1]; arr[2] = mats[2]; arr[3] = temp_ap; Cv2.Merge(arr, src); return src; } private static Mat CrystBinarization(Mat source) { Mat srcGray; if (source.Type() == MatType.CV_8UC1) { srcGray = source; } else { srcGray = source.CvtColor(ColorConversionCodes.BGR2GRAY); } temp = new Mat(source.Rows, source.Cols, MatType.CV_8UC4, new Scalar(0, 0, 0, 0)); srcGray.ForEachAsByte(CrystForEachAsByte); return temp.Clone(); } /// /// 并行循环 /// /// /// private static void CrystForEachAsByte(byte* value, int* position) { int y = position[0]; int x = position[1]; byte v = *value; if (v >= 240) { temp.Set(y, x, vec4B); } //if (AddPontins != null && AddPontins.Count > 0) //{ // for (int i = 0; i < AddPontins.Count; i++) // { // if (Cv2.PointPolygonTest(AddPontins[i], new OpenCvSharp.Point(x, y), false) > -1) // { // temp.Set(y, x, vec4B); // } // } //} } /// /// 单晶使用找轮廓找寻碎屑 /// /// /// private static Mat DebrisRemoval_Cryst1(Mat src) { if (AddPontins != null && AddPontins.Count > 0) { Cv2.DrawContours(src, AddPontins, -1, new Scalar(255, 255, 255, 255), -1); } //using (new Window("s",WindowMode.Normal, src)) //{ // Cv2.WaitKey(0); //} src = CrystBinarization(src); Mat[] arr = src.Split(); rgb_ap = BaseTools.MergeMatFromMatArr(arr); temp_ap = arr[3].Clone(); OpenCvSharp.Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(temp_ap, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone, null); //寻找在范围内需要删除的碎屑 for (int h = 1; h < contours.Length; h++) { Rect rect = Cv2.BoundingRect(contours[h]); int areaField1 = Convert.ToInt32(Cv2.ContourArea(contours[h])); int x = rect.X; int y = rect.Y; int width = rect.Width; int height = rect.Height; //边缘 if (x < 5 || x + width > src.Cols - 5 || y < 5 || y + height > src.Rows - 5) { temp_ap.DrawContours(contours, h, new Scalar(0), -1); continue; } //面积小于30的孔隙删除 else if (areaField1 < 2) { temp_ap.DrawContours(contours, h, new Scalar(0), -1); continue; } else { poArea += areaField1; Mat t = new Mat(temp_ap, new Rect(x, y, width, height)); int maxxx = 0; int maxyy = 0; int inde = h - 1; RotatedRect rectR = Cv2.MinAreaRect(contours[h]); if (maxxx < rectR.Size.Width) { maxxx = (int)rectR.Size.Width; } if (maxyy < rectR.Size.Height) { maxyy = (int)rectR.Size.Height; } double kgr = Convert.ToDouble(maxxx + maxyy) * 0.5 * Micron; double hlengh = maxxx > maxyy ? maxxx : maxyy; double wlengh = maxxx < maxyy ? maxxx : maxyy; double area = maxxx * maxyy * AreaRatio; if (wlengh > 0) { double hm = hlengh / wlengh; //颗粒尺寸超长 if (kgr < pointsize) { temp_ap.DrawContours(contours, h, new Scalar(0), -1); continue; } else if (hm > HW)//长宽比过大 { temp_ap.DrawContours(contours, h, new Scalar(0), -1); continue; } else if (areaField1 < area) { temp_ap.DrawContours(contours, h, new Scalar(0), -1); continue; } //正常颗粒 else { //afa参考代码 double s = areaField1;//轮廓面积 double c = contours[h].Length; //轮廓周长 double afa = Math.Sqrt(4 * Math.PI * s / (c * c)); //afa计算 int aa = Convert.ToInt32(afa * 1000); InputArray contoursAll = InputArray.Create(contours[h]); List outArr = new List(); OutputArray hull = OutputArray.Create(outArr); Cv2.ConvexHull(contoursAll, hull, true); double nc = Cv2.ArcLength(outArr.ToArray(), true) / Math.PI; double na = Math.Sqrt(areaField1 / Math.PI) * 2; aa = Convert.ToInt32((na / nc) * 1000); List po = new List() { x, y, width, height, areaField1, h, maxxx, maxyy, aa }; poList.Add(po); } } else { temp_ap.DrawContours(contours, h, new Scalar(0), -1); continue; } } } //合并rgb和透明度 Mat[] mats = rgb_ap.Split(); arr[0] = mats[0]; arr[1] = mats[1]; arr[2] = mats[2]; arr[3] = temp_ap; Cv2.Merge(arr, src); return src; } /// /// 单晶使用连通分量找寻碎屑 /// /// /// private static int hindex = -1; private static Mat ground = new Mat(); private static Mat DebrisRemoval_Cryst(Mat src) { src = CrystBinarization(src); keyValuePairs.Clear(); Mat[] arr = src.Split(); rgb_ap = BaseTools.MergeMatFromMatArr(arr); temp_ap = arr[3].Clone(); //寻找连通分量 Mat labelMat = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat(); int nonenum = Cv2.ConnectedComponentsWithStats(temp_ap, labelMat, stats, centroids, PixelConnectivity.Connectivity8); if (delPointFs != null && delPointFs.Count > 0) { for (int i = 0; i < delPointFs.Count; i++) { int qx = (int)delPointFs[i].X; int qy = (int)delPointFs[i].Y; int label = labelMat.At(qy, qx); if (label > 0 && !keyValuePairs.ContainsKey(label)) { keyValuePairs.Add(label, 1); } } } labelMat.ForEachAsInt32(CommonForEachDel); //寻找连通分量 labelMat = new Mat(); stats = new Mat(); centroids = new Mat(); nonenum = Cv2.ConnectedComponentsWithStats(temp_ap, labelMat, stats, centroids, PixelConnectivity.Connectivity8); //Mat oo = temp_ap.Clone(); //Mat respend = new Mat(); //temp_view.ConvertTo(respend, MatType.CV_8UC3); //OpenCvSharp.Point[][] contours = new OpenCvSharp.Point[][] { }; //HierarchyIndex[] hierarchyIndex = new HierarchyIndex[] { }; //Cv2.FindContours(oo, out contours, out hierarchyIndex, RetrievalModes.External, ContourApproximationModes.ApproxNone); //for (int i = 0; i < contours.Length; i++) //{ // double art = Cv2.ContourArea(contours[i]); // if (art < 50) // continue; // if (contours[i][0].Y > oo.Height - border) // { // respend.DrawContours(contours, i, Scalar.Black, -1); // continue; // } // respend.DrawContours(contours, i, Scalar.RandomColor(), -1); //} //using (new Window("s", WindowMode.Normal, respend)) //{ // Cv2.WaitKey(0); //} //Cv2.ImWrite("E://tt.jpg", respend); AllFields = new List>(); for (int i = 0; i < centroids.Height; i++) { AllFields.Add(new List()); } labelMat.ForEachAsInt32(CommonForEachForCon); //寻找在范围内需要删除的碎屑 keyValuePairs.Clear(); keyValueSel.Clear(); for (int i = 0; i < circleCount; i++) { poAreaList.Add(0); } ////旧的删除方式 //if (delPointFs != null && delPointFs.Count > 0) //{ // for (int i = 0; i < delPointFs.Count; i++) // { // int qx = (int)delPointFs[i].X; // int qy = (int)delPointFs[i].Y; // int label = labelMat.At(qy, qx); // if (label > 0 && !keyValuePairs.ContainsKey(label)) // { // keyValuePairs.Add(label, 1); // } // } //} List rectList = new List(); List> rectListPoint = new List>(); for (int h = 1; h < centroids.Height; h++) { int areaField1 = stats.At(h, 4); int x = stats.At(h, 0); int y = stats.At(h, 1); int width = stats.At(h, 2); int height = stats.At(h, 3); if (keyValuePairs.ContainsKey(h)) { continue; } if (Contour != null && Contour.Count > 0) { OpenCvSharp.Point p1 = new OpenCvSharp.Point(x, y); double d = Cv2.PointPolygonTest(Contour, p1, false); if (d < 0) { keyValuePairs.Add(h, 1); continue; } p1 = new OpenCvSharp.Point(x + width, y); d = Cv2.PointPolygonTest(Contour, p1, false); if (d < 0) { keyValuePairs.Add(h, 1); continue; } p1 = new OpenCvSharp.Point(x + width, y + height); d = Cv2.PointPolygonTest(Contour, p1, false); if (d < 0) { keyValuePairs.Add(h, 1); continue; } p1 = new OpenCvSharp.Point(x, y + height); d = Cv2.PointPolygonTest(Contour, p1, false); if (d < 0) { keyValuePairs.Add(h, 1); continue; } } //边缘 if (x < border || x + width > src.Cols - border || y < border || y + height > src.Rows - border - borderBottom) { keyValuePairs.Add(h, 1); } else if (areaField1 > src.Rows * src.Cols * 0.3)//面积最大的是轮廓,这里算大于整体面积的0.3 { keyValuePairs.Add(h, 1); maxArea = areaField1; } else { poArea += areaField1; Mat t = new Mat(temp_ap, new Rect(x, y, width, height)); int maxxx = 0; int maxyy = 0; int inde = h - 1; RotatedRect rectR = Cv2.MinAreaRect(AllFields[inde]); if (maxxx < rectR.Size.Width) { maxxx = (int)rectR.Size.Width; } if (maxyy < rectR.Size.Height) { maxyy = (int)rectR.Size.Height; } double kgr = Convert.ToDouble(maxxx + maxyy) * 0.5 * Micron; double hlengh = maxxx > maxyy ? maxxx : maxyy; double wlengh = maxxx < maxyy ? maxxx : maxyy; double area = maxxx * maxyy * AreaRatio; InputArray contoursAll = InputArray.Create(AllFields[inde]); List outArr = new List(); OutputArray hull = OutputArray.Create(outArr); Cv2.ConvexHull(contoursAll, hull, true); area = Cv2.ContourArea(outArr) * AreaRatio; if (wlengh > 0) { double hm = hlengh / wlengh; //颗粒尺寸超长 if (kgr < pointsize) { keyValuePairs.Add(h, 1); } else if (hm > HW)//长宽比过大 { keyValuePairs.Add(h, 1); } else if (areaField1 < area) { keyValuePairs.Add(h, 1); } //正常颗粒 else { ////圆润度 //hindex = h; //ground = temp_ap.Clone(); //labelMat.ForEachAsInt32(CommonForEachForArc); //double roundness= GetRoundness2(width, height, x, y); //double c = contours[0].Length; //轮廓周长 //double xa = Math.Sqrt(areaField1 / Math.PI) * 2; //double xp = c / Math.PI; //int aa = Convert.ToInt32((xa / xp) * 1000); double nc = Cv2.ArcLength(outArr.ToArray(), true) ; double na = Math.Sqrt(areaField1 / Math.PI) * 2; int aa = Convert.ToInt32((na / nc) * 1000); List listpoint = new List(); Point2f[] point2F = rectR.Points(); foreach (var item in point2F) { listpoint.Add(new OpenCvSharp.Point(Convert.ToInt32(item.X), Convert.ToInt32(item.Y))); } rectListPoint.Add(listpoint); rectList.Add(rectR); List po = new List() { x, y, width, height, areaField1, h, maxxx, maxyy, 1 , (int)nc }; poList.Add(po); } } else { keyValuePairs.Add(h, 1); } } } labelMatForSel = labelMat; fieldsCount = centroids.Height; labelMat.ForEachAsInt32(CommonForEachForInt32); labelMat.ForEachAsInt32(CommonForEachForSel); #region 添加颗粒 Mat MatAdd = new Mat(src.Rows, src.Cols, MatType.CV_8UC1,new Scalar(0)); if (AddPontins != null && AddPontins.Count > 0) { for (int i = 0; i < AddPontins.Count; i++) { Cv2.DrawContours(MatAdd, AddPontins, i, new Scalar(255), -1); Cv2.DrawContours(rgb_ap, AddPontins, i,new Scalar( vec4B.Item0, vec4B.Item1, vec4B.Item2), -1); Cv2.DrawContours(temp_ap, AddPontins, i, new Scalar(255), -1); } // Cv2.DrawContours(src, AddPontins, -1, new Scalar(255, 255, 255, 255), -1); } OpenCvSharp.Point[][] contours = new OpenCvSharp.Point[][] { }; HierarchyIndex[] hierarchyIndex = new HierarchyIndex[] { }; //轮廓 Cv2.FindContours(MatAdd, out contours, out hierarchyIndex, RetrievalModes.External, ContourApproximationModes.ApproxNone); labelMatForSelAdd = contours; for (int i = 0; i < contours.Length; i++) { Rect rect = Cv2.BoundingRect(contours[i]); int areaField1 =Convert.ToInt32( Cv2.ContourArea(contours[i])); int nc = Convert.ToInt32(Cv2.ArcLength(contours[i], true)); int x = rect.X; int y = rect.Y; int width = rect.Width; int height = rect.Height; int maxxx = 0; int maxyy = 0; RotatedRect rectR = Cv2.MinAreaRect(contours[i]); if (maxxx < rectR.Size.Width) { maxxx = (int)rectR.Size.Width; } if (maxyy < rectR.Size.Height) { maxyy = (int)rectR.Size.Height; } List listpoint = new List(); Point2f[] point2F = rectR.Points(); foreach (var item in point2F) { listpoint.Add(new OpenCvSharp.Point(Convert.ToInt32(item.X), Convert.ToInt32(item.Y))); } rectListPoint.Add(listpoint); rectList.Add(rectR); List po = new List() { x, y, width, height, areaField1, centroids.Height+i, maxxx, maxyy, 1 , nc }; poList.Add(po); } //using (new Window("s", WindowMode.Normal, src)) //{ // Cv2.WaitKey(0); //} #endregion //合并rgb和透明度 Mat[] mats = rgb_ap.Split(); arr[0] = mats[0]; arr[1] = mats[1]; arr[2] = mats[2]; arr[3] = temp_ap; Cv2.Merge(arr, src); Scalar scalar = new Scalar(255, 255, 255, 255); if (isDis) { foreach (var p in rectList) { Point2f[] point2F = p.Points(); double width = (point2F[0].X - point2F[1].X) / 2; double height = (point2F[0].Y - point2F[1].Y) / 2; OpenCvSharp.Point p1 = new OpenCvSharp.Point(point2F[1].X + width, point2F[1].Y + height); OpenCvSharp.Point p2 = new OpenCvSharp.Point(point2F[2].X + width, point2F[2].Y + height); src.Line(p1, p2, scalar, 1); int wid = (int)p.Size.Width; double d1= wid* Micron; src.PutText(Math.Round(d1, 2).ToString(), p2, HersheyFonts.HersheyPlain, 1, new Scalar(0, 255, 0, 255), 1); width = (point2F[3].X - point2F[0].X) / 2; height = (point2F[0].Y - point2F[3].Y) / 2; OpenCvSharp.Point p3 = new OpenCvSharp.Point(point2F[0].X + width, point2F[3].Y + height); OpenCvSharp.Point p4 = new OpenCvSharp.Point(point2F[1].X + width, point2F[2].Y + height); src.Line(p3, p4, scalar, 1); int hei = (int)p.Size.Height; double d2 = hei * Micron; src.PutText(Math.Round(d2, 2).ToString(), p3, HersheyFonts.HersheyPlain, 1, new Scalar(0, 0, 255, 255), 1); } } if (isJu) { src.DrawContours(rectListPoint, -1, scalar, 1); } return src; } /// /// 单晶删除颗粒 /// /// /// private static Mat DebrisRemoval_Cryst_Del(Mat src) { temp_ap = src.CvtColor(ColorConversionCodes.BGR2GRAY); using (new Window("s", WindowMode.Normal, temp_ap)) { Cv2.WaitKey(0); } //寻找连通分量 Mat labelMat = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat(); int nonenum = Cv2.ConnectedComponentsWithStats(temp_ap, labelMat, stats, centroids, PixelConnectivity.Connectivity8); //寻找在范围内需要删除的碎屑 keyValuePairs.Clear(); if (delPointFs != null && delPointFs.Count > 0) { for (int i = 0; i < delPointFs.Count; i++) { int qx = (int)delPointFs[i].X; int qy = (int)delPointFs[i].Y; int label = labelMat.At(qy, qx); if (label > 0 && !keyValuePairs.ContainsKey(label)) { keyValuePairs.Add(label, 1); } } } labelMat.ForEachAsInt32(CommonForEachDel); return temp_ap.Clone(); } private static void CommonForEachDel(int* value, int* position) { int y = position[0]; int x = position[1]; int v = *value; if (v > 0 && keyValuePairs.ContainsKey(v)) { temp_ap.Set(y, x, 0); } } //寻找角点做角曲率 private static double GetRoundness1(int width, int height, int x, int y) { OpenCvSharp.Point core = new OpenCvSharp.Point(); OpenCvSharp.Point[][] contours = new OpenCvSharp.Point[][] { }; HierarchyIndex[] hierarchyIndex = new HierarchyIndex[] { }; Cv2.FindContours(ground, out contours, out hierarchyIndex, RetrievalModes.External, ContourApproximationModes.ApproxNone); Mat open = Mat.Zeros(ground.Size(), MatType.CV_8UC3); double dist = 0; double maxdist = 0; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { OpenCvSharp.Point point = new OpenCvSharp.Point(x + i, y + j); dist = Cv2.PointPolygonTest(contours[0], point, true); if (dist > maxdist) { maxdist = dist; core = point; } } } Cv2.Circle(ground, Convert.ToInt16(core.X), Convert.ToInt16(core.Y), Convert.ToInt32(maxdist), Scalar.Black, 2); double roundness = 0; //寻找角点 InputArray contoursAll = InputArray.Create(contours[0]); List outArr = new List(); OutputArray hull = OutputArray.Create(outArr); Cv2.ConvexHull(contoursAll, hull, true); Point2f[] cornersPoint = Cv2.GoodFeaturesToTrack(ground, 100, 0.01, 30, new Mat(), 7, false, 0.04); foreach (var item in cornersPoint) { Cv2.Circle(ground, Convert.ToInt16(item.X), Convert.ToInt16(item.Y), 10, Scalar.White, 2); int index = contours[0].ToList().FindIndex(u => Math.Abs(u.X - item.X) < 3 && Math.Abs(u.Y - item.Y) < 3); List list = new List(); list.Add(item); int nv = 10; if (index > nv) { list.Add(contours[0][index - nv]); } else { int ind = nv - index; list.Add(contours[0][contours[0].Length - nv - 1]); } if (index + nv < contours[0].Length) { list.Add(contours[0][index + nv]); } else { list.Add(contours[0][index + nv - contours[0].Length]); } double dis1, dis2, dis3; double cosA, sinA, dis; OpenCvSharp.Point2f P1 = list[0]; OpenCvSharp.Point2f P2 = list[1]; OpenCvSharp.Point2f P3 = list[2]; dis1 = Math.Sqrt((P1.X - P2.X) * (P1.X - P2.X) + (P1.Y - P2.Y) * (P1.Y - P2.Y)); dis2 = Math.Sqrt((P1.X - P3.X) * (P1.X - P3.X) + (P1.Y - P3.Y) * (P1.Y - P3.Y)); dis3 = Math.Sqrt((P2.X - P3.X) * (P2.X - P3.X) + (P2.Y - P3.Y) * (P2.Y - P3.Y)); dis = dis1 * dis1 + dis3 * dis3 - dis2 * dis2; cosA = dis / (2 * dis1 * dis3);//余弦定理求角度 sinA = Math.Sqrt(1 - cosA * cosA);//求正弦 double curvity = 0.5 * dis2 / sinA;//正弦定理求外接圆半径 curvity = 1 / curvity;//半径的倒数是曲率,半径越小曲率越大 roundness += curvity; } double ri = roundness / maxdist; ri = ri / cornersPoint.Length; using (new Window("ss", WindowMode.Normal, ground)) { Cv2.WaitKey(0); } return ri; } //寻找凸包做角曲率 private static double GetRoundness2(int width, int height, int x, int y) { OpenCvSharp.Point core = new OpenCvSharp.Point(); OpenCvSharp.Point[][] contours = new OpenCvSharp.Point[][] { }; HierarchyIndex[] hierarchyIndex = new HierarchyIndex[] { }; Cv2.FindContours(ground, out contours, out hierarchyIndex, RetrievalModes.External, ContourApproximationModes.ApproxNone); Mat open = Mat.Zeros(ground.Size(), MatType.CV_8UC3); double dist = 0; double maxdist = 0; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { OpenCvSharp.Point point = new OpenCvSharp.Point(x + i, y + j); dist = Cv2.PointPolygonTest(contours[0], point, true); if (dist > maxdist) { maxdist = dist; core = point; } } } //寻找角点 InputArray contoursAll = InputArray.Create(contours[0]); List outArr = new List(); OutputArray hull = OutputArray.Create(outArr); Cv2.ConvexHull(contoursAll, hull, true); //内切圆 Cv2.Circle(ground, Convert.ToInt16(core.X), Convert.ToInt16(core.Y), Convert.ToInt32(maxdist), Scalar.Black, 2); double roundness = 0; Cv2.DrawContours(open, new List>() { outArr }, 0, Scalar.White, 2); for (int i = 0; i < outArr.Count(); i++) { Point2f item = outArr[i]; List list = new List(); list.Add(item); if (i == 0) { list.Add(outArr[outArr.Count() - 1]); } else { list.Add(outArr[i - 1]); } if (i == (outArr.Count() - 1)) { list.Add(outArr[0]); } else { list.Add(outArr[i + 1]); } double dis1, dis2, dis3; double cosA, sinA, dis; OpenCvSharp.Point2f P1 = list[0]; OpenCvSharp.Point2f P2 = list[1]; OpenCvSharp.Point2f P3 = list[2]; dis1 = Math.Sqrt((P1.X - P2.X) * (P1.X - P2.X) + (P1.Y - P2.Y) * (P1.Y - P2.Y)); dis2 = Math.Sqrt((P1.X - P3.X) * (P1.X - P3.X) + (P1.Y - P3.Y) * (P1.Y - P3.Y)); dis3 = Math.Sqrt((P2.X - P3.X) * (P2.X - P3.X) + (P2.Y - P3.Y) * (P2.Y - P3.Y)); dis = dis1 * dis1 + dis3 * dis3 - dis2 * dis2; cosA = dis / (2 * dis1 * dis3);//余弦定理求角度 sinA = Math.Sqrt(1 - cosA * cosA);//求正弦 double curvity = 0.5 * dis2 / sinA;//正弦定理求外接圆半径 curvity = 1 / curvity;//半径的倒数是曲率,半径越小曲率越大 roundness += curvity; } double ri = roundness / maxdist; ri = ri / outArr.Count(); using (new Window("open", WindowMode.Normal, open)) using (new Window("ss", WindowMode.Normal, ground)) { Cv2.WaitKey(0); } return ri; } private static readonly object locker = new object(); //获取连通域点 private static void CommonForEachForCon(int* value, int* position) { int y = position[0]; int x = position[1]; int v = *value; if (v > 0) { try { lock (locker) { AllFields[v - 1].Add(new OpenCvSharp.Point(x, y)); } } catch (Exception e) { throw; } } } private static void CommonForEachForArc(int* value, int* position) { int y = position[0]; int x = position[1]; int v = *value; if (v > 0 && hindex != v) { ground.Set(y, x, 0); } } /// /// 单晶Canny去噪点 /// /// /// private static Mat DebrisRemoval_CrystCanny(Mat src) { temp_ap = src; //寻找连通分量 Mat labelMat = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat(); int nonenum = Cv2.ConnectedComponentsWithStats(temp_ap, labelMat, stats, centroids, PixelConnectivity.Connectivity8); //寻找在范围内需要删除的碎屑 keyValuePairs.Clear(); for (int h = 1; h < centroids.Height; h++) { int areaField1 = stats.At(h, 4); int x = stats.At(h, 0); int y = stats.At(h, 1); int width = stats.At(h, 2); int height = stats.At(h, 3); //面积小于30的孔隙删除 if (areaField1 <= 500) { keyValuePairs.Add(h, 1); } } labelMatForSel = labelMat; labelMat.ForEachAsInt32(CommonForEachForInt32_CrystCanny); return temp_ap; } private static void CommonForEachForInt32_CrystCanny(int* value, int* position) { int y = position[0]; int x = position[1]; int v = *value; if (v > 0 && keyValuePairs.ContainsKey(v)) { temp_ap.Set(y, x, 0); } } #endregion #region 有视场 二值提取 /// /// 二值操作-二值提取-有视场 /// /// 视场mat /// 原图mat /// 参数列表 /// public static Mat ImageBinaryExtraction(Mat source, Mat mat, List lists, bool findContours = false) { //以下是参数信息--------------------- ///1个颜色区间还是2个 colorInterval = 1; //第一个二值区间 colorOneStart = 0; colorOneEnd = 0; //第二个二值区间 colorTwoStart = 0; colorTwoEnd = 0; //第三个二值区间 colorThreeStart = 0; colorThreeEnd = 0; //处理细节 //删除边界对象 bool deleteBoundaryObject = false; //孔洞填充 bool holeFilling = false; //碎屑删除 bool debrisRemoval = false; //碎屑删除面积起 debrisAreaStart = 0; //碎屑删除面积止 debrisAreaEnd = 0; //二值样式 //1实心 2边线 int binaryStyle = 0; //相颜色 Color phaseColor = Color.Red; //目标选择 int targetSelection = 1; for (int i = 0; i < lists.Count; i++) { Args args = lists[i]; switch (args.Key) { case "colorInterval": { if (args.Value is Boolean) colorInterval = (Boolean)args.Value ? 2 : 1; else colorInterval = (int)args.Value; } break; case "scope1": colorOneStart = (int)((List)args.Value)[0]; colorOneEnd = (int)((List)args.Value)[1]; break; case "scope2": colorTwoStart = (int)((List)args.Value)[0]; colorTwoEnd = (int)((List)args.Value)[1]; break; case "scope3": colorThreeStart = (int)((List)args.Value)[0]; colorThreeEnd = (int)((List)args.Value)[1]; break; case "deleteBoundaryObject": deleteBoundaryObject = (bool)args.Value; break; case "holeFilling": holeFilling = (bool)args.Value; break; case "debrisRemoval": debrisRemoval = (bool)args.Value; break; case "binaryStyle": binaryStyle = (int)args.Value; break; case "phaseColor": phaseColor = Color.FromArgb((int)args.Value); break; case "targetSelection": targetSelection = (int)args.Value; break; case "scope4": debrisAreaStart = (int)((List)args.Value)[0]; debrisAreaEnd = (int)((List)args.Value)[1]; break; default: break; } } vec4B.Item0 = phaseColor.B; vec4B.Item1 = phaseColor.G; vec4B.Item2 = phaseColor.R; vec4B.Item3 = phaseColor.A; //二值提取 Mat src = BinarizationWithView(source); //目标选择 if (targetSelection != 2) src = CalcContoursByTargetSelection_New(temp_view, targetSelection, source); //碎屑删除,参考冈萨雷斯,414,9.5.3,连通分量提取 if (debrisRemoval && debrisAreaEnd > 0) src = DebrisRemoval_NewWithView(src); //孔洞填充,参考冈萨雷斯,413,9.5.2 if (holeFilling) src = HoleFilling_NewWithView(src); //实心/边线,参考冈萨雷斯,412,9.5.1,边界提取 if (binaryStyle == 2) { Cv2.Erode(src, temp, null); src = src - temp; src = BaseTools.MergeMatFromMatArr(src, vec4B); } return src; } /// /// 二值提取 /// /// 视场图像 /// 原图像 /// 1个或2个颜色区间 /// /// /// /// /// /// /// 相颜色 /// private static Mat BinarizationWithView(Mat source) { Mat[] arr = source.Split(); alpha = arr[3]; Mat srcGray; if (source.Type() == MatType.CV_8UC1) { srcGray = source; } else { srcGray = source.CvtColor(ColorConversionCodes.BGR2GRAY); } temp_view = new Mat(source.Rows, source.Cols, MatType.CV_8UC4, new Scalar(0, 0, 0, 0)); temp = new Mat(source.Rows, source.Cols, MatType.CV_8UC4, new Scalar(0, 0, 0, 0)); srcGray.ForEachAsByte(GrayForEachAsByteWithView); return temp.Clone(); } /// /// 并行循环 /// /// /// private static void GrayForEachAsByteWithView(byte* value, int* position) { int y = position[0]; int x = position[1]; byte v = *value; if (colorInterval == 1) { if (v >= colorOneStart && v <= colorOneEnd) { if (alpha.At(y, x) > 0) { temp.Set(y, x, vec4B); temp_view.Set(y, x, vec4B); } else { temp_view.Set(y, x, new Vec4b(vec4B.Item0, vec4B.Item1, vec4B.Item2, 0)); } } } else { if (((v >= colorTwoStart && v <= colorTwoEnd) || (v >= colorThreeStart && v <= colorThreeEnd))) { if (alpha.At(y, x) > 0) { temp.Set(y, x, vec4B); temp_view.Set(y, x, vec4B); } else { temp_view.Set(y, x, new Vec4b(vec4B.Item0, vec4B.Item1, vec4B.Item2, 0)); } } } } /// /// 新碎屑删除,使用连通分量找寻碎屑 /// /// /// private static Mat DebrisRemoval_NewWithView(Mat src) { Mat[] arr = src.Split(); rgb_ap = BaseTools.MergeMatFromMatArr(arr); temp_ap = arr[3].Clone(); //寻找连通分量 Mat labelMat = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat(); int nonenum = Cv2.ConnectedComponentsWithStats(temp_ap, labelMat, stats, centroids, PixelConnectivity.Connectivity8); //寻找在范围内需要删除的碎屑 keyValuePairs.Clear(); for (int h = 1; h < centroids.Height; h++) { int areaField1 = stats.At(h, 4); if (debrisAreaStart <= areaField1 && areaField1 <= debrisAreaEnd) { keyValuePairs.Add(h, 1); } } labelMat.ForEachAsInt32(CommonForEachForInt32); //合并rgb和透明度 Mat[] mats = rgb_ap.Split(); arr[0] = mats[0]; arr[1] = mats[1]; arr[2] = mats[2]; arr[3] = temp_ap; Cv2.Merge(arr, src); return src; } /// /// 新孔洞填充,采用形态学填充 /// /// /// private static Mat HoleFilling_NewWithView(Mat src) { Mat[] arr2 = src.Split(); Mat tempc = arr2[3]; //去掉透明层 Mat mat = src.CvtColor(ColorConversionCodes.BGRA2BGR); //填充孔洞 mat = BaseTools.FillHole(mat, new Scalar(255 - vec4B.Item0, 255 - vec4B.Item1, 255 - vec4B.Item2)); tempc = BaseTools.FillHole(tempc, new Scalar(255)); //循环处理 mat.ForEachAsVec3b(RGBForEachAsByteForHoleFillingNewWithView); Mat[] arr1 = mat.Split(); arr2[0] = arr1[0]; arr2[1] = arr1[1]; arr2[2] = arr1[2]; arr2[3] = tempc; Cv2.Merge(arr2, src); return src; } private static void RGBForEachAsByteForHoleFillingNewWithView(Vec3b* value, int* position) { int y = position[0]; int x = position[1]; if (value->Item0 == 255 && value->Item1 == 255 && value->Item2 == 255) { value->Item0 = vec4B.Item0; value->Item1 = vec4B.Item1; value->Item2 = vec4B.Item2; } } /// /// 目标选择 /// /// /// /// /// /// public static Mat CalcContoursByTargetSelection_New(Mat src, int targetSelection, Mat source) { Mat[] arr = src.Split(); alpha = arr[3].Clone(); Mat rgb = BaseTools.MergeMatFromMatArr(arr); Mat alphatemp = arr[3].Clone(); Mat mask = Mat.Zeros(rgb.Rows + 2, rgb.Cols + 2, MatType.CV_8UC1); //考虑循环填充,填充视场的透明层和原图的透明层,然后比较填充区域的大小 //但是循环的时候需要少循环像素,可以处理视场的透明层,减少循环量 //同时记录种子点,然后根据targetSelection判断是填充透明还是不透明 Mat rgbClone = rgb.Clone(); List points = new List(); for (int h = 0; h < alphatemp.Height; h++) { for (int w = 0; w < alphatemp.Width; w++) { int v = alphatemp.At(h, w); if (v > 0) { int a = Cv2.FloodFill(alphatemp, new OpenCvSharp.Point(w, h), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); int b = Cv2.FloodFill(rgbClone, new OpenCvSharp.Point(w, h), new Scalar(0, 0, 0), out rect, null, null, FloodFillFlags.Link8); if (a != b) { points.Add(new OpenCvSharp.Point(w, h)); } } } } if (points.Count > 0) { foreach (OpenCvSharp.Point p in points) { if (targetSelection == 1) { Cv2.FloodFill(alpha, p, new Scalar(0), out rect, null, null, FloodFillFlags.Link8); } else if (targetSelection == 3) { Cv2.FloodFill(rgb, mask, p, new Scalar(vec4B.Item0, vec4B.Item1, vec4B.Item2), out rect, null, null, FloodFillFlags.Link8); } } } if (targetSelection == 3) { Mat t = new Mat(mask, new Rect(1, 1, rgb.Width, rgb.Height)); alpha = alpha + t * 255; } //合并rgb和透明度 Mat[] mats = rgb.Split(); arr[0] = mats[0]; arr[1] = mats[1]; arr[2] = mats[2]; arr[3] = alpha; Cv2.Merge(arr, src); return src; } #endregion private static void CommonForEachForInt32(int* value, int* position) { int y = position[0]; int x = position[1]; int v = *value; if (v > 0 && keyValuePairs.ContainsKey(v)) { rgb_ap.Set(y, x, new Vec3b(0, 0, 0)); temp_ap.Set(y, x, 0); //手动画圆 if (ListRadiusColor.Count > 0) { int d = Convert.ToInt32(Math.Sqrt((x - center.X) * (x - center.X) + (y - center.Y) * (y - center.Y))); if (ListRadiusColor.Count > 1) { for (int i = 0; i < ListRadiusColor.Count - 1; i++) { int r = i == 0 ? 0 : ListRadiusColor.ElementAt(ListRadiusColor.Count - i).Key; int r2 = ListRadiusColor.ElementAt(ListRadiusColor.Count - 1 - i).Key; if (r < d && d <= r2) { poAreaList[i]--; break; } } } } else if (circleCount > 1) { int d = Convert.ToInt32(Math.Sqrt((x - center.X) * (x - center.X) + (y - center.Y) * (y - center.Y))); for (int i = 0; i < circleCount; i++) { int r = Convert.ToInt32(CircleR * (i)); int r2 = Convert.ToInt32(CircleR * (i + 1)); if (r < d && d <= r2) { poAreaList[i]--; break; } } } } } private static void CommonForEachForSel(int* value, int* position) { int y = position[0]; int x = position[1]; int v = *value; if (v > 0 && keyValueSel.ContainsKey(v)) { rgb_ap.Set(y, x, new Vec3b(255, 255, 0)); } } /// /// 开裂球识别霍夫圆 /// /// public static Mat DrwCrackBall(Mat src) { temp = src.Clone(); Mat dst = new Mat(); //1:因为霍夫圆检测对噪声比较敏感,所以首先对图像做一个中值滤波或高斯滤波(噪声如果没有可以不做) Mat m1 = new Mat(); Cv2.MedianBlur(temp, m1, 3); // ksize必须大于1且是奇数 //2:转为灰度图像 Mat m2 = m1.Clone(); // m1.Release(); Cv2.CvtColor(m1, m2, ColorConversionCodes.BGR2GRAY); CircleSegment[] cs = Cv2.HoughCircles(m2, HoughMethods.Gradient, 1, 130, 60, 25, 35, 80); temp.CopyTo(dst); //大圆 for (int i = 0; i < cs.Length; i++) { //画圆 Cv2.Circle(dst, (int)cs[i].Center.X, (int)cs[i].Center.Y, (int)cs[i].Radius, new Scalar(0, 0, 255), 2, LineTypes.AntiAlias); //加强圆心显示 Cv2.Circle(dst, (int)cs[i].Center.X, (int)cs[i].Center.Y, 3, new Scalar(0, 0, 255), 2, LineTypes.AntiAlias); } Mat srcBlack; int sucessCs = 0; int badCs = 0; for (int i = 0; i < cs.Length; i++) { int left = (int)cs[i].Center.X - (int)cs[i].Radius; int right = (int)cs[i].Center.X + (int)cs[i].Radius; int top = (int)cs[i].Center.Y - (int)cs[i].Radius; int bottom = (int)cs[i].Center.Y + (int)cs[i].Radius; if (left < 10 || right - 10 > temp.Width || top < 10 || bottom - 10 > temp.Height - 140) { continue; } srcBlack = new Mat(temp.Height, temp.Width, MatType.CV_8UC1, new Scalar(0));//黑色底图 //画圆 Cv2.Circle(srcBlack, (int)cs[i].Center.X, (int)cs[i].Center.Y, (int)cs[i].Radius, Scalar.White, 1, LineTypes.AntiAlias); OpenCvSharp.Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(srcBlack, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone, null); Cv2.DrawContours(srcBlack, contours, -1, Scalar.White, -1, LineTypes.Link8, hierarchy, 4, new OpenCvSharp.Point(0, 0)); //取所有的点 List srPoints = new List(); int rows = srcBlack.Height, cols = srcBlack.Width; for (int k = 0; k < rows; k++) { IntPtr a = srcBlack.Ptr(k); byte* b = (byte*)a.ToPointer(); for (int j = 0; j < cols; j++) { if (b[j] != 0) { srPoints.Add(new OpenCvSharp.Point(j, k)); } } } for (int j = 0; j < srPoints.Count; j++) { int item = temp.Get(srPoints[j].Y, srPoints[j].X); srcBlack.Set(srPoints[j].Y, srPoints[j].X, item); } Rect bigrect = Cv2.BoundingRect(contours[0]); Mat rect = new Mat(srcBlack, bigrect); //Cv2.EqualizeHist(rect, dst); Cv2.GaussianBlur(rect, dst, new OpenCvSharp.Size(3, 3), 0); //Cv2.MedianBlur(dst, dst, 1); Mat aa = dst.Threshold(colorOneStart, colorOneEnd, ThresholdTypes.BinaryInv); Cv2.FindContours(aa, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone, null); Point2f center = new Point2f(aa.Cols / 2, aa.Rows / 2); Mat bb = new Mat(aa.Height, aa.Width, MatType.CV_8UC1, new Scalar(0));//黑色底图 Cv2.Circle(bb, (int)center.X, (int)center.Y, (int)cs[i].Radius - 15, Scalar.White, 1, LineTypes.AntiAlias); OpenCvSharp.Point[][] contoursCircleLine; HierarchyIndex[] hierarchyLine; Cv2.FindContours(bb, out contoursCircleLine, out hierarchyLine, RetrievalModes.External, ContourApproximationModes.ApproxNone, null); List contoursCircleLineOne = new List(); for (int m = 0; m < contoursCircleLine.Length; m++) { for (int n = 0; n < contoursCircleLine[m].Length; n++) { contoursCircleLineOne.Add(contoursCircleLine[m][n]); } } //内缩 Rect bigRect = new Rect(0, 0, rect.Width, rect.Height); for (int nX = bigRect.X; nX <= bigRect.Right; nX++) { for (int nY = bigRect.Y; nY <= bigRect.Bottom; nY++) { double localPos = Cv2.PointPolygonTest(contoursCircleLineOne, new Point2f(nX, nY), false); if (localPos == 1 || localPos == 0)//像素点在多边形内和边缘 { } else { aa.Set(nX, nY, 0); } } } OpenCvSharp.Point[][] contours1 = new OpenCvSharp.Point[][] { }; HierarchyIndex[] hierarchy1 = new HierarchyIndex[] { }; Cv2.FindContours(aa, out contours1, out hierarchy1, RetrievalModes.External, ContourApproximationModes.ApproxNone, null); // Cv2.CvtColor(aa, aa, ColorConversionCodes.RGB2BGR); List contoursHoleList = contours1.OrderByDescending(t => t.Count()).ToList(); //if (contoursHoleList.Count == 0) //{ // continue; //} double isk = 0; float widthto = 0; float heightto = 0; for (int k = 0; k < contours1.Count(); k++) { RotatedRect rectR = Cv2.MinAreaRect(contours1[k]); //计算每个轮廓最小外接矩形 Rect rectB = Cv2.BoundingRect(contours1[k]); float width = rectR.Size.Width >= rectR.Size.Height ? rectR.Size.Width : rectR.Size.Height; float height = rectR.Size.Width < rectR.Size.Height ? rectR.Size.Width : rectR.Size.Height; height = height == 0 ? 1 : height; double distance = 0; for (int m = 0; m < contours1[k].Count(); m++) { Point2f centerCoutours = new Point2f(contours1[k][m].X, contours1[k][m].Y); distance += centerCoutours.DistanceTo(center); } distance = distance / contours1[k].Count(); OpenCvSharp.Point[] lineDmax = new OpenCvSharp.Point[2]; RotatedRect minRect; // double ratio = GetDMax(contours[k], out lineDmax) / GetDMin(contours[k], out minRect); if (distance > 55) { //再边缘 //Cv2.DrawContours(aa, contours, k, Scalar.Yellow, -1, LineTypes.Link8, hierarchy, 4, new OpenCvSharp.Point(0, 0)); } else if (/*ratio > 2 && */Cv2.ArcLength(contours1[k], true) < 15) { //像素太少的去掉 // Cv2.DrawContours(aa, contours, k, Scalar.Blue, -1, LineTypes.Link8, hierarchy, 4, new OpenCvSharp.Point(0, 0)); } else { widthto = widthto + width; isk = isk + Cv2.ContourArea(contours1[k]); if (Cv2.ContourArea(contours1[k]) > Math.PI * cs[i].Radius * cs[i].Radius * 0.3) { break; } //最终想要的裂缝 //Cv2.DrawContours(aa, contours1, k, Scalar.Green, -1, LineTypes.Link8, hierarchy, 4, new OpenCvSharp.Point(0, 0)); List bigmap = new List(); foreach (OpenCvSharp.Point item in contours1[k]) { bigmap.Add(new OpenCvSharp.Point() { X = item.X + bigrect.X, Y = item.Y + bigrect.Y }); } List> tol = new List>(); tol.Add(bigmap); Cv2.DrawContours(temp, tol, 0, colorList[1], 1, LineTypes.Link8, null, 4, new OpenCvSharp.Point(0, 0)); } } if (isk > Math.PI * cs[i].Radius * cs[i].Radius * 0.3) { continue; } if (isk > 0) { heightto = (float)isk / widthto; heightto = heightto < 1 ? 1 : heightto; //画圆 Cv2.Circle(temp, (int)cs[i].Center.X, (int)cs[i].Center.Y, (int)cs[i].Radius, colorList[1], 2, LineTypes.AntiAlias); //加强圆心显示 Cv2.Circle(temp, (int)cs[i].Center.X, (int)cs[i].Center.Y, 3, colorList[1], 6, LineTypes.AntiAlias); } else { //画圆 Cv2.Circle(temp, (int)cs[i].Center.X, (int)cs[i].Center.Y, (int)cs[i].Radius, colorList[0], 2, LineTypes.AntiAlias); //加强圆心显示 Cv2.Circle(temp, (int)cs[i].Center.X, (int)cs[i].Center.Y, 3, colorList[0], 6, LineTypes.AntiAlias); } List po = new List() { (int)cs[i].Center.X, (int)cs[i].Center.Y, (int)cs[i].Radius, (int)widthto, (int)heightto, isk > 0 ? 1 : 0 }; poList.Add(po); } return temp.Clone(); } /// /// 开裂球识别分水岭 /// /// public static Mat DrwCrackBall_New(Mat src, Mat source) { temp = source.Clone(); Mat gray = new Mat(); Mat dst = new Mat(); Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY); OpenCvSharp.Point[][] cs; HierarchyIndex[] hierarchycs; Cv2.FindContours(gray, out cs, out hierarchycs, RetrievalModes.External, ContourApproximationModes.ApproxNone, null); particlePixles.Clear(); Mat srcBlack; int sucessCs = 0; int badCs = 0; int index = 1; double heig = (double)140 / (double)1920; for (int i = 0; i < cs.Length; i++) { //边界颗粒去除 int coutp = 0; for (int j = 0; j < cs[i].Length; j++) { int cspx = cs[i][j].X; int cspy = cs[i][j].Y; if (cspx == 0 || cspy == 0 || cspx > src.Cols - 5 || cspy > src.Rows - heig * src.Rows - 5) { coutp++; } } if (coutp > 5) { continue; } //面积过小去除 if (Cv2.ContourArea(cs[i]) < 4000) { continue; } Rect bigrect = Cv2.BoundingRect(cs[i]); if (CreackBallPointFs.Count > 0) { bool isnei = false; foreach (var item in CreackBallPointFs) { double dq = Cv2.PointPolygonTest(cs[i], new Point2f(item.X, item.Y), false); if (dq > 0) { isnei = true; break; } } if (isnei) { continue; } } //圆度过大去除 //afa参考代码 double s = Cv2.ContourArea(cs[i]);//轮廓面积 double c = Cv2.ArcLength(cs[i], true); //轮廓周长 double afa = 4 * Math.PI * s / (c * c); //afa计算 afa = Math.Abs(afa - 1); //if (afa > 0.6) //{ // continue; //} afa = afa * 1000; if (CreackBallPointFsK.Count > 0) { bool isnei = false; foreach (var item in CreackBallPointFsK) { double dq = Cv2.PointPolygonTest(cs[i], new Point2f(item.X, item.Y), false); if (dq > 0) { isnei = true; break; } } if (isnei) { Cv2.DrawContours(temp, cs, i, new Scalar(0, 0, 255, 255), 2, LineTypes.Link8, null, 4, new OpenCvSharp.Point(0, 0)); List po1 = new List() { (int)bigrect.X, (int)bigrect.Y, (int)bigrect.Height, -1, -1, 1, (int)afa }; poList.Add(po1); continue; } } if (CreackBallPointFsP.Count > 0) { bool isnei = false; foreach (var item in CreackBallPointFsP) { double dq = Cv2.PointPolygonTest(cs[i], new Point2f(item.X, item.Y), false); if (dq > 0) { isnei = true; break; } } if (isnei) { Cv2.DrawContours(temp, cs, i, new Scalar(255, 0, 0, 255), 2, LineTypes.Link8, null, 4, new OpenCvSharp.Point(0, 0)); List po1 = new List() { (int)bigrect.X, (int)bigrect.Y, (int)bigrect.Height, -1, -1, 0, (int)afa }; poList.Add(po1); continue; } } srcBlack = new Mat(gray.Height, gray.Width, MatType.CV_8UC1, new Scalar(0));//黑色底图 Cv2.DrawContours(srcBlack, cs, i, Scalar.White, -1, LineTypes.Link4, hierarchycs, 2, new OpenCvSharp.Point(0, 0)); //取所有的点 List srPoints = new List(); int rows = srcBlack.Height, cols = srcBlack.Width; for (int k = 0; k < rows; k++) { IntPtr a = srcBlack.Ptr(k); byte* b = (byte*)a.ToPointer(); for (int j = 0; j < cols; j++) { if (b[j] != 0) { srPoints.Add(new OpenCvSharp.Point(j, k)); } } } for (int j = 0; j < srPoints.Count; j++) { int item = source.Get(srPoints[j].Y, srPoints[j].X); srcBlack.Set(srPoints[j].Y, srPoints[j].X, item); } double outR = Math.Sqrt(s / Math.PI) * 0.5; double dist = 0; double maxdist = 0; //中心点 OpenCvSharp.Point ballCenter = new OpenCvSharp.Point(); foreach (var item in srPoints) { dist = Cv2.PointPolygonTest(cs[i], item, true); if (dist > maxdist) { maxdist = dist; ballCenter = item; } } List sel = new List(); for (int k = 0; k < cs[i].Length; k++) { sel.Add(cs[i][k]); } Mat rect = new Mat(srcBlack, bigrect); Cv2.GaussianBlur(rect, dst, new OpenCvSharp.Size(3, 3), 0); Mat aa = dst.Threshold(colorOneStart, colorOneEnd, ThresholdTypes.BinaryInv); for (int x = 0; x < aa.Cols; x++) { for (int y = 0; y < aa.Rows; y++) { double localPos = Cv2.PointPolygonTest(sel, new Point2f(x + bigrect.X, y + bigrect.Y), false); if (localPos == 1 || localPos == 0)//像素点在多边形内和边缘 { } else { aa.Set(y, x, 0); } } } InputArray kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3), new OpenCvSharp.Point(-1, -1)); //开操作,也可省落变量前缀名 Cv2.MorphologyEx(aa, aa, MorphTypes.Dilate, kernel, new OpenCvSharp.Point(-1, -1)); OpenCvSharp.Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(aa, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone, null); List contoursHoleList = contours.OrderByDescending(t => t.Count()).ToList(); double isk = 0; float widthto = 0; double heightto = 0; double arclength = 0; Point2f center = new Point2f(aa.Cols / 2, aa.Rows / 2); double area = Cv2.ContourArea(cs[i]); double ra = aa.Cols < aa.Rows ? aa.Cols / 2 : aa.Rows / 2; for (int k = 0; k < contoursHoleList.Count(); k++) { double tarea = Cv2.ContourArea(contoursHoleList[k]); RotatedRect rectR = Cv2.MinAreaRect(contoursHoleList[k]); //计算每个轮廓最小外接矩形 Rect rectB = Cv2.BoundingRect(contoursHoleList[k]); float width = rectR.Size.Width >= rectR.Size.Height ? rectR.Size.Width : rectR.Size.Height; float height = rectR.Size.Width < rectR.Size.Height ? rectR.Size.Width : rectR.Size.Height; height = height == 0 ? 1 : height; List poingtForUse = new List(); List tempList = new List(); int outCount = 0; foreach (OpenCvSharp.Point item in contoursHoleList[k]) { OpenCvSharp.Point point1 = new OpenCvSharp.Point() { X = item.X + bigrect.X, Y = item.Y + bigrect.Y }; double d = Cv2.PointPolygonTest(cs[i], point1, true); tempList.Add(point1); if (d < 5) { outCount++; } } if (((outCount * 100) / contoursHoleList[k].Count()) < 70) { tempList.ForEach(p => poingtForUse.Add(p)); } // double ratio = GetDMax(contoursHoleList[k], out lineDmax) / GetDMin(contoursHoleList[k], out minRect); double carea = Cv2.ContourArea(contoursHoleList[k]); double cleng = Cv2.ArcLength(contoursHoleList[k], true); //轮廓周长 double cafa = 4 * Math.PI * s / (c * c); //afa计算 cafa = Math.Abs(cafa - 1); if (poingtForUse.Count < 25) { } else if (cleng < 30) { } else { arclength = arclength + Cv2.ArcLength(contoursHoleList[k], true); widthto = widthto + width; isk = isk + Cv2.ContourArea(contoursHoleList[k]); List> tol = new List>(); tol.Add(poingtForUse); Cv2.DrawContours(temp, tol, 0, colorList[1], -1, LineTypes.Link8, null, 2, new OpenCvSharp.Point(0, 0)); //for (int p = 0; p < poingtForUse.Count(); p++) //{ // temp.Set(poingtForUse[p].Y, poingtForUse[p].X, vec4BList[1]); //} } } if (isk > 0) { heightto = isk / arclength; heightto = heightto < 1 ? 1 : heightto; Cv2.DrawContours(temp, cs, i, new Scalar(0, 0, 255, 255), 2, LineTypes.Link8, null, 4, new OpenCvSharp.Point(0, 0)); } else { Cv2.DrawContours(temp, cs, i, new Scalar(255, 0, 0, 255), 2, LineTypes.Link8, null, 4, new OpenCvSharp.Point(0, 0)); } particlePixles.Add(index++, sel); List po = new List() { (int)bigrect.X, (int)bigrect.Y, (int)bigrect.Height, (int)widthto, (int)heightto, isk > 0 ? 1 : 0, (int)afa }; poList.Add(po); } return temp.Clone(); } /// /// 开裂球选择 /// /// /// private static Mat SelectBall(Mat src, int x, int y, int r) { temp = src.Clone(); //画圆 // Cv2.Circle(temp, x, y, r, colorList[4], 2, LineTypes.AntiAlias); //加强圆心显示 Cv2.Circle(temp, x + r / 2, y + r / 2, 8, colorList[4], 6, LineTypes.AntiAlias); return temp; } /// /// 开裂球选择 /// /// /// private static Mat SelectBallInt(Mat src, int index) { temp = src.Clone(); //画圆 // Cv2.Circle(temp, x, y, r, colorList[4], 2, LineTypes.AntiAlias); List> tol = new List>(); tol.Add(particlePixles[index]); Cv2.DrawContours(temp, tol, 0, colorList[4], 4, LineTypes.Link8, null, 4, new OpenCvSharp.Point(0, 0)); RotatedRect rectR = Cv2.MinAreaRect(particlePixles[index]); double are = Cv2.ContourArea(particlePixles[index]); //加强圆心显示 // Cv2.Circle(temp, x + r / 2, y + r / 2, 8, colorList[4], 6, LineTypes.AntiAlias); return temp; } private static void GetHalfCircles(Mat color) { Mat canny = new Mat(); Mat gray = new Mat(); Cv2.CvtColor(color, gray, ColorConversionCodes.BGRA2GRAY); Cv2.Canny(gray, canny, 200, 20); CircleSegment[] circles = Cv2.HoughCircles(gray, HoughMethods.Gradient, 1, 80, 70, 24, 33, 52); for (int i = 0; i < circles.Length; i++) { //加强圆心显示 Cv2.Circle(color, (int)circles[i].Center.X, (int)circles[i].Center.Y, 3, new Scalar(0, 255, 255), -1, LineTypes.AntiAlias); //画圆 Cv2.Circle(color, (int)circles[i].Center.X, (int)circles[i].Center.Y, (int)circles[i].Radius, new Scalar(0, 0, 255), 1, LineTypes.AntiAlias); } Mat dt = new Mat(); Cv2.BitwiseNot(canny, canny); Cv2.DistanceTransform(canny, dt, DistanceTypes.L2, DistanceMaskSize.Mask3); float minInlierDist = 2.0f; for (int i = 0; i < circles.Length; i++) { int counter = 0; int inlier = 0; Point2f center = circles[i].Center; float radius = circles[i].Radius; float maxInlierDist = radius / 25.0f; if (maxInlierDist < minInlierDist) maxInlierDist = minInlierDist; for (float t = 0; t < 2 * Math.PI; t += 0.1f) { counter++; float cX = radius * (float)Math.Cos(t) + circles[i].Center.X; float cY = radius * (float)Math.Sin(t) + circles[i].Center.Y; if (cX < 0) { cX = 0; } if (cY < 0) { cY = 0; } if (dt.At((int)cY, (int)cX) < maxInlierDist) { inlier++; Cv2.Circle(color, (int)cX, (int)cY, 3, new Scalar(0, 255, 0)); } else { Cv2.Circle(color, (int)cX, (int)cY, 3, new Scalar(255, 0, 0)); } } } using (new Window("color", WindowMode.Normal, color)) { Cv2.WaitKey(0); } } /// /// 二值提取隔膜 /// /// 源 /// 1个或2个颜色区间 /// /// /// /// /// /// /// private static Mat BinarizationForM(Mat source) { Mat srcGray; if (source.Type() == MatType.CV_8UC1) { srcGray = source; } else { srcGray = source.CvtColor(ColorConversionCodes.BGR2GRAY); } temp = new Mat(source.Rows, source.Cols, MatType.CV_8UC4, new Scalar(0, 0, 0, 0)); try { srcGray.ForEachAsByte(GrayForEachAsByteForM); } catch (Exception) { throw; } return temp.Clone(); } /// /// 并行循环 /// /// /// private static void GrayForEachAsByteForM(byte* value, int* position) { int y = position[0]; int x = position[1]; byte v = *value; if (v >= colorOneStart && v <= colorOneEnd && y < imageHight - 70) { temp.Set(y, x, vec4B); } } } }