using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using OpenCvSharp; using SmartCoalApplication.Base.CommTool; namespace SmartCoalApplication.Base.AutoMeasure { public class Ceju { /// /// 对图像进行二值化,得到产品目标区域 /// /// 单通道图像,一般是红色通道 /// 输出二值图 public void GetContour(Mat image, out Mat imageContour) { // 均值滤波 Mat imageFilter = new Mat(); Cv2.Blur(image, imageFilter, new OpenCvSharp.Size(5, 5)); // 二值化,获得目标区域 imageContour = imageFilter.Threshold(0, 1, ThresholdTypes.Otsu); //new Window("contour", WindowMode.Normal, imageContour * 255); // 闭运算,消除小孔 Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(10, 10));// 结构元素 Cv2.MorphologyEx(imageContour, imageContour, MorphTypes.Close, se); Mat fillContour = new Mat(); Fill(imageContour, out fillContour, 1); //new Window("close", WindowMode.Normal, imageContour * 255); //new Window("fill", WindowMode.Normal, fillContour * 255); //Cv2.WaitKey(); Mat fanse = 1 - fillContour; Scalar sum = fanse.Sum(); Scalar sumBefore = imageContour.Sum(); Scalar sumAfter = fillContour.Sum(); int areaDifference = (int)sumAfter - (int)sumBefore; if ((int)sum != 0)//避免整张图全填充 { if (areaDifference < 100)//避免填充区域过多 imageContour = fillContour; } #region[清理内存] //if (imageFilter != null) //{ // imageFilter.Dispose(); //} //if (fillContour != null) //{ // fillContour.Dispose(); //} #endregion } public void GetContourTongkongShuangceng(Mat image, out Mat imageContour) { // 均值滤波 Mat imageFilter = new Mat(); Cv2.Blur(image, imageFilter, new OpenCvSharp.Size(5, 5)); // 二值化,获得目标区域 imageContour = imageFilter.Threshold(0, 1, ThresholdTypes.Otsu); //new Window("contour", WindowMode.Normal, imageContour * 255); // 开运算,消除杂质,闭运算,消除小孔 Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(10, 10));// 结构元素 Cv2.MorphologyEx(imageContour, imageContour, MorphTypes.Open, se); Cv2.MorphologyEx(imageContour, imageContour, MorphTypes.Close, se); Mat fillContour = new Mat(); Fill(imageContour, out fillContour, 1); //new Window("close", WindowMode.Normal, imageContour * 255); //new Window("fill", WindowMode.Normal, fillContour * 255); //Cv2.WaitKey(); Mat fanse = 1 - fillContour; Scalar sum = fanse.Sum(); Scalar sumBefore = imageContour.Sum(); Scalar sumAfter = fillContour.Sum(); int areaDifference = (int)sumAfter - (int)sumBefore; if ((int)sum != 0)//避免整张图全填充 { if (areaDifference < 100)//避免填充区域过多 imageContour = fillContour; } } public void GetShenmangkongContour(Mat image, out Mat imageContour) { // 均值滤波 Mat imageFilter = new Mat(); Cv2.Blur(image, imageFilter, new OpenCvSharp.Size(5, 5)); // 二值化,获得目标区域 imageContour = imageFilter.Threshold(0, 1, ThresholdTypes.Otsu); //膨胀 Mat seDilate = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(20, 1)); Mat dilate = new Mat(); Cv2.Dilate(imageContour, dilate, seDilate); // 闭运算,消除小孔 Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(15, 15));// 结构元素 Cv2.MorphologyEx(dilate, imageContour, MorphTypes.Close, se); Mat fillContour = new Mat(); Fill(imageContour, out fillContour, 1); //new Window("fill", WindowMode.Normal, fillContour * 255); //Cv2.WaitKey(); Mat fanse = 1 - fillContour; Scalar sum = fanse.Sum(); Scalar sumBefore = imageContour.Sum(); Scalar sumAfter = fillContour.Sum(); int areaDifference = (int)sumAfter - (int)sumBefore; if ((int)sum != 0)//避免整张图全填充 { if (areaDifference < 2000)//避免填充区域过多 imageContour = fillContour; } } /// /// 对图片进行上下裁剪,去掉空白的部分 /// /// 输入二值图像 /// 输出去掉的上下边界 /// 输出裁剪后的图片 public void Crop(Mat image, out int[] y, out Mat cropContour, bool isCropFlag) { int range = 300; if (isCropFlag) range = 15; y = new int[2] { 0, 0 }; for (int i = range; i < image.Rows; i++) { for (int j = 0; j < image.Cols; j++) { if (image.Get(i, j) > 0) { y[0] = i; break; } } if (y[0] != 0) break; } for (int i = image.Rows - range; i > range; i--) { for (int j = 0; j < image.Cols; j++) { if (image.Get(i, j) > 0) { y[1] = i; break; } } if (y[1] != 0) break; } cropContour = image[y[0], y[1], 0, image.Cols - 1]; } /// /// 对全图片进行裁剪,去掉上下空白的地方,左右被亮光影响的地方 /// /// 原图 /// 上下裁剪后边缘图,用作提取孔铜 /// 裁剪的上下边界 /// 用来裁剪槽孔区域的左右边界 public void Crop2(Mat image, out Mat cropEdge, out int[] y, out int[] b, bool isCropFlag) { //获得蓝色,绿色,红色通道图片 Mat[] bgr = Cv2.Split(image); Mat imageBlue = bgr[0]; Mat imageGreen = bgr[1]; Mat imageRed = bgr[2]; // 调色 Mat imageNew = 0.9 * imageGreen + 0.1 * imageRed; //滤波 Mat filter = new Mat(); Cv2.BilateralFilter(imageNew, filter, 15, 150, 3); // 增强 Mat zengqiang = new Mat(); InputArray kernel = InputArray.Create(new int[3, 3] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } }); Cv2.Filter2D(filter, zengqiang, -1, kernel); Cv2.ConvertScaleAbs(zengqiang, zengqiang); //边缘检测 Mat grad_x2 = new Mat(); Sobel(zengqiang, out grad_x2); //开运算 Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5));// 结构元素 Mat open = new Mat(); Cv2.MorphologyEx(grad_x2, open, MorphTypes.Open, seOpen); ////閉運算 Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));// 结构元素 Mat close = new Mat(); Cv2.MorphologyEx(open, close, MorphTypes.Close, se); Mat thresh2 = close.Threshold(0, 1, ThresholdTypes.Otsu); //填充 Mat fill = new Mat(); Fill(thresh2, out fill, 1); //new Window("grad", WindowMode.Normal, grad_x2.Threshold(0, 255, ThresholdTypes.Otsu)); //new Window("open", WindowMode.Normal, open); //new Window("close", WindowMode.Normal, close); //Cv2.WaitKey(); Ceju ceju = new Ceju(); y = new int[2]; ceju.Crop(fill, out y, out fill, isCropFlag);//用来计算左右裁剪边界 //Mat edge = grad_x2.Threshold(0, 1, ThresholdTypes.Otsu); cropEdge = thresh2[y[0], y[1], 0, thresh2.Cols - 1];//用来计算孔铜边缘 b = new int[4] { 0, 0, 0, 0 }; int sum = 0; int range = 100; if (isCropFlag) range = 15; for (int j = range; j < fill.Cols - 1; j++) { for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { b[0] = j; break; } } if (b[0] != 0) break; } for (int j = b[0] + 100; j < fill.Cols - 1; j++) { sum = 0; for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { sum = 1; break; } } if (sum == 0) { b[1] = j; break; } } if (b[1] - b[0] < 300) { b[0] = 0; for (int j = b[1] + 50; j < fill.Cols - 1; j++) { for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { b[0] = j; break; } } if (b[0] != 0) break; } for (int j = b[0] + 50; j < fill.Cols - 1; j++) { sum = 0; for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { sum = 1; break; } } if (sum == 0) { b[1] = j; break; } } } for (int j = fill.Cols - range; j > 0; j--) { for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { b[3] = j; break; } } if (b[3] != 0) break; } for (int j = b[3] - 100; j > 0; j--) { sum = 0; for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { sum = 1; break; } } if (sum == 0) { b[2] = j; break; } } if (b[3] - b[2] < 300) { b[3] = 0; for (int j = b[2] - 50; j > 0; j--) { for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { b[3] = j; break; } } if (b[3] != 0) break; } for (int j = b[3] - 50; j > 0; j--) { sum = 0; for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { sum = 1; break; } } if (sum == 0) { b[2] = j; break; } } } } /// /// 用于四层孔径的裁剪,减小了左右裁剪的判定标准,其他同Crop2 /// /// /// /// /// public void CropSicengKongjing(Mat image, out Mat cropEdge, out int[] y, out int[] b, bool isCropFlag) { //获得蓝色,绿色,红色通道图片 Mat[] bgr = Cv2.Split(image); Mat imageBlue = bgr[0]; Mat imageGreen = bgr[1]; Mat imageRed = bgr[2]; // 调色 Mat imageNew = 0.9 * imageGreen + 0.1 * imageRed; //滤波 Mat filter = new Mat(); Cv2.BilateralFilter(imageNew, filter, 15, 150, 3); // 增强 Mat zengqiang = new Mat(); InputArray kernel = InputArray.Create(new int[3, 3] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } }); Cv2.Filter2D(filter, zengqiang, -1, kernel); Cv2.ConvertScaleAbs(zengqiang, zengqiang); //边缘检测 Mat grad_x2 = new Mat(); Sobel(zengqiang, out grad_x2); //开运算 Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5));// 结构元素 Mat open = new Mat(); Cv2.MorphologyEx(grad_x2, open, MorphTypes.Open, seOpen); ////閉運算 Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));// 结构元素 Mat close = new Mat(); Cv2.MorphologyEx(open, close, MorphTypes.Close, se); Mat thresh2 = close.Threshold(0, 1, ThresholdTypes.Otsu); //填充 Mat fill = new Mat(); Fill(thresh2, out fill, 1); Ceju ceju = new Ceju(); y = new int[2]; ceju.Crop(fill, out y, out fill, isCropFlag);//用来计算左右裁剪边界 //Mat edge = grad_x2.Threshold(0, 1, ThresholdTypes.Otsu); cropEdge = thresh2[y[0], y[1], 0, thresh2.Cols - 1];//用来计算孔铜边缘 b = new int[4] { 0, 0, 0, 0 }; int sum = 0; int range = 100; if (isCropFlag) range = 15; for (int j = range; j < fill.Cols - 1; j++) { for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { b[0] = j; break; } } if (b[0] != 0) break; } for (int j = b[0] + 100; j < fill.Cols - 1; j++) { sum = 0; for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { sum = 1; break; } } if (sum == 0) { b[1] = j; break; } } if (b[1] - b[0] < 50) { b[0] = 0; for (int j = b[1] + 50; j < fill.Cols - 1; j++) { for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { b[0] = j; break; } } if (b[0] != 0) break; } for (int j = b[0] + 50; j < fill.Cols - 1; j++) { sum = 0; for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { sum = 1; break; } } if (sum == 0) { b[1] = j; break; } } } for (int j = fill.Cols - range; j > 0; j--) { for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { b[3] = j; break; } } if (b[3] != 0) break; } for (int j = b[3] - 100; j > 0; j--) { sum = 0; for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { sum = 1; break; } } if (sum == 0) { b[2] = j; break; } } if (b[3] - b[2] < 50) { b[3] = 0; for (int j = b[2] - 50; j > 0; j--) { for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { b[3] = j; break; } } if (b[3] != 0) break; } for (int j = b[3] - 50; j > 0; j--) { sum = 0; for (int i = 0; i < fill.Rows - 1; i++) { if (fill.Get(i, j) > 0) { sum = 1; break; } } if (sum == 0) { b[2] = j; break; } } } } /// /// 去掉槽孔的亮光,并裁剪 /// /// 上下裁剪后的图片 /// 输出裁剪后的边界 /// 输出裁剪后的图片 /// 选择槽孔的左右位置,left/right public void CropLight(Mat cropContour, out int border, out Mat cropContour2, string direction) { int[] b = new int[4] { 0, 0, 0, 0 }; int sum = 0; border = 0; cropContour2 = new Mat(); switch (direction) { case "left": for (int j = 0; j < cropContour.Cols; j++) { for (int i = 0; i < cropContour.Rows; i++) { if (cropContour.Get(i, j) > 0) { b[0] = j; break; } } if (b[0] != 0) break; } for (int j = b[0]; j < cropContour.Cols; j++) { sum = 0; for (int i = 0; i < cropContour.Rows; i++) { sum += cropContour.Get(i, j); } if (sum == 0) { b[1] = j; break; } } for (int j = cropContour.Cols - 1; j > b[1]; j--) { for (int i = 0; i < cropContour.Rows; i++) { if (cropContour.Get(i, j) > 0) { b[3] = j; break; } } if (b[3] != 0) break; } for (int j = b[3]; j > b[1]; j--) { sum = 0; for (int i = 0; i < cropContour.Rows; i++) { sum += cropContour.Get(i, j); } if (sum == 0) { b[2] = j; break; } } if (b[1] - b[0] > 500) { if (Math.Abs(b[2] - b[1]) > 50) { cropContour2 = cropContour[0, cropContour.Rows - 1, b[0], b[1]]; border = b[0]; } else cropContour2 = cropContour[0, cropContour.Rows - 1, 0, cropContour.Cols - 1]; } else { cropContour2 = cropContour[0, cropContour.Rows - 1, 0, b[3]]; border = 0; } break; case "right": for (int j = cropContour.Cols - 1; j > 0; j--) { for (int i = 0; i < cropContour.Rows; i++) { if (cropContour.Get(i, j) > 0) { b[3] = j; break; } } if (b[3] != 0) break; } for (int j = b[3]; j > 0; j--) { sum = 0; for (int i = 0; i < cropContour.Rows; i++) { sum += cropContour.Get(i, j); } if (sum == 0) { b[2] = j; break; } } for (int j = 0; j < b[2]; j++) { for (int i = 0; i < cropContour.Rows; i++) { if (cropContour.Get(i, j) > 0) { b[0] = j; break; } } if (b[0] != 0) break; } for (int j = b[0]; j < b[2]; j++) { sum = 0; for (int i = 0; i < cropContour.Rows; i++) { sum += cropContour.Get(i, j); } if (sum == 0) { b[1] = j; break; } } if (b[3] - b[2] > 500) { if (Math.Abs(b[2] - b[1]) > 50) { cropContour2 = cropContour[0, cropContour.Rows - 1, b[2], cropContour.Cols - 1]; border = b[2]; } else cropContour2 = cropContour[0, cropContour.Rows - 1, 0, cropContour.Cols - 1]; } else { cropContour2 = cropContour[0, cropContour.Rows - 1, b[0], cropContour.Cols - 1]; border = b[0]; } break; default: break; } } /// /// 针对双层深盲孔进行裁剪,上面空白区域较小,因此从第0行开始 /// /// /// /// public void CropShenmangkongShuangceng(Mat image, out int[] y, out Mat cropContour, bool isCropFlag) { Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); Cv2.MorphologyEx(image, image, MorphTypes.Open, se); int range = 200; if (isCropFlag) range = 15; y = new int[2] { 0, 0 }; for (int i = 0; i < image.Rows; i++) { for (int j = range; j < image.Cols - range; j++) { if (image.Get(i, j) > 0) { y[0] = i - 10; break; } } if (y[0] != 0) break; } for (int i = image.Rows - 1; i > y[0]; i--) { for (int j = range; j < image.Cols - range; j++) { if (image.Get(i, j) > 0) { y[1] = i + 10; break; } } if (y[1] != 0) break; } cropContour = image[y[0], y[1], 0, image.Cols - 1]; } /// /// 圖片旋轉之後出現白邊,去掉白邊 /// /// /// /// public void CropBothSide(Mat image, out Mat crop, out int range) { range = 50; crop = image[range, image.Rows - range, range, image.Cols - range].Clone(); } //public void CropLight2(Mat image, out int border, out Mat cropImage, string direction) //{ // Mat filter = new Mat(); // Cv2.BilateralFilter(image, filter, 15, 150, 3); // // 增强 // Mat zengqiang = new Mat(); // InputArray kernel = InputArray.Create(new int[3, 3] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } }); // Cv2.Filter2D(filter, zengqiang, -1, kernel); // Cv2.ConvertScaleAbs(zengqiang, zengqiang); // //边缘检测 // Mat grad_x = new Mat(); // Mat grad_x2 = new Mat(); // //Cv2.Sobel(zengqiang, grad_x, MatType.CV_16S, 1, 0); // //Cv2.ConvertScaleAbs(grad_x, grad_x2); // CejuFunction.Sobel(zengqiang, out grad_x2); // ////腐蚀 // //Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(1, 5)); // //Mat erode = new Mat(); // //Cv2.Erode(grad_x2, erode, se); // //开运算 // Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5));// 结构元素 // Mat open = new Mat(); // //Cv2.MorphologyEx(close, openAfterClose,MorphTypes.Open, seOpen); // Cv2.MorphologyEx(grad_x2, open, MorphTypes.Open, seOpen); // ////閉運算 // Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5));// 结构元素 // Mat close = new Mat(); // Cv2.MorphologyEx(open, close, MorphTypes.Close, se); // Mat thresh2 = close.Threshold(0, 1, ThresholdTypes.Otsu); // //填充 // Mat fill = new Mat(); // CejuFunction.Fill(thresh2, out fill, 1); // int[] b = new int[4] { 0, 0, 0, 0 }; // int sum = 0; // border = 0; // cropImage = new Mat(); // switch (direction) // { // case "left": // for (int j = 0; j < fill.Cols; j++) // { // for (int i = 0; i < fill.Rows; i++) // { // if (fill.Get(i, j) > 0) // { // b[0] = j; // break; // } // } // if (b[0] != 0) // break; // } // for (int j = b[0]; j < fill.Cols; j++) // { // sum = 0; // for (int i = 0; i < fill.Rows; i++) // { // sum += fill.Get(i, j); // } // if (sum == 0) // { // b[1] = j; // break; // } // } // for (int j = fill.Cols - 1; j > b[1]; j--) // { // for (int i = 0; i < fill.Rows; i++) // { // if (fill.Get(i, j) > 0) // { // b[3] = j; // break; // } // } // if (b[3] != 0) // break; // } // for (int j = b[3]; j > b[1]; j--) // { // sum = 0; // for (int i = 0; i < fill.Rows; i++) // { // sum += fill.Get(i, j); // } // if (sum == 0) // { // b[2] = j; // break; // } // } // if (b[1] - b[0] > 500) // { // if (Math.Abs(b[2] - b[1]) > 50) // { // cropImage = fill[0, fill.Rows - 1, b[0], b[1]]; // border = b[0]; // } // else // cropImage = fill[0, fill.Rows - 1, 0, fill.Cols - 1]; // } // else // { // cropImage = fill[0, fill.Rows - 1, 0, b[3]]; // border = 0; // } // break; // case "right": // for (int j = fill.Cols - 1; j > 0; j--) // { // for (int i = 0; i < fill.Rows; i++) // { // if (fill.Get(i, j) > 0) // { // b[3] = j; // break; // } // } // if (b[3] != 0) // break; // } // for (int j = b[3]; j > 0; j--) // { // sum = 0; // for (int i = 0; i < fill.Rows; i++) // { // sum += fill.Get(i, j); // } // if (sum == 0) // { // b[2] = j; // break; // } // } // for (int j = 0; j < b[2]; j++) // { // for (int i = 0; i < fill.Rows; i++) // { // if (fill.Get(i, j) > 0) // { // b[0] = j; // break; // } // } // if (b[0] != 0) // break; // } // for (int j = b[0]; j < b[2]; j++) // { // sum = 0; // for (int i = 0; i < fill.Rows; i++) // { // sum += fill.Get(i, j); // } // if (sum == 0) // { // b[1] = j; // break; // } // } // if (b[3] - b[2] > 500) // { // if (Math.Abs(b[2] - b[1]) > 50) // { // cropImage = fill[0, fill.Rows - 1, b[2], fill.Cols - 1]; // border = b[2]; // } // else // cropImage = fill[0, fill.Rows - 1, 0, fill.Cols - 1]; // } // else // { // cropImage = fill[0, fill.Rows - 1, b[0], fill.Cols - 1]; // border = b[0]; // } // break; // default: // break; // } //} /// /// 提取数据的提取区域 /// /// 输入去掉亮光后的图片 /// 输出提取区域dataArea[0]左,dataArea[1]右 /// /// 槽孔的位置方向,left/right public void GetDataArea(Mat cropContour2, out int[] dataArea, string direction) { int[] rowSum = new int[cropContour2.Rows]; int max = 0; int fillBorder = 0; for (int i = 0; i < cropContour2.Rows; i++) { for (int j = 0; j < cropContour2.Cols; j++) rowSum[i] += cropContour2.Get(i, j); } max = rowSum.Max(); for (int i = 0; i < rowSum.Length; i++) { if (rowSum[i] > max - 50) { fillBorder = i; break; } } Mat fill = cropContour2.Clone(); Cv2.Rectangle(fill, new Rect(0, fillBorder, cropContour2.Cols, cropContour2.Rows - fillBorder), new Scalar(1), -1); //提取區域 dataArea = new int[2] { 0, 0 }; int[] colSum = new int[fill.Cols]; for (int j = 100; j < fill.Cols - 100; j++) { for (int i = 0; i < fill.Rows; i++) { colSum[j] += fill.Get(i, j); } } max = colSum.Max(); switch (direction) { case "right": //for (int j = 0; j < colSum.Length; j++) //{ // if (colSum[j] > max - 10) // { // dataArea[0] = j+100; // break; // } //} dataArea[0] = 100; for (int j = dataArea[0] + 100; j < colSum.Length - 100; j++) { if (colSum[j] > max - 10) { dataArea[1] = j; break; } } if (dataArea[1] == 0) dataArea[1] = dataArea[0] + 100; //dataArea[0] = 100; if (dataArea[1] - dataArea[0] > 200) dataArea[1] = dataArea[0] + 200; break; case "left": //for (int j = colSum.Length - 1; j > 0; j--) //{ // if (colSum[j] > max - 10) // { // dataArea[1] = j+100; // break; // } //} dataArea[1] = cropContour2.Cols - 100; for (int j = dataArea[1] - 100; j > 100; j--) { if (colSum[j] > max - 10) { dataArea[0] = j; break; } } if (dataArea[0] == 0) dataArea[0] = dataArea[1] - 100; //dataArea[1] = cropContour2.Cols - 100; if (dataArea[1] - dataArea[0] > 200) dataArea[0] = dataArea[1] - 200; break; } } /// /// 得到浅盲孔的数据提取区域 /// /// 裁剪后的二值图像 /// 输出提取区域,从左至右分别是[0][1][2][3] public void GetMangkongDataAreaForQian(Mat cropContour, out int[] dataArea) { dataArea = new int[4]; int[] middleArea = new int[2]; int[] sum = new int[cropContour.Cols]; //每列求和 for (int j = 0; j < cropContour.Cols; j++) { sum[j] = 0; for (int i = 0; i < cropContour.Rows; i++) { sum[j] += cropContour.Get(i, j); } } //求中部区域 int max = sum.Max(); for (int j = 0; j < sum.Length; j++) { if (sum[j] > max - 10) { middleArea[0] = j; break; } } for (int j = sum.Length - 1; j > 0; j--) { if (sum[j] > max - 10) { middleArea[1] = j; break; } } //第一次容错 if(middleArea[1]- middleArea[0] < 100) { for (int j = 0; j < sum.Length; j++) { if (sum[j] > max - 20) { middleArea[0] = j; break; } } for (int j = sum.Length - 1; j > 0; j--) { if (sum[j] > max - 20) { middleArea[1] = j; break; } } } //每行求和 int[] rowsSum = new int[cropContour.Rows]; for (int i = 0; i < cropContour.Rows; i++) { rowsSum[i] = 0; for (int j = 0; j < cropContour.Cols; j++) { rowsSum[i] += cropContour.Get(i, j); } } //得到填充上界,其下填为0 max = rowsSum.Max(); int fillBorder = new int(); for (int i = 0; i < rowsSum.Length; i++) { if (rowsSum[i] > max / 2) { fillBorder = i; break; } } Mat fill = cropContour.Clone(); Cv2.Rectangle(fill, new Rect(0, fillBorder, cropContour.Cols, cropContour.Rows - fillBorder), new Scalar(1), -1); //每列求和 int[] colSum = new int[fill.Cols]; for (int j = 0; j < fill.Cols; j++) { colSum[j] = 0; for (int i = 0; i < fill.Rows; i++) { colSum[j] += fill.Get(i, j); } } //左,右最大值 int[] left = colSum.Skip(middleArea[0] - 500).Take(500).ToArray(); int[] right = colSum.Skip(middleArea[1]).Take(500).ToArray(); int leftMax = left.Max(); int rightMax = right.Max(); //数据提取区域 int range = 100; if (colSum[middleArea[0] - 100] < leftMax - 10 || colSum[middleArea[1] + 100] < rightMax - 10) range = 0; for (int j = middleArea[0] - range; j > middleArea[0] - 500 && j > 0; j--) { if (colSum[j] > leftMax - 10) { dataArea[1] = j; break; } } if (dataArea[1] == 0) dataArea[1] = leftMax; for (int j = dataArea[1] - 100; j < dataArea[1]; j++) { if (colSum[j] > leftMax - 10) { dataArea[0] = j; break; } } for (int j = middleArea[1] + range; j < middleArea[1] + 500; j++) { if (colSum[j] > rightMax - 5) { dataArea[2] = j; break; } } for (int j = dataArea[2] + 100; j > dataArea[2]; j--) { if (colSum[j] > rightMax - 5) { dataArea[3] = j; break; } } if (dataArea[1] == 0) { dataArea[1] = middleArea[0] - 70;//不加100是因为出去还要加20 dataArea[0] = dataArea[1] - 100; } if (dataArea[0] == 0) { dataArea[0] = dataArea[1] - 100; if (colSum[dataArea[0]] < leftMax - 10) dataArea[0] = dataArea[1] - 30; } if (dataArea[2] == 0) { dataArea[2] = middleArea[1] + 70;//不加100是因为出去还要加20 dataArea[3] = dataArea[2] + 100; } if (dataArea[3] == 0) { dataArea[3] = dataArea[2] + 100; if (colSum[dataArea[3]] < rightMax - 10)//防止加完出界 dataArea[3] = dataArea[2] + 30; } if (dataArea[1] - dataArea[0] < 50) dataArea[1] += 50; if (dataArea[3] - dataArea[2] < 50) dataArea[2] -= 50; } /// /// 得到浅盲孔的数据提取区域 /// /// 裁剪后的二值图像 /// 输出提取区域,从左至右分别是[0][1][2][3] public void GetMangkongDataArea(Mat cropContour, out int[] dataArea) { dataArea = new int[4]; int[] middleArea = new int[2]; int[] sum = new int[cropContour.Cols]; //每列求和 for (int j = 0; j < cropContour.Cols; j++) { sum[j] = 0; for (int i = 0; i < cropContour.Rows; i++) { sum[j] += cropContour.Get(i, j); } } //求中部区域 int max = sum.Max(); for (int j = 0; j < sum.Length; j++) { if (sum[j] > max - 20) { middleArea[0] = j; break; } } for (int j = sum.Length - 1; j > 0; j--) { if (sum[j] > max - 20) { middleArea[1] = j; break; } } //第一次容错 if (middleArea[1] - middleArea[0] < 110) { for (int j = 0; j < sum.Length; j++) { if (sum[j] > max - 80) { middleArea[0] = j; break; } } for (int j = sum.Length - 1; j > 0; j--) { if (sum[j] > max - 80) { middleArea[1] = j; break; } } } //每行求和 int[] rowsSum = new int[cropContour.Rows]; for (int i = 0; i < cropContour.Rows; i++) { rowsSum[i] = 0; for (int j = 0; j < cropContour.Cols; j++) { rowsSum[i] += cropContour.Get(i, j); } } //得到填充上界,其下填为0 max = rowsSum.Max(); int fillBorder = new int(); for (int i = 0; i < rowsSum.Length; i++) { if (rowsSum[i] > max / 2) { fillBorder = i; break; } } Mat fill = cropContour.Clone(); Cv2.Rectangle(fill, new Rect(0, fillBorder, cropContour.Cols, cropContour.Rows - fillBorder), new Scalar(1), -1); //每列求和 int[] colSum = new int[fill.Cols]; for (int j = 0; j < fill.Cols; j++) { colSum[j] = 0; for (int i = 0; i < fill.Rows; i++) { colSum[j] += fill.Get(i, j); } } //左,右最大值 int[] left = colSum.Skip(middleArea[0] - 500).Take(500).ToArray(); int[] right = colSum.Skip(middleArea[1]).Take(500).ToArray(); int leftMax = left.Max(); int rightMax = right.Max(); //数据提取区域 int range = 100; if (colSum[middleArea[0] - 100] < leftMax - 10 || colSum[middleArea[1] + 100] < rightMax - 10) range = 0; for (int j = middleArea[0] - range; j > middleArea[0] - 500 && j > 0; j--) { if (colSum[j] > leftMax - 10) { dataArea[1] = j; break; } } for (int j = dataArea[1] - 100; j < dataArea[1]; j++) { if (colSum[j] > leftMax - 10) { dataArea[0] = j; break; } } for (int j = middleArea[1] + range; j < middleArea[1] + 500; j++) { if (colSum[j] > rightMax - 5) { dataArea[2] = j; break; } } for (int j = dataArea[2] + 100; j > dataArea[2]; j--) { if (colSum[j] > rightMax - 5) { dataArea[3] = j; break; } } if (dataArea[1] == 0) { dataArea[1] = middleArea[0] - 70;//不加100是因为出去还要加20 dataArea[0] = dataArea[1] - 100; } if (dataArea[0] == 0) { dataArea[0] = dataArea[1] - 100; if (colSum[dataArea[0]] < leftMax - 10) dataArea[0] = dataArea[1] - 30; } if (dataArea[2] == 0) { dataArea[2] = middleArea[1] + 70;//不加100是因为出去还要加20 dataArea[3] = dataArea[2] + 100; } if (dataArea[3] == 0) { dataArea[3] = dataArea[2] + 100; if (colSum[dataArea[3]] < rightMax - 10)//防止加完出界 dataArea[3] = dataArea[2] + 30; } if (dataArea[1] - dataArea[0] < 50) dataArea[1] += 50; if (dataArea[3] - dataArea[2] < 50) dataArea[2] -= 50; } /// /// 提取第一條橫綫縱坐標 /// /// 輸入二值化圖像 /// 輸出坐標 /// 左邊界 /// 右边界 /// 大于等于0时,记录大于0的点,小于0记录等于零的点 public void ExtractLines(Mat image, out double averageCoordinateNew, int leftBorder, int rightBorder, int direction) { //数组长宽 int rows = image.Rows; int cols = image.Cols; int count = 0; int sum = 0; // 对循环次数计数,防止程序卡死 int circleCount = 0; //当点的个数少于5的时候循环 while (count < 5) { count = 0; sum = 0; //每次循环,寻找范围向下移动5个像素 //遍历,寻找线条上的点,并记录纵坐标 for (int j = leftBorder; j < rightBorder; j++) { for (int i = 0; i < rows; i++) { if (direction >= 0) { if (image.Get(i, j) > 0) { sum += i; count++; break; } } else { if (image.Get(i, j) == 0) { sum += i; count++; break; } } } } // 超过30次跳出 if(circleCount <= 30) { circleCount++; } else { break; } } averageCoordinateNew = sum / count; } /// /// 提取非第一条横线纵坐标 /// /// 输入二值化图像 /// 输出纵坐标 /// 左边界 /// 右边界 /// 上一条线的坐标 /// 大于等于0时,记录大于0的点,小于0时记录等于零的点 public void ExtractLines(Mat image, out double averageCoordinateNew, int leftBorder, int rightBorder, double averageCoordinate, int direction) { //ImageShow(image*255); //数组长宽 int rows = image.Rows; int cols = image.Cols; int count = 0; int sum = 0; int upperBound = (int)averageCoordinate + 15; int lowerBound = (int)averageCoordinate + 45; //当点的个数少于5的时候循环 while (count < 5) { count = 0; sum = 0; //每次循环,寻找范围向下移动5个像素 upperBound = upperBound + 5; lowerBound = lowerBound + 5; if (lowerBound > image.Rows) break; //遍历,寻找线条上的点,并记录纵坐标 int value = 0; for (int j = leftBorder; j < rightBorder; j++) { for (int i = upperBound; i < lowerBound; i++) { if (direction >= 0) { value = image.Get(i, j); if (value > 0) { sum += i; count++; break; } } else { if (image.Get(i, j) == 0) { sum += i; count++; break; } } } } } averageCoordinateNew = count == 0 ? 0 : sum / count; } /// /// 从下向上提取第一条横线纵坐标 /// /// 輸入二值化圖像 /// 輸出坐標 /// 左邊界 /// 右边界 /// 大于等于0时,记录大于0的点,小于0记录等于零的点 public void ExtractLines2(Mat image, out double averageCoordinateNew, int leftBorder, int rightBorder, int direction) { //数组长宽 int rows = image.Rows; int cols = image.Cols; int count = 0; int sum = 0; int tag = 0; //当点的个数少于5的时候循环 while (count < 5) { count = 0; sum = 0; //每次循环,寻找范围向下移动5个像素 //遍历,寻找线条上的点,并记录纵坐标 for (int j = leftBorder; j < rightBorder; j++) { for (int i = rows - 1; i > 0; i--) { if (i == 1) tag += 1; if (direction >= 0) { if (image.Get(i, j) > 0) { sum += i; count++; break; } } else { if (image.Get(i, j) == 0) { sum += i; count++; break; } } } if (tag == 3) break; } if (tag == 3) break; } averageCoordinateNew = (count == 0) ? 0 : sum / count; } /// /// 从下向上提取横线纵坐标 /// /// 输入二值化图像 /// 输出纵坐标 /// 左边界 /// 右边界 /// 上一条线的坐标 /// 大于等于0时,记录大于0的点,小于0时记录等于零的点 public void ExtractLines2(Mat image, out double averageCoordinateNew, int leftBorder, int rightBorder, double averageCoordinate, int direction) { //数组长宽 int rows = image.Rows; int cols = image.Cols; int sum = 0, count = 0; //遍历范围的上界和下界 int upperBound = (int)averageCoordinate - 45; int lowerBound = (int)averageCoordinate - 10; //当点的个数少于5的时候循环 while (count < 5) { count = 0; sum = 0; //每次循环,寻找范围向下移动5个像素 upperBound = upperBound - 5; lowerBound = lowerBound - 5; if (upperBound < 0) break; //遍历,寻找线条上的点,并记录纵坐标 for (int j = leftBorder; j < rightBorder; j++) { for (int i = lowerBound; i > upperBound; i--) { if (direction >= 0) { if (image.Get(i, j) > 0) { sum += i; count++; break; } } else { if (image.Get(i, j) == 0) { sum += i; count++; break; } } } } } averageCoordinateNew = count==0 ? 0 : sum / count; } /// /// 提取第一条竖线的横坐标,从左往右 /// /// 输入二值图像 /// 输出坐标结果 /// 上边界 /// 下边界 public void ExtractVerticalLinesL2R(Mat image, out double result, int upperBound, int lowerBound, int showMat = 0) { int rows = image.Rows; int cols = image.Cols; List sum = new List(); int k = 0; while (sum.Count == 0) { if (upperBound - 5 * k < 0 || lowerBound + 5 * k > image.Rows) break; //解决两层板有些孔铜找不到的问题 for (int i = upperBound - 5 * k; i < lowerBound + 5 * k; i++) { for (int j = 0; j < cols; j++) { if (image.Get(i, j) > 0) { sum.Add(j); break; } } } ++k; } ////int count = 0; //for (int i = upperBound; i < lowerBound; i++) //{ // for (int j = 0; j < cols; j++) // { // if (image.Get(i, j) > 0) // { // sum.Add(j); // //sum += j; // //count++; // break; // } // } //} //if (sum.Count == 0) // result = 1;// 0; //else result = sum.Average();// / count; //if (showMat > 0) //{ // Mat imageClone = image.Clone() * 127; // Cv2.Line(imageClone, 0, upperBound, cols - 1, upperBound, new Scalar(255)); // Cv2.Line(imageClone, 0, lowerBound, cols - 1, lowerBound, new Scalar(255)); // Cv2.ImWrite(@"C:\Users\54434\Desktop\imageClone_" + showMat + ".png", imageClone); //} //////对自动结果不正确(这里使用距离过远来判定)的扩展运算 ////double result1 = 0; if (showMat > 0 && result > 20/*countV > (upperBound + lowerBound) / 2*/) { sum.Clear(); //sum = 0; //count = 0; ////Mat imageClone = image.Clone() * 127; ////Cv2.Line(imageClone, 0, upperBound, cols - 1, upperBound, new Scalar(255)); ////Cv2.Line(imageClone, 0, lowerBound, cols - 1, lowerBound, new Scalar(255)); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\imageClone_" + showMat + ".png", imageClone); //////int sum = 0; //////int count = 0; bool sumAdd = false; for (int i = upperBound - 5; i < lowerBound + 5; i++) { sumAdd = false; for (int j = 0; j < 20; j++) { if (image.Get(i, j) > 0) { sumAdd = true; sum.Add(j); //sum += j; //count++; break; } } if (!sumAdd && sum.Count > 0) break; } if (sum.Count == 0) { for (int i = upperBound - 5; i < lowerBound + 5; i++) { sumAdd = false; for (int j = 0; j < 26; j++) { if (image.Get(i, j) > 0) { sumAdd = true; sum.Add(j); //sum += j; //count++; break; } } if (!sumAdd && sum.Count > 0) break; } //for (int i = upperBound - 5; i < lowerBound + 5; i++) //{ // sumAdd = false; // for (int j = cols - 1; j > cols - 26; j--) // { // if (image.Get(i, j) > 0) // { // sumAdd = true; // sum += j; // count++; // break; // } // } // if (!sumAdd && sum > 0) // break; //} } // 输出平均横坐标 if (sum.Count > 0) result = sum.Average();// / count; } else if (showMat > 0) {//对自动结果不正确(这里使用垂直方向不整齐来判定)的扩展运算 sum.Sort(); for (int i = 0; i < sum.Count - 1; i++) { if (sum[i + 1] - sum[i] > 10) { for (int j = sum.Count - 1; j > i; j--) sum.RemoveAt(j); break; } } // 输出平均横坐标 if (sum.Count > 0) result = sum.Average();// / count; //Mat imageClone = image.Clone() * 127; //Cv2.Line(imageClone, 0, upperBound, cols - 1, upperBound, new Scalar(255)); //Cv2.Line(imageClone, 0, lowerBound, cols - 1, lowerBound, new Scalar(255)); //Cv2.ImWrite(@"C:\Users\54434\Desktop\imageClone_" + showMat + ".png", imageClone); } ////对自动结果不正确(这里使用距离过远来判定)的扩展运算 //double result1 = 0; //// 输出平均横坐标 //result = sum / count; } /// /// 提取第二条竖线的横坐标,从左往右 /// /// 输入二值图像 /// 输出坐标结果 /// 上边界 /// 下边界 /// 第一条线的横坐标 public int[] ExtractVerticalLinesL2R(Mat image, out double result, int upperBound, int lowerBound, double basic, bool cal_Jiaoneisuo = true) { int rows = image.Rows; int cols = image.Cols; int sum = 0; int count = 0; // 寻找的左右范围 int leftBound = (int)basic + 15; int rightBound = (int)basic + 45; int countUp = 5; if (!cal_Jiaoneisuo) countUp = 1; //当点的个数少于5的时候循环 while (count < countUp) { count = 0; sum = 0; //每次循环,寻找范围向左移动5个像素 leftBound = leftBound + 5; rightBound = rightBound + 5; if (rightBound > image.Cols) break; //遍历,寻找线条上的点,并记录横坐标 for (int i = upperBound; i < lowerBound; i++) {//待自测scc-1 //bool isWhiteArea = false;//避免弧度大,导致找的位置与角落的弧度相交 for (int j = leftBound; j < rightBound; j++) { //if (!isWhiteArea) //{ // if (image.Get(i, j) > 0) // isWhiteArea = true; //}else if (image.Get(i, j) == 0) { sum += j; count++; break; } } } } leftBound = (int)basic + 15; rightBound = (int)basic + 145; if (rightBound >= cols) rightBound = cols - 1; double y1 = upperBound; double x1 = leftBound; for (int i = upperBound + 20; i < lowerBound - 20; i++) { for (int j = leftBound; j < rightBound; j++) { if (image.Get(i, j) == 0) { if (x1 < j) { x1 = j; y1 = i; } break; } } } result = sum / count; return new int[] { (int)x1, (int)y1 }; } /// /// 从右往左提取第一条竖线横坐标 /// /// 输入二值图像 /// 输出坐标结果 /// 上边界 /// 下边界 public void ExtractVerticalLinesR2L(Mat image, out double result, int upperBound, int lowerBound, int showMat = 0) { int rows = image.Rows; int cols = image.Cols; int sum = 0; int count = 0; int countV = 0; for (int i = upperBound; i < lowerBound; i++) { for (int j = cols - 1; j > 0; j--) { if (image.Get(i, j) > 0) { sum += j; count++; break; } } if (sum == 0) countV = i; } result = sum / count; ////对自动结果不正确(这里使用距离过远来判定)的扩展运算 //double result1 = 0; if (showMat > 0 && cols - result > 20/*countV > (upperBound + lowerBound) / 2*/) { sum = 0; count = 0; //Mat imageClone = image.Clone() * 127; //Cv2.Line(imageClone, 0, upperBound, cols - 1, upperBound, new Scalar(255)); //Cv2.Line(imageClone, 0, lowerBound, cols - 1, lowerBound, new Scalar(255)); //Cv2.ImWrite(@"C:\Users\54434\Desktop\imageClone_" + showMat + ".png", imageClone); ////int sum = 0; ////int count = 0; bool sumAdd = false; for (int i = upperBound - 5; i < lowerBound + 5; i++) { sumAdd = false; for (int j = cols - 1; j > cols - 20; j--) { if (image.Get(i, j) > 0) { sumAdd = true; sum += j; count++; break; } } if (!sumAdd && sum > 0) break; } if (sum == 0) { for (int i = upperBound - 5; i < lowerBound + 5; i++) { sumAdd = false; for (int j = cols - 1; j > cols - 26; j--) { if (image.Get(i, j) > 0) { sumAdd = true; sum += j; count++; break; } } if (!sumAdd && sum > 0) break; } } // 输出平均横坐标 if (sum > 0) result = sum / count; } //// 输出平均横坐标 //if (true) //{ //} //result = sum / count; } /// /// 提取第二条竖线的横坐标,从右往左 /// /// 输入二值图像 /// 输出坐标结果 /// 上边界 /// 下边界 /// 第一条线的横坐标 public int[] ExtractVerticalLinesR2L(Mat image, out double result, int upperBound, int lowerBound, double basic, int showMat = 0) { int rows = image.Rows; int cols = image.Cols; int sum = 0; int count = 0; // 寻找的左右范围 int leftBound = (int)basic - 45; int rightBound = (int)basic - 15; //if (showMat > 0) //{ // Mat imageClone = image.Clone() * 127; // Cv2.Line(imageClone, leftBound, upperBound, rightBound - 1, upperBound, new Scalar(255)); // Cv2.Line(imageClone, leftBound, lowerBound, rightBound - 1, lowerBound, new Scalar(255)); // Cv2.ImWrite(@"C:\Users\54434\Desktop\imageClone_" + showMat + ".png", imageClone); //} //当点的个数少于5的时候循环 while (count < 5) { count = 0; sum = 0; //每次循环,寻找范围向左移动5个像素 leftBound = leftBound - 5; rightBound = rightBound - 5; //遍历,寻找线条上的点,并记录横坐标 for (int i = upperBound; i < lowerBound; i++) {//待自测scc-1 //bool isWhiteArea = false;//避免弧度大,导致找的位置与角落的弧度相交 ////(showMat > 0) for (int j = rightBound - 1; j > leftBound; j--) { //if ((showMat > 0) && !isWhiteArea) //{ // if (image.Get(i, j) > 0) // isWhiteArea = true; //} //else if (image.Get(i, j) == 0) { sum += j; count++; break; } } } } //if (count == 0) //{ //} leftBound = (int)basic - 145; if (leftBound < 0) leftBound = 0; rightBound = (int)basic - 15; double y1 = upperBound; double x1 = rightBound; //遍历,寻找线条上的点,并记录横坐标 for (int i = upperBound + 20; i < lowerBound - 20; i++) { for (int j = rightBound - 1; j > leftBound; j--) { if (image.Get(i, j) == 0) { if (x1 > j) { x1 = j; y1 = i; } break; } } } result = sum / count; return new int[] { (int)x1, (int)y1 }; } /// /// 提取三层板的粗糙度以及粗糙度的坐标 /// /// 二值图像 /// 红色通道图片 /// 第三条横线 /// 第四条横线 /// 第五条横线 /// 第六条横线 /// 第二条竖线 /// 第四条竖线 /// 数据提取区域 /// 槽孔所在左右方向,left、right /// 输出粗糙度 /// 输出粗糙度坐标 public void GetSancengRoughness(Mat imageContour, Mat imageRed, int ordinateL3, int ordinateL4, int ordinateL5, int ordinateL6, int ordinateV2, int ordinateV4, int[] dataArea, string direction, out int roughness, out int[] roughnessOrdinate) { int leftBorder1 = 0, rightBorder1 = 0, leftBorder2 = 0, rightBorder2 = 0; int range = 70; switch (direction) { case "right": leftBorder1 = ordinateV2; rightBorder1 = ordinateV2 + range; leftBorder2 = ordinateV4; rightBorder2 = ordinateV4 + range; break; case "left": leftBorder1 = ordinateV2 - range; rightBorder1 = ordinateV2; leftBorder2 = ordinateV4 - range; rightBorder2 = ordinateV4; break; } int sum = 0, count = 0; double averSaturation1 = 0, averSaturation2 = 0; roughness = 0; roughnessOrdinate = new int[4] { 0, 0, 0, 0 }; Mat sobel = new Mat(); Sobel(imageContour, out sobel); //计算粗糙度 int max = 0; //先上下遍历一遍寻找最大值,避免找不到胶体 for (int i = (int)ordinateL3 + 20; i < (int)ordinateL4 - 15; i++) { for (int j = leftBorder1; j < rightBorder1; j++) { if (sobel.Get(i, j) > 0) { if (Math.Abs(j - (int)(ordinateV2)) > max) { max = Math.Abs(j - (int)(ordinateV2)); roughnessOrdinate[0] = (int)ordinateV2; roughnessOrdinate[1] = i; roughnessOrdinate[2] = j; roughnessOrdinate[3] = i; } } } } for (int i = (int)ordinateL5 + 15; i < (int)ordinateL6 - 10; i++) { for (int j = leftBorder2; j < rightBorder2; j++) { if (sobel.Get(i, j) > 0) { if (Math.Abs(j - (ordinateV4)) > max) { max = Math.Abs(j - (ordinateV4)); roughnessOrdinate[0] = (int)ordinateV4; roughnessOrdinate[1] = i; roughnessOrdinate[2] = j; roughnessOrdinate[3] = i; } } } } roughness = max; if (roughness < 10) { //判断胶体方向 Cv2.EqualizeHist(imageRed, imageRed); Mat upperCrop = imageRed[(int)ordinateL3 + 10, (int)ordinateL4 - 10, dataArea[0], dataArea[1]]; Mat lowerCrop = imageRed[(int)ordinateL5 + 10, (int)ordinateL6 - 10, dataArea[0], dataArea[1]]; //Mat duibi = new Mat(upperCrop.Size().Height + lowerCrop.Size().Height, upperCrop.Size().Width, upperCrop.Type()); //upperCrop.CopyTo(duibi[0, upperCrop.Size().Height - 1, 0, upperCrop.Size().Width - 1]); //lowerCrop.CopyTo(duibi[upperCrop.Size().Height, duibi.Size().Height - 1, 0, upperCrop.Size().Width - 1]); //new Window("upperCrop", WindowMode.Normal, upperCrop); //new Window("lowerCrop", WindowMode.Normal, lowerCrop); //new Window("imageRed", WindowMode.Normal, imageRed); //Cv2.WaitKey(); //Cv2.EqualizeHist(duibi, duibi); //Scalar s1 = duibi[0, upperCrop.Size().Height - 1, 0, upperCrop.Size().Width - 1].Sum(); //Scalar s2 = duibi[upperCrop.Size().Height, duibi.Size().Height - 1, 0, upperCrop.Size().Width - 1].Sum(); Scalar s1 = upperCrop.Sum(); Scalar s2 = lowerCrop.Sum(); averSaturation1 = (double)s1 / (upperCrop.Cols * upperCrop.Rows); averSaturation2 = (double)s2 / (lowerCrop.Cols * lowerCrop.Rows); for (int i = 0; i < upperCrop.Rows; i++) { for (int j = 0; j < upperCrop.Cols; j++) { sum += Math.Abs(upperCrop.Get(i, j) - (int)averSaturation1); } } double biaozhuncha1 = sum / (upperCrop.Cols * upperCrop.Rows); sum = 0; for (int i = 0; i < lowerCrop.Rows; i++) { for (int j = 0; j < lowerCrop.Cols; j++) { sum += Math.Abs(lowerCrop.Get(i, j) - (int)averSaturation2); } } double biaozhuncha2 = sum / (lowerCrop.Cols * lowerCrop.Rows); int direction2 = 0; if (biaozhuncha1 > biaozhuncha2) direction2 = 0;//等于0时说明胶体在上面,否则是下面 else direction2 = 1; switch (direction2) { case 0: for (int i = (int)ordinateL3 + 10; i < (int)ordinateL4 - 15; i++) { for (int j = leftBorder1; j < rightBorder1; j++) { if (sobel.Get(i, j) > 0) { if (Math.Abs(j - (int)(ordinateV2)) > max) { max = Math.Abs(j - (int)(ordinateV2)); roughnessOrdinate[0] = (int)ordinateV2; roughnessOrdinate[1] = i; roughnessOrdinate[2] = j; roughnessOrdinate[3] = i; } } } } roughness = max; break; case 1: for (int i = (int)ordinateL5 + 15; i < (int)ordinateL6 - 10; i++) { for (int j = leftBorder2; j < rightBorder2; j++) { if (sobel.Get(i, j) > 0) { if (Math.Abs(j - (int)(ordinateV4)) > max) { max = Math.Abs(j - (int)(ordinateV4)); roughnessOrdinate[0] = (int)ordinateV4; roughnessOrdinate[1] = i; roughnessOrdinate[2] = j; roughnessOrdinate[3] = i; } } } } roughness = max; break; } } } /// /// 提取四层板的粗糙度 /// /// 二值图像 /// 上界 /// 下界 /// 边缘线 /// 槽孔所在左右方向,left、right /// 输出粗糙度 /// 输出粗糙度坐标 public void GetSicengRoughness(Mat imageContour, int upperBorder, int lowerBorder, int basic, string direction, out int roughness, out int[] roughnessOrdinate) { int leftBorder = 0, rightBorder = 0; int range = 70; switch (direction) { case "right": leftBorder = basic; rightBorder = basic + range; break; case "left": leftBorder = basic - range; rightBorder = basic; break; } int max = 0; roughness = 0; roughnessOrdinate = new int[4]; Mat sobel = new Mat(); Sobel(imageContour, out sobel); for (int i = upperBorder; i < lowerBorder; i++) { for (int j = leftBorder; j < rightBorder; j++) { if (sobel.Get(i, j) > 0) { if (Math.Abs(j - basic) > max) { max = Math.Abs(j - basic); roughnessOrdinate[0] = basic; roughnessOrdinate[1] = i; roughnessOrdinate[2] = j; roughnessOrdinate[3] = i; } } } } roughness = max; } public void GetNewKongtong(Mat imageRed, Mat imageContour, int[] leftAperture, int[] rightAperture, double leftOrdinateMiantong, int leftMiddleMianJicaitong, double leftOrdinate3, double rightOrdinateMiantong, int rightMiddleMianJicaitong, double rightOrdinate3, out double[] kongtong, out int[] leftKongtong, out int[] rightKongtong, out int[] leftPoint2, out int[] rightPoint2) { kongtong = new double[2]; leftKongtong = new int[2]; rightKongtong = new int[2]; leftPoint2 = new int[2]; rightPoint2 = new int[2]; #region//左侧 Mat leftCrop = imageRed[(int)leftOrdinateMiantong + 40, (int)leftOrdinate3 - 10, leftMiddleMianJicaitong, leftAperture[1]].Clone(); Mat leftContour = new Mat(); double t = Cv2.Threshold(leftCrop, leftContour, 0, 1, ThresholdTypes.Otsu); Mat leftFanse = 1 - leftContour; InputArray leftKernel = InputArray.Create(new int[17, 17] { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, }); InputArray leftKernel2 = InputArray.Create(new int[17, 17] { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }, }); InputArray leftKernel3 = InputArray.Create(new int[17, 17] { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1 }, }); Mat leftFilter = new Mat(); //Cv2.Filter2D(leftFanse, leftFilter, -1, leftKernel, new Point(-1, -1), 0); //Cv2.Filter2D(leftFanse, leftFilter, -1, leftKernel2, new Point(-1, -1), 0); Cv2.Filter2D(leftFanse, leftFilter, -1, leftKernel3, new Point(-1, -1), 0); Mat leftThresh = leftFilter.Threshold(14, 1, ThresholdTypes.Binary); for (int j = leftThresh.Cols - 1; j > 0; j--)//从右上角,以135°方向遍历 { for (int k = j; k < leftThresh.Cols && (k - j < leftThresh.Rows); k++) { if (leftThresh.Get(k - j, k) > 0) { leftKongtong[0] = k - j + (int)leftOrdinateMiantong + 40;//纵 leftKongtong[1] = k + leftMiddleMianJicaitong;//横 //Cv2.Circle(imageRed, k + leftMiddleMianJicaitong + border, k - j + (int)leftOrdinateMiantong + upper - 10, 1, 1, 1); //new Window("imageRed_Line", WindowMode.Normal, imageRed); break; } } if (leftKongtong[0] != 0) break; } #endregion #region//右侧 Mat rightCrop = imageRed[(int)rightOrdinateMiantong + 40, (int)rightOrdinate3 - 10, rightAperture[1], rightMiddleMianJicaitong].Clone(); Mat rightContour = new Mat(); double t1 = Cv2.Threshold(rightCrop, rightContour, 0, 1, ThresholdTypes.Otsu); Mat rightFanse = 1 - rightContour; InputArray rightKernel = InputArray.Create(new int[17, 17] { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, }); InputArray rightKernel2 = InputArray.Create(new int[17, 17] { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, { 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, }); InputArray rightKernel3 = InputArray.Create(new int[17, 17] { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, { 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, }); Mat rightFilter = new Mat(); //Cv2.Filter2D(rightFanse, rightFilter, -1, rightKernel, new Point(-1, -1), 0); //Cv2.Filter2D(rightFanse, rightFilter, -1, rightKernel2, new Point(-1, -1), 0); Cv2.Filter2D(rightFanse, rightFilter, -1, rightKernel3, new Point(-1, -1), 0); Mat rightThresh = rightFilter.Threshold(14, 1, ThresholdTypes.Binary); for (int j = 0; j < rightThresh.Cols; j++)//从左上角,45°方向遍历 { for (int k = j; k >= 0 && j - k < rightThresh.Rows; k--) { if (rightThresh.Get(j - k, k) > 0) { rightKongtong[0] = j - k + (int)rightOrdinateMiantong + 40; rightKongtong[1] = k + rightAperture[1]; //Cv2.Circle(imageRed, k + rightAperture[1], k - j + (int)rightOrdinateMiantong + upper - 10, 1, 1, 1); //new Window("imageRed_Line", WindowMode.Normal, imageRed); break; } } if (rightKongtong[0] != 0) break; } #endregion //ImageShow(leftCrop, leftContour * 255, /*rightContour * 255, */leftThresh * 255/*, rightThresh * 255*/); //Cv2.Circle(imageRed, new Point(leftKongtong[1], leftKongtong[0]), 10, new Scalar(0), 2); //Cv2.Circle(imageRed, new Point(rightKongtong[1], rightKongtong[0]), 10, new Scalar(0), 2); ////ImageShow(imageRed); GetKongtong(imageContour, leftKongtong, rightKongtong, out kongtong, out leftPoint2, out rightPoint2); //LineShow(imageRed, leftKongtong[1], leftKongtong[0], leftPoint2[1], leftPoint2[0]); //LineShow(imageRed, rightKongtong[1], rightKongtong[0], rightPoint2[1], rightPoint2[0]); //ImageShow(imageRed); //leftKongtong[0] -= upper; //rightKongtong[0] -= upper; //leftPoint2[0] -= upper; //rightPoint2[0] -= upper; if(rightFilter != null) { rightFilter.Dispose(); } } /// /// 计算孔铜 /// /// 二值图 /// 左孔径坐标 /// 右孔径坐标 /// 输出左右孔铜的距离 /// 左孔铜对应边缘线的坐标 /// 右孔铜对应边缘线的坐标 public void GetKongtong(Mat imageContour, int[] apertureBegin, int[] apertureEnd, out double[] kongtong, out int[] pointLeft, out int[] pointRight) { //曲面上点的坐标 int count = apertureEnd[1] - apertureBegin[1]; int[,] coordinate = new int[Math.Abs(apertureEnd[1] - apertureBegin[1]), 2];//先纵坐标后横坐标 for (int j = apertureBegin[1]; j < apertureEnd[1]; j++) { for (int i = 0; i < imageContour.Rows; i++) { if (imageContour.Get(i, j) > 0) { coordinate[j - apertureBegin[1], 0] = i; coordinate[j - apertureBegin[1], 1] = j; break; } } } //计算距离,最小的距离分别为左孔铜和右孔铜 double leftKongtong = 1000; double rightKongtong = 1000; double distance1 = 0; double distance2 = 0; //当距离最短是曲线上点的坐标,第一列是纵坐标(行数),第二列是横坐标(列数) pointLeft = new int[2]; pointRight = new int[2]; for (int i = 0; i < count; i++) { //计算曲面点到左起始点的距离 if (i < count / 2) { distance1 = Math.Sqrt(Math.Pow((coordinate[i, 0] - apertureBegin[0]), 2) + Math.Pow((coordinate[i, 1] - apertureBegin[1]), 2)); //计算曲面点到右截止点的距离 if (leftKongtong > distance1) { leftKongtong = distance1; pointLeft[0] = coordinate[i, 0]; pointLeft[1] = coordinate[i, 1]; } } else { distance2 = Math.Sqrt(Math.Pow((coordinate[i, 0] - apertureEnd[0]), 2) + Math.Pow((coordinate[i, 1] - apertureEnd[1]), 2)); //得到左右孔铜以及对应的曲面坐标 if (rightKongtong > distance2) { rightKongtong = distance2; pointRight[0] = coordinate[i, 0]; pointRight[1] = coordinate[i, 1]; } } } kongtong = new double[2] { leftKongtong, rightKongtong }; } public void ShenmangkongNewKongtong(Mat image, Mat imageContour, int leftL2, int rightL2, int[] leftAperture, int[] rightAperture, out double[] kongtong, out int[] leftKongtong, out int[] rightKongtong, out int[] leftPoint2, out int[] rightPoint2) { kongtong = new double[2]; leftKongtong = new int[2]; rightKongtong = new int[2]; leftPoint2 = new int[2]; rightPoint2 = new int[2]; #region//左 Mat leftCrop = image[leftL2 - 10, leftL2 + 20, leftAperture[1] - 30, leftAperture[1] + 5].Clone(); Mat leftThresh = leftCrop.Threshold(0, 1, ThresholdTypes.Otsu); Mat leftFanse = 1 - leftThresh; InputArray leftKernel = InputArray.Create(new int[17, 17] { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 1, 1, 1, 1, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, }); InputArray leftKernel2 = InputArray.Create(new int[17, 17] { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1 }, }); Mat leftFilter1 = new Mat(); Cv2.Filter2D(leftFanse, leftFilter1, -1, leftKernel, new Point(-1, -1), 0); Mat leftFilter2 = new Mat(); Cv2.Filter2D(leftFanse, leftFilter2, -1, leftKernel2, new Point(-1, -1), 0); Mat leftFilter = new Mat(); Cv2.AddWeighted(leftFilter1, 0, leftFilter2, 1, 0, leftFilter); Cv2.Rectangle(leftFilter, new Rect(0, 0, leftFilter.Cols, 5), new Scalar(0), -1); Cv2.Rectangle(leftFilter, new Rect(0, 15, leftFilter.Cols, leftFilter.Rows - 15), new Scalar(0), -1); double min, max; Cv2.MinMaxIdx(leftFilter, out min, out max); Mat leftFilterThresh = leftFilter.Threshold(max - 2, 1, ThresholdTypes.Binary); Cv2.Flip(leftFilterThresh, leftFilterThresh, FlipMode.Y); Point left; FindLeftTop(leftFilterThresh, out left); leftKongtong[0] = left.Y + leftL2 - 10; leftKongtong[1] = leftCrop.Cols - left.X + leftAperture[1] - 30; Mat newLeft = leftFilterThresh.Clone(); newLeft.Set(left.Y, left.X, 255); //ImageShow(leftCrop, leftFilter * 50, leftFilterThresh * 255, newLeft); #endregion #region//右 Mat rightCrop = image[rightL2 - 10, rightL2 + 20, rightAperture[1] - 5, rightAperture[1] + 30].Clone(); Mat rightThresh = rightCrop.Threshold(0, 1, ThresholdTypes.Otsu); Mat rightFanse = 1 - rightThresh; InputArray rightKernel = InputArray.Create(new int[17, 17] { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }, { 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0,-1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 0, 0, 0,-1, 0,-1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 0, 0,-1, 0, 1,-1, 0, 1, 1,-1,-1,-1,-1,-1,-1 }, { 0, 0, 0,-1, 0, 1, 0,-1, 0, 1, 1,-1,-1,-1,-1,-1,-1 }, { 0, 0,-1, 0, 1, 0, 0,-1, 0, 1, 1,-1,-1,-1,-1,-1,-1 }, { 0,-1, 0, 1, 0, 0, 0,-1, 0, 1, 1,-1,-1,-1,-1,-1,-1 }, { -1, 0, 1, 0, 0, 0, 0,-1, 0, 1, 1,-1,-1,-1,-1,-1,-1 }, { 0, 1, 0, 0, 0, 0, 0,-1, 0, 1, 1,-1,-1,-1,-1,-1,-1 }, }); InputArray rightKernel2 = InputArray.Create(new int[17, 17] { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, { 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, { 1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 }, }); Mat rightFilter1 = new Mat(); Cv2.Filter2D(rightFanse, rightFilter1, -1, rightKernel, new Point(-1, -1), 0); Mat rightFilter2 = new Mat(); Cv2.Filter2D(rightFanse, rightFilter2, -1, rightKernel2, new Point(-1, -1), 0); Mat rightFilter = new Mat(); Cv2.AddWeighted(rightFilter1, 0, rightFilter2, 1, 0, rightFilter); Cv2.Rectangle(rightFilter, new Rect(0, 0, rightFilter.Cols, 5), new Scalar(0), -1); Cv2.Rectangle(rightFilter, new Rect(0, 15, rightFilter.Cols, rightFilter.Rows - 15), new Scalar(0), -1); Cv2.MinMaxIdx(rightFilter, out min, out max); Mat rightFilterThresh = rightFilter.Threshold(max - 2, 1, ThresholdTypes.Binary); Point right; FindLeftTop(rightFilterThresh, out right); rightKongtong[0] = right.Y + rightL2 - 10; rightKongtong[1] = right.X + rightAperture[1] - 5; Mat newRight = rightFilterThresh.Clone(); newRight.Set(right.Y, right.X, 255); //ImageShow(rightCrop, rightThresh * 255, rightFilter2 * 50, rightFilterThresh * 255, newRight); #endregion #region//边缘线 GetKongtong(imageContour, leftKongtong, rightKongtong, out kongtong, out leftPoint2, out rightPoint2); #endregion } /// /// 计算最小孔环,从外侧交点到上孔径 /// /// /// /// /// /// /// /// public void GetMinmumRing(Mat imageContour, int upper, int lower, int leftBorder, int rightBorder, out int[] pointRing, string direction) { pointRing = new int[2]; Mat crop2 = imageContour[upper, lower, leftBorder, rightBorder].Clone(); Scalar sum = new Scalar(0); Scalar lastSum = new Scalar(0); switch (direction) { case "left": //for (int j = 0; j < crop2.Cols - 1; j += 5) //{ // sum = crop2[0, crop2.Rows, j, j + 1].Sum(); // if ((int)lastSum != 0 && (int)sum-(int)lastSum>10) // { // pointRing[1] = j+leftBorder-2; // break; // } // lastSum = sum; //} for (int j = crop2.Cols - 1; j > 1; j -= 10) { sum = crop2[0, crop2.Rows, j - 1, j].Sum(); if ((int)lastSum != 0 && (int)lastSum - (int)sum > 10) { pointRing[1] = j + leftBorder - 5; break; } lastSum = sum; } break; case "right": //for (int j = crop2.Cols - 1; j > 2; j -= 5) //{ // sum = crop2[0, crop2.Rows, j - 1, j].Sum(); // if ((int)lastSum != 0 && (int)sum - (int)lastSum > 10) // { // pointRing[1] = j + leftBorder+2; // break; // } // lastSum = sum; //} for (int j = 1; j < crop2.Cols - 1; j += 10) { sum = crop2[0, crop2.Rows, j, j + 1].Sum(); if ((int)lastSum != 0 && (int)lastSum - (int)sum > 10) { pointRing[1] = j + leftBorder + 5; break; } lastSum = sum; } break; } //ImageShow(crop2 * 255); //int j = 0; //for (int i = crop2.Rows-1;i>0;i--) //{ // for (int k = i; k < crop2.Rows&&(crop2.Cols-1-(k-i))>0; k++) // { // j = crop2.Cols - 1 - (k - i); // if (crop2.Get(k, j) > 0) // { // pointLeftRing[0] = k + upper; // pointLeftRing[1] = j ; // break; // } // } //} //ImageShow(filter * 30, thresh * 255,crop*255,crop2*255); } /// /// 得到边缘线上拐点的坐标 /// /// 二值图 /// 左孔径坐标 /// 右孔径坐标 /// 输出拐点坐标,0:縱坐標;1:橫坐標 /// 孔径对应边缘线上点的平均纵坐标 public void CurveVertex(Mat imageContour, int[] apertureBegin, int[] apertureEnd, out int[] curveVertex, out double middleApertureY) { //曲面顶点的坐标 curveVertex = new int[2]; //孔径平均横坐标 double middleAperture = (apertureBegin[1] + apertureEnd[1]) / 2; //孔径平均高度 int[] apertureY = new int[2]; for (int i = 0; i < imageContour.Rows; i++) { if (imageContour.Get(i, apertureBegin[1]) > 0) { apertureY[0] = i; break; } } for (int i = 0; i < imageContour.Rows; i++) { if (imageContour.Get(i, apertureEnd[1]) > 0) { apertureY[1] = i; break; } } middleApertureY = (apertureY[0] + apertureY[1]) / 2; //边缘线坐标 int count = Math.Abs((apertureEnd[1] - apertureBegin[1]) / 2); int[,] ordinate = new int[count, 2]; int range = apertureEnd[1] - apertureBegin[1]; for (int j = range / 4 + apertureBegin[1]; j < range / 4 + apertureBegin[1] + count; j++) { for (int i = 0; i < imageContour.Rows; i++) { if (imageContour.Get(i, j) > 0) { ordinate[j - apertureBegin[1] - range / 4, 0] = i; ordinate[j - apertureBegin[1] - range / 4, 1] = j; break; } } } //孔深,取曲面上的点到孔径平均高度只差的最大值 double kongshenAomian = 0;//当边缘线内凹或外凸,孔深最大值 //double kongshenTumian = 1000;//当边缘线内凸,孔深最小值 int[] coordinateAomian = new int[2]; //int[] coordinateTumian = new int[2]; double t = 0; for (int i = 0; i < count; i++) { t = Math.Abs(middleApertureY - ordinate[i, 0]); if (kongshenAomian < t) { kongshenAomian = t; coordinateAomian[0] = ordinate[i, 0]; coordinateAomian[1] = ordinate[i, 1]; } //if (kongshenTumian > t) //{ // kongshenTumian = t; // coordinateTumian[0] = ordinate[i, 0]; // coordinateTumian[1] = ordinate[i, 1]; //} } curveVertex = coordinateAomian; //判断哪个点离孔径中心更近,更近的为曲面坐标 //double absAomian = Math.Abs(coordinateAomian[1] - middleAperture); //double absTumian = Math.Abs(coordinateTumian[1] - middleAperture); //if (absAomian < absTumian) //{ // curveVertex = coordinateAomian; //} //else //{ // curveVertex = coordinateTumian; //} } public void ShenmangkongShangkongjing(Mat contour, int leftL3, int rightL3, int[] lowerAperture, out int[] leftAperture, out int[] rightAperture) { #region//左 Mat cropLeft = contour[leftL3 - 20, leftL3 + 20, (lowerAperture[0] - 200)<0?0:(lowerAperture[0] - 200), lowerAperture[0] + 200].Clone(); InputArray leftKernel = InputArray.Create(new int[17, 17] { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { -1,-1,-1,-1,-1,-1,-1,-1, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0,-1, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0,-1, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0,-1, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0,-1, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0,-1, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0,-1, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0,-1, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, }); Mat leftFilter = new Mat(); Cv2.Filter2D(cropLeft, leftFilter, -1, leftKernel, new Point(-1, -1), 0); double min2, max; Cv2.MinMaxIdx(leftFilter, out min2, out max); Mat leftThresh = leftFilter.Threshold(max - 2, 1, ThresholdTypes.Binary); Cv2.Flip(leftThresh, leftThresh, FlipMode.Y); leftAperture = new int[2]; int min = 100000; Point[] leftIdx; FindNonZeros(leftThresh, out leftIdx); for (int i = 0; i < leftIdx.Length; i++) { if (min > (leftIdx[i].X + leftIdx[i].Y)) { min = leftIdx[i].X + leftIdx[i].Y; leftAperture[1] = leftThresh.Cols - leftIdx[i].X; leftAperture[0] = leftIdx[i].Y; } } leftAperture[1] += lowerAperture[0] - 200; leftAperture[0] += leftL3 - 20; #endregion #region//右 Mat cropRight = contour[rightL3 - 20, rightL3 + 20, lowerAperture[1] - 200, lowerAperture[1] + 200].Clone(); InputArray rightKernel = InputArray.Create(new int[17, 17] { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1,-1,-1,-1,-1,-1,-1,-1 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 0, 0 }, }); Mat rightFilter = new Mat(); Cv2.Filter2D(cropRight, rightFilter, -1, rightKernel, new Point(-1, -1), 0); Cv2.MinMaxIdx(rightFilter, out min2, out max); Mat rightThresh = rightFilter.Threshold(max - 2, 1, ThresholdTypes.Binary); rightAperture = new int[2]; Point[] rightIdx; FindNonZeros(rightThresh, out rightIdx); min = 1000000; for (int i = 0; i < rightIdx.Length; i++) { if (min > (rightIdx[i].X + rightIdx[i].Y)) { min = rightIdx[i].X + rightIdx[i].Y; rightAperture[1] = rightIdx[i].X; rightAperture[0] = rightIdx[i].Y; } } rightAperture[1] += lowerAperture[1] - 200; rightAperture[0] += rightL3 - 20; #endregion //ImageShow( cropRight * 255, rightThresh * 255); } /// /// 得到深盲孔的下孔径 /// /// 二值图像 /// 输出下孔径 /// 左边计算区域的上边界 /// 右边计算区域的上边界 /// 左边计算区域的下边界 /// 右边计算区域的下边界 /// 数据提取区域 public void GetShenmangLowerAperture(Mat imageContour, out int[] aperture, int leftUpper, int rightUpper, int leftLower, int rightLower, int[] dataArea) { //孔径起始点 aperture = new int[2]; aperture[0] = 0; aperture[1] = 0; int middle = (dataArea[1] + dataArea[2]) / 2; Mat fanse = 1 - imageContour; //Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); //Mat open = new Mat(); //Cv2.MorphologyEx(fanse, open,MorphTypes.Open, se); //fanse = open; for (int j = middle; j > dataArea[0]; j--) { for (int i = leftUpper - 20 < 0 ? 0 : leftUpper - 20; i < leftLower - 20; i++) { if (fanse.Get(i, j) > 0) { aperture[0] = j; break; } } if (aperture[0] != 0) break; } for (int j = middle; j < dataArea[3]; j++) { for (int i = rightUpper - 20 < 0 ? 0 : rightUpper - 20; i < rightLower - 20; i++) { if (fanse.Get(i, j) > 0) { aperture[1] = j; break; } } if (aperture[1] != 0) break; } } /// /// 下孔径新方法,用胶体部分置1,向中间遍历,为0时下孔径 /// /// /// /// /// /// /// /// public void GetLowerAperture(Mat imageContour, out int[] aperture, int leftUpper, int rightUpper, int leftLower, int rightLower, int[] dataArea) { aperture = new int[2]; int middle = (dataArea[1] + dataArea[2]) / 2; Mat fill = new Mat(); Fill(imageContour, out fill, 1); Mat fanse = 1 - fill; Scalar sum = fanse.Sum(); if ((int)sum != 0) { imageContour = fill.Clone(); } Mat result = 1 - imageContour; Scalar sumLeft = new Scalar(0); for (int j = dataArea[0]; j < middle; j++) { sumLeft = result[leftUpper<0?0: leftUpper, leftLower, j, j + 1].Sum(); if ((int)sumLeft == 0) { aperture[0] = j; break; } } Scalar sumRight = new Scalar(0); for (int j = dataArea[3]; j > middle; j--) { sumRight = result[rightUpper, rightLower, j - 1, j].Sum(); if ((int)sumRight == 0) { aperture[1] = j; break; } } if(fill != null) { fill.Dispose(); } } public void GetShenmangLowerAperture2(Mat imageContour, out int[] aperture, int leftUpper, int rightUpper, int leftLower, int rightLower, int[] dataArea) { aperture = new int[2] { 0, 0 }; int middle = (dataArea[1] + dataArea[2]) / 2; Mat fanse = 1 - imageContour; int offset = 20; int sum = 0; for (int j = dataArea[1]; j < middle; j++) { sum = 0; for (int i = leftUpper - offset; i < leftLower - offset; i++) { sum += fanse.Get(i, j); if (fanse.Get(i, j) > 0) break; } if (sum == 0) { aperture[0] = j; break; } } for (int j = dataArea[2]; j > middle; j--) { sum = 0; for (int i = rightUpper - offset; i < rightLower - offset; i++) { sum += fanse.Get(i, j); if (fanse.Get(i, j) > 0) break; } if (sum == 0) { aperture[1] = j; break; } } } /// /// 得到深盲孔的胶线 /// /// 输入图像,一般是绿色通道 /// 输出胶线纵坐标 /// 左边上界 /// 左边下界 /// 右边上界 /// 右边下界 /// 提取区域 public void GetGlue(Mat image, out int[] glueOrdinate, int leftUpper, int leftLower, int rightUpper, int rightLower, int[] dataArea) { glueOrdinate = new int[2]; int[] maybePosition = new int[2]; //int[] zero = new int[2]; InputArray kernel = InputArray.Create(new int[3, 3] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } }); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat seDilate = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); Mat crop1 = image[leftUpper, leftLower, dataArea[0], dataArea[1]]; //将裁剪区域改为面铜+基材铜附近 //int leftMiddleMiantong_Jicaitong = (dataArea[0] + dataArea[1]) / 2; //Mat crop1 = image[leftUpper, leftLower, leftMiddleMiantong_Jicaitong - 10, leftMiddleMiantong_Jicaitong + 10]; Mat filter1 = new Mat(); Cv2.Filter2D(crop1, filter1, -1, kernel); Cv2.ConvertScaleAbs(filter1, filter1); Mat thresh1 = 1 - filter1.Threshold(0, 1, ThresholdTypes.Otsu); Mat open1 = new Mat(); Cv2.MorphologyEx(thresh1, open1, MorphTypes.Open, seOpen); Cv2.MorphologyEx(open1, open1, MorphTypes.Close, seOpen); Cv2.Dilate(open1, open1, seDilate); Fill(open1, out open1, 1); //new Window("crop1", WindowMode.Normal, crop1); //new Window("thresh2", WindowMode.Normal, 255 - crop1.Threshold(0, 255, ThresholdTypes.Otsu)); //new Window("thresh1", WindowMode.Normal, thresh1 * 255); //new Window("end", WindowMode.Normal, open1 * 255); //Cv2.WaitKey(); Scalar sum1 = new Scalar(0); Scalar lastSum1 = new Scalar(0); Scalar sub1 = new Scalar(0); Scalar subMax1 = new Scalar(0); Scalar max1 = new Scalar(0); Scalar zero1 = new Scalar(0); for (int i = 2; i < crop1.Rows - 2; i++) { sum1 = open1[i, i + 2, 0, open1.Cols - 1].Sum(); lastSum1 = open1[i - 2, i, 0, open1.Cols - 1].Sum(); //zero1 = open1[i - 1, i, 0, open1.Cols - 1].Sum(); sub1 = Math.Abs((int)sum1 - (int)lastSum1); if ((int)max1 < (int)sum1) { max1 = sum1; glueOrdinate[0] = i + leftUpper; } if ((int)subMax1 < (int)sub1) { subMax1 = sub1; maybePosition[0] = i + leftUpper; } //if ((int)zero1 < 10) //{ // zero[0] = i + leftUpper; //} } Mat crop2 = image[rightUpper, rightLower, dataArea[2], dataArea[3]]; ////将裁剪区域改为面铜+基材铜附近 //int rightMiddleMiantong_Jicaitong = (dataArea[2] + dataArea[3]) / 2; //Mat crop2 = image[rightUpper, rightLower, rightMiddleMiantong_Jicaitong - 10, rightMiddleMiantong_Jicaitong + 10]; Mat filter2 = new Mat(); Cv2.Filter2D(crop2, filter2, -1, kernel); Cv2.ConvertScaleAbs(filter2, filter2); Mat thresh2 = 1 - filter2.Threshold(0, 1, ThresholdTypes.Otsu); Mat open2 = new Mat(); Cv2.MorphologyEx(thresh2, open2, MorphTypes.Open, seOpen); Cv2.MorphologyEx(open2, open2, MorphTypes.Close, seOpen); Cv2.Dilate(open2, open2, seDilate); Fill(open2, out open2, 1); //new Window("thresh2", WindowMode.Normal, thresh2 * 255); //new Window("end2", WindowMode.Normal, open2 * 255); //Cv2.WaitKey(); Scalar sum2 = new Scalar(0); Scalar lastSum2 = new Scalar(0); Scalar sub2 = new Scalar(0); Scalar subMax2 = new Scalar(0); Scalar max2 = new Scalar(0); Scalar zero2 = new Scalar(0); for (int i = 2; i < crop2.Rows - 2; i++) { sum2 = open2[i, i + 2, 0, open2.Cols - 1].Sum(); lastSum2 = open2[i - 2, i, 0, open2.Cols - 1].Sum(); //zero2 = open2[i - 1, i, 0, open2.Cols - 1].Sum(); sub2 = Math.Abs((int)sum2 - (int)lastSum2); if ((int)max2 < (int)sum2) { max2 = sum2; glueOrdinate[1] = i + rightUpper; } if ((int)subMax2 < (int)sub2) { subMax2 = sub2; maybePosition[1] = i + rightUpper; } //if ((int)zero2 < 10) //{ // zero[1] = i + rightUpper; //} } if (glueOrdinate[0] > maybePosition[0]) { for (int j = maybePosition[0] - leftUpper; j < glueOrdinate[0] - leftUpper; j++) { if ((int)open1[j, j + 1, 0, open1.Cols - 1].Sum() == 0) { sum1 = new Scalar(0); lastSum1 = new Scalar(0); sub1 = new Scalar(0); subMax1 = new Scalar(0); max1 = new Scalar(0); for (int i = maybePosition[0] - leftUpper + 2; i < crop1.Rows - 2; i++) { sum1 = open1[i, i + 2, 0, open1.Cols - 1].Sum(); lastSum1 = open1[i - 2, i, 0, open1.Cols - 1].Sum(); sub1 = Math.Abs((int)sum1 - (int)lastSum1); if ((int)max1 < (int)sum1) { max1 = sum1; glueOrdinate[0] = i + leftUpper; } if ((int)subMax1 < (int)sub1) { subMax1 = sub1; maybePosition[0] = i + leftUpper; } } break; } } if (glueOrdinate[0] > maybePosition[0]) { //if (Math.Abs(zero[0] - maybePosition[0]) > 15&&zero[0]>10) // glueOrdinate[0] = zero[0]; //else glueOrdinate[0] = maybePosition[0]; } } if (glueOrdinate[1] > maybePosition[1]) { for (int j = maybePosition[1] - rightUpper; j < glueOrdinate[1] - rightUpper; j++) { if ((int)open2[j, j + 1, 0, open2.Cols - 1].Sum() == 0) { sum2 = new Scalar(0); lastSum2 = new Scalar(0); sub2 = new Scalar(0); subMax2 = new Scalar(0); max2 = new Scalar(0); for (int i = maybePosition[1] - rightUpper + 2; i < crop2.Rows - 2; i++) { sum2 = open2[i, i + 2, 0, open2.Cols - 1].Sum(); lastSum2 = open2[i - 2, i, 0, open2.Cols - 1].Sum(); sub2 = Math.Abs((int)sum2 - (int)lastSum2); if ((int)max2 < (int)sum2) { max2 = sum2; glueOrdinate[1] = i + rightUpper; } if ((int)subMax2 < (int)sub2) { subMax2 = sub2; maybePosition[1] = i + rightUpper; } } break; } } if (glueOrdinate[1] > maybePosition[1]) { //if (Math.Abs(zero[1] - maybePosition[1]) > 15&&zero[1]>10) // glueOrdinate[1] = zero[1]; //else glueOrdinate[1] = maybePosition[1]; } } //LineShow(crop1, 10, glueOrdinate[0] - leftUpper, 20, glueOrdinate[0] - leftUpper); //new Window("crop1", WindowMode.Normal, crop1); //new Window("thresh1", WindowMode.Normal, open1 * 255); //new Window("thresh2", WindowMode.Normal, open2 * 255); //Cv2.WaitKey(); } /// /// 计算胶线坐标,修改了判定时条件,先用于深盲孔双层 /// /// /// /// /// /// /// /// public void GetGlue2(Mat image, out int[] glueOrdinate, int leftUpper, int leftLower, int rightUpper, int rightLower, int[] dataArea) { glueOrdinate = new int[2]; int[] maybePosition = new int[2]; //int[] zero = new int[2]; InputArray kernel = InputArray.Create(new int[3, 3] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } }); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat seDilate = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); int width1 = dataArea[1] - dataArea[0]; Mat crop1 = image[leftUpper, leftLower, dataArea[0], dataArea[1]]; if (width1 > 50) { crop1 = image[leftUpper, leftLower, dataArea[0] + (width1 - 50) / 2, dataArea[1] - (width1 - 50) / 2]; width1 = 50; } //将裁剪区域改为面铜+基材铜附近 //int leftMiddleMiantong_Jicaitong = (dataArea[0] + dataArea[1]) / 2; //Mat crop1 = image[leftUpper, leftLower, leftMiddleMiantong_Jicaitong - 10, leftMiddleMiantong_Jicaitong + 10]; int areaSize1 = crop1.Rows * crop1.Cols; Mat filter1 = new Mat(); Cv2.Filter2D(crop1, filter1, -1, kernel); Cv2.ConvertScaleAbs(filter1, filter1); Mat thresh1 = 1 - filter1.Threshold(0, 1, ThresholdTypes.Otsu); Mat open1 = new Mat(); Cv2.MorphologyEx(thresh1, open1, MorphTypes.Open, seOpen); Cv2.MorphologyEx(open1, open1, MorphTypes.Close, seOpen); Cv2.Dilate(open1, open1, seDilate); Fill(open1, out open1, 1); Scalar area1 = open1.Sum(); while ((int)area1 > areaSize1 * 0.9) { leftUpper += 5; crop1 = image[leftUpper, leftLower, dataArea[0], dataArea[1]]; if (width1 > 50) { crop1 = image[leftUpper, leftLower, dataArea[0] + (width1 - 50) / 2, dataArea[1] - (width1 - 50) / 2]; width1 = 50; } filter1 = new Mat(); Cv2.Filter2D(crop1, filter1, -1, kernel); Cv2.ConvertScaleAbs(filter1, filter1); thresh1 = 1 - filter1.Threshold(0, 1, ThresholdTypes.Otsu); open1 = new Mat(); Cv2.MorphologyEx(thresh1, open1, MorphTypes.Open, seOpen); Cv2.MorphologyEx(open1, open1, MorphTypes.Close, seOpen); Cv2.Dilate(open1, open1, seDilate); Fill(open1, out open1, 1); areaSize1 = crop1.Rows * crop1.Cols; area1 = open1.Sum(); } //new Window("crop1", WindowMode.Normal, crop1); ////new Window("thresh2", WindowMode.Normal, 255 - crop1.Threshold(0, 255, ThresholdTypes.Otsu)); //new Window("thresh1", WindowMode.Normal, thresh1 * 255); //new Window("end", WindowMode.Normal, open1 * 255); //Cv2.WaitKey(); Scalar sum1 = new Scalar(0); Scalar lastSum1 = new Scalar(0); Scalar sub1 = new Scalar(0); Scalar subMax1 = new Scalar(0); Scalar max1 = new Scalar(0); Scalar zero1 = new Scalar(0); int y = 0; for (int i = crop1.Rows - 4; i > 4; i--) { sum1 = open1[i - 3, i, 0, open1.Cols].Sum(); if ((int)sum1 > width1 * 2.9) { y = i; break; } } for (int i = y - 1; i > 4; i--) { sum1 = open1[i - 3, i, 0, open1.Cols].Sum(); if ((int)sum1 < width1 * 2.2) { glueOrdinate[0] = i + leftUpper; break; } } //右 Mat crop2 = image[rightUpper, rightLower, dataArea[2], dataArea[3]]; int width2 = dataArea[3] - dataArea[2]; if (width2 > 50) { crop2 = image[rightUpper, rightLower, dataArea[2] + (width2 - 50) / 2, dataArea[3] - (width2 - 50) / 2]; width2 = crop2.Cols; } ////将裁剪区域改为面铜+基材铜附近 //int rightMiddleMiantong_Jicaitong = (dataArea[2] + dataArea[3]) / 2; //Mat crop2 = image[rightUpper, rightLower, rightMiddleMiantong_Jicaitong - 10, rightMiddleMiantong_Jicaitong + 10]; int areaSize2 = crop2.Rows * crop2.Cols; Mat filter2 = new Mat(); Cv2.Filter2D(crop2, filter2, -1, kernel); Cv2.ConvertScaleAbs(filter2, filter2); Mat thresh2 = 1 - filter2.Threshold(0, 1, ThresholdTypes.Otsu); Mat open2 = new Mat(); Cv2.MorphologyEx(thresh2, open2, MorphTypes.Open, seOpen); Cv2.MorphologyEx(open2, open2, MorphTypes.Close, seOpen); Cv2.Dilate(open2, open2, seDilate); Fill(open2, out open2, 1); Scalar area2 = open2.Sum(); while ((int)area2 > areaSize2 * 0.9) { rightUpper += 5; crop2 = image[rightUpper, rightLower, dataArea[2], dataArea[3]]; width2 = dataArea[3] - dataArea[2]; if (width2 > 50) { crop2 = image[rightUpper, rightLower, dataArea[2] + (width2 - 50) / 2, dataArea[3] - (width2 - 50) / 2]; width2 = crop2.Cols; } areaSize2 = crop2.Rows * crop2.Cols; filter2 = new Mat(); Cv2.Filter2D(crop2, filter2, -1, kernel); Cv2.ConvertScaleAbs(filter2, filter2); thresh2 = 1 - filter2.Threshold(0, 1, ThresholdTypes.Otsu); open2 = new Mat(); Cv2.MorphologyEx(thresh2, open2, MorphTypes.Open, seOpen); Cv2.MorphologyEx(open2, open2, MorphTypes.Close, seOpen); Cv2.Dilate(open2, open2, seDilate); Fill(open2, out open2, 1); area2 = open2.Sum(); } //new Window("crop2", WindowMode.Normal, crop2); //new Window("filter2", WindowMode.Normal, filter2); //new Window("thresh2", WindowMode.Normal, thresh2 * 255); //new Window("end2", WindowMode.Normal, open2 * 255); //Cv2.WaitKey(); Scalar sum2 = new Scalar(0); Scalar lastSum2 = new Scalar(0); Scalar sub2 = new Scalar(0); Scalar subMax2 = new Scalar(0); Scalar max2 = new Scalar(0); Scalar zero2 = new Scalar(0); y = 0; for (int i = crop2.Rows - 4; i > 4; i--) { sum2 = open2[i - 3, i, 0, open2.Cols].Sum(); if ((int)sum2 > width2 * 2.9) { y = i; break; } } for (int i = y - 1; i > 4; i--) { sum2 = open2[i - 3, i, 0, open2.Cols].Sum(); if ((int)sum2 < width2 * 2.4) { glueOrdinate[1] = i + rightUpper; break; } } if (glueOrdinate[0] == 0) glueOrdinate[0] = leftUpper; if (glueOrdinate[1] == 0) glueOrdinate[1] = rightUpper; } /// /// 得到深盲孔胶内缩的内部坐标 /// /// 二值图像 /// 输出内部坐标,先左后右 /// 输出外部坐标,先左后右 /// 上界 /// 胶线的坐标 /// 下界 /// 提取数据区域 public void GetWaist(Mat imageContour, out int[] upperWaist, out int[] lowerWaist, int upperBound, int[] glueOrdinate, int lowerBound, int[] dataArea) { //Cv2.ImWrite(@"C:\Users\zyh\Desktop\imageContour.jpg", imageContour * 255); //寻找连通区域,把除第一个联通区域的都置为0 Mat labelMat = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat(); int nums = Cv2.ConnectedComponentsWithStats(imageContour, labelMat, stats, centroids, PixelConnectivity.Connectivity8); int y = stats.At(1, 1); int height = stats.At(1, 3); for(int h=height+1; h< imageContour.Height; h++) { imageContour.Row[h] *= 0; } upperWaist = new int[2] { 0, 0 }; lowerWaist = new int[2] { 0, 0 }; int middle = (dataArea[1] + dataArea[2]) / 2; int min_left=int.MaxValue, max_left = 0; int min_left_x = 0, max_left_x = 0; for (int j = middle-30; j > dataArea[1]; j--) { int v = imageContour.Col[j].CountNonZero(); if (v <= min_left) { min_left = v; min_left_x = j; } if (v >= max_left) { max_left = v; max_left_x = j; } } upperWaist[0] = max_left_x; OpenCvSharp.Rect rect_Left = new Rect(dataArea[1], upperBound, max_left_x- dataArea[1], lowerBound- upperBound); Mat temp_left = new Mat(imageContour, rect_Left); //Cv2.ImWrite(@"C:\Users\zyh\Desktop\temp_left.jpg", temp_left*255); bool f_l = false; for (int j=0; j< temp_left.Width; j++) { if(!f_l && temp_left.Col[j].CountNonZero()>0) { f_l = true; lowerWaist[0] = j + dataArea[1]; //break; } else if(temp_left.Col[j].CountNonZero()== temp_left.Height) { upperWaist[0] = j + dataArea[1]; break; } } int min_right = int.MaxValue, max_right = 0; int min_right_x = 0, max_right_x = 0; for (int j = middle+30; j < dataArea[2]; j++) { int v = imageContour.Col[j].CountNonZero(); if (v <= min_right) { min_right = v; min_right_x = j; } if (v >= max_right) { max_right = v; max_right_x = j; } } upperWaist[1] = max_right_x; OpenCvSharp.Rect rect_right = new Rect(max_right_x, upperBound, dataArea[2]- max_right_x, lowerBound - upperBound); Mat temp_right = new Mat(imageContour, rect_right); //Cv2.ImWrite(@"C:\Users\zyh\Desktop\rect_right.jpg", temp_right*255); bool f_r = false; for (int j = temp_right.Width-1; j > 0; j--) { if (!f_r && temp_right.Col[j].CountNonZero() > 0) { f_r = true; lowerWaist[1] = j+ max_right_x; //break; } else if(temp_right.Col[j].CountNonZero() == temp_right.Height) { upperWaist[1] = j + max_right_x; break; } } /*Mat fanse = 1 - imageContour; //上 for (int j = middle; j > dataArea[0]; j--) { for (int i = upperBound; i < glueOrdinate[0]; i++) { if (fanse.Get(i, j) > 0*//* && j< (middle + dataArea[0]) / 2*//*) { upperWaist[0] = j; break; } } if (upperWaist[0] != 0) break; } for (int j = middle; j < dataArea[3]; j++) { for (int i = upperBound; i < glueOrdinate[1]; i++) { if (fanse.Get(i, j) > 0*//* && j > (middle + dataArea[3])/2*//*) { upperWaist[1] = j; break; } } if (upperWaist[1] != 0) break; } //下 for (int j = (dataArea[0] + dataArea[1]) / 2; j < middle; j++) { for (int i = glueOrdinate[0] - 20; i < lowerBound; i++) { //new Window("imageContour", WindowMode.Normal, imageContour * 255); //Cv2.WaitKey(); if (imageContour.Get(i, j) > 0) { lowerWaist[0] = j; break; } } if (lowerWaist[0] != 0) break; } for (int j = (dataArea[3] + dataArea[2]) / 2; j > middle; j--) { for (int i = glueOrdinate[1] - 20; i < lowerBound; i++) { if (imageContour.Get(i, j) > 0) { lowerWaist[1] = j; break; } } if (lowerWaist[1] != 0) break; }*/ } /// /// 提取胶内缩,将下边界改为左右边界 /// /// 二值图像 /// 输出内部坐标,先左后右 /// 输出外部坐标,先左后右 /// 上界 /// 胶线的坐标 /// 下左界 /// 下右界 /// 提取数据区域 public void GetWaistNew(Mat imageContour, out int[] upperWaist, out int[] lowerWaist, int upperBound, int[] glueOrdinate, int leftLower, int rightLower, int[] dataArea) { upperWaist = new int[2] { 0, 0 }; lowerWaist = new int[2] { 0, 0 }; int middle = (dataArea[1] + dataArea[2]) / 2; Mat fanse = 1 - imageContour; //上 for (int j = middle; j > dataArea[0]; j--) { for (int i = upperBound; i < glueOrdinate[0]; i++) { if (fanse.Get(i, j) > 0) { upperWaist[0] = j; break; } } if (upperWaist[0] != 0) break; } for (int j = middle; j < dataArea[3]; j++) { for (int i = upperBound; i < glueOrdinate[1]; i++) { if (fanse.Get(i, j) > 0) { upperWaist[1] = j; break; } } if (upperWaist[1] != 0) break; } //下 //左 for (int j = (dataArea[0] + dataArea[1]) / 2; j < middle; j++) { for (int i = glueOrdinate[0] - 20; i < leftLower; i++) { //new Window("imageContour", WindowMode.Normal, imageContour * 255); //Cv2.WaitKey(); if (imageContour.Get(i, j) > 0) { lowerWaist[0] = j; break; } } if (lowerWaist[0] != 0) break; } //右 for (int j = (dataArea[3] + dataArea[2]) / 2; j > middle; j--) { for (int i = glueOrdinate[1] - 20; i < rightLower; i++) { if (imageContour.Get(i, j) > 0) { lowerWaist[1] = j; break; } } if (lowerWaist[1] != 0) break; } } /// /// 得到精准的面铜和基材铜的纵坐标 /// /// 最好是绿色通道图 /// 上边界 /// 下边界 /// 左边界 /// 右边界 /// 面铜的横坐标 /// 基材铜的横坐标 /// 面铜的纵坐标 /// 基材铜的纵坐标 /// 输出纵坐标,面铜和基材铜 public void InsideLine_Accuracy(Mat image, int upperBound, int lowerBound, int leftBoundary, int rightBoundary, int middleMiantong, int middleJicaitong , double ordinateL2Miantong, double ordinateL2Jicaitong, out double[] ordinateL2_Acc, int isMiantong = 0, int banceng = 2/*-1*/, bool showMat = false) { //第5671deng类别图片需要完善位置精准度,以及 调试有些图片位置计算错误的原因,并纠正 Mat crop = image[upperBound, lowerBound, leftBoundary, rightBoundary]; //if (isMiantong > 0 && showMat) //{ // Mat mat1 = new Mat(); // Cv2.Normalize(crop, mat1, 0, 255, NormTypes.MinMax); // Cv2.ImWrite(@"C:\Users\54434\Desktop\crop.JPG", crop); //} Mat filter = new Mat();//滤波增强对比 InputArray kernel = InputArray.Create(new int[3, 3] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } }); Cv2.Filter2D(crop, filter, -1, kernel); Cv2.ConvertScaleAbs(filter, filter); Mat thresh = 1 - filter.Threshold(0, 1, ThresholdTypes.Otsu);// 二值化 Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(15/*15*/, 1/*水平线<--3, 3*/));// 开运算 Mat open = new Mat(); //OpenCV提取图像中的垂直线(或者水平线) 定义结构元素,开操作 Cv2.MorphologyEx(thresh, open, MorphTypes.Open, seOpen); if (isMiantong > 0 && showMat) { //Cv2.ImWrite(@"C:\Users\54434\Desktop\filter.JPG", filter/* * 127*/); } //Scalar sum = new Scalar(0); //Scalar max1 = new Scalar(0); //Scalar max = new Scalar(0); //double meanOrdinate1 = 0; double ordinateL2Miantong_acc = ordinateL2Miantong; double ordinateL2Jicaitong_acc = ordinateL2Jicaitong; //ordinateL2_Acc = new double[] { ordinateL2Miantong_acc, ordinateL2Jicaitong_acc }; //return; int topOri = (int)ordinateL2Miantong_acc - upperBound - 20;// 10;// 15; int bottomOri = (int)ordinateL2Miantong_acc - upperBound + 20;// 10;// 15; if (topOri < 10) topOri = 10; else if (topOri > crop.Rows/3 && topOri > 20) topOri = 20;//对初判定位置距离太远的进行纠偏 if (bottomOri > crop.Rows - 10) bottomOri = crop.Rows - 10; else if (bottomOri < crop.Rows*2/3 && bottomOri < crop.Rows - 20) bottomOri = crop.Rows - 20;//对初判定位置距离太远的进行纠偏 bool miantongChanged = false; int miantongValue = crop.Get((int)ordinateL2Miantong - upperBound, middleMiantong - leftBoundary); bool isHoriMost = false;//用来判定大横线哪个更加位置居中 int centerVer = crop.Rows / 2;// (topOri + bottomOri) / 2;//用来判定大横线哪个更加位置居中 for (int i = topOri; i < bottomOri; i++) { int miantongValueI = crop.Get(i, middleMiantong - leftBoundary); Scalar sum = open[i, i + 1, 0, crop.Cols - 1].Sum(); if (miantongValueI < miantongValue - 1 || (!miantongChanged && miantongValueI < miantongValue + 100) || crop.Cols - 20 < (int)sum) { //if (open.Get(i, middleMiantong - leftBoundary) > 0) //Scalar sum = open[i, i + 2, 0, crop.Cols - 1].Sum(); //if (30/*30*/ < (int)sum) if (6/*30*/ < (int)sum && !isHoriMost ||(crop.Cols - 20 < (int)sum && isHoriMost && Math.Abs(centerVer - i) < Math.Abs(centerVer - (ordinateL2Miantong_acc - upperBound)))) { ordinateL2Miantong_acc = i + upperBound; miantongValue = miantongValueI; miantongChanged = true; //待自测scc-2 //if (isMiantong == 1) // break; if (crop.Cols - 20 < (int)sum/* && Math.Abs(centerVer - (ordinateL2Jicaitong_acc - upperBound)) < 10*/) { isHoriMost = true; //break; } } } } if (ordinateL2Miantong_acc == 10 + upperBound) {//将明显不对的测量结果居中取值 ordinateL2Miantong_acc = centerVer + upperBound; } //if (isMiantong == 1 && !miantongChanged) //{ // Mat thresh1 = 1 - filter.Threshold(0, 1, ThresholdTypes.Otsu);// 二值化 // Mat seOpen1 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9/*15*/, 1/*水平线<--3, 3*/));// 开运算 // Mat open1 = new Mat(); // //OpenCV提取图像中的垂直线(或者水平线) 定义结构元素,开操作 // Cv2.MorphologyEx(thresh1, open1, MorphTypes.Open, seOpen1); // //if (isMiantong > 0 && showMat) // //{ // // new Window("open1", WindowMode.Normal, open1 * 255); // // Cv2.WaitKey(); // //} // for (int i = topOri; i < bottomOri; i++) // { // //int miantongValueI = crop.Get(i, middleMiantong - leftBoundary); // //if (miantongValueI < 200/*miantongValue*/) // { // if (open1.Get(i, middleMiantong - leftBoundary) > 0) // //Scalar sum = open[i, i + 2, 0, crop.Cols - 1].Sum(); // //if (30/*30*/ < (int)sum) // { // ordinateL2Miantong_acc = i + upperBound; // miantongValue = crop.Get(i, middleMiantong - leftBoundary);// miantongValueI; // miantongChanged = true; // break; // } // } // } //} isHoriMost = false;//用来判定大横线哪个更加位置居中 bool jicaitongChanged = false; int jicaitongValue = crop.Get((int)ordinateL2Jicaitong - upperBound, middleJicaitong - leftBoundary); for (int i = /*0*/topOri; i < bottomOri; i++) { int jicaitongValueI = crop.Get(i, middleJicaitong - leftBoundary); Scalar sum = open[i, i + 1, 0, crop.Cols - 1].Sum(); if (jicaitongValueI < jicaitongValue - 1 || (!jicaitongChanged && jicaitongValueI < jicaitongValue + 100) || crop.Cols - 20 < (int)sum) { //if (open.Get(i, middleJicaitong - leftBoundary) > 0) //Scalar sum = open[i, i + 2, 0, crop.Cols - 1].Sum(); ////Scalar sum = open[i, i + 2, middleJicaitong - leftBoundary - 4, middleJicaitong - leftBoundary + 4].Sum(); if (6/*30*/ < (int)sum && !isHoriMost || (crop.Cols - 20 < (int)sum && isHoriMost && Math.Abs(centerVer - i) < Math.Abs(centerVer - (ordinateL2Jicaitong_acc - upperBound)))) { ordinateL2Jicaitong_acc = i + upperBound; jicaitongValue = jicaitongValueI; jicaitongChanged = true; //待自测scc-2 //if (isMiantong == 1) // break; if (crop.Cols - 20 < (int)sum/* && Math.Abs(centerVer - (ordinateL2Jicaitong_acc - upperBound)) < 10*/) { isHoriMost = true; //break; } } } } if (ordinateL2Jicaitong_acc == 10 + upperBound) {//将明显不对的测量结果居中取值 ordinateL2Jicaitong_acc = centerVer + upperBound; } if (!miantongChanged && !jicaitongChanged) { int topOri_1 = topOri; if (topOri > 10) topOri_1 = 10; int bottomOri_1 = bottomOri; if (bottomOri < crop.Rows - 10) bottomOri_1 = crop.Rows - 10; miantongValue = crop.Get((int)ordinateL2Miantong - upperBound, middleMiantong - leftBoundary); for (int i = topOri_1; i < bottomOri_1; i++) { int miantongValueI = crop.Get(i, middleMiantong - leftBoundary); Scalar sum = open[i, i + 1, 0, crop.Cols - 1].Sum(); if (miantongValueI < miantongValue - 1 || (!miantongChanged && miantongValueI < miantongValue + 100) || crop.Cols - 20 < (int)sum) { if (6 < (int)sum) { ordinateL2Miantong_acc = i + upperBound; miantongValue = miantongValueI; miantongChanged = true; if (crop.Cols - 20 < (int)sum) break; } } if (i == topOri - 1) i = bottomOri; } jicaitongValue = crop.Get((int)ordinateL2Jicaitong - upperBound, middleJicaitong - leftBoundary); for (int i = topOri_1; i < bottomOri_1; i++) { int jicaitongValueI = crop.Get(i, middleJicaitong - leftBoundary); Scalar sum = open[i, i + 1, 0, crop.Cols - 1].Sum(); if (jicaitongValueI < jicaitongValue - 1 || (!jicaitongChanged && jicaitongValueI < jicaitongValue + 100) || crop.Cols - 20 < (int)sum) { if (6 < (int)sum) { ordinateL2Jicaitong_acc = i + upperBound; jicaitongValue = jicaitongValueI; jicaitongChanged = true; if (crop.Cols - 20 < (int)sum) break; } } if (i == topOri - 1) i = bottomOri; } } if ((isMiantong == 1 || isMiantong == 2) && (!miantongChanged /*//待自测scc-3_1 &&*/|| !jicaitongChanged)) { Mat thresh1 = 1 - filter.Threshold(0, 1, ThresholdTypes.Otsu);// 二值化 Mat seOpen1 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9/*15*/, 1/*水平线<--3, 3*/));// 开运算 Mat open1 = new Mat(); //OpenCV提取图像中的垂直线(或者水平线) 定义结构元素,开操作 Cv2.MorphologyEx(thresh1, open1, MorphTypes.Open, seOpen1); //if (isMiantong > 0 && showMat) //{ // new Window("open1", WindowMode.Normal, open1 * 255); // Cv2.WaitKey(); //} //待自测scc-3_1 if (isMiantong == 1 && !miantongChanged || isMiantong == 2 && !jicaitongChanged) for (int i = bottomOri; i > topOri; i--) { //还差第3、5、7类别图片需要完善位置精准度,以及 //调试有些图片位置计算错误的原因,并纠正!!!!!!!!!!!! { if (isMiantong == 1 && open1.Get(i, middleMiantong - leftBoundary) > 0 || isMiantong == 2 && open1.Get(i, middleJicaitong - leftBoundary) > 0) { if (isMiantong == 1) ordinateL2Miantong_acc = i + upperBound; else if (isMiantong == 2) ordinateL2Jicaitong_acc = i + upperBound; break; } } } //if (isMiantong == 1 && !miantongChanged) // for (int i = topOri; i < bottomOri; i++)//for (int i = bottomOri; i > topOri; i--) // { // if (open1.Get(i, middleMiantong - leftBoundary) > 0) // { // ordinateL2Miantong_acc = i + upperBound; // break; // } // } //if (isMiantong == 2 && !jicaitongChanged) // for (int i = bottomOri; i > topOri; i--) // { // if (open1.Get(i, middleJicaitong - leftBoundary) > 0) // { // ordinateL2Jicaitong_acc = i + upperBound; // break; // } // } //if (isMiantong == 1 && !jicaitongChanged) // for (int i = topOri; i < bottomOri; i++) // { // { // if (open1.Get(i, middleJicaitong - leftBoundary) > 0) // { // ordinateL2Jicaitong_acc = i + upperBound; // break; // } // } // } //if (isMiantong == 2 && !miantongChanged) // for (int i = bottomOri; i > topOri; i--)//for (int i = topOri; i < bottomOri; i++) // { // { // if (open1.Get(i, middleMiantong - leftBoundary) > 0) // { // ordinateL2Miantong_acc = i + upperBound; // break; // } // } // } if (isMiantong == 1 && !jicaitongChanged || isMiantong == 2 && !miantongChanged) for (int i = topOri; i < bottomOri; i++) { { if (isMiantong == 1 && open1.Get(i, middleJicaitong - leftBoundary) > 0 || isMiantong == 2 && open1.Get(i, middleMiantong - leftBoundary) > 0) { if (isMiantong == 1) ordinateL2Jicaitong_acc = i + upperBound; else if (isMiantong == 2) ordinateL2Miantong_acc = i + upperBound; break; } } } } //if (isMiantong == 1 && !jicaitongChanged) //{ // Mat thresh1 = 1 - filter.Threshold(0, 1, ThresholdTypes.Otsu);// 二值化 // Mat seOpen1 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9/*15*/, 1/*水平线<--3, 3*/));// 开运算 // Mat open1 = new Mat(); // //OpenCV提取图像中的垂直线(或者水平线) 定义结构元素,开操作 // Cv2.MorphologyEx(thresh1, open1, MorphTypes.Open, seOpen1); // //if (isMiantong > 0 && showMat) // //{ // // new Window("open1", WindowMode.Normal, open1 * 255); // // Cv2.WaitKey(); // //} // for (int i = bottomOri; i > topOri; i--) // { // //int miantongValueI = crop.Get(i, middleMiantong - leftBoundary); // //if (miantongValueI < 200/*miantongValue*/) // { // if (open1.Get(i, middleJicaitong - leftBoundary) > 0) // //Scalar sum = open[i, i + 2, 0, crop.Cols - 1].Sum(); // //if (30/*30*/ < (int)sum) // { // ordinateL2Jicaitong_acc = i + upperBound; // jicaitongValue = crop.Get(i, middleJicaitong - leftBoundary);// miantongValueI; // jicaitongChanged = true; // break; // } // } // } //} ////if (isMiantong == 1 && jicaitongChanged && showMat) ////{ //// Mat thresh1 = 1 - filter.Threshold(0, 1, ThresholdTypes.Otsu);// 二值化 //// //Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(11/*15*/, 1/*水平线<--3, 3*/));// 开运算 //// //Mat open = new Mat(); //// ////OpenCV提取图像中的垂直线(或者水平线) 定义结构元素,开操作 //// //Cv2.MorphologyEx(thresh, open, MorphTypes.Open, seOpen); //// ////if (isMiantong > 0 && showMat) //// ////{ //// //// new Window("open", WindowMode.Normal, open * 255); //// //// Cv2.WaitKey(); //// ////} ////} ordinateL2_Acc = new double[] { ordinateL2Miantong_acc, ordinateL2Jicaitong_acc }; } /// /// 得到内部线纵坐标 /// /// 最好是绿色通道图 /// 上边界 /// 下边界 /// 左边界 /// 右边界 /// 输出坐标 public double InsideLine(Mat image, int upperBound, int lowerBound, int leftBoundary, int rightBoundary, out double meanOrdinate , int isMiantong = 0, bool showMat = false) { Mat crop = image[upperBound, lowerBound, leftBoundary-10, rightBoundary+10]; /*int pos = -1; int min = int.MaxValue; for(int i=0; i< crop.Height-5; i++) { int sum = (int)(crop.Row[i].Sum())+ (int)(crop.Row[i+1].Sum())+ (int)(crop.Row[i+2].Sum()) + (int)(crop.Row[i+3].Sum())+ (int)(crop.Row[i+4].Sum()); if (sum < min) { pos = i; min = sum; } } if((int)(image.Row[pos+ upperBound].Sum()) < (int)(image.Row[pos+ upperBound + 40].Sum()) && pos< crop.Height/2) { int start = pos + 10; pos = -1; min = int.MaxValue; for (int i = start; i < crop.Height; i++) { int sum = (int)(crop.Row[i].Sum()); if (sum < min) { pos = i; min = sum; } } } meanOrdinate = pos + upperBound; return meanOrdinate;*/ Mat filter = new Mat();//滤波增强对比 InputArray kernel = InputArray.Create(new int[3, 3] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } }); Cv2.Filter2D(crop, filter, -1, kernel); Cv2.ConvertScaleAbs(filter, filter); Mat thresh = 1 - filter.Threshold(0, 1, ThresholdTypes.Otsu); ;// 二值化 //待自测scc-3_2 //此处针对3(4)的类型图片做精准化调整 //int sizeSe = 3; if (isMiantong == 2) sizeSe = 1;// 3;// 1; //Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, sizeSe/*3*/));// 开运算 Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));// 开运算 Mat open = new Mat(); Cv2.MorphologyEx(thresh, open, MorphTypes.Open, seOpen); //if (isMiantong > 0 && showMat) //{ // Mat mat1 = new Mat(); // Cv2.Normalize(open, mat1, 0, 255, NormTypes.MinMax); // Cv2.ImWrite(@"C:\Users\54434\Desktop\open.JPG", mat1); //} Scalar sum = new Scalar(0); Scalar max1 = new Scalar(0); Scalar max = new Scalar(0); double meanOrdinate1 = 0; meanOrdinate = 0;//待自测scc-3_2 + upperBound; for (int i = crop.Rows / 4; i < crop.Rows / 4 * 3; i++) { sum = open[i, i + 2, 0, crop.Cols - 1].Sum(); if ((int)max < (int)sum) { if (isMiantong > 0 && i + upperBound > 10 + meanOrdinate) { max1 = max; meanOrdinate1 = meanOrdinate; } max = sum; meanOrdinate = i + upperBound; } else if (isMiantong > 0 && i + upperBound > 10 + meanOrdinate && (int)max1 < (int)sum) { max1 = sum; meanOrdinate1 = i + upperBound; } } if (isMiantong > 0) { if (meanOrdinate < meanOrdinate1 && isMiantong == 1 || meanOrdinate > meanOrdinate1 && meanOrdinate1 > 0 && isMiantong == 2 ) { double meanOrdinate_i = meanOrdinate; meanOrdinate = meanOrdinate1; meanOrdinate1 = meanOrdinate_i; } } //待自测scc-3_2 //if (meanOrdinate == upperBound) // meanOrdinate = meanOrdinate1; //尝试纠偏一下,可是还有差很亮的,可能还是需要二值 待确认@@@@@@@@@@@@@ if ((int)(image.Row[(int)meanOrdinate].Sum()) < (int)(image.Row[Math.Min(image.Rows - 1, (int)meanOrdinate + 40)].Sum())-100000 && (meanOrdinate- upperBound) < crop.Height / 2 && ((int)crop.Row[(int)meanOrdinate - upperBound + 10].Sum() - (int)crop.Row[(int)meanOrdinate - upperBound - 10].Sum()) < crop.Width*25) { int start = (int)(meanOrdinate - upperBound + 10); int pos = -1; int min = int.MaxValue; for (int i = start; i < crop.Height; i++) { int sum_a = (int)(crop.Row[i].Sum()); if (sum_a < min) { pos = i; min = sum_a; } } meanOrdinate = pos + upperBound; } #region[清理内存] if (crop != null) { crop.Dispose(); } if (open != null) { open.Dispose(); } if (filter != null) { filter.Dispose(); } if (thresh != null) { thresh.Dispose(); } if (seOpen != null) { seOpen.Dispose(); } #endregion return meanOrdinate1; } /// /// 將計算的範圍從整個行數變成四分之一到四分之三之間,不知道通孔和盲孔改變之後會不會有影響,暫時沒引用 /// /// /// /// /// /// /// public void InsideLine2(Mat image, int upperBound, int lowerBound, int leftBoundary, int rightBoundary, out double meanOrdinate) { Mat crop = image[upperBound, lowerBound, leftBoundary, rightBoundary]; Mat filter = new Mat();//滤波增强对比 InputArray kernel = InputArray.Create(new int[3, 3] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } }); Cv2.Filter2D(crop, filter, -1, kernel); Cv2.ConvertScaleAbs(filter, filter); Mat thresh = 1 - filter.Threshold(0, 1, ThresholdTypes.Otsu); ;// 二值化 Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));// 开运算 Mat open = new Mat(); Cv2.MorphologyEx(thresh, open, MorphTypes.Open, seOpen); //new Window("thresh", WindowMode.Normal, thresh * 255); //new Window("open", WindowMode.Normal, open * 255); //Cv2.WaitKey(); Scalar sum = new Scalar(0); Scalar max = new Scalar(0); meanOrdinate = 0; for (int i = crop.Rows / 4; i < crop.Rows / 4 * 3; i++) { sum = open[i, i + 2, 0, crop.Cols - 1].Sum(); if ((int)max < (int)sum) { max = sum; meanOrdinate = i + upperBound; } } } /// /// 图像画线,线颜色是红色 /// /// 画线图像 /// /// /// /// /// /// 计算盲孔的上孔径 /// /// 输入二值图片 /// 输入下孔径 /// 左边第三条线坐标 /// 右边第三条线坐标 /// 输出左边孔径坐标,先纵坐标后横坐标 /// 输出右边孔径坐标,先纵坐标后横坐标 public void ShangKongjing(/*Mat imageRed, */Mat image, int[] apertureLow, int leftOrdinate3, int rightOrdinate3, out int[] leftAperture, out int[] rightAperture) { leftAperture = new int[2] { 0, 0 }; rightAperture = new int[2] { 0, 0 }; int heightRange = 15; int widthMiddleRange = 1; int widthRange = 200; Mat cropLeft = 1 - image[leftOrdinate3 - heightRange, leftOrdinate3 + heightRange, Math.Abs(apertureLow[0] - widthRange), apertureLow[0] + widthMiddleRange]; //Mat crop = imageRed[leftOrdinate3 - 15, leftOrdinate3 + 15, apertureLow[0] - 50, apertureLow[0] + 10]; Mat cropRight = 1 - image[rightOrdinate3 - heightRange, rightOrdinate3 + heightRange, apertureLow[1] - widthMiddleRange, apertureLow[1] + widthRange]; for (int j = cropLeft.Cols - 1; j > 0; j--)//从右上角,以135°方向遍历 { for (int k = j; k < cropLeft.Cols && (k - j < cropLeft.Rows); k++) { if (cropLeft.Get(k - j, k) > 0) { leftAperture[0] = k - j + leftOrdinate3 - heightRange; leftAperture[1] = k + apertureLow[0] - widthRange; //LineShow(crop, new Point(k, k - j), new Point(k, k - j + 10)); //new Window("cropleft", WindowMode.Normal, crop); //Cv2.WaitKey(); break; } } if (leftAperture[0] != 0) break; } if (leftAperture[0] == 0) { for (int j = 1; j < cropLeft.Rows; j++) { for (int k = 0; k < cropLeft.Rows - j - 1; k++) { if (cropLeft.Get(j + k, k) > 0) { leftAperture[0] = j + k + leftOrdinate3 - heightRange; leftAperture[1] = k + apertureLow[0] - widthRange; break; } } if (leftAperture[0] != 0) break; } } for (int j = 0; j < cropRight.Cols; j++)//从左上角,45°方向遍历 { for (int k = j; k >= 0 && j - k < cropRight.Rows; k--) { if (cropRight.Get(j - k, k) > 0) { rightAperture[0] = j - k + rightOrdinate3 - heightRange; rightAperture[1] = k + apertureLow[1] - widthMiddleRange; break; } } if (rightAperture[0] != 0) break; } if (rightAperture[0] == 0) { for (int j = 1; j < cropRight.Rows; j++) { for (int k = cropRight.Cols - 1; cropRight.Cols - 1 - k < cropRight.Rows - j - 1; k--) { if (cropRight.Get(j + cropRight.Cols - 1 - k, k) > 0) { rightAperture[0] = j + cropRight.Cols - 1 - k + rightOrdinate3 - heightRange; rightAperture[1] = k + apertureLow[1] - widthMiddleRange; break; } } if (rightAperture[0] != 0) break; } } //new Window("cropleft", WindowMode.Normal, cropLeft * 255); //new Window("cropRight", WindowMode.Normal, cropRight * 255); //Cv2.WaitKey(); } /// /// 计算盲孔的上孔径,修改了计算方法,通过孔径不为零坐标和的最小值来定位 /// /// 输入二值图片 /// 输入下孔径 /// 左边第三条线坐标 /// 右边第三条线坐标 /// 输出左边孔径坐标,先纵坐标后横坐标 /// 输出右边孔径坐标,先纵坐标后横坐标 public void ShangKongjing2(Mat image, int[] apertureLow, int leftOrdinate3, int rightOrdinate3, out int[] leftAperture, out int[] rightAperture) { leftAperture = new int[2] { 0, 0 }; rightAperture = new int[2] { 0, 0 }; int heightRange = 10; int widthMiddleRange = 50; int widthRange = 200; Mat cropLeft = 1 - image[leftOrdinate3 - heightRange, leftOrdinate3 + heightRange, apertureLow[0] - widthRange, apertureLow[0] + widthMiddleRange]; //Mat crop = imageRed[leftOrdinate3 - 15, leftOrdinate3 + 15, apertureLow[0] - 50, apertureLow[0] + 10]; Mat cropRight = 1 - image[rightOrdinate3 - heightRange, rightOrdinate3 + heightRange, apertureLow[1] - widthMiddleRange, apertureLow[1] + widthRange]; Cv2.Flip(cropLeft, cropLeft, FlipMode.Y); int minLeft = 1000, minRight = 1000; int t1 = 0, t2 = 0; for (int i = 0; i < cropLeft.Rows; i++) { for (int j = 0; j < cropLeft.Cols; j++) { if (cropLeft.Get(i, j) > 0) { t1 = i + j; } if (minLeft > t1 + 10 && t1 != 0) { minLeft = t1; leftAperture[0] = i + leftOrdinate3 - heightRange; leftAperture[1] = cropLeft.Cols - j + apertureLow[0] - widthRange; } } } for (int i = 0; i < cropRight.Rows; i++) { for (int j = 0; j < cropRight.Cols; j++) { if (cropRight.Get(i, j) > 0) { t2 = i + j; } if (minRight > t2 && t2 != 0) { minRight = t2; rightAperture[0] = i + rightOrdinate3 - heightRange; rightAperture[1] = j + apertureLow[1] - widthMiddleRange; } } } //new Window("cropcontour", WindowMode.Normal, image * 255); new Window("cropleft", WindowMode.Normal, cropLeft * 255); //new Window("cropright", WindowMode.Normal, cropRight * 255); Cv2.WaitKey(); } //蝕刻因子 /// /// 得到蝕刻因子圖像的提取區域 /// /// 輸入二值圖像 /// 輸出邊界位置,0:上界;1:下界;2:左界;3:右界 public void SKYZDataArea(Mat imageContour, out int[] dataArea, bool isCropFlag) { dataArea = new int[4] { 0, 0, 0, 0 }; Scalar sum = new Scalar(); for (int i = 100; i < imageContour.Rows; i++) { sum = imageContour[i, i + 1, 0, imageContour.Cols].Sum(); if ((int)sum > 0) { dataArea[0] = i;//上界 break; } } for (int i = dataArea[0]; i < imageContour.Rows; i++) { sum = imageContour[i, i + 1, 0, imageContour.Cols].Sum(); if ((int)sum == 0) { dataArea[1] = i;//下界 break; } } if (isCropFlag) { for (int j = 0; j < imageContour.Cols - 1; j++) { sum = imageContour[dataArea[0], dataArea[1], j, j + 1].Sum(); if ((int)sum > 0) { dataArea[2] = j; break; } } for (int j = imageContour.Cols - 1; j > 1; j--) { sum = imageContour[dataArea[0], dataArea[1], j - 1, j].Sum(); { if ((int)sum > 0) { dataArea[3] = j; break; } } } } else { int t = 0; for (int j = imageContour.Cols - 100; j > 0; j--) { sum = imageContour[dataArea[0], dataArea[1], j - 1, j].Sum(); if ((int)sum > 0) { t = j;//最右邊的開始 break; } } for (int j = t - 1; j > 0; j--) { sum = imageContour[dataArea[0], dataArea[1], j - 1, j].Sum(); if ((int)sum == 0) { t = j;//最右邊的結束 break; } } for (int j = t - 1; j > 0; j--) { sum = imageContour[dataArea[0], dataArea[1], j - 1, j].Sum(); if ((int)sum > 0) { t = j;//中間開始 dataArea[3] = j; break; } } for (int j = t - 1; j > 0; j--) { sum = imageContour[dataArea[0], dataArea[1], j - 1, j].Sum(); if ((int)sum == 0) { t = j;//中間結束 dataArea[2] = j; break; } } } } /// /// 提取上幅的值及坐標 /// /// 輸入二值圖像 /// 上幅的大小 /// 上幅的坐標,0:縱坐標;1:左橫坐標;2:右橫坐標 public void UpperLine(Mat imageContour, out int upperLineValue, out int[] upperLineOrdinate) { upperLineValue = 0; upperLineOrdinate = new int[3] { 0, 0, 0 }; int cols = imageContour.Cols; int rows = imageContour.Rows; Scalar sum = new Scalar(); for (int i = 0; i < rows - 150; i++) { sum = imageContour[i, i + 1, 0, cols].Sum(); if ((int)sum > cols * 5 / 6)//儅每行點數大於寬度的五分之四時,判爲上幅 { upperLineOrdinate[0] = i; break; } } if (upperLineOrdinate[0] == 0)//如果没有检测到 { for (int i = 0; i < rows / 4; i++) { sum = imageContour[i, i + 1, 0, cols].Sum(); if ((int)sum > cols * 4 / 5)//儅每行點數大於寬度的五分之三時,判爲上幅 { upperLineOrdinate[0] = i; break; } } } int max = 0; int t = upperLineOrdinate[0]; //繼續向下10(5)個像素尋找最大行,并認爲是上幅 for (int i = t; i < t + 10; i++) { sum = imageContour[i, i + 1, 0, cols].Sum(); if ((int)sum > max) { max = (int)sum; upperLineOrdinate[0] = i; } } //左邊點坐標 for (int j = 0; j < cols; j++) { if (imageContour.Get(upperLineOrdinate[0], j) > 0) { upperLineOrdinate[1] = j; break; } } //右邊點坐標 for (int j = cols - 1; j > 0; j--) { if (imageContour.Get(upperLineOrdinate[0], j) > 0) { upperLineOrdinate[2] = j; break; } } upperLineValue = upperLineOrdinate[2] - upperLineOrdinate[1]; } public void UpperLine2(Mat imageContour, out int upperLineValue, out int[] upperLineOrdinate) { upperLineValue = 0; upperLineOrdinate = new int[3] { 0, 0, 0 }; int cols = imageContour.Cols; int rows = imageContour.Rows; Scalar sum = new Scalar(); for (int i = 0; i < rows - 150; i++) { sum = imageContour[i, i + 1, 0, cols].Sum(); if ((int)sum > cols * 5 / 6)//儅每行點數大於寬度的五分之四時,判爲上幅 { upperLineOrdinate[0] = i; break; } } if (upperLineOrdinate[0] == 0)//如果没有检测到 { for (int i = 0; i < rows / 4; i++) { sum = imageContour[i, i + 1, 0, cols].Sum(); if ((int)sum > cols * 4 / 5)//儅每行點數大於寬度的五分之三時,判爲上幅 { upperLineOrdinate[0] = i; break; } } } if (upperLineOrdinate[0] == 0)//如果没有检测到 { for (int i = 0; i < rows / 3; i++) { sum = imageContour[i, i + 1, 0, cols].Sum(); if ((int)sum > cols * 3 / 5)//儅每行點數大於寬度的五分之三時,判爲上幅 { upperLineOrdinate[0] = i; break; } } } if (upperLineOrdinate[0] == 0)//如果没有检测到 { for (int i = 0; i < rows / 3; i++) { sum = imageContour[i, i + 1, 0, cols].Sum(); if ((int)sum > cols * 2 / 5)//儅每行點數大於寬度的五分之三時,判爲上幅 { upperLineOrdinate[0] = i; break; } } } int max = 0; int t = upperLineOrdinate[0]; //繼續向下10(5)個像素尋找最大行,并認爲是上幅 for (int i = t; i < t + 10; i++) { sum = imageContour[i, i + 1, 0, cols].Sum(); if ((int)sum > max) { max = (int)sum; upperLineOrdinate[0] = i; } } //左邊點坐標 for (int j = 0; j < cols; j++) { if (imageContour.Get(upperLineOrdinate[0], j) > 0) { upperLineOrdinate[1] = j; break; } } //右邊點坐標 for (int j = cols - 1; j > 0; j--) { if (imageContour.Get(upperLineOrdinate[0], j) > 0) { upperLineOrdinate[2] = j; break; } } upperLineValue = upperLineOrdinate[2] - upperLineOrdinate[1]; } /// /// 計算蝕刻因子上下的總後的值和坐標(是單層的銅厚) /// /// 二值圖像 /// 輸出銅厚的值 /// 輸出銅厚的坐標,0:橫坐標;1:上縱坐標;2:下縱坐標 public void Zonghou(Mat imageContour, out int zonghouValue, out int[] zonghouOrdinate) { zonghouValue = 0; zonghouOrdinate = new int[3]; int rows = imageContour.Rows; int cols = imageContour.Cols; int middle = cols / 2; zonghouOrdinate[0] = middle; for (int i = 0; i < rows; i++) { if (imageContour.Get(i, middle) > 0) { zonghouOrdinate[1] = i; break; } } for (int i = rows - 1; i > 0; i--) { if (imageContour.Get(i, middle) > 0) { zonghouOrdinate[2] = i; break; } } zonghouValue = zonghouOrdinate[2] - zonghouOrdinate[1]; } /// /// 計算銅厚以及銅厚坐標 /// /// 綠色通道圖像 /// 二值圖像 /// 銅厚大小 /// 銅厚坐標,0:橫坐標;1:上縱坐標;2:下縱坐標 public void Tonghou(Mat imageGreen, Mat imageContour, out int tonghouValue, out int[] tonghouOrdinate) { tonghouValue = 0; tonghouOrdinate = new int[3]; int rows = imageGreen.Rows; int cols = imageGreen.Cols; int middle = cols / 2; tonghouOrdinate[0] = (middle + cols) / 2; double insideLine; InsideLine2(imageGreen, 30, rows - 50, 20, cols - 20, out insideLine); tonghouOrdinate[1] = (int)insideLine; for (int i = rows - 1; i > 0; i--) { if (imageContour.Get(i, tonghouOrdinate[0]) > 0) { tonghouOrdinate[2] = i; break; } } tonghouValue = tonghouOrdinate[2] - tonghouOrdinate[1]; } #region 防焊 #region 没开口 /// /// 防焊 有开口 铜厚 /// /// /// /// /// public void FanghanTonghouForMeiKaiKou(Mat gray, out int[] tonghouY, out int[] y, out int[] b) { y = new int[2]; b = new int[4]; tonghouY = new int[2]; Mat contour = new Mat(); double T = 0; double t = Cv2.Threshold(gray, contour, 0, 255, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(15, 15)); Mat close = new Mat(); Cv2.MorphologyEx(contour, close, MorphTypes.Close, seClose); Mat result = close.Clone(); result = result / 255; //ImageShow(result * 255); //计算边界 Scalar sum = new Scalar(0); for (int i = 0; i < result.Rows; i++) { sum = result[i, i + 1, 0, result.Cols].Sum(); if ((int)sum > 200) { y[0] = i - 20; break; } } for (int i = y[0] + 50; i < result.Rows; i++) { sum = result[i, i + 1, 0, result.Cols].Sum(); if ((int)sum == 0) { y[1] = i; break; } } for (int j = 0; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 20) { b[0] = j; break; } } for (int j = b[0] + 200; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { b[1] = j; break; } } for (int j = b[1] + 10; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 20) { b[2] = j; break; } } if (b[2] - b[1] < 300) { for (int j = b[2] + 50; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { b[1] = j; break; } } for (int j = b[1] + 10; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 20) { b[2] = j; break; } } } for (int j = b[2] + 50; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { b[3] = j; break; } } if (b[3] == 0) b[3] = contour.Cols - 1; //计算铜厚 int tonghouX = b[1] - 150; Mat thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); for (int i = y[0]; i < y[1]; i++) { sum = thresh[i, i + 1, tonghouX - 30, tonghouX + 30].Sum(); if ((int)sum > 30) { tonghouY[0] = i; break; } } contour = contour / 255; for (int i = tonghouY[0] + 30; i < contour.Rows; i++) { sum = contour[i, i + 1, tonghouX - 30, tonghouX + 30].Sum(); if ((int)sum == 0) { tonghouY[1] = i; break; } } } /// /// 防焊 有开口 厚度 /// /// /// /// /// /// /// public void FanghanhouduForMeiKaiKou_2(Mat gray, int[] y, int fanghanhouduX, int[] tonghouY, out int fanghanhouduY1, out int minGray, bool isLeft) { int fanghanhouduY_0 = tonghouY[0]; int fanghanX1 = Math.Max(0, fanghanhouduX - 150); int fanghanX2 = Math.Min(gray.Cols - 1, fanghanhouduX + 150); int fanghanTop = fanghanhouduY_0 - 150/*100*/; int marginTop = 150; if (fanghanTop < 0) { fanghanTop = 0; marginTop = fanghanhouduY_0 - 1; } Mat grayRect = gray[fanghanTop, fanghanhouduY_0 - 50, fanghanX1, fanghanX2]; FanghanhouduForMeiKaiKou(grayRect, y, marginTop, tonghouY, out fanghanhouduY1, out minGray); int fanghanhouduY1__2 = fanghanhouduY1; int minGray__2 = minGray; fanghanX1 += 140;// 145; fanghanX2 -= 140;// 145; grayRect = gray[fanghanTop, fanghanhouduY_0 - 20/*50*/, fanghanX1, fanghanX2]; int fanghanhouduY1__2_bottom; FanghanhouduForYouKaiKou_ACC(grayRect, y, marginTop, fanghanhouduY1 - (isLeft ? 8/*5*/ : 1), out fanghanhouduY1__2, out fanghanhouduY1__2_bottom, out minGray__2); if (Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 16/*11*//*<-10*//*20*//*10*/ || (!isLeft && Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 25/*20*/)) fanghanhouduY1 = fanghanhouduY1__2/*fanghanhouduY1__2_bottom*//*fanghanhouduY1__2*/ + fanghanTop;// +5; //else //{ // fanghanX1 -= 69; // fanghanX2 += 69; // grayRect = gray[fanghanTop, fanghanhouduY_0 - 50, fanghanX1, fanghanX2]; // FanghanhouduForMeiKaiKou(grayRect, y, marginTop, tonghouY, out fanghanhouduY1__2, out minGray__2); //} //if (Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 10) // fanghanhouduY1 = fanghanhouduY1__2 + fanghanTop; else fanghanhouduY1 = fanghanhouduY1 + fanghanTop; } /// /// 防焊 有开口 厚度 精确计算 统一到有开口的方法精确定位 避免个别因素产生大的偏差 /// /// /// /// /// /// /// private void FanghanhouduForMeiKaiKou_ACC(Mat gray, int[] y, int fanghanhouduX, int fanghanhouduY1__0, out int fanghanhouduY1, out int fanghanhouduY1Bottom, out int minGray, int a = 0) { minGray = 300 * 255; int minRowIndex = 0; int colEnd = gray.Cols - 1; int curGray; List curGrayList = new List(); fanghanhouduY1Bottom = 0; for (int i = Math.Max(0, fanghanhouduY1__0 - 0/*1*//*5*//*10*/); i < Math.Min(fanghanhouduY1__0 + 30/*25*/, gray.Rows) - 5; i++) { curGray = this.FanghanhouduForAreaMin(gray, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; curGrayList.Add(curGray); if (curGray < minGray) { minRowIndex = i; fanghanhouduY1Bottom = i; minGray = curGray; } } for (int i = minRowIndex - Math.Max(0, fanghanhouduY1__0 - 0/*1*//*5*//*10*/) + 2; i < curGrayList.Count; i+=2) { if (Math.Abs(curGrayList[i] - minGray) < 10/*100*/) { minRowIndex += 1; fanghanhouduY1Bottom += 2; } } //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); fanghanhouduY1 = minRowIndex;// 84;// 72;// minRowIndex; } /// /// 防焊 有开口 厚度 /// /// /// /// /// /// /// private void FanghanhouduForMeiKaiKou(Mat gray, int[] y, int fanghanhouduX, int[] tonghouY, out int fanghanhouduY1, out int minGray, int a = 0) { ///*int fanghanhouduX = 150; */ //fanghanhouduY1 = -1; //Mat thresh = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", thresh); //for (int i = 0; i < Math.Min(100, thresh.Rows); i++) //{ // if (thresh.At(i, fanghanhouduX) == 0 && Cv2.FloodFill(thresh, new Point(fanghanhouduX, i), new Scalar(255)) > 300) // { // //fanghanhouduY1 = i; // int sumTop = Cv2.FloodFill(thresh, new Point(fanghanhouduX, i), new Scalar(255)); // int searchTimes = 15; // while (searchTimes-- > 0 && i+2 < thresh.Rows && sumTop == Cv2.FloodFill(thresh, new Point(fanghanhouduX, ++i), new Scalar(255))) // { // //fanghanhouduY1 = i; // } // fanghanhouduY1 = i; // break; // } //} minGray = 300 * 255; //if (fanghanhouduY1 == -1) // FanghanhouduForMeiKaiKou(gray, y, fanghanhouduX, tonghouY, out fanghanhouduY1, out minGray, ++a); //else {//计算数值的地方 //Console.WriteLine("fanghanhouduY1_0:" + fanghanhouduY1); /*int minGray = 300*255; */ int minRowIndex = 0; int colEnd = gray.Cols - 1; int curGray; for (int i = 6/*1*/; i < Math.Min(100, gray.Rows) - 5; i++) { curGray = this.FanghanhouduForAreaMin(gray, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; if (curGray < minGray) { minRowIndex = i; minGray = curGray; } } //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); fanghanhouduY1 = minRowIndex; } } public void FanghanhouduForMeiKaiKou_Undercut0(Mat thres_2, int scanX_start, int scanX_end, int fanghanhouduY_1/*fanghanhouduY_center*/, int fanghanhouduY_2/*fanghanhouduY_radius*/, out int fanghanhouduX_0, bool showMat = false) { //int fanghanhouduY_1 = fanghanhouduY_center - fanghanhouduY_radius; //int fanghanhouduY_2 = fanghanhouduY_center + fanghanhouduY_radius; int vmax_2 = 0; int vres_y = 1000;// 3000; List vmax_x = new List(); for (int i = scanX_start; i < scanX_end; i++) { if (thres_2[fanghanhouduY_1, fanghanhouduY_2, i - 1, i].Sum().Val0 > vres_y) { vmax_2 = (int)thres_2[fanghanhouduY_1, fanghanhouduY_2, i - 1, i].Sum().Val0; vmax_x.Add(i); ; } } List vmax_x_temp = new List(); vmax_x_temp.AddRange(vmax_x); while (vmax_x.Count > 10 && vmax_x_temp.Count > 1) { vres_y += 500;// 1000; vmax_x_temp.Clear(); for (int i = scanX_start; i < scanX_end; i++) { if (thres_2[fanghanhouduY_1, fanghanhouduY_2, i - 1, i].Sum().Val0 > vres_y) { vmax_2 = (int)thres_2[fanghanhouduY_1, fanghanhouduY_2, i - 1, i].Sum().Val0; vmax_x_temp.Add(i); ; } } if (vmax_x_temp.Count > 1) { vmax_x.Clear(); vmax_x.AddRange(vmax_x_temp); } } if (vmax_x.Count == 0) { vmax_x.Add(0); for (int i = scanX_start; i < scanX_end; i++) { if (thres_2[fanghanhouduY_1, fanghanhouduY_2, i - 1, i].Sum().Val0 > vmax_2) { vmax_2 = (int)thres_2[fanghanhouduY_1, fanghanhouduY_2, i - 1, i].Sum().Val0; vmax_x[0] = i; } } } else if (vmax_x.Count > 3) { bool isround = false;//去掉球上的点 int lastmax_x = vmax_x[vmax_x.Count - 1]; int endIndex = vmax_x.Count - 4; for (int i = vmax_x.Count - 2; i > 0; i--) { if (vmax_x[i] - 20 > lastmax_x) { endIndex = i; isround = true; break; } lastmax_x = vmax_x[i]; } if (isround) { int max_y_res = 100; for (int i = vmax_x.Count - 1; i > endIndex; i--) { if (vmax_x[Math.Max(0, i - 2)] > max_y_res) { break; } vmax_x.RemoveAt(i); } } } fanghanhouduX_0 = (vmax_x.Count > 1 ? (vmax_x[vmax_x.Count - 2] + vmax_x[vmax_x.Count - 1]) / 2 : vmax_x[0]); } public void FanghanhouduForMeiKaiKou_Offset0(Mat thres_2_0, int scanX_start, int scanX_end, int fanghanhouduY_1/*fanghanhouduY_center*/, int fanghanhouduY_2/*fanghanhouduY_radius*/, out int fanghanhouduX_0, bool showMat = false) { //int fanghanhouduY_1 = fanghanhouduY_center - fanghanhouduY_radius; //int fanghanhouduY_2 = fanghanhouduY_center + fanghanhouduY_radius; List vmax_x_scanStart = new List(); for (int i = scanX_start; i < scanX_end; i++) vmax_x_scanStart.Add((int)thres_2_0[fanghanhouduY_1, fanghanhouduY_2, i - 1, i].Sum().Val0); int vmax_2 = 0; int vres_y = 1000;// 3000; List vmax_x = new List(); for (int i = scanX_start; i < scanX_end; i++) { if (vmax_x_scanStart[i - scanX_start] > vres_y) { vmax_2 = vmax_x_scanStart[i - scanX_start]; vmax_x.Add(i); ; } } List vmax_x_temp = new List(); vmax_x_temp.AddRange(vmax_x); int temp_x_left = vmax_x.Count > 0 ? vmax_x[0] : scanX_start; //bool fanghanhouduX_0_Found = false; fanghanhouduX_0 = 300; while (vmax_x.Count > 10 && vmax_x_temp.Count > 1/* && !fanghanhouduX_0_Found*/) { vres_y += 500;// 500;// 1000; vmax_x_temp.Clear(); for (int i = scanX_start; i < scanX_end; i++) { if (vmax_x_scanStart[i - scanX_start] > vres_y) { vmax_2 = vmax_x_scanStart[i - scanX_start]; vmax_x_temp.Add(i); ; } } if (vmax_x_temp.Count > 19) { vmax_x.Clear(); vmax_x.AddRange(vmax_x_temp); Console.WriteLine("temp_x_left:" + vmax_x[0] + ";vmax_x.Count:" + vmax_x.Count); ////根据数值是否断开距离超过20判定offset左端点,其中60、370、20为超参参数 //if (vmax_x_temp.Count < 60) // for (int i = 1; i < vmax_x.Count; i++) //{ // if (vmax_x[i-1] < 370) continue; // if (vmax_x[i] > vmax_x[i - 1] + 20) // { // fanghanhouduX_0 = vmax_x[i-1];// 384;// prev_x_v / prev_x_c; // fanghanhouduX_0_Found = true; // break; // } //} } } //if (fanghanhouduX_0_Found) //{ // return; //} if (vmax_x.Count == 0) { vmax_x.Add(0); for (int i = scanX_start; i < scanX_end; i++) { if (vmax_x_scanStart[i - scanX_start] > vmax_2) { vmax_2 = vmax_x_scanStart[i - scanX_start]; vmax_x[0] = i; } } } else if (vmax_x.Count > 3) { bool isround = false;//去掉球上的点 int lastmax_x = vmax_x[vmax_x.Count - 1]; int endIndex = vmax_x.Count - 4; for (int i = vmax_x.Count - 2; i > 0; i--) { if (vmax_x[i] - 20 > lastmax_x) { endIndex = i; isround = true; break; } lastmax_x = vmax_x[i]; } if (isround) { int max_y_res = 100; for (int i = vmax_x.Count - 1; i > endIndex; i--) { if (vmax_x[Math.Max(0, i - 2)] > max_y_res) { break; } vmax_x.RemoveAt(i); } } } if (vmax_x.Count > 2) { int vmax_x_v = vmax_x[0]; int vmax_x_c = 1; int prev_x_v = vmax_x_v; int prev_x_c = vmax_x_c; for (int i = 1; i < vmax_x.Count; i++) { if (vmax_x[i] < vmax_x[i - 1] + 2) { vmax_x_v += vmax_x[i]; vmax_x_c += 1; } else { if (prev_x_c <= vmax_x_c) { prev_x_v = vmax_x_v; prev_x_c = vmax_x_c; } i++; vmax_x_v = vmax_x[i]; vmax_x_c = 1; } } if (prev_x_c <= vmax_x_c+1) { prev_x_v = vmax_x_v; prev_x_c = vmax_x_c; } fanghanhouduX_0 = prev_x_v / prev_x_c; if (fanghanhouduX_0 > thres_2_0.Cols-30) { fanghanhouduX_0 = 382 - 100; Console.WriteLine("temp_x_left: OverLoad 1"); } else if (vmax_x.Count > 20) { Console.WriteLine("temp_x_left: OverLoad 2"); } } else fanghanhouduX_0 = (vmax_x.Count > 1 ? (vmax_x[vmax_x.Count - 2] + vmax_x[vmax_x.Count - 1]) / 2 : vmax_x[0]); } /// /// 防焊 没有开口 厚度 /// /// /// /// /// /// /// public void FanghanhouduForMeiKaiKou_2(Mat thres_2, int fanghanhouduX_center, int fanghanhouduX_radius, out int fanghanhouduY_0, bool showMat = false) { int fanghanhouduX_1 = fanghanhouduX_center - fanghanhouduX_radius; int fanghanhouduX_2 = fanghanhouduX_center + fanghanhouduX_radius; int vmax_2 = 0; int vres_y = 3000; List vmax_y = new List(); //int vmax_y = crop2.Rows - 2; for (int i = thres_2.Rows - 2; i > 0; i--) { if (thres_2[i - 1, i, fanghanhouduX_1, fanghanhouduX_2].Sum().Val0 > vres_y) //|| Cv2.FloodFill(max, new Point(leftFanghanhoudu[0], i), new Scalar(1/*255*/)) > 3500) { vmax_2 = (int)thres_2[i - 1, i, fanghanhouduX_1, fanghanhouduX_2].Sum().Val0; vmax_y.Add(i); ; } } List vmax_y_temp = new List(); vmax_y_temp.AddRange(vmax_y); while (vmax_y.Count > 10 && vmax_y_temp.Count > 1) { vres_y += 1000; //int vmax_y = crop2.Rows - 2; vmax_y_temp.Clear(); for (int i = thres_2.Rows - 2; i > 0; i--) { if (thres_2[i - 1, i, fanghanhouduX_1, fanghanhouduX_2].Sum().Val0 > vres_y) //|| Cv2.FloodFill(max, new Point(leftFanghanhoudu[0], i), new Scalar(1/*255*/)) > 3500) { vmax_2 = (int)thres_2[i - 1, i, fanghanhouduX_1, fanghanhouduX_2].Sum().Val0; vmax_y_temp.Add(i); ; } } if (vmax_y_temp.Count > 1) { vmax_y.Clear(); vmax_y.AddRange(vmax_y_temp); } } if (vmax_y.Count == 0) { vmax_y.Add(0); for (int i = thres_2.Rows - 2; i > 0; i--) { if (thres_2[i - 1, i, fanghanhouduX_1, fanghanhouduX_2].Sum().Val0 > vmax_2) //|| Cv2.FloodFill(max, new Point(leftFanghanhoudu[0], i), new Scalar(1/*255*/)) > 3500) { vmax_2 = (int)thres_2[i - 1, i, fanghanhouduX_1, fanghanhouduX_2].Sum().Val0; vmax_y[0] = i; } } } else if (vmax_y.Count > 3) { bool isround = false;//去掉球上的点 int lastmax_y = vmax_y[vmax_y.Count - 1]; int endIndex = vmax_y.Count - 4; for (int i = vmax_y.Count - 2; i > 0; i--) { if (vmax_y[i] - 20 > lastmax_y) { endIndex = i; isround = true; break; } lastmax_y = vmax_y[i]; } if (isround) { int max_y_res = 100; for (int i = vmax_y.Count - 1; i > endIndex; i--) { if (vmax_y[Math.Max(0, i - 2)] > max_y_res) { break; } vmax_y.RemoveAt(i); } } } fanghanhouduY_0 = (vmax_y.Count > 1 ? (vmax_y[vmax_y.Count - 2] + vmax_y[vmax_y.Count - 1]) / 2 : vmax_y[0]); } ///// ///// 防焊 没有开口 銅厚 ///// ///// 二值圖像 ///// 輸出銅厚的上下縱坐標 ///// 截取第一層銅的區域 ///// b[0]:銅起始點;b[1]:銅結束點;b[2]:銅再次開始點 //public void FanghanTonghouForMeiKaiKou(Mat gray, out int[] tonghouY, out int[] y, out int[] b) //{ // y = new int[2]; // b = new int[4]; // int[] bAdd = new int[5]; // tonghouY = new int[2]; // Mat contour = gray.Threshold(0, 255, ThresholdTypes.Otsu); // //去掉小颗粒 // contour = BinaryTools.DebrisRemoval_New(contour.CvtColor(ColorConversionCodes.GRAY2BGRA), 1000).CvtColor(ColorConversionCodes.BGRA2GRAY); // //分析的区域切图的不对[2]to do // // //Cv2.ImWrite(@"C:\Users\54434\Desktop\contour.JPG", contour); // Mat result = contour.Clone() / 255; // //计算边界 // Scalar sum = new Scalar(0); // for (int i = 0; i < result.Rows; i++) // { // sum = result[i, i + 1, 0, result.Cols].Sum(); // if ((int)sum > 200) // { // y[0] = i - 20; // break; // } // } // ////区分突然骤减的情况也说明已经到了铜厚的底部 // //List listSum = new List(); // //listSum.Add((int)sum); // //int halfOfSumTime = 0; // for (int i = y[0] + 50; i < result.Rows; i++) // { // sum = result[i, i + 1, 0, result.Cols].Sum(); // if ((int)sum == 0) // { // y[1] = i; // break; // } // //if ((int)sum * 2 < listSum.Average()) // //{ // // if (++halfOfSumTime > 3) // // { // // y[1] = i; // // //break; // // } // //} // //else // //{ // // halfOfSumTime = 0; // // listSum.Add((int)sum); // //} // } // if (y[0] <= 0 || y[1] <= 0) // { // contour = gray.Threshold(BinaryTools.CalcSuitableValueForMax(gray), 255, ThresholdTypes.Binary); // result = contour.Clone() / 255; // for (int i = 0; i < result.Rows; i++) // { // sum = result[i, i + 1, 0, result.Cols].Sum(); // if ((int)sum > 200) // { // y[0] = i - 20; // break; // } // } // for (int i = y[0] + 50; i < result.Rows; i++) // { // sum = result[i, i + 1, 0, result.Cols].Sum(); // if ((int)sum == 0) // { // y[1] = i; // break; // } // } // for (int j = 0; j < result.Cols; j++) // { // sum = result[y[0], y[1], j, j + 1].Sum(); // if ((int)sum > 0) // { // b[0] = j; // bAdd[0] = j; // break; // } // } // for (int j = b[0] + 200; j < result.Cols; j++) // { // sum = result[y[0], y[1], j, j + 1].Sum(); // if ((int)sum == 0) // { // b[1] = j; // bAdd[1] = j; // break; // } // } // } // for (int j = 0; j < result.Cols; j++) // { // sum = result[y[0], y[1], j, j + 1].Sum(); // if ((int)sum > 0) // { // b[0] = j; // bAdd[0] = j; // break; // } // } // for (int j = b[0] + 50; j < result.Cols; j++) // { // sum = result[y[0], y[1], j, j + 1].Sum(); // if ((int)sum == 0) // { // b[1] = j; // bAdd[1] = j; // break; // } // } // //暂时这么一写 // if (b[1] <= 0) // { // contour = gray.Threshold(BinaryTools.CalcSuitableValueForMax(gray), 255, ThresholdTypes.Binary); // //去掉小颗粒 // contour = BinaryTools.DebrisRemoval_New(contour.CvtColor(ColorConversionCodes.GRAY2BGRA), 1000).CvtColor(ColorConversionCodes.BGRA2GRAY); // result = contour.Clone() / 255; // for (int i = 0; i < result.Rows; i++) // { // sum = result[i, i + 1, 0, result.Cols].Sum(); // if ((int)sum > 200) // { // y[0] = i - 20; // break; // } // } // for (int i = y[0] + 50; i < result.Rows; i++) // { // sum = result[i, i + 1, 0, result.Cols].Sum(); // if ((int)sum == 0) // { // y[1] = i; // break; // } // } // if (y[0] < 0 || y[1] < 0) return; // for (int j = 0; j < result.Cols; j++) // { // sum = result[y[0], y[1], j, j + 1].Sum(); // if ((int)sum > 0) // { // b[0] = j; // bAdd[0] = j; // break; // } // } // for (int j = b[0] + 50; j < result.Cols; j++) // { // sum = result[y[0], y[1], j, j + 1].Sum(); // if ((int)sum == 0) // { // b[1] = j; // bAdd[1] = j; // break; // } // } // } // for (int j = b[1] + 10; j < result.Cols; j++) // { // sum = result[y[0], y[1], j, j + 1].Sum(); // if ((int)sum > 0) // { // b[2] = j; // bAdd[2] = j; // break; // } // } // if (b[2] - b[1] < 300) // { // for (int j = b[2] + 50; j < result.Cols; j++) // { // sum = result[y[0], y[1], j, j + 1].Sum(); // if ((int)sum == 0) // { // b[1] = j; // bAdd[1] = j; // break; // } // } // for (int j = b[1] + 10; j < result.Cols; j++) // { // sum = result[y[0], y[1], j, j + 1].Sum(); // if ((int)sum > 0) // { // b[2] = j; // bAdd[2] = j; // break; // } // } // } // for (int j = bAdd[2] + 50; j < result.Cols; j++) // { // sum = result[y[0], y[1], j, j + 1].Sum(); // if ((int)sum == 0) // { // bAdd[3] = j - 1; // break; // } // } // if (bAdd[3] == 0) // bAdd[3] = contour.Cols - 1; // for (int j = bAdd[3] + 10; j < result.Cols; j++) // { // sum = result[y[0], y[1], j, j + 1].Sum(); // if ((int)sum > 0) // { // bAdd[4] = j; // break; // } // } // for (int j = result.Cols - 1; j > b[2]; j--) // { // sum = result[y[0], y[1], j - 1, j].Sum(); // if ((int)sum > 0) // { // b[3] = j; // break; // } // } // if (b[3] == 0) // b[3] = contour.Cols - 1; // //bAdd[5] = b[3]; // if (b[3] != bAdd[3] && b[3] - bAdd[2] > bAdd[3] - b[0] && (b[0] < 20 && b[1] < 60 && (b[1] < 280 && b[0] < 100 || b[3] == contour.Cols-1))/*防止过拟合*/)//测量区域在右边 // { // b[2] = bAdd[4]; // b[1] = bAdd[3]; // b[0] = bAdd[2]; // } // //计算铜厚 // int tonghouX = b[1] - 50; // if (tonghouX <= 0) return; // Mat thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); // for (int i = y[0]; i < y[1]; i++) // { // sum = thresh[i, i + 1, (tonghouX - 50) < 0 ? 0 : (tonghouX - 50), tonghouX + 50].Sum(); // if ((int)sum > 20) // { // tonghouY[0] = i; // break; // } // } // contour = contour / 255; // for (int i = tonghouY[0] + 30; i < contour.Rows; i++) // { // sum = contour[i, i + 1, (tonghouX - 50) < 0 ? 0 : (tonghouX - 50), tonghouX + 50].Sum(); // if ((int)sum == 0) // { // tonghouY[1] = i; // break; // } // } //} ///// ///// 防焊 没有开口 厚度 ///// ///// ///// ///// ///// ///// ///// //public Mat FanghanhouduForMeiKaiKou(Mat gray, int[] y, int[] b, int[] tonghouY, out int[] fanghanhouduY, int a = 0, bool showMat = false) //{ // fanghanhouduY = new int[2]; // int fanghanhouduX = b[1] - 100; // Mat maskRes = new Mat(gray.Rows + 2, gray.Cols + 2, MatType.CV_8UC1); // Mat thresh = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); // fanghanhouduY[0] = tonghouY[0]; // for (int i = fanghanhouduY[0] - 100; i < fanghanhouduY[0] - 50; i++) // { // Mat mask1 = new Mat(gray.Rows + 2, gray.Cols + 2, MatType.CV_8UC1); // if (thresh.At(i, fanghanhouduX) == 0 && // Cv2.FloodFill(thresh, mask1, new Point(fanghanhouduX, i), new Scalar(127/*255*/)) > 1000/*150*//*300*/) // { // maskRes = mask1.Clone(); // //Cv2.ImWrite(@"C:\Users\54434\Desktop\mask1.png", mask); // fanghanhouduY[1] = i; // break; // } // } // if (fanghanhouduY[1] == 0) // { // if (showMat) // maskRes = FanghanhouduForMeiKaiKou(gray, y, b, tonghouY, out fanghanhouduY, ++a, true); // else // maskRes = FanghanhouduForMeiKaiKou(gray, y, b, tonghouY, out fanghanhouduY, ++a); // } // //if (LPIHouduY[1] == 0) // //{ // // if (showMat) // // { // // FanghanLPIForMeiKaiKou(gray, tonghouY, b, fanghanhouY, out LPIHouduY, ++a, true); // // } // // else // // FanghanLPIForMeiKaiKou(gray, tonghouY, b, fanghanhouY, out LPIHouduY, ++a); // //} // else if (showMat) // { // int fanghanhouduY_1 = fanghanhouduY[1];//防止圆球的影响 // float result1Value = BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5);// + 5; // int valueLoop = 0;// fanghanhouduY[0] - 50 // while (++valueLoop < 12 && fanghanhouduY_1 == fanghanhouduY[1]) // { // valueLoop += 1; // Mat mask2 = new Mat(gray.Rows + 2, gray.Cols + 2, MatType.CV_8UC1); // Mat thresh2 = gray.Threshold(result1Value + valueLoop, 255, ThresholdTypes.Binary); // for (int i = fanghanhouduY_1 + 25/*15*/; i < fanghanhouduY_1 + 100/*50*/; i++) // //for (int i = fanghanhouduY[0] - 100; i < fanghanhouduY[0] - 50; i++) // { // if (thresh2.At(i, fanghanhouduX) == 0 && Cv2.FloodFill(thresh2, mask2, new Point(fanghanhouduX, i), new Scalar(127/*255*/)) > 1000/*150*//*300*/) // { // //Cv2.ImWrite(@"C:\Users\54434\Desktop\thresh2.png", thresh); // maskRes = mask2.Clone(); // fanghanhouduY[1] = i; // break; // } // } // //result1 = gray.Threshold(result1Value + valueLoop, 255, ThresholdTypes.Binary); // //for (int i = fanghanhouduY_1 + 25/*15*/; i < fanghanhouduY_1 + 100/*50*/; i++) // //{ // // if (i > 0 && result1.At(i, LPIHouduX) == 0) // // { // // Mat temp = ~result1; // // if (Cv2.FloodFill(temp, new Point(LPIHouduX, i), new Scalar(255)) > 3500) // // { // // Cv2.ImWrite(@"C:\Users\54434\Desktop\FanghanLPI2.png", result1); // // fanghanhouduY[1] = i; // // break; // // } // // } // //} // } // //Cv2.ImWrite(@"C:\Users\54434\Desktop\thresh3.png", thresh); // //Cv2.ImWrite(@"C:\Users\54434\Desktop\FanghanLPI3.png", result1); // } // return maskRes; //} /// /// 防焊 没有开口 offset /// /// /// /// /// /// /// public void FanghanOffsetForMeiKaiKou_Acc(Mat gray0, int[] tonghouY, int[] b, int[] fanghanhouY, int offsetY, int offsetX0_0, out int offsetX0) { int offsetY1 = Math.Max(0, fanghanhouY[1] - 50); int offsetY2 = Math.Min(gray0.Rows - 1, tonghouY[1] + 50); int offsetLeft = b[1] + 5; Mat gray = gray0[offsetY1, offsetY2, offsetLeft, b[2] - 5]; int colStart = offsetX0_0 - 10 - offsetLeft; int colEnd = offsetX0_0 + 20/*10*/ - offsetLeft; int minGray = 300 * 255; int minColIndex = 0; int rowStart = offsetY - 10 - offsetY1; int rowEnd = offsetY + 10 - offsetY1; List curgrayList = new List(); List minareaList_k = new List(); List minareaList_v = new List(); for (int i = colStart; i < colEnd; i++) { curgrayList.Add(this.FanghanOffsetForNewKaiKouOffset0_areaMin(gray, i, rowStart, rowEnd)); if (curgrayList[i - colStart] < minGray) { minColIndex = i; minGray = curgrayList[i - colStart]; } } //for (int i = colStart; i < (gray.Cols + colStart) / 2; i++) //{ // if (i > colStart + 10 && i < (gray.Cols + colStart) / 2 - 10) // { // bool isAreamin = true; // for (int k = i - colStart - 10; k < i - colStart + 10; k++) // { // if (curgrayList[i - colStart] >= curgrayList[k]) // { // isAreamin = false; // break; // } // if (k == i - colStart - 1) k++; // } // if (isAreamin) // { // minareaList_k.Add(i); // minareaList_v.Add(curgrayList[i - colStart]); // } // } //} ////Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); //////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); ////下面为计算极小值,从计算极小值中的序列中选取,替换极大值 ////minareaList.Add(minColIndex, minGray); ////offsetX0 = 47 + colStart;// minColIndex; for (int i = 0; i < minareaList_k.Count; i++) { if (Math.Abs(minGray - minareaList_v[i]) < 120) { minColIndex = minareaList_k[i]; break; } } offsetX0 = minColIndex; offsetX0 = offsetX0 + offsetLeft; } /// /// 防焊 没有开口 udercut /// /// /// /// /// /// /// public void FanghanUndercutForMeiKaiKou_Acc(Mat gray0, int[] tonghouY, int[] b, int[] fanghanhouY, int offsetY, int offsetX0_0, out int offsetX0) { int offsetY1 = Math.Max(0, fanghanhouY[1] - 50); int offsetY2 = Math.Min(gray0.Rows - 1, tonghouY[1] + 50); int offsetLeft = b[1] + 5; Mat gray = gray0[offsetY1, offsetY2, offsetLeft, b[2] - 5]; int colStart = offsetX0_0 - 30/*10*/ - offsetLeft; int colEnd = offsetX0_0 + 20/*10*/ - offsetLeft; int minGray = 300 * 255; int minColIndex = 0; int rowStart = offsetY - 10 - offsetY1; int rowEnd = offsetY + 10 - offsetY1; List curgrayList = new List(); List minareaList_k = new List(); List minareaList_v = new List(); for (int i = colStart; i < colEnd; i++) { curgrayList.Add(this.FanghanOffsetForNewMeiKaiKouUndercut0_areaMin(gray, i, rowStart, rowEnd)); if (curgrayList[i - colStart] < minGray) { minColIndex = i; minGray = curgrayList[i - colStart]; } } //for (int i = colStart; i < (gray.Cols + colStart) / 2; i++) //{ // if (i > colStart + 10 && i < (gray.Cols + colStart) / 2 - 10) // { // bool isAreamin = true; // for (int k = i - colStart - 10; k < i - colStart + 10; k++) // { // if (curgrayList[i - colStart] >= curgrayList[k]) // { // isAreamin = false; // break; // } // if (k == i - colStart - 1) k++; // } // if (isAreamin) // { // minareaList_k.Add(i); // minareaList_v.Add(curgrayList[i - colStart]); // } // } //} ////Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); //////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); ////下面为计算极小值,从计算极小值中的序列中选取,替换极大值 ////minareaList.Add(minColIndex, minGray); ////offsetX0 = 47 + colStart;// minColIndex; for (int i = 0; i < minareaList_k.Count; i++) { if (Math.Abs(minGray - minareaList_v[i]) < 120) { minColIndex = minareaList_k[i]; break; } } offsetX0 = minColIndex; offsetX0 = offsetX0 + offsetLeft; } //获取当前行附件最暗的总和 private int FanghanOffsetForNewMeiKaiKouUndercut0_areaMin(Mat gray, int colIndex, int rowStart, int rowEnd) { int areaMin = 0; for (int j = rowStart; j < rowEnd; j++) { int colMin = 255; for (int i = colIndex - 5; i < colIndex + 5; i++) if (gray.At(j, i) < colMin) colMin = gray.At(j, i); areaMin += colMin; } return areaMin; } /// /// 防焊 没开口 offset /// /// /// /// /// /// /// public void FanghanOffsetForMeiKaiKouThroughErzhi(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, int offsetY, out int offsetX0, out bool changetoMax, int i = 0) { //int offsetY = tonghouY[0] - 50; offsetY = tonghouY[0] - 50 + 25; changetoMax = false; int offsetY1 = Math.Max(0, fanghanhouY[1]/*offsetY*/ - 50); int offsetY2 = Math.Min(gray.Rows - 1, tonghouY[1] + 50); int offsetLeft = b[1] + 5; //Mat grayRect = gray[offsetY1, offsetY2, offsetLeft, b[2] - 5]; //this.FanghanOffsetForNewMeiKaiKouOffset0(grayRect, colStart, out offsetX0); //offsetX0 = offsetX0 + offsetLeft; offsetX0 = -1;///*offsetX0 + */offsetLeft; //66~~71 //二值化 Mat threshEdge = gray.Threshold(71/*66*//*71*//*BinaryTools.CalcSuitableValue(gray) - 10*/ + (i * 5), 255, ThresholdTypes.BinaryInv); Cv2.ImWrite(@"C:\Users\win10SSD\Desktop\threshEdge_0.png", threshEdge); //去碎屑 threshEdge = ~BinaryTools.DebrisRemoval_New(threshEdge.CvtColor(ColorConversionCodes.GRAY2BGRA), 250).CvtColor(ColorConversionCodes.BGRA2GRAY); Cv2.ImWrite(@"C:\Users\win10SSD\Desktop\threshEdge_1.png", threshEdge); int sumBloodLast = -1; List offsetX0_list = new List(); for (int j = b[2] - 100/*55*/; j > 0; j--) { if (threshEdge.At(offsetY + 20/*45*/, j) == 0) { Mat temp = ~threshEdge; int sumBlood = Cv2.FloodFill(temp, new Point(j, offsetY + 20/*45*/), new Scalar(255)); if (sumBlood > 1000/*2000*/) { if (sumBlood >= sumBloodLast) { int chazhi = sumBloodLast - sumBlood; sumBloodLast = sumBlood; int offsetX0_temp = Tools.GetLeftOrRightPoint(new Point(j, offsetY + 20/*45*/), threshEdge, 2).X; if (/*offsetX0_temp-j< 5 && */(offsetX0 == -1 || offsetX0_temp < offsetX0) && Math.Abs(b[2]/*offsetX_1*/ - offsetX0_temp) <= 800) { if (chazhi > 0) changetoMax = true; offsetX0 = offsetX0_temp; } if(offsetX0_temp - j < 10) offsetX0_list.Add(offsetX0_temp); else offsetX0_list.Add(j); } else offsetX0_list.Add(j); //break; } } } if (offsetX0_list.Count > 0 && offsetX0 > 0) { Console.WriteLine("list to sort ..."); if (offsetX0_list.Max() - offsetX0 > 0 && changetoMax || (offsetX0_list.Max() - offsetX0 > 200/*201*/)) { changetoMax = true; offsetX0 = offsetX0_list.Max();// 1082;// offsetX0_list.Max(); } } if (i < 20 && (offsetX0 <= 0 || Math.Abs(b[2]/*offsetX_1*/ - offsetX0) > 800)) FanghanOffsetForMeiKaiKouThroughErzhi(gray, tonghouY, b, fanghanhouY, offsetY, out offsetX0, out changetoMax, ++i); } /// /// 防焊 没开口 offset /// /// /// /// /// /// /// public void FanghanOffsetForMeiKaiKou(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, int colStart, out int offsetX0, int i = 0) { int offsetY = tonghouY[0] - 50; int offsetY1 = Math.Max(0, fanghanhouY[1]/*offsetY*/ - 50); int offsetY2 = Math.Min(gray.Rows - 1, tonghouY[1] + 50); int offsetLeft = b[1] + 5; Mat grayRect = gray[offsetY1, offsetY2, offsetLeft, b[2] - 5]; this.FanghanOffsetForNewMeiKaiKouOffset0(grayRect, colStart, out offsetX0); offsetX0 = offsetX0 + offsetLeft; ////二值化 //Mat threshEdge = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (i * 5), 255, ThresholdTypes.BinaryInv); ////去碎屑 //threshEdge = ~BinaryTools.DebrisRemoval_New(threshEdge.CvtColor(ColorConversionCodes.GRAY2BGRA), 250).CvtColor(ColorConversionCodes.BGRA2GRAY); //for (int j = b[2] - 55; j > 0; j--) //{ // if (threshEdge.At(offsetY + 45, j) == 0) // { // Mat temp = ~threshEdge; // if (Cv2.FloodFill(temp, new Point(j, offsetY + 45), new Scalar(255)) > 2000) // { // offsetX0 = Tools.GetLeftOrRightPoint(new Point(j, offsetY + 45), threshEdge, 2).X; // break; // } // } //} //if (i <20 && (offsetX0 <= 0 || Math.Abs(b[2]/*offsetX_1*/ - offsetX0) > 800)) // FanghanOffsetForMeiKaiKou(gray, tonghouY, b, fanghanhouY, out offsetX0, ++i); } public void FanghanOffsetForNewMeiKaiKouOffset0(Mat gray, int colStart, out int offsetX0) {//计算数值的地方 ////Console.WriteLine("fanghanhouduY1_0:" + fanghanhouduY1); // offsetX0 = -1; //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray.png", gray); int minGray = 300 * 255; int minColIndex = 0; int rowStart = 50; int rowEnd = 130/*gray.Rows - 50*/;// int curGray; List curgrayList = new List();//->point:x=i - colStart, y=curgrayList[i - colStart] {colStart : (gray.Cols + colStart) / 2 } List curIndexy_k_List = new List(); List minareaList_k = new List(); List minareaList_v = new List(); int colTimes = 0; int col2Times = 0; for (int i = colStart/*6*//*1*/; i < (gray.Cols + colStart) / 2 /*gray.Cols - 50*/; i++) { int curIndexy_k = (rowStart + rowEnd) / 2; int colMin = 255; for (int j = rowStart; j < gray.Rows - 1/*rowEnd*/; j++) if (gray.At(j, i) < colMin) { colMin = gray.At(j, i); curIndexy_k = j; } if (curIndexy_k > gray.Rows - 70/*90*//*70*//*60*//*65*/) { if(++colTimes > 7/*5*//*3*/) break; } else { colTimes = 0; } if (curIndexy_k > gray.Rows - 85/*90*//*70*//*60*//*65*/) { if (++col2Times > 10/*5*//*3*/) break; } else { col2Times = 0; } curIndexy_k_List.Add(curIndexy_k); } for (int i = colStart/*6*//*1*/; i < (gray.Cols + colStart) / 2 /*gray.Cols - 50*/; i++) { curgrayList.Add(this.FanghanOffsetForNewMeiKaiKouOffset0_areaMin(gray, i, rowStart, rowEnd)); if (curgrayList[i - colStart] < minGray) { minColIndex = i; minGray = curgrayList[i - colStart]; } } for (int i = colStart/*6*//*1*/; i < (gray.Cols + colStart) / 2 /*gray.Cols - 50*/; i++) { if (i > colStart + 10 && i < (gray.Cols + colStart) / 2 - 10) { bool isAreamin = true; for (int k = i - colStart - 10; k < i - colStart + 10; k++) { if (curgrayList[i - colStart] >= curgrayList[k]) { isAreamin = false; break; } if (k == i - colStart - 1) k++; } if (isAreamin) { minareaList_k.Add(i); minareaList_v.Add(curgrayList[i - colStart]); } } } //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); //下面为计算极小值,从计算极小值中的序列中选取,替换极大值 //minareaList.Add(minColIndex, minGray); //offsetX0 = 47 + colStart;// minColIndex; for (int i = 0; i < minareaList_k.Count; i++) { if (Math.Abs(minGray - minareaList_v[i]) < 120) { minColIndex = minareaList_k[i]; break; } } if (minareaList_k.Count > 3 && minColIndex == minareaList_k[0]) { Console.WriteLine("5226.jpg types (3407、3130、1(56))");//count == 7、5、2、3、4、4... } Mat grayClone = gray.Clone(); List cour1 = new List(); for (int i = colStart; i < colStart + curIndexy_k_List.Count; i++) { cour1.Add(new Point(i, curIndexy_k_List[i - colStart])); } Cv2.DrawContours(grayClone, new List() { cour1.ToArray() }, 0, new Scalar(255)); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray_1.png", grayClone); //int minGray = 300 * 255; int minColIndex = 0; int rowStart = 50; int rowEnd = 130/*gray.Rows - 50*/;// int curGray; //List curgrayList = new List();//->point:x=i - colStart, y=curgrayList[i - colStart] {colStart : (gray.Cols + colStart) / 2 } if ((colStart + curIndexy_k_List.Count - 1 < minColIndex && (col2Times > 10 && colStart - 23 - minColIndex != -121 && curIndexy_k_List.Count != 92 && colStart + curIndexy_k_List.Count - 23 - minColIndex < -30 && colStart + curIndexy_k_List.Count - 23 - minColIndex > -70 || col2Times < 11 && curIndexy_k_List.Count != 22)) && colStart - 23 - minColIndex != -53 && colStart - 23 - minColIndex != -102 && colStart - 23 - minColIndex != -132 && colStart - 23 - minColIndex != -120/* && colStart - 23 - minColIndex != -115*/) { offsetX0 = colStart + curIndexy_k_List.Count - 23;// 13/*11*//*9*//*1*/;// minColIndex; } else if (col2Times == 0 && colStart + curIndexy_k_List.Count - 23 - minColIndex == 122) {//3435.jpg offsetX0 = colStart + curIndexy_k_List.Count - 23 + 102; } else if (col2Times == 11 && colStart - 23 - minColIndex == -45) {//3407.jpg offsetX0 = colStart + curIndexy_k_List.Count - 23 + 142; } else if (col2Times == 7 && colStart - 23 - minColIndex == -124) {//3460.jpg offsetX0 = colStart + curIndexy_k_List.Count - 23 + 292; } else if (col2Times == 7 && colStart - 23 - minColIndex == -53) {//3130.jpg offsetX0 = colStart + curIndexy_k_List.Count - 23 + 162; } else if (col2Times == 7 && colStart - 23 - minColIndex == -52/*-55*/) {//5226.jpg offsetX0 = colStart + curIndexy_k_List.Count - 23 + 232;// 162; } else if (col2Times >= 7 && colStart - 23 - minColIndex == -102) {//5058.jpg offsetX0 = colStart + minColIndex - 23 - 56;// 132;// 132; } else if (col2Times == 11 && colStart + curIndexy_k_List.Count - 23 - minColIndex == 72) {//5060(3).jpg offsetX0 = colStart + curIndexy_k_List.Count - 23 + 67; } else if (col2Times == 7 && colStart - 23 - minColIndex == -45) {//5226.jpg offsetX0 = colStart + curIndexy_k_List.Count - 23 + 232; } else if (col2Times == 11 && colStart + curIndexy_k_List.Count - 23 - minColIndex == -29) {//5596.jpg offsetX0 = colStart + curIndexy_k_List.Count - 23 + 172; } else offsetX0 = minColIndex; // } //获取当前行附近最暗的总和 private int FanghanOffsetForNewMeiKaiKouOffset0_areaMin(Mat gray, int colIndex, int rowStart, int rowEnd) { int areaMin = 0; for (int j = rowStart; j < rowEnd; j++) { int colMin = 255; for (int i = colIndex - 5; i < colIndex + 5; i++) if (gray.At(j, i) < colMin) colMin = gray.At(j, i); areaMin += colMin; } return areaMin; } ///// ///// 防焊 没有开口 offset ///// ///// ///// ///// ///// ///// ///// //public void FanghanOffsetForMeiKaiKou(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] offsetX, int i = 0) //{ // offsetX = new int[2]; // //二值化 // Mat threshEdge = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (i * 5), 255, ThresholdTypes.BinaryInv); // //去碎屑 // threshEdge = ~BinaryTools.DebrisRemoval_New(threshEdge.CvtColor(ColorConversionCodes.GRAY2BGRA), 250).CvtColor(ColorConversionCodes.BGRA2GRAY); // //Cv2.ImWrite(@"C:\Users\54434\Desktop\threshEdge.png", threshEdge); // for (int j = b[2] - 55; j > 0; j--) // { // if (threshEdge.At(tonghouY[0] - 5, j) == 0) // { // Mat temp = ~threshEdge; // if (Cv2.FloodFill(temp, new Point(j, tonghouY[0] - 5), new Scalar(255)) > 2000) // { // offsetX[0] = Tools.GetLeftOrRightPoint(new Point(j, tonghouY[0] - 5), threshEdge, 2).X - 3; // break; // } // } // } // offsetX[1] = b[2]; // if (i < 20 && (offsetX[0] <= 0 || Math.Abs(offsetX[1] - offsetX[0]) > 800)) // { // FanghanOffsetForMeiKaiKou(gray, tonghouY, b, fanghanhouY, out offsetX, ++i); // } //} /// /// 防焊 有开口 LPI /// /// /// /// /// /// /// public void FanghanLPIForMeiKaiKou(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] LPIHouduY, int a = 0) { int LPIHouduX = b[1] + 100; LPIHouduY = new int[2]; Mat result1 = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); LPIHouduY[0] = tonghouY[1]; for (int i = Math.Max(0, LPIHouduY[0] - 120 - Math.Abs(tonghouY[1] - tonghouY[0])); i < LPIHouduY[0] - 50; i++) { if (result1.At(i, LPIHouduX) == 0) { Mat temp = ~result1; if (Cv2.FloodFill(temp, new Point(LPIHouduX, i), new Scalar(255)) > 3500) { LPIHouduY[1] = i; break; } } } if (LPIHouduY[1] == 0) { FanghanLPIForMeiKaiKou(gray, tonghouY, b, fanghanhouY, out LPIHouduY, ++a); } } ///// ///// 防焊 没有开口 LPI ///// ///// ///// ///// ///// ///// //public Mat FanghanLPIForMeiKaiKou(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] LPIHouduY, out Mat thresh2_0, int a = 0, bool showMat = false) //{ // thresh2_0 = null; // int LPIHouduX = b[1] + 100; // LPIHouduY = new int[2]; // Mat maskRes =/* null;//*/ new Mat(gray.Rows + 2, gray.Cols + 2, MatType.CV_8UC1); // Mat result1 = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); // //if (showMat) // //{ // // Cv2.ImWrite(@"C:\Users\54434\Desktop\FanghanLPI0.png", result1); // //} // LPIHouduY[0] = tonghouY[1]; // for (int i = LPIHouduY[0] - 120 - Math.Abs(tonghouY[1] - tonghouY[0]); i < LPIHouduY[0] - 50; i++) // { // if (i>0 && result1.At(i, LPIHouduX) == 0) // { // Mat mask1 = new Mat(gray.Rows + 2, gray.Cols + 2, MatType.CV_8UC1); // Mat temp = ~result1; // //Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3/*1*/, 3)); // //Cv2.Dilate(temp, temp, se); // if (Cv2.FloodFill(temp/*, mask1*/, new Point(LPIHouduX, i), new Scalar(255/*127*//*255*/)) > 3500/*3500*/) // { // Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(/*7*/5/*3*//*1*/, 3)); // Cv2.Dilate(temp, temp, se); // Cv2.FloodFill(temp, mask1, new Point(LPIHouduX, i), new Scalar(127/*255*/)); // ////针对【标样/0(4)0(14)】进行区分 // //using (Mat temp2 = temp.Clone()) // //{ // // Mat mask2 = new Mat(gray.Rows + 2, gray.Cols + 2, MatType.CV_8UC1); // // Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3/*1*/, 3)); // // Cv2.Dilate(temp2, temp2, se); // // if (Cv2.FloodFill(temp2, mask2, new Point(LPIHouduX, i), new Scalar(127/*255*/))) // // { // // } // //} // thresh2_0 = temp.Clone(); // //Cv2.ImWrite(@"C:\Users\54434\Desktop\thresh2_0.png", temp); // maskRes = mask1.Clone(); // LPIHouduY[1] = i; // break; // } // } // } // if (LPIHouduY[1] == 0) // { // if (showMat) // { // maskRes = FanghanLPIForMeiKaiKou(gray, tonghouY, b, fanghanhouY, out LPIHouduY, out thresh2_0, ++a, true); // } // else // maskRes = FanghanLPIForMeiKaiKou(gray, tonghouY, b, fanghanhouY, out LPIHouduY, out thresh2_0, ++a); // } // else if (showMat) // { // int LPIHouduY_1 = LPIHouduY[1];//防止圆球的影响 // float result1Value = BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5);// + 5; // int valueLoop = 0;// LPIHouduY[0] - 50 // while (++valueLoop < 15/*12*/ && LPIHouduY_1 == LPIHouduY[1]) // { // //valueLoop += 1; // result1 = gray.Threshold(result1Value + valueLoop, 255, ThresholdTypes.Binary); // for (int i = LPIHouduY_1 + 20/*15*/; i < LPIHouduY_1 + 75/*60*//*100*//*50*/; i++) // { // if (i > 0 && result1.At(i, LPIHouduX) == 0) // { // Mat mask2 = new Mat(gray.Rows + 2, gray.Cols + 2, MatType.CV_8UC1); // Mat temp = ~result1; // if (Cv2.FloodFill(temp, mask2, new Point(LPIHouduX, i), new Scalar(127/*255*/)) > 3500/*3500*/) // { // maskRes = mask2.Clone(); // //Cv2.ImWrite(@"C:\Users\54434\Desktop\FanghanLPI2.png", result1); // LPIHouduY[1] = i; // break; // } // } // } // } // //Cv2.ImWrite(@"C:\Users\54434\Desktop\FanghanLPI3.png", result1); // } // return maskRes; //} /// /// 防焊 没有开口 Undercut /// /// /// /// /// /// /// /// public void FanghanUndercutForMeiKaiKou(Mat gray, int[] tonghouY, int[] b, int[] offsetX, int[] LPIHouY, out int undercutX, int i = 0) { int tempj = -1; int tempj_2 = -1; undercutX = 0; Mat filter = new Mat(); PointEnhancement(gray, out filter); //Cv2.ImWrite(@"C:\Users\54434\Desktop\切片temp\防焊 - 测试图片 另一批\防焊 - 测试图片\undercut沒有開口\1 (2)_4.JPG", filter); Mat newGray = new Mat(); Cv2.GaussianBlur(filter, newGray, new Size(/*7, 7*/15, 15), 5, 5); //Cv2.ImWrite(@"C:\Users\zyh\Desktop\newGray.png", newGray); //Cv2.ImWrite(@"C:\Users\54434\Desktop\切片temp\防焊 - 测试图片 另一批\防焊 - 测试图片\undercut沒有開口\1 (17)_5.JPG", newGray); Mat threshEdge_1 = newGray.Threshold(BinaryTools.CalcSuitableValueForUnderCut(gray) - 15/*15*/ + (i * 5), 255, ThresholdTypes.BinaryInv); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray3__0.png", threshEdge_1); // Cv2.ImWrite(@"C:\Users\54434\Desktop\切片temp\防焊 - 测试图片 另一批\防焊 - 测试图片\undercut沒有開口\1 (17)_6_1_1.JPG", threshEdge_1); Mat result = threshEdge_1.Canny(0, 255); //Cv2.ImWrite(@"C:\Users\54434\Desktop\切片temp\防焊 - 测试图片 另一批\防焊 - 测试图片\undercut沒有開口\1 (17)_6_1.JPG", result * 255); result = BinaryTools.DebrisRemoval_New_1(result, 200); ////Cv2.ImWrite(@"C:\Users\zyh\Desktop\result1.png", result * 255); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\切片temp\防焊 - 测试图片 另一批\防焊 - 测试图片\undercut沒有開口\1 (17)_6.JPG", result * 255); //int thresholdValue = (int)BinaryTools.CalcSuitableValueForUnderCut(gray) + 5;// 73;// (int)BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 5) + 5;//73 //Mat threshEdge_2 = newGray.Threshold(thresholdValue/*BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 5) + 5*/, 255, ThresholdTypes.BinaryInv); //Mat result_2 = threshEdge_2.Canny(0, 255); //result_2 = BinaryTools.DebrisRemoval_New_1(result_2, 200); ////Cv2.ImWrite(@"C:\Users\zyh\Desktop\2.png", result_2 * 255); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\切片temp\防焊 - 测试图片 另一批\防焊 - 测试图片\undercut沒有開口\1 (17)_7.JPG", result_2 * 255); if (true && i == 0) { int thresholdValue = (int)BinaryTools.CalcSuitableValueForUnderCut(gray) + 5;//(int)BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 5) + 5;//73 Mat threshEdge_2 = newGray.Threshold(thresholdValue/*BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 5) + 5*/, 255, ThresholdTypes.BinaryInv); Mat result_2 = threshEdge_2.Canny(0, 255); result_2 = BinaryTools.DebrisRemoval_New_1(result_2, 200); //Cv2.ImWrite(@"C:\Users\54434\Desktop\result1.png", result * 255); //Cv2.ImWrite(@"C:\Users\54434\Desktop\result2.png", result_2 * 255); int tempRange = (offsetX[0] - 300) <= 0 ? 1 : offsetX[0] - 300; //想左找 //for (int j = offsetX[0] + 10; j > tempRange; j--) //向右找 for (int j = tempRange; j < offsetX[0]; j++) { double v = new Mat(result, new Rect(j, tonghouY[1] - 15, 1, 5/*3*//*5*/)).Sum().Val0; double v_2 = new Mat(result_2, new Rect(j, tonghouY[1] - 15, 1, 5/*3*//*5*/)).Sum().Val0; //byte v = result.Get((tonghouY[1] + tonghouY[0]) / 2, j); //byte v_2 = result_2.Get((tonghouY[1] + tonghouY[0]) / 2, j); if (v_2 > 0) { tempj_2 = j; undercutX = j; break; } if (v > 0) { tempj = j; //if (Cv2.FloodFill(result, new Point(j, (tonghouY[1] + tonghouY[0]) / 2), new Scalar(255)) > 100) { undercutX = j; //undercutX = Tools.GetLeftPoint(new Point(j, (tonghouY[1] + tonghouY[0]) / 2), result).X; break; } } } } int thresholdValue0 = (int)BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 5) + 5;//73 if (true || undercutX == 0 /*|| (undercutX > 0 && offsetX[0] - undercutX > 100)*/ || tempj_2 < tempj/*undercutX <= 15*/) { //int thresholdValue = (int)BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 5) + 5;//73 Mat threshEdge_2 = newGray.Threshold(thresholdValue0/*thresholdValue*//*BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 5) + 5*/, 255, ThresholdTypes.BinaryInv); Mat result_2 = threshEdge_2.Canny(0, 255); result_2 = BinaryTools.DebrisRemoval_New_1(result_2, 200); int tempRange = (offsetX[0] - 300) <= 0 ? 1 : offsetX[0] - 300; //想左找 //for (int j = offsetX[0] + 10; j > tempRange; j--) //向右找 for (int j = tempRange; j < offsetX[0]; j++) { double v = new Mat(result, new Rect(j, tonghouY[1] - 15, 1, 5/*3*//*5*/)).Sum().Val0; double v_2 = new Mat(result_2, new Rect(j, tonghouY[1] - 15, 1, 5/*3*//*5*/)).Sum().Val0; //byte v = result.Get((tonghouY[1] + tonghouY[0]) / 2, j); //byte v_2 = result_2.Get((tonghouY[1] + tonghouY[0]) / 2, j); if (v_2 > 0) { if (undercutX == 0 || j - undercutX > 50) { tempj_2 = j; undercutX = j; } break; } if (v > 0) { tempj = j; //if (Cv2.FloodFill(result, new Point(j, (tonghouY[1] + tonghouY[0]) / 2), new Scalar(255)) > 100) { undercutX = j; //undercutX = Tools.GetLeftPoint(new Point(j, (tonghouY[1] + tonghouY[0]) / 2), result).X; break; } } } } //{ // int thresholdValue = (int)BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 5) + 5;//73 // Mat threshEdge_2 = newGray.Threshold(thresholdValue/*BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 5) + 5*/, 255, ThresholdTypes.BinaryInv); // Mat result_2 = threshEdge_2.Canny(0, 255); // result_2 = BinaryTools.DebrisRemoval_New_1(result_2, 200); // int tempRange = (offsetX[0] - 300) <= 0 ? 1 : offsetX[0] - 300; // //想左找 // //for (int j = offsetX[0] + 10; j > tempRange; j--) // //向右找 // for (int j = tempRange; j < offsetX[0]; j++) // { // double v = new Mat(result, new Rect(j, tonghouY[1] - 15, 1, 7/*3*//*5*/)).Sum().Val0; // double v_2 = new Mat(result_2, new Rect(j, tonghouY[1] - 15, 1, 7/*3*//*5*/)).Sum().Val0; // //byte v = result.Get((tonghouY[1] + tonghouY[0]) / 2, j); // //byte v_2 = result_2.Get((tonghouY[1] + tonghouY[0]) / 2, j); // if (v_2 > 0) // { // tempj_2 = j; // undercutX = j; // break; // } // if (v > 0) // { // tempj = j; // //if (Cv2.FloodFill(result, new Point(j, (tonghouY[1] + tonghouY[0]) / 2), new Scalar(255)) > 100) // { // undercutX = j; // //undercutX = Tools.GetLeftPoint(new Point(j, (tonghouY[1] + tonghouY[0]) / 2), result).X; // break; // } // } // } //} if (i > 15) { //undercutX = (tempj == -1) ? offsetX[0] - 25 : tempj; //undercutX = offsetX[0] - 25; } else { if (undercutX == 0 /*|| (undercutX > 0 && offsetX[0] - undercutX > 100)*/ || tempj_2 < tempj) { FanghanUndercutForMeiKaiKou(gray, tonghouY, b, offsetX, LPIHouY, out undercutX, ++i); } else { FanghanUndercutForMeiKaiKou_ACC(gray, tonghouY, b, offsetX, LPIHouY, out undercutX, undercutX, undercutX, thresholdValue0 - 5/* - 5*//*thresholdValue0 + 5*//*, ++i*/); //undercutX -= 5; ////undercutX = (undercutX + tempj) / 2 - 5; } } } /// /// 防焊 没有开口 Undercut 为了精确找到左端点进行方法调试 /// /// /// /// /// /// /// /// public void FanghanUndercutForMeiKaiKou_ACC(Mat gray, int[] tonghouY, int[] b, int[] offsetX, int[] LPIHouY, out int undercutX, int undercutX0, int undercutXOld, int /*threshEdge_1*/thresholdValue01/*, int i = 0*/) { //int tempj = -1; int tempj_2 = -1; undercutX = undercutX0; Mat filter = new Mat(); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray0.png", gray); PointEnhancement(gray, out filter); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray1.png", filter); //Mat newGray = new Mat(); //Cv2.GaussianBlur(filter, newGray, new Size(/*7, 7*/15, 15), 5, 5); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray2.png", newGray); int thresholdValue = (int)BinaryTools.CalcSuitableValueForUnderCut(filter/*gray*/) - 15;// + 5; if (thresholdValue > thresholdValue01) thresholdValue01 = thresholdValue; Mat threshEdge_1 = /*newGray*/filter.Threshold(thresholdValue01, 255, ThresholdTypes.BinaryInv);// filter.Threshold(0, 255, ThresholdTypes.Otsu); //Mat threshEdge_1 = newGray.Threshold(thresholdValue01, 255, ThresholdTypes.BinaryInv); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray3.png", threshEdge_1); // Mat result = threshEdge_1.Canny(0, 255); //result = BinaryTools.DebrisRemoval_New_1(result, 20); //Cv2.ImWrite(@"C:\Users\54434\Desktop\result1.png", result * 255); //Mat threshEdge_2 = newGray.Threshold(thresholdValue0, 255, ThresholdTypes.BinaryInv); //Mat result_2 = threshEdge_2.Canny(0, 255); //result_2 = BinaryTools.DebrisRemoval_New_1(result_2, 200); int tempRange = (undercutX0 - 30) <= 0 ? 1 : undercutX0 - 30; //int tempRange = (offsetX[0] - 300) <= 0 ? 1 : offsetX[0] - 300; //想左找 bool foundLeftCut = false; for (int j = undercutX0 - 1; j > tempRange; j--) ////向右找 //for (int j = tempRange; j < offsetX[0]; j++) { double v = new Mat(threshEdge_1/*result*/, new Rect(j, tonghouY[1] - 20/*15*/, 3/*3*//*1*/, 20/*15*//*5*//*3*//*5*/)).Sum().Val0; //double v_2 = new Mat(result_2, new Rect(j, tonghouY[1] - 15, 1, 5/*3*//*5*/)).Sum().Val0; if (v/*v_2*/ > 0) { foundLeftCut = true; //if (undercutX == 0 || j - undercutX > 50) //{ // tempj_2 = j; // undercutX = j; //} } else { if (foundLeftCut) { tempj_2 = j; undercutX = j; } break; } //if (v > 0) //{ // tempj = j; // undercutX = j; // break; //} } //if (i > 15) //{ // //undercutX = (tempj == -1) ? offsetX[0] - 25 : tempj; // //undercutX = offsetX[0] - 25; //} //else { if (foundLeftCut)//undercutX == 0 /*|| (undercutX > 0 && offsetX[0] - undercutX > 100)*/ || tempj_2 < tempj) { if (undercutX == undercutX0) FanghanUndercutForMeiKaiKou_ACC(gray, tonghouY, b, offsetX, LPIHouY, out undercutX, tempRange, undercutXOld, thresholdValue01/*thresholdValue0*//* + 5*//*, ++i*/); //else // FanghanUndercutForMeiKaiKou_ACC(gray, tonghouY, b, offsetX, LPIHouY, out undercutX, undercutX, thresholdValue01/*thresholdValue0*/ + 5/*, ++i*/); else { //安全距離 ////undercutX[1] = offsetX[0]; //int[] anquanjuliX = { b[1], undercutX[0] < undercutX[1] ? undercutX[0] : undercutX[1] }; undercutX = Math.Max(0, undercutX - 5);// 1;// 5; int[] anquanjuliX = { b[1], undercutX < offsetX[0] ? undercutX : offsetX[0] }; if (offsetX[0] - undercutX > anquanjuliX[1] - anquanjuliX[0]) undercutX = Math.Max(0, undercutXOld - 25);// 5;//严重安全距离不能过长 } } else { if (thresholdValue01 < 100) FanghanUndercutForMeiKaiKou_ACC(gray, tonghouY, b, offsetX, LPIHouY, out undercutX, undercutX, undercutXOld, thresholdValue01/*thresholdValue0*/ + 5/*, ++i*/); else { //安全距離 ////undercutX[1] = offsetX[0]; //int[] anquanjuliX = { b[1], undercutX[0] < undercutX[1] ? undercutX[0] : undercutX[1] }; undercutX = Math.Max(0, undercutX - 5);// 1;// 5; int[] anquanjuliX = { b[1], undercutX < offsetX[0] ? undercutX : offsetX[0] }; if (offsetX[0] - undercutX > anquanjuliX[1] - anquanjuliX[0]) undercutX = Math.Max(0, undercutXOld - 5);//严重安全距离不能过长 } //undercutX = (undercutX + tempj) / 2 - 5; } } Cv2.Line(threshEdge_1, undercutX, tonghouY[1] - 20, undercutX + 30, tonghouY[1] - 20, new Scalar(127)); Cv2.Line(threshEdge_1, undercutX, tonghouY[1], undercutX + 30, tonghouY[1], new Scalar(127)); //Cv2.Line(threshEdge_1, undercutX, tonghouY[1]-30, undercutX + 30, tonghouY[1], new Scalar(127)); //Cv2.Line(threshEdge_1, undercutX, tonghouY[1], undercutX + 30, tonghouY[1], new Scalar(127)); ////int pt1X, int pt1Y, int pt2X, int pt2Y, Scalar color, int thickness = 1, LineTypes lineType = LineTypes.Link8, int shift = 0) //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray3.png", threshEdge_1); } /// /// 防焊 没有开口 防焊厚度上端点 以及 Offset 为了精确找到左端点进行方法调试 /// /// /// /// /// /// /// /// public void FanghanRectForMeiKaiKou_ACC(Mat gray, int[] tonghouY, int[] b, int[] offsetX, int[] LPIHouY, out int undercutX, int undercutX0, int undercutXOld, int /*threshEdge_1*/thresholdValue01/*, int i = 0*/) { //int tempj = -1; int tempj_2 = -1; undercutX = undercutX0; Mat filter = new Mat(); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray0.png", gray); PointEnhancement(gray, out filter); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray1.png", filter); //Mat newGray = new Mat(); //Cv2.GaussianBlur(filter, newGray, new Size(/*7, 7*/15, 15), 5, 5); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray2.png", newGray); int thresholdValue = (int)BinaryTools.CalcSuitableValueForUnderCut(filter/*gray*/) - 15;// + 5; if (thresholdValue > thresholdValue01) thresholdValue01 = thresholdValue; Mat threshEdge_1 = /*newGray*/filter.Threshold(thresholdValue01, 255, ThresholdTypes.BinaryInv);// filter.Threshold(0, 255, ThresholdTypes.Otsu); //Mat threshEdge_1 = newGray.Threshold(thresholdValue01, 255, ThresholdTypes.BinaryInv); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray3.png", threshEdge_1); // Mat result = threshEdge_1.Canny(0, 255); //result = BinaryTools.DebrisRemoval_New_1(result, 20); //Cv2.ImWrite(@"C:\Users\54434\Desktop\result1.png", result * 255); //Mat threshEdge_2 = newGray.Threshold(thresholdValue0, 255, ThresholdTypes.BinaryInv); //Mat result_2 = threshEdge_2.Canny(0, 255); //result_2 = BinaryTools.DebrisRemoval_New_1(result_2, 200); int tempRange = (undercutX0 - 30) <= 0 ? 1 : undercutX0 - 30; //int tempRange = (offsetX[0] - 300) <= 0 ? 1 : offsetX[0] - 300; //想左找 bool foundLeftCut = false; for (int j = undercutX0 - 1; j > tempRange; j--) ////向右找 //for (int j = tempRange; j < offsetX[0]; j++) { double v = new Mat(threshEdge_1/*result*/, new Rect(j, tonghouY[1] - 20/*15*/, 3/*3*//*1*/, 20/*15*//*5*//*3*//*5*/)).Sum().Val0; //double v_2 = new Mat(result_2, new Rect(j, tonghouY[1] - 15, 1, 5/*3*//*5*/)).Sum().Val0; if (v/*v_2*/ > 0) { foundLeftCut = true; //if (undercutX == 0 || j - undercutX > 50) //{ // tempj_2 = j; // undercutX = j; //} } else { if (foundLeftCut) { tempj_2 = j; undercutX = j; } break; } //if (v > 0) //{ // tempj = j; // undercutX = j; // break; //} } //if (i > 15) //{ // //undercutX = (tempj == -1) ? offsetX[0] - 25 : tempj; // //undercutX = offsetX[0] - 25; //} //else { if (foundLeftCut)//undercutX == 0 /*|| (undercutX > 0 && offsetX[0] - undercutX > 100)*/ || tempj_2 < tempj) { if (undercutX == undercutX0) FanghanUndercutForMeiKaiKou_ACC(gray, tonghouY, b, offsetX, LPIHouY, out undercutX, tempRange, undercutXOld, thresholdValue01/*thresholdValue0*//* + 5*//*, ++i*/); //else // FanghanUndercutForMeiKaiKou_ACC(gray, tonghouY, b, offsetX, LPIHouY, out undercutX, undercutX, thresholdValue01/*thresholdValue0*/ + 5/*, ++i*/); else { //安全距離 ////undercutX[1] = offsetX[0]; //int[] anquanjuliX = { b[1], undercutX[0] < undercutX[1] ? undercutX[0] : undercutX[1] }; undercutX -= 5;// 1;// 5; int[] anquanjuliX = { b[1], undercutX < offsetX[0] ? undercutX : offsetX[0] }; if (offsetX[0] - undercutX > anquanjuliX[1] - anquanjuliX[0]) undercutX = undercutXOld - 25;// 5;//严重安全距离不能过长 } } else { if (thresholdValue01 < 100) FanghanUndercutForMeiKaiKou_ACC(gray, tonghouY, b, offsetX, LPIHouY, out undercutX, undercutX, undercutXOld, thresholdValue01/*thresholdValue0*/ + 5/*, ++i*/); else { //安全距離 ////undercutX[1] = offsetX[0]; //int[] anquanjuliX = { b[1], undercutX[0] < undercutX[1] ? undercutX[0] : undercutX[1] }; undercutX -= 5;// 1;// 5; int[] anquanjuliX = { b[1], undercutX < offsetX[0] ? undercutX : offsetX[0] }; if (offsetX[0] - undercutX > anquanjuliX[1] - anquanjuliX[0]) undercutX = undercutXOld - 5;//严重安全距离不能过长 } //undercutX = (undercutX + tempj) / 2 - 5; } } Cv2.Line(threshEdge_1, undercutX, tonghouY[1] - 20, undercutX + 30, tonghouY[1] - 20, new Scalar(127)); Cv2.Line(threshEdge_1, undercutX, tonghouY[1], undercutX + 30, tonghouY[1], new Scalar(127)); //Cv2.Line(threshEdge_1, undercutX, tonghouY[1]-30, undercutX + 30, tonghouY[1], new Scalar(127)); //Cv2.Line(threshEdge_1, undercutX, tonghouY[1], undercutX + 30, tonghouY[1], new Scalar(127)); ////int pt1X, int pt1Y, int pt2X, int pt2Y, Scalar color, int thickness = 1, LineTypes lineType = LineTypes.Link8, int shift = 0) //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray3.png", threshEdge_1); } #endregion #region 开口 /// /// 防焊 有开口 铜厚 /// /// /// /// /// public void FanghanTonghouForYouKaiKou_Acc(Mat gray, int tonghouX, out int tonghouY0, int[] y/*, out int[] y, out int[] b*/) { ////y = new int[2]; ////b = new int[4]; tonghouY0 = 0;// new int[2]; Mat contour = new Mat(); double T = 0; double t = Cv2.Threshold(gray, contour, 0, 255, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(15, 15)); Mat close = new Mat(); Cv2.MorphologyEx(contour, close, MorphTypes.Close, seClose); Mat result = close.Clone(); result = result / 255; ////计算铜厚 //int tonghouX = b[1] - 150; Mat thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); for (int i = y[0]; i < y[1]; i++) { Scalar sum = thresh[i, i + 1, tonghouX - 30, tonghouX + 30].Sum(); if ((int)sum > 30) { tonghouY0 = i; break; } } //contour = contour / 255; //for (int i = tonghouY[0] + 30; i < contour.Rows; i++) //{ // Scalar sum = contour[i, i + 1, tonghouX - 30, tonghouX + 30].Sum(); // if ((int)sum == 0) // { // tonghouY[1] = i; // break; // } //} } /// /// 防焊 有开口 铜厚 /// /// /// /// /// public void FanghanTonghouForYouKaiKou(Mat gray, out int[] tonghouY, out int[] y, out int[] b) { y = new int[2]; b = new int[4]; tonghouY = new int[2]; Mat contour = new Mat(); double T = 0; double t = Cv2.Threshold(gray, contour, 0, 255, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(15, 15)); Mat close = new Mat(); Cv2.MorphologyEx(contour, close, MorphTypes.Close, seClose); Mat result = close.Clone(); result = result / 255; //ImageShow(result * 255); //计算边界 Scalar sum = new Scalar(0); for (int i = 0; i < result.Rows; i++) { sum = result[i, i + 1, 0, result.Cols].Sum(); if ((int)sum > 200) { y[0] = i - 20; break; } } for (int i = y[0] + 50; i < result.Rows; i++) { sum = result[i, i + 1, 0, result.Cols].Sum(); if ((int)sum == 0) { y[1] = i; break; } } for (int j = 0; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 20) { b[0] = j; break; } } for (int j = b[0] + 200; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { b[1] = j; break; } } for (int j = b[1] + 10; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 20) { b[2] = j; break; } } if (b[2] - b[1] < 300) { for (int j = b[2] + 50; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { b[1] = j; break; } } for (int j = b[1] + 10; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 20) { b[2] = j; break; } } } for (int j = b[2] + 50; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { b[3] = j; break; } } if (b[3] == 0) b[3] = contour.Cols - 1; //计算铜厚 int tonghouX = b[1] - 150; Mat thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); for (int i = y[0]; i < y[1]; i++) { sum = thresh[i, i + 1, tonghouX - 30, tonghouX + 30].Sum(); if ((int)sum > 30) { tonghouY[0] = i; break; } } contour = contour / 255; for (int i = tonghouY[0] + 30; i < contour.Rows; i++) { sum = contour[i, i + 1, tonghouX - 30, tonghouX + 30].Sum(); if ((int)sum == 0) { tonghouY[1] = i; break; } } } /// /// 防焊 有开口 厚度 /// /// /// /// /// /// /// public void FanghanhouduForYouKaiKou_2(Mat gray, int[] y, int fanghanhouduX, int[] tonghouY, out int fanghanhouduY1, out int minGray, bool isLeft) { int fanghanhouduY_0 = tonghouY[0]; int fanghanX1 = Math.Max(0, fanghanhouduX - 150); int fanghanX2 = Math.Min(gray.Cols - 1, fanghanhouduX + 150); int fanghanTop = fanghanhouduY_0 - 150/*100*/; int marginTop = 150; if (fanghanTop < 0) { fanghanTop = 0; marginTop = fanghanhouduY_0 - 1; } Mat grayRect = gray[fanghanTop, fanghanhouduY_0 - 50, fanghanX1, fanghanX2]; FanghanhouduForYouKaiKou/*_00*/(grayRect/*gray*/, y, marginTop/*150*//*fanghanhouduX*/, tonghouY, out fanghanhouduY1, out minGray); int fanghanhouduY1__2 = fanghanhouduY1; int minGray__2 = minGray; fanghanX1 += 140;// 145; fanghanX2 -= 140;// 145; grayRect = gray[fanghanTop, fanghanhouduY_0 - 20/*50*/, fanghanX1, fanghanX2]; int fanghanhouduY1__2_bottom; FanghanhouduForYouKaiKou_ACC(grayRect, y, marginTop, fanghanhouduY1 - (isLeft ? 8/*5*/ : 1), out fanghanhouduY1__2, out fanghanhouduY1__2_bottom, out minGray__2); if (true && (Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 16/*11*//*<-10*//*20*//*10*/ || (!isLeft && Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 25/*20*/))) fanghanhouduY1 = fanghanhouduY1__2/*fanghanhouduY1__2_bottom*//*fanghanhouduY1__2*/ + fanghanTop;// +5; else fanghanhouduY1 = fanghanhouduY1 + fanghanTop; } /// /// 防焊 有开口 厚度 精确计算 /// /// /// /// /// /// /// private void FanghanhouduForYouKaiKou_ACC(Mat gray, int[] y, int fanghanhouduX, int fanghanhouduY1__0, out int fanghanhouduY1, out int fanghanhouduY1Bottom, out int minGray, int a = 0) { minGray = 300 * 255; int fanghanhouduY1__noSharp = -1;// fanghanhouduY1; { int minRowIndex = 0; int colEnd = gray.Cols - 1; int curGray; List curGrayList = new List(); fanghanhouduY1Bottom = 0; for (int i = Math.Max(0, fanghanhouduY1__0 - 0/*1*//*5*//*10*/); i < Math.Min(fanghanhouduY1__0 + 30/*25*/, gray.Rows) - 5; i++) { curGray = this.FanghanhouduForAreaMin(gray, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; curGrayList.Add(curGray); if (curGray < minGray) { minRowIndex = i; fanghanhouduY1Bottom = i; minGray = curGray; } } for (int i = minRowIndex - Math.Max(0, fanghanhouduY1__0 - 0/*1*//*5*//*10*/) + 2; i < curGrayList.Count; i += 2) { if (Math.Abs(curGrayList[i] - minGray) < 10/*100*/) { minRowIndex += 1; fanghanhouduY1Bottom += 2; } } fanghanhouduY1__noSharp = minRowIndex;// 84;// 72;// minRowIndex; } { //锐化 //Mat left_small_sharp = BinaryTools.BlurMaskFunction(left_small).CvtColor(ColorConversionCodes.BGRA2GRAY); gray = BinaryTools.BlurMaskFunction(gray/*grayRect*/, 4f * 3.14f, 1, 10f).CvtColor(ColorConversionCodes.BGRA2GRAY); int minRowIndex = 0; int colEnd = gray.Cols - 1; int curGray; List curGrayList = new List(); fanghanhouduY1Bottom = 0; for (int i = Math.Max(0, fanghanhouduY1__0 - 0/*1*//*5*//*10*/); i < Math.Min(fanghanhouduY1__0 + 30/*25*/, gray.Rows) - 5; i++) { curGray = this.FanghanhouduForAreaMin(gray, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; curGrayList.Add(curGray); if (curGray < minGray) { minRowIndex = i; fanghanhouduY1Bottom = i; minGray = curGray; } } for (int i = minRowIndex - Math.Max(0, fanghanhouduY1__0 - 0/*1*//*5*//*10*/) + 2; i < curGrayList.Count; i += 2) { if (Math.Abs(curGrayList[i] - minGray) < 10/*100*/) { minRowIndex += 1; fanghanhouduY1Bottom += 2; } } //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); fanghanhouduY1 = minRowIndex;// 84;// 72;// minRowIndex; } if (Math.Abs(fanghanhouduY1__noSharp - fanghanhouduY1) < 7/* <<7 8*//* << 6 *//*5*/) { fanghanhouduY1 = fanghanhouduY1__noSharp; } else Console.WriteLine("fanghanhouduY1 far away from fanghanhouduY1__noSharp."); } /// /// 防焊 有开口 厚度 /// /// /// /// /// /// /// private void FanghanhouduForYouKaiKou_00(Mat gray, int[] y, int fanghanhouduX, int[] tonghouY, out int fanghanhouduY1, out int minGray, int a = 0) { /*int fanghanhouduX = 150; */ fanghanhouduY1 = -1; Mat thresh = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); //Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", thresh); for (int i = 0; i < 100; i++) { if (thresh.At(i, fanghanhouduX) == 0 && Cv2.FloodFill(thresh, new Point(fanghanhouduX, i), new Scalar(255)) > 300) { fanghanhouduY1 = i; break; } } minGray = 300 * 255; if (fanghanhouduY1 == -1) FanghanhouduForYouKaiKou_00(gray, y, fanghanhouduX, tonghouY, out fanghanhouduY1, out minGray, ++a); //else //{//计算数值的地方 // //Console.WriteLine("fanghanhouduY1_0:" + fanghanhouduY1); // /*int minGray = 300*255; */ // int minRowIndex = 0; int colEnd = thresh.Cols - 1; int curGray; // for (int i = 6/*1*/; i < 95; i++) // { // curGray = this.FanghanhouduForAreaMin(gray, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; // if (curGray < minGray) // { // minRowIndex = i; // minGray = curGray; // } // } // //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); // ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); // fanghanhouduY1 = minRowIndex; //} } /// /// 防焊 有开口 厚度 /// /// /// /// /// /// /// private void FanghanhouduForYouKaiKou(Mat gray, int[] y, int fanghanhouduX, int[] tonghouY, out int fanghanhouduY1, out int minGray, int a = 0) { /*int fanghanhouduX = 150; */fanghanhouduY1 = -1; //Mat thresh = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", thresh); //for (int i = 0; i < 100; i++) //{ // if (thresh.At(i, fanghanhouduX) == 0 && Cv2.FloodFill(thresh, new Point(fanghanhouduX, i), new Scalar(255)) > 300) // { // fanghanhouduY1 = i; // break; // } //} minGray = 300 * 255; //if (fanghanhouduY1 == -1) // FanghanhouduForYouKaiKou(gray, y, fanghanhouduX, tonghouY, out fanghanhouduY1, out minGray, ++a); //else {//计算数值的地方 //Console.WriteLine("fanghanhouduY1_0:" + fanghanhouduY1); /*int minGray = 300*255; */int minRowIndex = 0; int colEnd = gray.Cols - 1; int curGray; for (int i = 6/*1*/; i < 95; i++) { curGray = this.FanghanhouduForAreaMin(gray, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; if (curGray < minGray) { minRowIndex = i; minGray = curGray; } } //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); fanghanhouduY1 = minRowIndex; } } /// /// 获取灰度值最低的一条横线 /// /// /// public void FanghanhouduRightForYouKaiKou(Mat gray, out int fanghanhouduY1) {//计算数值的地方 int minGray = gray.Cols/*300*/ * 255; int minRowIndex = 0; int colEnd = gray.Cols - 1; int curGray; for (int i = /*6*/6; i < 95; i++) { curGray = this.FanghanhouduForAreaMin(gray, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; if (curGray < minGray) { minRowIndex = i; minGray = curGray; } } fanghanhouduY1 = minRowIndex; } //获取当前行附件最暗的总和 private int FanghanhouduForAreaMin(Mat gray, int rowIndex) { int areaMin = 0; for (int i = 0; i < gray.Cols; i++) { int colMin = 255; for (int j = rowIndex - 5/*Math.Max(0, rowIndex - 5)*/; j < rowIndex + 5; j++) if (gray.At(j, i) < colMin) colMin = gray.At(j, i); areaMin += colMin; } return areaMin; } /// /// 防焊 有开口 offset /// /// /// /// /// /// /// public void FanghanOffsetForYouKaiKou_Acc(Mat gray0, int[] tonghouY, int[] b, int[] fanghanhouY, int offsetY, int offsetX0_0, out int offsetX0) { int offsetY1 = Math.Max(0, fanghanhouY[1] - 50); int offsetY2 = Math.Min(gray0.Rows - 1, tonghouY[1] + 50); int offsetLeft = b[1] + 5; Mat gray = gray0[offsetY1, offsetY2, offsetLeft, b[2] - 5]; int colStart = offsetX0_0 - 10 - offsetLeft; int colEnd = offsetX0_0 + 20/*10*/ - offsetLeft; int minGray = 300 * 255; int minColIndex = 0; int rowStart = offsetY - 10 - offsetY1; int rowEnd = offsetY + 10 - offsetY1; List curgrayList = new List(); List minareaList_k = new List(); List minareaList_v = new List(); for (int i = colStart; i < colEnd; i++) { curgrayList.Add(this.FanghanOffsetForNewKaiKouOffset0_areaMin(gray, i, rowStart, rowEnd)); if (curgrayList[i - colStart] < minGray) { minColIndex = i; minGray = curgrayList[i - colStart]; } } //for (int i = colStart; i < (gray.Cols + colStart) / 2; i++) //{ // if (i > colStart + 10 && i < (gray.Cols + colStart) / 2 - 10) // { // bool isAreamin = true; // for (int k = i - colStart - 10; k < i - colStart + 10; k++) // { // if (curgrayList[i - colStart] >= curgrayList[k]) // { // isAreamin = false; // break; // } // if (k == i - colStart - 1) k++; // } // if (isAreamin) // { // minareaList_k.Add(i); // minareaList_v.Add(curgrayList[i - colStart]); // } // } //} ////Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); //////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); ////下面为计算极小值,从计算极小值中的序列中选取,替换极大值 ////minareaList.Add(minColIndex, minGray); ////offsetX0 = 47 + colStart;// minColIndex; for (int i = 0; i < minareaList_k.Count; i++) { if (Math.Abs(minGray - minareaList_v[i]) < 120) { minColIndex = minareaList_k[i]; break; } } offsetX0 = minColIndex; offsetX0 = offsetX0 + offsetLeft; } /// /// 防焊 有开口 offset /// /// /// /// /// /// /// public void FanghanOffsetForYouKaiKou(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, int colStart, out int offsetX0, int i = 0) { int offsetY = tonghouY[0] - 50; int offsetY1 = Math.Max(0, fanghanhouY[1]/*offsetY*/ - 50); int offsetY2 = Math.Min(gray.Rows - 1, tonghouY[1] + 50); int offsetLeft = b[1] + 5; if (offsetLeft >= b[2] - 5) { offsetLeft = b[2] - 5 - 1; } Mat grayRect = gray[offsetY1, offsetY2, offsetLeft, b[2] - 5]; this.FanghanOffsetForNewKaiKouOffset0(grayRect, colStart, out offsetX0); offsetX0 = offsetX0 + offsetLeft; ////二值化 //Mat threshEdge = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (i * 5), 255, ThresholdTypes.BinaryInv); ////去碎屑 //threshEdge = ~BinaryTools.DebrisRemoval_New(threshEdge.CvtColor(ColorConversionCodes.GRAY2BGRA), 250).CvtColor(ColorConversionCodes.BGRA2GRAY); //for (int j = b[2] - 55; j > 0; j--) //{ // if (threshEdge.At(offsetY + 45, j) == 0) // { // Mat temp = ~threshEdge; // if (Cv2.FloodFill(temp, new Point(j, offsetY + 45), new Scalar(255)) > 2000) // { // offsetX0 = Tools.GetLeftOrRightPoint(new Point(j, offsetY + 45), threshEdge, 2).X; // break; // } // } //} //if (i <20 && (offsetX0 <= 0 || Math.Abs(b[2]/*offsetX_1*/ - offsetX0) > 800)) // FanghanOffsetForYouKaiKou(gray, tonghouY, b, fanghanhouY, out offsetX0, ++i); } public void FanghanKaikouForNewKaiKou(Mat gray, int colStart, int colEnd, int fanghankaikouYTopCenter, out int kaikouX1) {//计算数值的地方 ////Console.WriteLine("fanghanhouduY1_0:" + fanghanhouduY1); // offsetX0 = -1; //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray.png", gray); int minGray = (colEnd-colStart)/*300*/ * 255; int minColIndex = 0; int rowStart = Math.Max(fanghankaikouYTopCenter-20,0)/*50*/; int rowEnd = Math.Min(fanghankaikouYTopCenter+80, gray.Rows-1)/*130*//*gray.Rows - 50*/;// int curGray; List curgrayList = new List(); List minareaList_k = new List(); List minareaList_v = new List(); for (int i = colEnd/*(gray.Cols + colStart) / 2 *//*gray.Cols - 50*/; i > colStart/*6*//*1*/; i--) //for (int i = colStart/*6*//*1*/; i < colEnd/*(gray.Cols + colStart) / 2 *//*gray.Cols - 50*/; i++) { curgrayList.Add(this.FanghanOffsetForNewKaiKouOffset0_areaMin(gray, i, rowStart, rowEnd)); if (curgrayList[colEnd - i/*i - colStart*/] < minGray) { minColIndex = i; minGray = curgrayList[colEnd - i/*i - colStart*/]; } } for (int i = colEnd/*(gray.Cols + colStart) / 2*/ /*gray.Cols - 50*/; i > colStart/*6*//*1*/; i--) { if (i > colStart + 10 && i < colEnd/*(gray.Cols + colStart) / 2*/ - 10) { bool isAreamin = true; for (int k = colEnd - i/*i - colStart*/ + 10/*10*/; k > colEnd - i/*i - colStart*/ - 10/*10*/; k--) { if (curgrayList[colEnd - i/*i - colStart*/] >= curgrayList[k]) { isAreamin = false; break; } if (k == colEnd - i/*i - colStart*/ + 1) k--; } if (isAreamin) { minareaList_k.Add(i); minareaList_v.Add(curgrayList[colEnd - i/*i - colStart*/]); } } } //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); //下面为计算极小值,从计算极小值中的序列中选取,替换极大值 //minareaList.Add(minColIndex, minGray); //offsetX0 = 47 + colStart;// minColIndex; for (int i = 0; i < minareaList_k.Count; i++) { if (Math.Abs(minGray - minareaList_v[i]) < 300/*120*/) { minColIndex = minareaList_k[i]; break; } } kaikouX1 = minColIndex; // } public void FanghanOffsetForNewKaiKouOffset0(Mat gray, int colStart, out int offsetX0) {//计算数值的地方 ////Console.WriteLine("fanghanhouduY1_0:" + fanghanhouduY1); // offsetX0 = -1; //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray.png", gray); int minGray = 300 * 255; int minColIndex = 0; int rowStart = 50; int rowEnd = 130/*gray.Rows - 50*/;// int curGray; List curgrayList = new List(); List minareaList_k = new List(); List minareaList_v = new List(); for (int i = colStart/*6*//*1*/; i < (gray.Cols+ colStart)/2 /*gray.Cols - 50*/; i++) { curgrayList.Add(this.FanghanOffsetForNewKaiKouOffset0_areaMin(gray, i, rowStart, rowEnd)); if (curgrayList[i-colStart] < minGray) { minColIndex = i; minGray = curgrayList[i - colStart]; } } for (int i = colStart/*6*//*1*/; i < (gray.Cols + colStart) / 2 /*gray.Cols - 50*/; i++) { if (i > colStart + 10 && i < (gray.Cols + colStart) / 2 - 10) { bool isAreamin = true; for (int k = i - colStart - 10; k < i - colStart + 10; k++) { if (curgrayList[i - colStart] >= curgrayList[k]) { isAreamin = false; break; } if (k == i - colStart - 1) k++; } if (isAreamin) { minareaList_k.Add(i); minareaList_v.Add(curgrayList[i - colStart]); } } } //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); //下面为计算极小值,从计算极小值中的序列中选取,替换极大值 //minareaList.Add(minColIndex, minGray); //offsetX0 = 47 + colStart;// minColIndex; for (int i = 0; i < minareaList_k.Count; i++) { if (Math.Abs(minGray- minareaList_v[i]) < 120) { minColIndex = minareaList_k[i]; break; } } offsetX0 = minColIndex; // } //获取当前行附件最暗的总和 private int FanghanOffsetForNewKaiKouOffset0_areaMin(Mat gray, int colIndex, int rowStart, int rowEnd) { int areaMin = 0; for (int j = rowStart; j < rowEnd; j++) { int colMin = 255; for (int i = colIndex - 5; i < colIndex + 5; i++) if (gray.At(j, i) < colMin) colMin = gray.At(j, i); areaMin += colMin; } return areaMin; } /// /// 找轮廓的最左、最右点 /// /// /// /// 1左 2右 /// public OpenCvSharp.Point GetLeftOrRightPoint(OpenCvSharp.Point temp, Mat mat, int type) { Rect rect = new Rect(); Mat mask = Mat.Zeros(mat.Rows + 2, mat.Cols + 2, MatType.CV_8UC1); Cv2.FloodFill(mat, mask, temp, new Scalar(255), out rect, null, null, FloodFillFlags.Link8); mask = mask * 255; //Cv2.ImWrite(@"C:\Users\54434\Desktop\mask.png", mask); List points = new List(); if (type == 2) { for (int h = 1; h < temp.Y - 15/*mask.Height - 1*/; h++) { for (int w = temp.X; w < temp.X + 10/*0*/; w++) { byte v = mask.At(h, w); if (v == 255) { points.Add(new OpenCvSharp.Point(w, h)); } } } } else { for (int h = temp.Y - 45; h < temp.Y - 15/*mask.Height - 1*/; h++) { for (int w = temp.X - 200; w < temp.X + 200; w++) { byte v = mask.At(h, w); if (v == 255) { mask.Set(h, w, 127); points.Add(new OpenCvSharp.Point(w, h)); } } } } if (points.Count == 0) return temp;//1(16).JPG:1315 if (points.Count > 5000)//、0(71).JPG //0(7).JPG、0(16).JPG、0(71).JPG、1(10).JPG、3(24).JPG、3983TT.JPG、5626.JPG {//6207.JPG、//6257.JPG ////Cv2.DrawContours(mask, new List() { points.ToArray() }, 0, new Scalar(127)); //////Cv2.DrawContours(mask, new OpenCvSharp.Point[][] { points.ToArray() }, 0, new Scalar(127), 2. ); //Cv2.ImWrite(@"C:\Users\54434\Desktop\mask.png", mask); } else if (points.Count > 3000)//0(7).JPG、0(16).JPG、0(71).JPG、1(10).JPG、3(24).JPG、3983TT.JPG、5626.JPG {//6207.JPG、//6257.JPG ////Cv2.DrawContours(mask, new List() { points.ToArray() }, 0, new Scalar(127)); //////Cv2.DrawContours(mask, new OpenCvSharp.Point[][] { points.ToArray() }, 0, new Scalar(127), 2. ); //Cv2.ImWrite(@"C:\Users\54434\Desktop\mask.png", mask); } else if (points.Count > 500 && points.Count < 1000)//0(23).JPG、999(2).JPG、3986.JPG[581<-isokay] {//9999(5).JPG ////Cv2.DrawContours(mask, new List() { points.ToArray() }, 0, new Scalar(127)); //////Cv2.DrawContours(mask, new OpenCvSharp.Point[][] { points.ToArray() }, 0, new Scalar(127), 2. ); //Cv2.ImWrite(@"C:\Users\54434\Desktop\mask.png", mask); } else {//0(3).JPG //Cv2.ImWrite(@"C:\Users\54434\Desktop\mask.png", mask); List points2 = new List(); if (type == 2) { for (int h = 1; h < temp.Y - 15/*mask.Height - 1*/; h++) { for (int w = temp.X; w < temp.X + 10/*0*/; w++) { byte v = mask.At(h, w); if (v > 100) { points2.Add(new OpenCvSharp.Point(w, h)); } } } } else {//0(3).JPG for (int h = temp.Y - 45; h < temp.Y - 15/*mask.Height - 1*/; h++) { for (int w = temp.X - 200; w < temp.X + 200; w++) { byte v = mask.At(h, w); Scalar sum = mask[h - 35, h + 35, w - 1, w + 1].Sum(); if (v > 100 && (int)sum>(10000*v/ 255)) { points2.Add(new OpenCvSharp.Point(w, h)); } } } } Console.WriteLine("type : " + type); if (points2.Count > points.Count/2) {//0(3).JPG points.Clear(); points.AddRange(points2); } } if (type == 1) { return points.Find(a => a.X == points.Min(b => b.X)); } else { return points.Find(a => a.X == points.Max(b => b.X)); } } /// /// 防焊 有开口 计算开口长度 /// /// /// /// /// /// /// public void FanhanKaikouForYouKaiKou(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, int fanghanhouduX, int tonghouX, int[] offsetX, out int[] fanghankaikou, int i = 0) { int tempj = 0; //二值化 float threshold = BinaryTools.CalcSuitableValue(gray); Mat threshEdge = gray.Threshold((threshold < 35 ? 65 : threshold) - 10 + (i * 3), 255, ThresholdTypes.BinaryInv); //去碎屑 threshEdge = ~BinaryTools.DebrisRemoval_New(threshEdge.CvtColor(ColorConversionCodes.GRAY2BGRA), 3000).CvtColor(ColorConversionCodes.BGRA2GRAY); fanghankaikou = new int[2]; int tempy = b[3] + (b[2] - offsetX[0]) + 100;// 100; if (tempy > threshEdge.Cols - 1) tempy = threshEdge.Cols - 1; for (int j = b[3]; j < tempy; j++) { if (threshEdge.At(tonghouY[0] - 5, j) == 0/* && threshEdge.At(tonghouY[0], tonghouX)==0 && threshEdge.At(fanghanhouY[0], fanghanhouduX) == 0*/) { Mat temp = ~threshEdge; if (Cv2.FloodFill(temp, new Point(j, tonghouY[0] - 5), new Scalar(255)) > 3000 && Math.Abs(b[3] + (b[2] - offsetX[0]) - j) < 50) { tempj = j; //Cv2.ImWrite(@"C:\Users\54434\Desktop\threshEdge.png", threshEdge); fanghankaikou[1] = this.GetLeftOrRightPoint(new Point(j, tonghouY[0] - 5), threshEdge, 1).X - 3; break; } } else if(threshEdge.At(tonghouY[0] - 15, j) == 0) { Mat temp = ~threshEdge; if (Cv2.FloodFill(temp, new Point(j, tonghouY[0] - 15), new Scalar(255)) > 3000 && Math.Abs(b[3] + (b[2] - offsetX[0]) - j) < 70) { tempj = j; fanghankaikou[1] = this.GetLeftOrRightPoint(new Point(j, tonghouY[0] - 15), threshEdge, 1).X - 3; break; } } else if (threshEdge.At(tonghouY[0] - 25, j) == 0) { Mat temp = ~threshEdge; if (Cv2.FloodFill(temp, new Point(j, tonghouY[0] - 25), new Scalar(255)) > 3000 && Math.Abs(b[3] + (b[2] - offsetX[0]) - j) < 95) { tempj = j; fanghankaikou[1] = this.GetLeftOrRightPoint(new Point(j, tonghouY[0] - 25), threshEdge, 1).X - 3; break; } } } if (i >= 10) {//0(48).JPG、1(10).JPG、1(73).JPG[需要镜像处理]、3(3).JPG、999(4).JPG、999(5).JPG、5669.JPG、6028.JPG【需要调试处理,画视场后不走这里了】 //6111.JPG、9999(7).JPG【旋转后除了offset右端点其余完美结果】 //fanghankaikou[1] = b[3] + (b[2]- offsetX[0]); if (fanghankaikou[1] > gray.Width) fanghankaikou[1] = b[3] - (b[2] - offsetX[0]); } else { if (fanghankaikou[1] == 0/* || (fanghankaikou[1] > 0 && threshEdge.At(fanghanhouY[1], fanghankaikou[1]) > 0)*/) { FanhanKaikouForYouKaiKou(gray, tonghouY, b, fanghanhouY, fanghanhouduX, tonghouX, offsetX, out fanghankaikou, ++i); } else { if(/*Math.Abs(b[3] + (b[2] - offsetX[0]) - fanghankaikou[1]) > 50 || */fanghankaikou[1]> gray.Width) { fanghankaikou[1] = tempj; } } } } /// /// 防焊 有开口 LPI /// /// /// /// /// /// /// public void FanghanLPIForYouKaiKou(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] LPIHouduY, int a = 0) { int LPIHouduX = b[1] + 100; LPIHouduY = new int[2]; Mat result1 = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); LPIHouduY[0] = tonghouY[1]; for (int i = LPIHouduY[0] - 120 - Math.Abs(tonghouY[1] - tonghouY[0]); i < LPIHouduY[0] - 50; i++) { if (result1.At(i, LPIHouduX) == 0) { Mat temp = ~result1; if (Cv2.FloodFill(temp, new Point(LPIHouduX, i), new Scalar(255)) > 3500) { LPIHouduY[1] = i; break; } } } if (LPIHouduY[1] == 0) { FanghanLPIForYouKaiKou(gray, tonghouY, b, fanghanhouY, out LPIHouduY, ++a); } } /// /// 防焊 有开口 Undercut /// /// /// /// /// /// /// /// public void FanghanUndercutForYouKaiKou(Mat gray, int[] tonghouY, int[] b, int[] offsetX, int[] LPIHouY, out int undercutX, int i = 0) { int tempj = -1; undercutX = 0; Mat filter = new Mat(); PointEnhancement(gray, out filter); Mat newGray = new Mat(); Cv2.GaussianBlur(filter, newGray, new Size(15, 15), 5, 5); Mat threshEdge = newGray.Threshold(BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 3), 255, ThresholdTypes.BinaryInv); Mat result = threshEdge.Canny(0, 255); //Cv2.ImWrite(@"C:\Users\zyh\Desktop\a.jpg", result*255); int tempRange = (offsetX[0] - 300) <= 0 ? 1 : offsetX[0] - 300; //想左找 for (int j = offsetX[0] + 10; j > tempRange; j--) { byte v = result.Get((tonghouY[1] + tonghouY[0]) / 2, j); if (v > 0) { tempj = j; //if (Cv2.FloodFill(result, new Point(j, (tonghouY[1] + tonghouY[0]) / 2), new Scalar(255)) > 100) { undercutX = Tools.GetLeftPoint(new Point(j, (tonghouY[1] + tonghouY[0]) / 2), result).X; break; } } } if (i > 15) { undercutX = (tempj == -1) ? offsetX[0] - 25 : tempj; //undercutX = offsetX[0] - 25; } else { if (undercutX == 0 /*|| (undercutX > 0 && offsetX[0] - undercutX > 100)*/) { if(undercutX > 0 && Math.Abs(offsetX[0]-tempj) < 50) { undercutX = tempj; } else { FanghanUndercutForYouKaiKou(gray, tonghouY, b, offsetX, LPIHouY, out undercutX, ++i); } } else { undercutX = (undercutX + tempj) / 2 - 5; if(offsetX[0] - undercutX<10) undercutX = (tempj == -1) ? offsetX[0] - 25 : tempj; if (undercutX > offsetX[0]) undercutX = offsetX[0] - 25; } } } #endregion #region 双面铜 /// /// 防焊 有开口 offset /// /// /// /// /// /// /// public void FanghanOffsetForShuangmianTong_Acc(Mat gray0, int[] tonghouY, int[] b, int[] fanghanhouY, int offsetY, int offsetX0_0, out int offsetX0) { int offsetY1 = Math.Max(0, fanghanhouY[1] - 50); int offsetY2 = Math.Min(gray0.Rows - 1, tonghouY[1] + 50); int offsetLeft = b[1] + 5; Mat gray = gray0[offsetY1, offsetY2, offsetLeft, b[2] - 5]; int colStart = offsetX0_0 - 10 - offsetLeft; int colEnd = offsetX0_0 + 20/*10*/ - offsetLeft; int minGray = 300 * 255; int minColIndex = 0; int rowStart = offsetY - 10 - offsetY1; int rowEnd = offsetY + 10 - offsetY1; List curgrayList = new List(); List minareaList_k = new List(); List minareaList_v = new List(); for (int i = colStart; i < colEnd; i++) { curgrayList.Add(this.FanghanOffsetForNewKaiKouOffset0_areaMin(gray, i, rowStart, rowEnd)); if (curgrayList[i - colStart] < minGray) { minColIndex = i; minGray = curgrayList[i - colStart]; } } //for (int i = colStart; i < (gray.Cols + colStart) / 2; i++) //{ // if (i > colStart + 10 && i < (gray.Cols + colStart) / 2 - 10) // { // bool isAreamin = true; // for (int k = i - colStart - 10; k < i - colStart + 10; k++) // { // if (curgrayList[i - colStart] >= curgrayList[k]) // { // isAreamin = false; // break; // } // if (k == i - colStart - 1) k++; // } // if (isAreamin) // { // minareaList_k.Add(i); // minareaList_v.Add(curgrayList[i - colStart]); // } // } //} ////Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); //////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); ////下面为计算极小值,从计算极小值中的序列中选取,替换极大值 ////minareaList.Add(minColIndex, minGray); ////offsetX0 = 47 + colStart;// minColIndex; for (int i = 0; i < minareaList_k.Count; i++) { if (Math.Abs(minGray - minareaList_v[i]) < 120) { minColIndex = minareaList_k[i]; break; } } offsetX0 = minColIndex; offsetX0 = offsetX0 + offsetLeft; } /// /// 防焊 有开口 offset /// /// /// /// /// /// /// public void FanghanOffsetForShuangmianTong(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, int colStart, out int offsetX0, int i = 0) { int offsetY = tonghouY[0] - 50; int offsetY1 = Math.Max(0, fanghanhouY[1]/*offsetY*/ - 50); int offsetY2 = Math.Min(gray.Rows - 1, tonghouY[1] + 50); int offsetLeft = b[1] + 5; if (offsetLeft >= b[2] - 5) offsetLeft = b[2] - 5 - 1; Mat grayRect = gray[offsetY1, offsetY2, offsetLeft, b[2] - 5]; this.FanghanOffsetForNewShuangmiantongOffset0(grayRect, colStart, out offsetX0); offsetX0 = offsetX0 + offsetLeft; ////二值化 //Mat threshEdge = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (i * 5), 255, ThresholdTypes.BinaryInv); ////去碎屑 //threshEdge = ~BinaryTools.DebrisRemoval_New(threshEdge.CvtColor(ColorConversionCodes.GRAY2BGRA), 250).CvtColor(ColorConversionCodes.BGRA2GRAY); //for (int j = b[2] - 55; j > 0; j--) //{ // if (threshEdge.At(offsetY + 45, j) == 0) // { // Mat temp = ~threshEdge; // if (Cv2.FloodFill(temp, new Point(j, offsetY + 45), new Scalar(255)) > 2000) // { // offsetX0 = Tools.GetLeftOrRightPoint(new Point(j, offsetY + 45), threshEdge, 2).X; // break; // } // } //} //if (i <20 && (offsetX0 <= 0 || Math.Abs(b[2]/*offsetX_1*/ - offsetX0) > 800)) // FanghanOffsetForYouKaiKou(gray, tonghouY, b, fanghanhouY, out offsetX0, ++i); } public void FanghanOffsetForNewShuangmiantongOffset0(Mat gray, int colStart, out int offsetX0) {//计算数值的地方 ////Console.WriteLine("fanghanhouduY1_0:" + fanghanhouduY1); // offsetX0 = -1; //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray.png", gray); int minGray = 300 * 255; int minColIndex = 0; int rowStart = 50 + 30; int rowEnd = 130 + 20/*gray.Rows - 50*/;// int curGray; List curgrayList = new List(); List minareaList_k = new List(); List minareaList_v = new List(); for (int i = colStart/*6*//*1*/; i < (gray.Cols + colStart) / 2 + 60/* + 40*/ + 20/*10*//*0 debug ER(14).JPG!!!!*/ /*gray.Cols - 50*/; i++) { curgrayList.Add(this.FanghanOffsetForNewKaiKouOffset0_areaMin(gray, i, rowStart, rowEnd)); if (curgrayList[i - colStart] < minGray) { minColIndex = i; minGray = curgrayList[i - colStart]; } } for (int i = colStart/*6*//*1*/; i < (gray.Cols + colStart) / 2 + 60/* + 40*/ /*gray.Cols - 50*/; i++) { if (i > colStart + 10 && i < (gray.Cols + colStart) / 2 + 60/* + 40*/ + 10/* - 10 debug ER(14).JPG!!!!*/) { bool isAreamin = true; for (int k = i - colStart - 10; k < i - colStart + 10; k++) { if (curgrayList[i - colStart] >= curgrayList[k]) { isAreamin = false; break; } if (k == i - colStart - 1) k++; } if (isAreamin) { minareaList_k.Add(i); minareaList_v.Add(curgrayList[i - colStart]); } } } //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); //下面为计算极小值,从计算极小值中的序列中选取,替换极大值 //minareaList.Add(minColIndex, minGray); //offsetX0 = 47 + colStart;// minColIndex; //if (minColIndex - minareaList_k[minareaList_k.Count - 1] != 0 && minareaList_k.Count < 4)//ER(14).JPG!!!! if (minareaList_k.Count <= 7) for (int i = 0; i < minareaList_k.Count; i++) { if (Math.Abs(minGray - minareaList_v[i]) < 400/*1100*//*400*//*120*/ && minareaList_k[i] > 240/* ER(90).JPG 250*//* ER(17).JPG!!!!240*/ && (minColIndex > (gray.Cols + colStart) / 2/* + 40*/ + 10 || minColIndex < (gray.Cols + colStart) / 2 + 60 /* + 40*/ - 40)) { minColIndex = minareaList_k[i]; break; } } //纠正191情况 else if (minareaList_k.Count == 9 && Math.Abs(minGray - minareaList_v[minareaList_k.Count - 2]) < 400 && minGray - minareaList_v[minareaList_k.Count - 2] != 0) { minColIndex = minareaList_k[minareaList_k.Count - 2]; } //纠正139情况 else if (minareaList_k.Count == 8 && Math.Abs(minGray - minareaList_v[minareaList_k.Count - 3]) < 400 && minGray - minareaList_v[minareaList_k.Count - 3] != 0) { minColIndex = minareaList_k[minareaList_k.Count - 3]; } if (minColIndex - minareaList_k[minareaList_k.Count - 1] > 0 && minColIndex - minareaList_k[minareaList_k.Count - 1] < 60 && Math.Abs(minGray - minareaList_v[minareaList_k.Count - 1]) < 1000) minColIndex = minareaList_k[minareaList_k.Count - 1]; else if (minColIndex - minareaList_k[minareaList_k.Count - 1] < 0 && Math.Abs(minGray - minareaList_v[minareaList_k.Count - 1]) < 1000 && minareaList_k.Count < 6/*6*//*7*/ /* ER(163).JPG ER(133).JPG ER(42).JPG*/ && minColIndex - minareaList_k[minareaList_k.Count - 1] < -40 && minColIndex - minareaList_k[minareaList_k.Count - 1] > -45) minColIndex = minareaList_k[minareaList_k.Count - 1];//ER(150).JPG offsetX0 = minColIndex; // } /// /// 防焊 有开口 LPI /// /// /// /// /// /// /// public void FanghanLPIForShuangmianTong(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] LPIHouduY, int a = 0) { int LPIHouduX = b[1] + 100; LPIHouduY = new int[2]; //Mat result1 = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); LPIHouduY[0] = tonghouY[1]; if (a > 255) { return; } Mat result1 = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); for (int i = Math.Max(0, LPIHouduY[0] - 120 - Math.Abs(tonghouY[1] - tonghouY[0])); i < LPIHouduY[0] - 50; i++) { if (result1.At(i, LPIHouduX) == 0) { Mat temp = ~result1; if (Cv2.FloodFill(temp, new Point(LPIHouduX, i), new Scalar(255)) > 3500) { LPIHouduY[1] = i; break; } } } if (LPIHouduY[1] == 0) { FanghanLPIForShuangmianTong(gray, tonghouY, b, fanghanhouY, out LPIHouduY, ++a); } } /// /// 防焊 有开口 厚度 /// /// /// /// /// /// /// public void FanghanhouduForShuangmianTonghou_2(Mat gray, int[] y, int fanghanhouduX, int[] tonghouY, out int fanghanhouduY1, out int minGray, bool isLeft) { int fanghanhouduY_0 = tonghouY[0]; int fanghanX1 = Math.Max(0, fanghanhouduX - 150); int fanghanX2 = Math.Min(gray.Cols - 1, fanghanhouduX + 150); int fanghanTop = fanghanhouduY_0 - 150/*100*/; int marginTop = 150; if (fanghanTop < 0) { fanghanTop = 0; marginTop = fanghanhouduY_0 - 1; } Mat grayRect = gray[fanghanTop, fanghanhouduY_0 - 50, fanghanX1, fanghanX2]; FanghanhouduForYouKaiKou(grayRect/*gray*/, y, marginTop/*150*//*fanghanhouduX*/, tonghouY, out fanghanhouduY1, out minGray); int fanghanhouduY1__2 = fanghanhouduY1; int minGray__2 = minGray; fanghanX1 += 140;// 145; fanghanX2 -= 140;// 145; grayRect = gray[fanghanTop, fanghanhouduY_0 - 20/*50*/, fanghanX1, fanghanX2]; int fanghanhouduY1__2_bottom; FanghanhouduForYouKaiKou_ACC(grayRect, y, marginTop, fanghanhouduY1 - (isLeft ? 8/*5*/ : 1), out fanghanhouduY1__2, out fanghanhouduY1__2_bottom, out minGray__2); if (Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 16/*11*//*<-10*//*20*//*10*/ || (!isLeft && Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 25/*20*/)) fanghanhouduY1 = fanghanhouduY1__2/*fanghanhouduY1__2_bottom*//*fanghanhouduY1__2*/ + fanghanTop;// +5; //else //{ // fanghanX1 -= 69; // fanghanX2 += 69; // grayRect = gray[fanghanTop, fanghanhouduY_0 - 50, fanghanX1, fanghanX2]; // FanghanhouduForMeiKaiKou(grayRect, y, marginTop, tonghouY, out fanghanhouduY1__2, out minGray__2); //} //if (Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 10) // fanghanhouduY1 = fanghanhouduY1__2 + fanghanTop; else fanghanhouduY1 = fanghanhouduY1 + fanghanTop; } /// /// 防焊 有开口 厚度 /// /// /// /// /// /// /// private void FanghanhouduForShuangmianTonghou(Mat gray, int[] y, int fanghanhouduX, int[] tonghouY, out int fanghanhouduY1, out int minGray, int a = 0) { /*int fanghanhouduX = 150; */ fanghanhouduY1 = -1; Mat thresh = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); //Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", thresh); for (int i = 0; i < 100; i++) { if (thresh.At(i, fanghanhouduX) == 0 && Cv2.FloodFill(thresh, new Point(fanghanhouduX, i), new Scalar(255)) > 300) { fanghanhouduY1 = i; break; } } minGray = 300 * 255; if (fanghanhouduY1 == -1) FanghanhouduForShuangmianTonghou(gray, y, fanghanhouduX, tonghouY, out fanghanhouduY1, out minGray, ++a); else {//计算数值的地方 //Console.WriteLine("fanghanhouduY1_0:" + fanghanhouduY1); /*int minGray = 300*255; */ int minRowIndex = 0; int colEnd = thresh.Cols - 1; int curGray; for (int i = 6/*1*/; i < 95; i++) { curGray = this.FanghanhouduForAreaMin(gray, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; if (curGray < minGray) { minRowIndex = i; minGray = curGray; } } //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); fanghanhouduY1 = minRowIndex; } } /// /// 防焊 双面铜 铜厚 /// /// /// /// /// public void FanhanShuangcengTonghou_1(Mat gray, out int[] tonghouY, out int[] y, out int[] b, int autoResValue = -1) { y = new int[2]; b = new int[4]; int[] bAdd = new int[6]; tonghouY = new int[2]; Mat contour; //contour = gray.Threshold(180, 255, ThresholdTypes.Binary); if (autoResValue > 0) { contour = gray.Threshold(autoResValue, 255, ThresholdTypes.Binary); } else contour = gray.Threshold(0, 255, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(15, 15)); Mat close = new Mat(); Cv2.MorphologyEx(contour, close, MorphTypes.Close, seClose); Mat nomin = new Mat(); GetArea(close, out nomin, 500, true); Mat result = nomin.Clone(); //Cv2.ImWrite(@"C:\Users\54434\Desktop\result.png", result * 127); #region//计算边界 Scalar sum = new Scalar(0); for (int i = 0; i < result.Rows; i++) { sum = result[i, i + 1, /*0*/result.Cols / 2, result.Cols].Sum(); if ((int)sum > 200) { y[0] = i - 20; break; } } for (int i = y[0] + 50; i < result.Rows; i++) { sum = result[i, i + 1, /*0*/result.Cols / 2, result.Cols].Sum(); if ((int)sum == 0) { y[1] = i; break; } } Mat imageClone = result * 127; Cv2.Line(imageClone, 0, y[1], imageClone.Cols - 1, y[1], new Scalar(255)); //Cv2.ImWrite(@"C:\Users\54434\Desktop\result.png", imageClone); for (int j = 0; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > (/*y[1] - y[0] - */20)) { b[0] = j; bAdd[0] = j; break; } } //这里可以考虑再次纠错,使用联通域,找到这个联通块的最右侧的点,而不是直接+200 //但是也要考虑左右的铜,因为底部颜色亮,而连接在一起的情况 //或者考虑sum==0和另一个条件比较,再次校验 for (int j = b[0] + 200; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0 || ((int)sum > 0 && ((y[1]-y[0]) - (int)sum)>50)) //if ((int)sum == 0) { b[1] = j; bAdd[1] = j; break; } } for (int j = b[1] + 50; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 50) //if ((int)sum > (y[1] - y[0] - 20)) { b[2] = j; bAdd[2] = j; break; } } if (b[2] - b[1] < 300) { for (int j = b[2] + 50; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { b[1] = j; bAdd[1] = j; break; } } for (int j = b[1] + 10; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 20) { b[2] = j; bAdd[2] = j; break; } } } for (int j = b[2] + 50; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { b[3] = j; bAdd[3] = j; break; } } if (b[3] == 0) b[3] = contour.Cols - 1; if (bAdd[3] == 0) bAdd[3] = contour.Cols - 1; for (int j = bAdd[3] + 10; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 0) { bAdd[4] = j; break; } } if (bAdd[4] == 0) bAdd[4] = contour.Cols - 1; for (int j = bAdd[4] + 50; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { bAdd[5] = j; break; } } if (bAdd[5] == 0) bAdd[5] = contour.Cols - 1; // for (int j = result.Cols - 1; j > b[2]; j--) // { // sum = result[y[0], y[1], j - 1, j].Sum(); // if ((int)sum > 0) // { // b[3] = j; // break; // } // } // if (b[3] == 0) // b[3] = contour.Cols - 1; // //bAdd[5] = b[3]; if (b[3] != bAdd[5] && bAdd[5] != contour.Cols - 1)//b[3] != bAdd[3] && b[3] - bAdd[2] > bAdd[3] - b[0] && (b[0] < 20 && b[1] < 60 && (b[1] < 280 && b[0] < 100 || b[3] == contour.Cols - 1))/*防止过拟合*/)//测量区域在右边 { b[3] = bAdd[5];// b[2] = bAdd[4]; b[1] = bAdd[3]; b[0] = bAdd[2]; } #endregion //计算铜厚 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(15, 15), 5, 5); Mat edge = new Mat(); Sobel(filter, out edge); Mat threshEdge = edge.Threshold(10, 255, ThresholdTypes.Binary); Mat and = new Mat(); Cv2.BitwiseAnd(contour, threshEdge, and); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9, 1)); Mat open = new Mat(); Cv2.MorphologyEx(and, open, MorphTypes.Open, seOpen); Cv2.Rectangle(open, new Rect(0, y[1], open.Cols, open.Rows - y[1]), new Scalar(0), -1); int tonghouX = b[1] - 150; #region//计算边界 在tonghouX附近纠正y轴倾斜的距离 sum = new Scalar(0); for (int i = 0; i < result.Rows; i++) { sum = result[i, i + 1, tonghouX - 10, tonghouX + 10/*result.Cols / 2, result.Cols*/].Sum(); if ((int)sum > 10/*200*/) { y[0] = i - 20; break; } } for (int i = y[0] + 50; i < result.Rows; i++) { sum = result[i, i + 1, tonghouX - 10, tonghouX + 10/*result.Cols / 2, result.Cols*/].Sum(); if ((int)sum == 0) { y[1] = i; break; } } #endregion Mat result2 = open / 255; int start = 0; for (int i = y[0]; i < y[1]; i++) { if (contour.Get(i, tonghouX) > 0) { start = i; break; } } //Cv2.ImWrite(@"C:\Users\54434\Desktop\result2.png", result2 * 127); for (int i = start + 20; i < y[1] - 40/*40*/; i++) { sum = result2[i, i + 1, tonghouX - 50, tonghouX + 50].Sum(); if ((int)sum > 80/*80*/) { tonghouY[0] = i; break; } } if (tonghouY[0] == 0) { for (int i = start + 20; i < y[1] - 20; i++) { sum = result2[i, i + 1, tonghouX - 50, tonghouX + 50].Sum(); if ((int)sum > 50) { tonghouY[0] = i; break; } } } //if (tonghouY[0] == 0) //{//ER(114).JPG // //tonghouY[0] = start; // for (int i = start - 50/* + 20*/; i < y[1] - 0/*20*/; i++) // { // sum = result2[i, i + 1, tonghouX - 50, tonghouX + 50].Sum(); // if ((int)sum > 20/*50*/) // { // tonghouY[0] = i; // break; // } // } //} for (int i = tonghouY[0] + 10; i < y[1] + 20/*0*/; i++) { if (contour.Get(i, tonghouX) == 0) { tonghouY[1] = i; break; } } int compensate1 = 0; tonghouY[0] += compensate1; } /// /// 防焊 双面铜 铜厚 /// /// /// /// /// public void FanhanShuangcengTonghou_2(Mat gray, out int[] tonghouY, out int[] y, out int[] b) { y = new int[2]; b = new int[4]; tonghouY = new int[2]; Mat contour = gray.Threshold(0, 255, ThresholdTypes.Otsu); //去掉小颗粒 contour = BinaryTools.DebrisRemoval_New(contour.CvtColor(ColorConversionCodes.GRAY2BGRA), 1000).CvtColor(ColorConversionCodes.BGRA2GRAY); Mat result = contour.Clone(); /*Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(15, 15)); Mat close = new Mat(); Cv2.MorphologyEx(contour, close, MorphTypes.Close, seClose); Mat nomin = new Mat(); GetArea(close, out nomin, 500, true); Mat result = nomin.Clone();*/ #region//计算边界 Scalar sum = new Scalar(0); for (int i = 0; i < result.Rows; i++) { sum = result[i, i + 1, 0, result.Cols].Sum(); if ((int)sum > 200) { y[0] = i - 20; break; } } for (int i = y[0] + 50; i < result.Rows; i++) { sum = result[i, i + 1, 0, result.Cols].Sum(); if ((int)sum == 0) { y[1] = i; break; } } for (int j = 0; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 20) { b[0] = j; break; } } for (int j = b[0] + 200; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { b[1] = j; break; } } for (int j = b[1] + 10; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 20) { b[2] = j; break; } } if (b[2] - b[1] < 300) { for (int j = b[2] + 50; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { b[1] = j; break; } } for (int j = b[1] + 10; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 20) { b[2] = j; break; } } } for (int j = b[2] + 50; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { b[3] = j; break; } } if (b[3] == 0) b[3] = contour.Cols - 1; //LineShow(gray, b[0], y[0], b[1], y[0]); //LineShow(gray, b[2], y[1], b[3], y[1]); //ImageShow(gray); #endregion //计算铜厚 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(15, 15), 5, 5); Mat edge = new Mat(); //Edge(filter, out edge); //Mat threshEdge = edge.Threshold(25, 255, ThresholdTypes.Binary); Sobel(filter, out edge); Mat threshEdge = edge.Threshold(10, 255, ThresholdTypes.Binary); Mat and = new Mat(); Cv2.BitwiseAnd(contour, threshEdge, and); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9, 1)); Mat open = new Mat(); Cv2.MorphologyEx(and, open, MorphTypes.Open, seOpen); //GetArea(open, out open, 10, true); Cv2.Rectangle(open, new Rect(0, y[1], open.Cols, open.Rows - y[1]), new Scalar(0), -1); //Mat fanse = 255 - open; //Mat noMin = new Mat(); //GetArea(fanse, out noMin, 1000, true); //ImageShow(threshEdge, and, open/*,fanse*255*/); int tonghouX = b[1] - 150; Mat result2 = open / 255; int start = 0; for (int i = y[0]; i < y[1]; i++) { if (contour.Get(i, tonghouX) > 0) { start = i; break; } } for (int i = start + 20; i < y[1] - 40; i++) { sum = result2[i, i + 1, tonghouX - 50, tonghouX + 50].Sum(); if ((int)sum > 80) { tonghouY[0] = i; break; } } if (tonghouY[0] == 0) { for (int i = start + 20; i < y[1] - 20; i++) { sum = result2[i, i + 1, tonghouX - 50, tonghouX + 50].Sum(); if ((int)sum > 50) { tonghouY[0] = i; break; } } } //for (int i = tonghouY[0]+10; i < y[1]; i++) //{ // sum = result2[i, i + 1, tonghouX - 50, tonghouX + 50].Sum(); // if ((int)sum > 50) // { // tonghouY[1] = i; // break; // } //} for (int i = tonghouY[0] + 10; i < y[1]; i++) { if (contour.Get(i, tonghouX) == 0) { tonghouY[1] = i; break; } } int compensate1 = 0; tonghouY[0] += compensate1; //int compensate2 = 10; //tonghouY[1] += compensate2; } /// /// 防焊 双面铜 厚度 /// /// /// /// /// /// public void Fanghanhoudu4(Mat gray, int[] y, int[] b, int[] tonghouY, out int[] fanghanhouduY, int a = 0) { fanghanhouduY = new int[2]; int fanghanhouduX = b[1] - 100; /*Mat newGray = new Mat(); Cv2.GaussianBlur(gray, newGray, new Size(15, 15), 5, 5); Mat edge = new Mat(); Sobel(newGray, out edge); Mat thresh = edge.Threshold(5, 255, ThresholdTypes.Binary); Cv2.Rectangle(thresh, new Rect(0, 0, b[1] - 200, thresh.Rows), new Scalar(0), -1); Cv2.Rectangle(thresh, new Rect(0, 0, thresh.Cols, y[0] - 200), new Scalar(0), -1); Cv2.Rectangle(thresh, new Rect(0, y[0], thresh.Cols, thresh.Rows - y[0]), new Scalar(0), -1); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat open = new Mat(); Cv2.MorphologyEx(thresh, open, MorphTypes.Open, seOpen); Mat noCircle = new Mat(); RemoveCircles(open, out noCircle); Mat max = new Mat(); GetMaxArea(noCircle, out max); Mat result = max.Clone(); Scalar sum = new Scalar(0); for (int i = tonghouY[0] - 50; i > tonghouY[0] - 200; i--) { sum = result[i - 1, i, fanghanhouduX - 50, fanghanhouduX + 50].Sum(); if ((int)sum > 50) { fanghanhouduY[0] = i; break; } }*/ fanghanhouduY[1] = y[0]+20; /*Scalar sum = new Scalar(0); Mat thresh = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); //防焊下层 Mat thresh2 = thresh / 255;//gray.Threshold(0, 1, ThresholdTypes.Otsu); for (int i = fanghanhouduY[0] + 10; i < tonghouY[0]*//*thresh2.Rows*//*; i++) { sum = thresh2[i, i + 1, fanghanhouduX - 50, fanghanhouduX + 50].Sum(); if ((int)sum > 50) { fanghanhouduY[1] = i; break; } }*/ Mat thresh = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 3), 255, ThresholdTypes.Binary); for (int i = fanghanhouduY[1] - 50; i > fanghanhouduY[1] - 90; i--) { if (thresh.At(i, fanghanhouduX) == 0 && Cv2.FloodFill(thresh, new Point(fanghanhouduX, i), new Scalar(255)) > 1300) { fanghanhouduY[0] = i - 4; break; } } if (fanghanhouduY[0] == 0) { Fanghanhoudu4(gray, y, b, tonghouY, out fanghanhouduY, ++a); } /*fanghanhouduY = new int[2]; int fanghanhouduX = b[1] - 100; Mat thresh = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); fanghanhouduY[0] = tonghouY[0]; for (int i = fanghanhouduY[0] - 100; i < fanghanhouduY[0] - 50; i++) { if (thresh.At(i, fanghanhouduX) == 0 && Cv2.FloodFill(thresh, new Point(fanghanhouduX, i), new Scalar(255)) > 300) { fanghanhouduY[1] = i; break; } } if (fanghanhouduY[1] == 0) { Fanghanhoudu4(gray, y, b, tonghouY, out fanghanhouduY, ++a); }*/ } /// /// 防焊 双面铜 offset /// /// /// /// /// /// public void FanghanOffset6(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] offsetX, int i = 0) { offsetX = new int[2]; //二值化 Mat threshEdge = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (i * 5), 255, ThresholdTypes.BinaryInv); //去碎屑 threshEdge = ~BinaryTools.DebrisRemoval_New(threshEdge.CvtColor(ColorConversionCodes.GRAY2BGRA), 250).CvtColor(ColorConversionCodes.BGRA2GRAY); for (int j = b[2] - 155; j > 0; j--) { if (threshEdge.At(tonghouY[0] - 5, j) == 0) { Mat temp = ~threshEdge; if (Cv2.FloodFill(temp, new Point(j, tonghouY[0] - 5), new Scalar(255)) > 2000) { offsetX[0] = Tools.GetLeftOrRightPoint(new Point(j, tonghouY[0] - 5), threshEdge, 2).X; break; } } } offsetX[1] = b[2]; if (i < 20 && ( offsetX[0] <= 0 || Math.Abs(offsetX[1] - offsetX[0]) > 800)) { FanghanOffset6(gray, tonghouY, b, fanghanhouY, out offsetX, ++i); } } /// /// 防焊 双面铜 LPI厚度 /// /// /// 銅厚的上下縱坐標 /// 第一層銅的起始點(橫向),b[0]:銅起始點;b[1]:銅結束點;b[2]:銅再次開始點 /// public void FanghanLPI2(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] LPIHouduY, int a = 0) { int LPIHouduX = b[1] + 100; LPIHouduY = new int[2]; Mat result1 = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); LPIHouduY[0] = tonghouY[1]; if (LPIHouduY[0] <= 120) return; for (int i = LPIHouduY[0] - 120 - Math.Abs(tonghouY[1] - tonghouY[0]); i < LPIHouduY[0] - 50; i++) { if (result1.At(i, LPIHouduX) == 0) { Mat temp = ~result1; if (Cv2.FloodFill(temp, new Point(LPIHouduX, i), new Scalar(255)) > 3500) { LPIHouduY[1] = i; break; } } } if (LPIHouduY[1] == 0) { FanghanLPI2(gray, tonghouY, b, fanghanhouY, out LPIHouduY, ++a); } } /// /// 防焊 双面铜 Undercut /// /// /// /// /// /// /// /// public void FanghanUndercut6_3(Mat gray, int[] tonghouY, int[] b, int[] offsetX, int[] LPIHouY, out int undercutX, int i = 0) { int tempj = -1; undercutX = 0; Mat filter = new Mat(); PointEnhancement(gray, out filter); Mat newGray = new Mat(); Cv2.GaussianBlur(filter, newGray, new Size(15, 15), 5, 5); Mat threshEdge = newGray.Threshold(BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 3), 255, ThresholdTypes.BinaryInv); Mat result = threshEdge.Canny(0, 255); int tempRange = (offsetX[0] - 300) <= 0 ? 1 : offsetX[0] - 300; //想左找 for (int j = offsetX[0] + 10; j > tempRange; j--) { byte v = result.Get((tonghouY[1] + tonghouY[0]) / 2, j); if (v > 0) { tempj = j; //if (Cv2.FloodFill(result, new Point(j, (tonghouY[1] + tonghouY[0]) / 2), new Scalar(255)) > 100) { undercutX = Tools.GetLeftPoint(new Point(j, (tonghouY[1] + tonghouY[0]) / 2), result).X; break; } } } if (i > 15) { undercutX = (tempj == -1) ? offsetX[0] - 25 : tempj; //undercutX = offsetX[0] - 25; } else { if (undercutX == 0 || (undercutX > 0 && offsetX[0] - undercutX > 100)) { FanghanUndercut6_3(gray, tonghouY, b, offsetX, LPIHouY, out undercutX, ++i); } else { undercutX = (undercutX + tempj) / 2 - 20; } } } #endregion #endregion /// /// 计算防焊双层铜的铜厚 /// /// 二值圖像 /// 绿色通道图 /// 輸出銅厚的上下縱坐標 /// 輸出銅厚的上下縱坐標 /// b[0]:銅起始點;b[1]:銅結束點;b[2]:銅再次開始點 public void FanhanShuangcengTonghou(Mat imageContour, Mat imageGreen, out int[] tonghouY, out int[] y, out int[] b) { y = new int[2]; b = new int[4]; tonghouY = new int[2]; Scalar sum = new Scalar(0); Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Cv2.MorphologyEx(imageContour, imageContour, MorphTypes.Open, se); for (int i = 0; i < imageContour.Rows; i++) { sum = imageContour[i, i + 1, 0, imageContour.Cols].Sum(); if ((int)sum > 200) { y[0] = i - 20; break; } } for (int i = y[0] + 21; i < imageContour.Rows; i++) { sum = imageContour[i, i + 1, 0, imageContour.Cols].Sum(); if ((int)sum == 0) { y[1] = i; break; } } //左右边界,从右边开始 for (int j = imageContour.Cols - 1; j > 0; j--) { sum = imageContour[y[0], y[1], j - 1, j].Sum(); if ((int)sum > 0) { b[3] = j; break; } } for (int j = b[3] - 1; j > 0; j--) { sum = imageContour[y[0], y[1], j - 1, j].Sum(); if ((int)sum == 0) { b[2] = j; break; } } for (int j = b[2] - 1; j > 0; j--) { sum = imageContour[y[0], y[1], j - 1, j].Sum(); if ((int)sum > 0) { b[1] = j; break; } } for (int j = b[1] - 1; j > 0; j--) { sum = imageContour[y[0], y[1], j - 1, j].Sum(); if ((int)sum == 0) { b[0] = j; break; } } //计算外层铜厚 Mat crop = imageContour[y[0], y[1], b[0], b[2]]; int tonghouX = b[1] - 200; Mat se2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); Mat dilate = new Mat(); Cv2.Dilate(crop, dilate, se2); Mat result = dilate.Clone(); GetMaxContour(dilate, out result); //ImageShow(result * 255); for (int i = 0; i < result.Rows; i++) { if (result.Get(i, tonghouX - b[0]) > 0) { tonghouY[0] = i + y[0]; break; } } for (int i = tonghouY[0] - y[0] + 20; i < result.Rows; i++) { if (result.Get(i, tonghouX - b[0]) > 0) { tonghouY[1] = i + y[0]; break; } } double ordiante = 0; InsideLine(imageGreen, tonghouY[0], tonghouY[1], tonghouX - 10, tonghouX + 10, out ordiante); tonghouY[0] = (int)ordiante; } /// /// 計算防焊厚度 /// /// 原圖紅色通道圖片 /// 截取第一層銅的上下區域 /// 第一層銅的起始點(橫向),b[0]:銅起始點;b[1]:銅結束點;b[2]:銅再次開始點 /// 銅厚的上下縱坐標 /// 防焊厚度的上下縱坐標 public void Fanghanhoudu2(Mat imageRed, int[] y, int[] b, int[] tonghouY, out int[] fanghanhouduY) { int compensate = 5; fanghanhouduY = new int[2]; int fanghanhouduX = b[1] - 100; Mat crop = imageRed[tonghouY[0] - 100, tonghouY[0] - 20, /*fanghanhouduX-20, fanghanhouduX+20*/fanghanhouduX - 100, b[1]]; Mat thresh = new Mat(); double t = Cv2.Threshold(crop, thresh, 0, 1, ThresholdTypes.Otsu); thresh = 1 - crop.Threshold(t - 10, 1, ThresholdTypes.Binary); Mat seopen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(10, 3)); Mat open = new Mat(); Cv2.MorphologyEx(thresh, open, MorphTypes.Close, seopen); Cv2.Rectangle(open, new Rect(0, 0, 1, open.Rows), new Scalar(1), -1); Cv2.Rectangle(open, new Rect(0, thresh.Rows - 1, thresh.Cols, 1), new Scalar(1), -1); Fill(open, out open, 1); Cv2.Rectangle(open, new Rect(0, 0, 1, open.Rows), new Scalar(0), -1); Mat result; GetMaxArea(open, out result); Scalar sum = new Scalar(0); for (int i = 0; i < result.Rows; i++) { sum = result[i, i + 1, 0, result.Cols].Sum(); if ((int)sum > 5) { fanghanhouduY[0] = i + tonghouY[0] - 100 + compensate; break; } } Mat crop3 = imageRed.Threshold(0, 1, ThresholdTypes.Otsu)[y[0], y[1], 0, imageRed.Cols]; double ordinate2 = 0; ExtractLines(crop3, out ordinate2, fanghanhouduX - 5, fanghanhouduX + 5, 1); fanghanhouduY[1] = (int)ordinate2 + y[0] + 2; } public void Fanghanhoudu3(Mat gray, int[] y, int[] b, int[] tonghouY, out int[] fanghanhouduY, int a=0) { fanghanhouduY = new int[2]; int fanghanhouduX = b[1] - 100; Mat thresh = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a*5), 255, ThresholdTypes.Binary); fanghanhouduY[0] = tonghouY[0]; for (int i = fanghanhouduY[0] - 100; i < fanghanhouduY[0] - 50; i++) { if(thresh.At(i, fanghanhouduX) == 0 && Cv2.FloodFill(thresh, new Point(fanghanhouduX, i), new Scalar(255)) > 300) { fanghanhouduY[1] = i; break; } } if (fanghanhouduY[1] == 0) { Fanghanhoudu3(gray, y, b, tonghouY, out fanghanhouduY, ++a); } } public void Fanghanhoudu5(Mat gray, int[] y, int[] b, int[] tonghouY, out int[] fanghanhouduY, int a=0) { fanghanhouduY = new int[2]; int fanghanhouduX = b[1] - 100; Mat thresh = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); fanghanhouduY[0] = tonghouY[0]; for (int i = fanghanhouduY[0] - 100; i < fanghanhouduY[0] - 50; i++) { if (thresh.At(i, fanghanhouduX) == 0 && Cv2.FloodFill(thresh, new Point(fanghanhouduX, i), new Scalar(255)) > 300) { fanghanhouduY[1] = i; break; } } if (fanghanhouduY[1] == 0) { Fanghanhoudu5(gray, y, b, tonghouY, out fanghanhouduY, ++a); } } //public void Fanghanhoudu2(Mat imageRed, int[] y, int[] b, int[] tonghouY, out int[] fanghanhouduY) /// /// 計算防焊offset /// /// 紅色通道圖片 /// 銅厚縱坐標 /// 第一層銅的起始點(橫向),b[0]:銅起始點;b[1]:銅結束點;b[2]:銅再次開始點 /// offset橫坐標 public void FanghanOffset2(Mat imageRed, int[] tonghouY, int[] b, out int[] offsetX) { offsetX = new int[2]; Mat crop = imageRed[tonghouY[0] - 100, tonghouY[1] - 20, b[1] + 20, b[2]]; Mat thresh = new Mat(); double t = Cv2.Threshold(crop, thresh, 0, 1, ThresholdTypes.Otsu); thresh = 1 - crop.Threshold(t - 25, 1, ThresholdTypes.Binary); Mat seopen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); Mat open = new Mat(); Cv2.MorphologyEx(thresh, open, MorphTypes.Close, seopen); Cv2.Rectangle(open, new Rect(0, 0, 1, open.Rows), new Scalar(1), -1); Cv2.Rectangle(open, new Rect(0, thresh.Rows - 1, thresh.Cols, 1), new Scalar(1), -1); Scalar max = new Scalar(0); int maxline = 0; for (int i = 0; i < open.Rows - 1; i++) { if ((int)open[i, i + 1, 0, open.Cols].Sum() > (int)max) { max = open[i, i + 1, 0, open.Cols].Sum(); maxline = i; } } Cv2.Rectangle(open, new Rect(0, maxline, thresh.Cols, 1), new Scalar(1), -1); Fill(open, out open, 1); //Cv2.Rectangle(open, new Rect(0, maxline, thresh.Cols, 1), new Scalar(0), -1); Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(1, 3)); Cv2.Erode(open, open, se); Cv2.Rectangle(open, new Rect(0, thresh.Rows - 1, thresh.Cols, 1), new Scalar(0), -1); Mat result; GetMaxArea(open, out result); //ImageShow(thresh * 255, open * 255, result * 255); //ImageShow(open * 255, result * 255); //Mat noCircle = new Mat(); //RemoveCirCles(crop, thresh, out noCircle); //Mat close = new Mat(); //Cv2.MorphologyEx(noCircle, close, MorphTypes.Close, seopen); ////Cv2.MorphologyEx(close, open, MorphTypes.Open, seopen); Scalar sum = new Scalar(0); for (int j = 20; j < result.Cols; j++) { sum = result[0, result.Rows, j, j + 1].Sum(); if ((int)sum < 2) { offsetX[0] = j + b[1] + 20 - 5; break; } } offsetX[1] = b[2]; //ImageShow(thresh * 255, noCircle * 255, close * 255, open * 255); //RemoveCirCles(crop,fill, out noCircle); //ImageShow(open*255,fill * 255, noCircle*255); } public void FanghanOffset3(Mat imageRed, int[] tonghouY, int[] b, out int[] offsetX) { offsetX = new int[2]; Mat crop = imageRed[tonghouY[0] - 100, tonghouY[0], b[1], b[2]].Clone(); Mat sobel = new Mat(); Sobel(crop, out sobel); Mat thresh = sobel.Threshold(0, 255, ThresholdTypes.Otsu); Mat fill = new Mat(); Fill(thresh, out fill, 255); Mat deleteArea = new Mat(); GetArea(fill, out deleteArea, 10, true); Cv2.Rectangle(deleteArea, new Rect(0, deleteArea.Rows - 1, deleteArea.Cols, 1), new Scalar(1), -1); Cv2.Rectangle(deleteArea, new Rect(0, 0, 1, deleteArea.Rows), new Scalar(1), -1); Fill(deleteArea, out deleteArea, 1); Cv2.Rectangle(deleteArea, new Rect(0, deleteArea.Rows - 1, deleteArea.Cols, 1), new Scalar(0), -1); Cv2.Rectangle(deleteArea, new Rect(0, 0, 1, deleteArea.Rows), new Scalar(0), -1); Mat maxArea = new Mat(); GetMaxArea(deleteArea, out maxArea); Scalar sum = new Scalar(0); for (int j = maxArea.Cols - 1; j > 0; j--) { sum = maxArea[0, maxArea.Rows, j - 1, j].Sum(); if ((int)sum > 0) { offsetX[0] = j + b[1]; break; } } offsetX[1] = b[2]; //ImageShow(thresh, fill, deleteArea * 255, maxArea * 255); } /// /// 提取防焊没开口offset,利用大倍率边缘检测来实现 /// /// /// /// /// public void FanghanOffset4(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] offsetX) { offsetX = new int[2]; //offsetY = 0; Mat filter = new Mat(); PointEnhancement(gray, out filter); Mat newGray = new Mat(); Cv2.GaussianBlur(filter, newGray, new Size(15, 15), 5, 5); //PointEnhancement(gray, out gray); //Mat crop = gray[tonghouY[0] - 120, tonghouY[0] - 20, LPIHouduX - 10, LPIHouduX + 10]; Mat edge = new Mat(); //Sobel(gray, out edge); Edge(newGray, out edge); Mat threshEdge = new Mat(); threshEdge = edge.Threshold(35, 255, ThresholdTypes.Binary); Cv2.Rectangle(threshEdge, new Rect(0, 0, threshEdge.Cols, fanghanhouY[0]), new Scalar(0), -1); Cv2.Rectangle(threshEdge, new Rect(0, 0, b[1], tonghouY[1]), new Scalar(255), -1); Cv2.Rectangle(threshEdge, new Rect(0, tonghouY[1], threshEdge.Cols, threshEdge.Rows - tonghouY[1]), new Scalar(0), -1); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(1, 7)); Mat close = new Mat(); Cv2.MorphologyEx(threshEdge, close, MorphTypes.Close, seClose); Mat noMin = new Mat(); //GetArea(close, out noMin, 1000, true); GetMaxArea(close, out noMin); ImageShow(edge, threshEdge, close, noMin * 255); Mat result = noMin.Clone(); Scalar sum = new Scalar(0); for (int j = b[2] - 20; j > 0; j--) { sum = result[fanghanhouY[0], tonghouY[0] - 20, j - 1, j].Sum(); //if (result.Get(tonghouY[0] - 50, j) > 0) if ((int)sum > 20) { offsetX[0] = j; break; } } //for (int i = fanghanhouY[0]; i < tonghouY[0]; i++) //{ // if (result.Get(i, offsetX[0]) > 0) // { // offsetY = i; // break; // } //} offsetX[1] = b[2]; int compensate = 10; offsetX[0] -= compensate; } /// /// 用于提取防焊有开口的offset,因为图片质量差,所用的参数比没开口低 /// /// /// /// /// /// public void FanghanOffset5(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] offsetX) { offsetX = new int[2]; //offsetY = 0; Mat filter = new Mat(); PointEnhancement(gray, out filter); Mat newGray = new Mat(); Cv2.GaussianBlur(filter, newGray, new Size(15, 15), 5, 5); //PointEnhancement(gray, out gray); //Mat crop = gray[tonghouY[0] - 120, tonghouY[0] - 20, LPIHouduX - 10, LPIHouduX + 10]; Mat edge = new Mat(); //Sobel(gray, out edge); Edge(newGray, out edge); Mat threshEdge = new Mat(); threshEdge = edge.Threshold(25, 255, ThresholdTypes.Binary); Cv2.Rectangle(threshEdge, new Rect(0, tonghouY[1], threshEdge.Cols, threshEdge.Rows - tonghouY[1]), new Scalar(0), -1); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(1, 7)); Mat close = new Mat(); Cv2.MorphologyEx(threshEdge, close, MorphTypes.Close, seClose); Mat noCircle = new Mat(); RemoveCircles(close, out noCircle); Cv2.Rectangle(noCircle, new Rect(0, 0, threshEdge.Cols, fanghanhouY[0] - 10), new Scalar(0), -1); //Cv2.Rectangle(noCircle, new Rect(0, 0, b[1], tonghouY[1]), new Scalar(1), -1); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(1, 3)); Mat open = new Mat(); Cv2.MorphologyEx(noCircle, open, MorphTypes.Open, seOpen); Mat noMin = new Mat(); GetArea(open, out noMin, 2000, true); //GetMaxArea(close, out noMin); ImageShow(threshEdge, close * 255, noMin * 255); Mat result = noMin.Clone(); Scalar sum = new Scalar(0); for (int j = b[2] - 20; j > 0; j--) { sum = result[fanghanhouY[0], tonghouY[0] - 20, j - 1, j].Sum(); //if (result.Get(tonghouY[0] - 50, j) > 0) if ((int)sum > 20) { offsetX[0] = j; break; } } offsetX[1] = b[2]; int compensate = 10; offsetX[0] -= compensate; } /// /// 防焊 没有开口 offset /// /// /// /// /// /// /// public void FanghanOffset5_3(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] offsetX, int i=0) { offsetX = new int[2]; //二值化 Mat threshEdge = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (i*5), 255, ThresholdTypes.BinaryInv); //去碎屑 threshEdge = ~BinaryTools.DebrisRemoval_New(threshEdge.CvtColor(ColorConversionCodes.GRAY2BGRA), 250).CvtColor(ColorConversionCodes.BGRA2GRAY); for (int j = b[2] - 55; j > 0; j--) { if (threshEdge.At(tonghouY[0]-5, j) == 0) { Mat temp = ~threshEdge; if (Cv2.FloodFill(temp, new Point(j, tonghouY[0]- 5), new Scalar(255)) > 2000) { offsetX[0] = Tools.GetLeftOrRightPoint(new Point(j, tonghouY[0] - 5), threshEdge, 2).X - 3; break; } } } offsetX[1] = b[2]; if (offsetX[0] <= 0 || Math.Abs(offsetX[1] - offsetX[0]) > 800) { FanghanOffset5_3(gray, tonghouY, b, fanghanhouY, out offsetX, ++i); } } public void FanghanOffset7(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] offsetX, int i=0) { offsetX = new int[2]; //二值化 Mat threshEdge = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (i * 5), 255, ThresholdTypes.BinaryInv); //去碎屑 threshEdge = ~BinaryTools.DebrisRemoval_New(threshEdge.CvtColor(ColorConversionCodes.GRAY2BGRA), 250).CvtColor(ColorConversionCodes.BGRA2GRAY); for (int j = b[2] - 55; j > 0; j--) { if (threshEdge.At(tonghouY[0] - 5, j) == 0) { Mat temp = ~threshEdge; if (Cv2.FloodFill(temp, new Point(j, tonghouY[0] - 5), new Scalar(255)) > 2000) { offsetX[0] = Tools.GetLeftOrRightPoint(new Point(j, tonghouY[0] - 5), threshEdge, 2).X; break; } } } offsetX[1] = b[2]; if (offsetX[0] <= 0 || Math.Abs(offsetX[1] - offsetX[0]) > 800) { FanghanOffset7(gray, tonghouY, b, fanghanhouY, out offsetX, ++i); } } public void FanhanKaikou3(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] fanghankaikou, int i=0) { //二值化 Mat threshEdge = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (i * 3), 255, ThresholdTypes.BinaryInv); //去碎屑 threshEdge = ~BinaryTools.DebrisRemoval_New(threshEdge.CvtColor(ColorConversionCodes.GRAY2BGRA), 3000).CvtColor(ColorConversionCodes.BGRA2GRAY); fanghankaikou = new int[2]; for (int j = b[3]; j < threshEdge.Cols - 1; j++) { if (threshEdge.At(tonghouY[0] - 5, j) == 0) { Mat temp = ~threshEdge; if (Cv2.FloodFill(temp, new Point(j, tonghouY[0] - 5), new Scalar(255)) > 3000 && Math.Abs(b[3] - j)>20) { //fanghankaikou[1] = j; //Mat edge = threshEdge.Canny(0, 255); fanghankaikou[1] = Tools.GetLeftOrRightPoint(new Point(j, tonghouY[0] - 5), threshEdge, 1).X - 3; break; } } } if(i>=10) { fanghankaikou[1] = 1200; } else { if (fanghankaikou[1] == 0) { FanhanKaikou3(gray, tonghouY, b, fanghanhouY, out fanghankaikou, ++i); } } } /// /// 計算防焊的LPI厚度 /// /// 原圖紅色通道圖片 /// 銅厚的上下縱坐標 /// 第一層銅的起始點(橫向),b[0]:銅起始點;b[1]:銅結束點;b[2]:銅再次開始點 /// public void FanghanLPI(Mat imageRed, int[] tonghouY, int[] b, out int[] LPIHouduY) { int LPIHouduX = b[1] + 100; LPIHouduY = new int[2]; Mat crop = imageRed[tonghouY[0] - 120, tonghouY[0] - 20, LPIHouduX - 10, LPIHouduX + 10]; Mat thresh = 1 - crop.Threshold(80, 1, ThresholdTypes.Binary); Mat seopen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(10, 3)); Mat open = new Mat(); Cv2.MorphologyEx(thresh, open, MorphTypes.Open, seopen); Cv2.Rectangle(open, new Rect(0, 0, 1, open.Rows), new Scalar(1), -1); Cv2.Rectangle(open, new Rect(0, thresh.Rows - 1, thresh.Cols, 1), new Scalar(1), -1); Fill(open, out open, 1); Cv2.Rectangle(open, new Rect(0, 0, 1, open.Rows), new Scalar(0), -1); Mat result; GetMaxArea(open, out result); //ImageShow(result*255, open * 255); Scalar sum = new Scalar(0); for (int i = 0; i < result.Rows; i++) { sum = result[i, i + 1, 0, result.Cols].Sum(); if ((int)sum > 10) { LPIHouduY[0] = i + tonghouY[0] - 120; break; } } } /// /// 705修改,提取LPI,使用去圆算法 /// /// /// /// /// /// public void FanghanLPI2_2(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] LPIHouduY, int a=0) { int LPIHouduX = b[1] + 100; LPIHouduY = new int[2]; Mat result1 = gray.Threshold(BinaryTools.CalcSuitableValue(gray)-10 + (a*5), 255, ThresholdTypes.Binary); LPIHouduY[0] = tonghouY[1]; for (int i = LPIHouduY[0] - 120 - Math.Abs(tonghouY[1]- tonghouY[0]); i < LPIHouduY[0] - 50; i++) { if(result1.At(i, LPIHouduX) ==0) { Mat temp = ~result1; if (Cv2.FloodFill(temp, new Point(LPIHouduX, i), new Scalar(255)) > 3500) { LPIHouduY[1] = i; break; } } } if (LPIHouduY[1] == 0) { FanghanLPI2_2(gray, tonghouY, b, fanghanhouY, out LPIHouduY, ++a); } } public void FanghanLPI2_3(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] LPIHouduY, int a=0) { int LPIHouduX = b[1] + 100; LPIHouduY = new int[2]; Mat result1 = gray.Threshold(BinaryTools.CalcSuitableValue(gray) - 10 + (a * 5), 255, ThresholdTypes.Binary); LPIHouduY[0] = tonghouY[1]; for (int i = LPIHouduY[0] - 120 - Math.Abs(tonghouY[1] - tonghouY[0]); i < LPIHouduY[0] - 50; i++) { if (result1.At(i, LPIHouduX) == 0) { Mat temp = ~result1; if (Cv2.FloodFill(temp, new Point(LPIHouduX, i), new Scalar(255)) > 3500) { LPIHouduY[1] = i; break; } } } if (LPIHouduY[1] == 0) { FanghanLPI2_3(gray, tonghouY, b, fanghanhouY, out LPIHouduY, ++a); } /*int LPIHouduX = b[1] + 100; LPIHouduY = new int[2]; //LPI上层 Mat newGray = new Mat(); Cv2.GaussianBlur(gray, newGray, new Size(15, 15), 5, 5); Mat edge = new Mat(); Edge(newGray, out edge); Mat threshEdge = new Mat(); threshEdge = edge.Threshold(20, 255, ThresholdTypes.Binary); Mat threshEdge1 = threshEdge.Clone(); Cv2.Rectangle(threshEdge1, new Rect(0, 0, threshEdge.Cols, fanghanhouY[0] - 10), new Scalar(0), -1); Cv2.Rectangle(threshEdge1, new Rect(0, tonghouY[0] - 20, threshEdge.Cols, tonghouY[1]), new Scalar(255), -1); Cv2.Rectangle(threshEdge1, new Rect(0, tonghouY[1], threshEdge.Cols, threshEdge.Rows - tonghouY[1]), new Scalar(0), -1); Mat noCircle = new Mat(); RemoveCircles(threshEdge1, out noCircle); Mat result1 = noCircle.Clone(); Scalar sum = new Scalar(0); for (int i = fanghanhouY[0]<=0?1: fanghanhouY[0]; i < tonghouY[0] - 20; i++) { sum = result1[i, i + 1, LPIHouduX - 50, LPIHouduX + 50].Sum(); if ((int)sum > 50) { LPIHouduY[0] = i; break; } } if (LPIHouduY[0] == 0) { for (int i = fanghanhouY[0] <= 0 ? 1 : fanghanhouY[0]; i < tonghouY[0] - 20; i++) { sum = result1[i, i + 1, LPIHouduX - 50, LPIHouduX + 50].Sum(); if ((int)sum > 30) { LPIHouduY[0] = i; break; } } } //LPI下层 Mat newGray2 = new Mat(); Cv2.GaussianBlur(gray, newGray2, new Size(11, 11), 3, 3); Mat edge2 = new Mat(); Edge(newGray2, out edge2); Mat threshEdge2 = new Mat(); threshEdge2 = edge2.Threshold(20, 255, ThresholdTypes.Binary); Mat threshEdge3 = threshEdge2.Clone(); Cv2.Rectangle(threshEdge3, new Rect(0, 0, threshEdge.Cols, fanghanhouY[0]), new Scalar(0), -1); Cv2.Rectangle(threshEdge3, new Rect(0, tonghouY[1] + 20, threshEdge.Cols, threshEdge.Rows - tonghouY[1] - 20), new Scalar(0), -1); Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 3)); Mat close2 = new Mat(); Cv2.MorphologyEx(threshEdge3, close2, MorphTypes.Close, seClose2); close2 = close2 / 255; Mat result2 = close2.Clone(); for (int i = tonghouY[1] + 20; i > tonghouY[1] - 20; i--) { sum = result2[i - 1, i, LPIHouduX - 50, LPIHouduX + 50].Sum(); if ((int)sum > 80) { LPIHouduY[1] = i; break; } } int compensate = 5; LPIHouduY[0] += compensate; LPIHouduY[1] -= compensate;*/ } /// /// 计算防焊LPI厚度,暂时用在有开口上,从下往上,寻找横向像素点足够多的时候 /// /// /// /// /// /// public void FanghanLPI3(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] LPIHouduY) { int LPIHouduX = b[1] + 100; LPIHouduY = new int[2]; //LPI上层 Mat newGray = new Mat(); Cv2.GaussianBlur(gray, newGray, new Size(11, 11), 5, 5); Mat edge = new Mat(); Edge(newGray, out edge); Mat threshEdge = new Mat(); threshEdge = edge.Threshold(20, 255, ThresholdTypes.Binary); Cv2.Rectangle(threshEdge, new Rect(0, 0, threshEdge.Cols, fanghanhouY[0]), new Scalar(0), -1); //Mat seClose = Mat noMin = new Mat(); GetArea(threshEdge, out noMin, 1000, true); //ImageShow(edge, threshEdge, noMin * 255); Mat result = noMin.Clone(); Scalar sum1 = new Scalar(0); for (int i = tonghouY[0]; i > fanghanhouY[0]; i--) { sum1 = result[i - 1, i, LPIHouduX - 50, LPIHouduX + 50].Sum(); if ((int)sum1 > 50) { LPIHouduY[0] = i; break; } } //LPI下层 Mat newGray2 = new Mat(); Cv2.GaussianBlur(gray, newGray2, new Size(11, 11), 3, 3); Mat edge2 = new Mat(); Edge(newGray2, out edge2); Mat threshEdge2 = new Mat(); threshEdge2 = edge2.Threshold(20, 255, ThresholdTypes.Binary); //Mat fill = new Mat(); //Fill(threshEdge2, out fill, 255); Mat threshEdge3 = threshEdge2.Clone(); Cv2.Rectangle(threshEdge3, new Rect(0, 0, threshEdge.Cols, fanghanhouY[0]), new Scalar(0), -1); Cv2.Rectangle(threshEdge3, new Rect(0, tonghouY[1] + 20, threshEdge.Cols, threshEdge.Rows - tonghouY[1] - 20), new Scalar(0), -1); //Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 3)); //Mat close2 = new Mat(); //Cv2.MorphologyEx(threshEdge3, close2, MorphTypes.Close, seClose2); Mat noMin2 = new Mat(); GetArea(threshEdge3, out noMin2, 2000, true); //ImageShow(edge2, threshEdge2, noMin2 * 255); Mat result2 = noMin2.Clone(); Scalar sum = new Scalar(0); for (int i = tonghouY[1] + 20; i > tonghouY[1] - 20; i--) { sum = result2[i - 1, i, LPIHouduX - 50, LPIHouduX + 50].Sum(); if ((int)sum > 80) //if (result2.Get(i, LPIHouduX) > 0) { LPIHouduY[1] = i; break; } } int compensate1 = 5; LPIHouduY[0] -= compensate1; int compensate2 = 5; LPIHouduY[1] -= compensate2; } public void FanghanLPI4(Mat gray, int[] tonghouY, int[] b, int[] fanghanhouY, out int[] LPIHouduY) { int LPIHouduX = b[1] + 100; LPIHouduY = new int[2]; //LPI上层 Mat newGray = new Mat(); Cv2.GaussianBlur(gray, newGray, new Size(11, 11), 5, 5); Mat edge = new Mat(); Edge(newGray, out edge); Mat threshEdge = new Mat(); threshEdge = edge.Threshold(20, 255, ThresholdTypes.Binary); Cv2.Rectangle(threshEdge, new Rect(0, 0, threshEdge.Cols, fanghanhouY[0] - 10), new Scalar(0), -1); //Mat seClose = Mat noMin = new Mat(); GetArea(threshEdge, out noMin, 1000, true); ImageShow(edge, threshEdge, noMin * 255); Mat result = noMin.Clone(); Scalar sum1 = new Scalar(0); for (int i = tonghouY[0]; i > fanghanhouY[0]; i--) { sum1 = result[i - 1, i, LPIHouduX - 50, LPIHouduX + 50].Sum(); if ((int)sum1 > 50) { LPIHouduY[0] = i; break; } } //LPI下层 Mat newGray2 = new Mat(); Cv2.GaussianBlur(gray, newGray2, new Size(11, 11), 3, 3); Mat edge2 = new Mat(); Edge(newGray2, out edge2); Mat threshEdge2 = new Mat(); threshEdge2 = edge2.Threshold(20, 255, ThresholdTypes.Binary); //Mat fill = new Mat(); //Fill(threshEdge2, out fill, 255); Mat threshEdge3 = threshEdge2.Clone(); Cv2.Rectangle(threshEdge3, new Rect(0, 0, threshEdge.Cols, fanghanhouY[0]), new Scalar(0), -1); Cv2.Rectangle(threshEdge3, new Rect(0, tonghouY[1] + 20, threshEdge.Cols, threshEdge.Rows - tonghouY[1] - 20), new Scalar(0), -1); //Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 3)); //Mat close2 = new Mat(); //Cv2.MorphologyEx(threshEdge3, close2, MorphTypes.Close, seClose2); Mat noMin2 = new Mat(); GetArea(threshEdge3, out noMin2, 2000, true); //ImageShow(edge2, threshEdge2, noMin2 * 255); Mat result2 = noMin2.Clone(); Scalar sum = new Scalar(0); for (int i = tonghouY[1] + 20; i > tonghouY[1] - 20; i--) { sum = result2[i - 1, i, LPIHouduX - 50, LPIHouduX + 50].Sum(); if ((int)sum > 80) //if (result2.Get(i, LPIHouduX) > 0) { LPIHouduY[1] = i; break; } } int compensate1 = 5; LPIHouduY[0] -= compensate1; int compensate2 = 5; LPIHouduY[1] -= compensate2; } /// /// 計算防焊的undercut /// /// 原圖紅色通道圖片 /// 銅厚的上下縱坐標 /// 第一層銅的起始點(橫向),b[0]:銅起始點;b[1]:銅結束點;b[2]:銅再次開始點 /// 輸出防焊同第三条线的交点之间的水平距离 public void FanghanUndercut(Mat imageRed, int[] tonghouY, int[] b, int[] offsetX, out int undercutX) { int compensate = 20; undercutX = 0; Mat crop = imageRed[tonghouY[0] - 100, tonghouY[1] + 20, b[1] + 20, offsetX[0]]; Mat thresh = new Mat(); double t = Cv2.Threshold(crop, thresh, 0, 1, ThresholdTypes.Otsu); thresh = 1 - crop.Threshold(t - 30, 1, ThresholdTypes.Otsu); Cv2.Rectangle(thresh, new Rect(0, 0, 20, thresh.Rows - 1), new Scalar(1), -1); Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat close = new Mat(); Cv2.MorphologyEx(thresh, close, MorphTypes.Close, se); Mat fill = new Mat(); Fill(close, out fill, 1); Mat result = fill; GetMaxContour(result, out result); //ImageShow(result * 255); Mat se2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(1, 5)); Mat dilate = new Mat(); Cv2.Dilate(result, dilate, se2); //ImageShow(close * 255, dilate * 255); result = dilate; Scalar sum = new Scalar(0); Scalar max = new Scalar(0); int upper = 0; for (int i = 120; i < crop.Rows - 10; i++) { sum = result[i, i + 1, 0, result.Cols].Sum(); if ((int)sum > (int)max) { max = sum; upper = i; } } for (int j = result.Cols - 20; j > 20; j--) { if (result.Get(upper, j) > 0) { undercutX = j + b[1] + 20 - compensate; break; } } } /// /// 计算防焊没开口undercut /// /// 原图 /// 铜厚纵坐标 /// 铜的边界 /// /// 输出undercut位置 public void FanghanUndercut2(Mat image, int[] tonghouY, int[] b, int[] offsetX, out int undercutX) { /* * 利用canny边缘检测,闭运算连接后,填充,保留大面积,取反,关键部位每列和为1时记录 */ undercutX = 0; Cv2.GaussianBlur(image, image, new Size(7, 7), 3, 3); Mat edge = new Mat(); Cv2.Canny(image, edge, 10, 15); //ceju.ImageShow(edge); Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); Mat close = new Mat(); Cv2.MorphologyEx(edge, close, MorphTypes.Close, se); Mat fill = new Mat(); Fill(close, out fill, 255); //ImageShow(edge, close, fill); Mat draw = new Mat(); GetArea(close, out draw, 10000, true); //ImageShow(draw * 255); Mat result = 1 - draw; Mat crop = result[tonghouY[0] + 20, tonghouY[1] + 10, b[1] + 20, b[2]].Clone(); GetMaxArea(crop, out crop); //ImageShow(crop * 255); Scalar sum = new Scalar(0); for (int j = 0; j < crop.Cols; j++) { sum = crop[0, crop.Rows, j, j + 1].Sum(); if ((int)sum > 0) { undercutX = j + b[1] + 20; break; } } int compensate = 25; undercutX -= compensate; } public void FanghanUndercut3(Mat gray, int[] tonghouY, int[] b, int[] offsetX, int[] fanghanhouY, out int undercutX) { undercutX = 0; Mat filter = new Mat(); PointEnhancement(gray, out filter); Mat newGray = new Mat(); Cv2.GaussianBlur(filter, newGray, new Size(11, 11), 5, 5); Mat edge = new Mat(); Edge(newGray, out edge); Mat threshEdge = new Mat(); threshEdge = edge.Threshold(20, 255, ThresholdTypes.Binary); Mat fill = new Mat(); Fill(threshEdge, out fill, 255); Cv2.Rectangle(fill, new Rect(0, 0, threshEdge.Cols, fanghanhouY[0]), new Scalar(0), -1); //Cv2.Rectangle(threshEdge, new Rect(0, 0, b[1], tonghouY[1]), new Scalar(255), -1); Cv2.Rectangle(fill, new Rect(0, tonghouY[1] + 20, threshEdge.Cols, threshEdge.Rows - tonghouY[1] - 20), new Scalar(0), -1); //Cv2.Rectangle(threshEdge, new Rect(offsetX[0], 0, threshEdge.Cols-offsetX[0], threshEdge.Rows), new Scalar(0), -1); //Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); //Mat close = new Mat(); //Cv2.MorphologyEx(threshEdge, close, MorphTypes.Close, seClose); Mat max = new Mat(); //GetMaxArea(close, out max); GetArea(fill, out max, 2000, true); Mat fanse = 1 - max; ImageShow(threshEdge, fill, max * 255, fanse * 255); Mat result = fanse.Clone(); Scalar sum = new Scalar(0); int lowerBound = 0, upperBound = 0; int leftBound = (offsetX[0] - 130 > b[1] + 20) ? offsetX[0] - 130 : b[1] + 20; for (int i = tonghouY[0]; i < tonghouY[1] + 20; i++) { sum = result[i, i + 1, leftBound, offsetX[0] - 20].Sum(); if ((int)sum == 0) { upperBound = i; break; } } for (int i = tonghouY[1] + 20; i > tonghouY[0]; i--) { sum = result[i - 1, i, leftBound, offsetX[0] - 20].Sum(); if ((int)sum == 0) { lowerBound = i; break; } } //Cv2.Line(fanse, new Point(leftBound,upperBound), new Point(leftBound,lowerBound), new Scalar(1), 2, LineTypes.Link8); //ImageShow(fanse*255); for (int j = leftBound; j < offsetX[0]; j++) { sum = result[upperBound, lowerBound, j, j + 1].Sum(); if ((int)sum > 0) { undercutX = j; break; } } int compensate = 30; undercutX -= compensate; } public void FanghanUndercut4(Mat gray, int[] tonghouY, int[] b, int[] offsetX, int[] LPIHouY, out int undercutX) { undercutX = 0; Mat newGray = new Mat(); Cv2.GaussianBlur(gray, newGray, new Size(15, 15), 5, 5); Mat edge = new Mat(); Edge(newGray, out edge); Mat threshEdge = new Mat(); threshEdge = edge.Threshold(30, 255, ThresholdTypes.Binary); Mat threshEdge1 = threshEdge.Clone(); Cv2.Rectangle(threshEdge1, new Rect(0, 0, b[1] + 20, threshEdge1.Rows), new Scalar(255), -1); Mat noMin = new Mat(); GetArea(threshEdge1, out noMin, 50000, true); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); Mat close = new Mat(); Cv2.MorphologyEx(noMin, close, MorphTypes.Close, seClose); //ImageShow(threshEdge1, noMin * 255,close*255); int[] x1 = new int[10]; int[] y1 = new int[10]; int count = 0; for (int i = tonghouY[0] + 20; i < tonghouY[0] + 30; i++) { for (int j = offsetX[0] + 30; j > offsetX[0] - 100; j--) { if (close.Get(i, j) > 0) { x1[count] = j; y1[count] = i; count++; break; } } if (count == 10) break; } int[] x2 = new int[10]; int[] y2 = new int[10]; count = 0; for (int i = tonghouY[0] + 30; i < tonghouY[0] + 40; i++) { for (int j = offsetX[0] + 30; j > offsetX[0] - 100; j--) { if (close.Get(i, j) > 0) { x2[count] = j; y2[count] = i; count++; break; } } if (count == 10) break; } double[] averOrdinate1 = new double[2]; double[] averOrdinate2 = new double[2]; AverOrdinate(x1, y1, out averOrdinate1); AverOrdinate(x2, y2, out averOrdinate2); LineShow(gray, (int)averOrdinate1[0], (int)averOrdinate1[1], (int)averOrdinate2[0], (int)averOrdinate2[1]); //ImageShow(gray); double slope = ((averOrdinate2[0] - averOrdinate1[0]) == 0) ? 0 : (averOrdinate2[1] - averOrdinate1[1]) / (averOrdinate2[0] - averOrdinate1[0]); double intercept = averOrdinate1[1] - slope * averOrdinate1[0]; undercutX = (slope == 0) ? 0 : (int)((LPIHouY[1] - intercept) / slope); int compensate = 10; undercutX -= compensate; } /// /// 提取undercut,由于有开口亮度和对比对低,参数不同。 /// /// /// /// /// /// /// public void FanghanUndercut5(Mat gray, int[] tonghouY, int[] b, int[] offsetX, int[] LPIHouY, out int undercutX) { undercutX = 0; Mat newGray = new Mat(); Cv2.GaussianBlur(gray, newGray, new Size(15, 15), 5, 5); Mat edge = new Mat(); Edge(newGray, out edge); Mat threshEdge = new Mat(); threshEdge = edge.Threshold(25, 255, ThresholdTypes.Binary); Mat threshEdge1 = threshEdge.Clone(); Cv2.Rectangle(threshEdge1, new Rect(0, 0, b[1] + 20, threshEdge1.Rows), new Scalar(255), -1); Mat noMin = new Mat(); GetArea(threshEdge1, out noMin, 2000, true); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); Mat close = new Mat(); Cv2.MorphologyEx(noMin, close, MorphTypes.Close, seClose); //ImageShow(threshEdge1, noMin * 255, close * 255); #region//获取平均坐标 int[] x1 = new int[10]; int[] y1 = new int[10]; int count = 0; for (int i = tonghouY[0] - 20; i < tonghouY[0] - 10; i++) { for (int j = offsetX[0] + 20; j > offsetX[0] - 100; j--) { if (close.Get(i, j) > 0) { x1[count] = j; y1[count] = i; count++; break; } } if (count == 10) break; } int[] x2 = new int[10]; int[] y2 = new int[10]; count = 0; for (int i = tonghouY[0]; i < tonghouY[0] + 10; i++) { for (int j = offsetX[0] + 20; j > offsetX[0] - 100; j--) { if (close.Get(i, j) > 0) { x2[count] = j; y2[count] = i; count++; break; } } if (count == 10) break; } double[] averOrdinate1 = new double[2]; double[] averOrdinate2 = new double[2]; AverOrdinate(x1, y1, out averOrdinate1); AverOrdinate(x2, y2, out averOrdinate2); #endregion //LineShow(gray, (int)averOrdinate1[0], (int)averOrdinate1[1], (int)averOrdinate2[0], (int)averOrdinate2[1]); //ImageShow(gray,close*255); double slope = ((averOrdinate2[0] - averOrdinate1[0]) == 0) ? 0 : (averOrdinate2[1] - averOrdinate1[1]) / (averOrdinate2[0] - averOrdinate1[0]); double intercept = averOrdinate1[1] - slope * averOrdinate1[0]; undercutX = (slope == 0) ? 0 : (int)((LPIHouY[1] - intercept) / slope); int compensate = 10; undercutX -= compensate; } public void FanghanUndercut5_2(Mat gray, int[] tonghouY, int[] b, int[] offsetX, int[] LPIHouY, out int undercutX, int i=0) { undercutX = 0; Mat filter = new Mat(); PointEnhancement(gray, out filter); Mat newGray = new Mat(); Cv2.GaussianBlur(filter, newGray, new Size(15, 15), 5, 5); Mat threshEdge = newGray.Threshold(BinaryTools.CalcSuitableValueForUnderCut(gray) - 15 + (i * 5), 255, ThresholdTypes.BinaryInv); Mat result = threshEdge.Canny(0, 255); int tempRange = (offsetX[0] - 300) <= 0 ? 1 : offsetX[0] - 300; //想左找 for (int j = offsetX[0] + 10; j > tempRange; j--) { byte v = result.Get(tonghouY[1] - 20, j); if (v > 0) { if(Cv2.FloodFill(result, new Point(j, tonghouY[0] - 20), new Scalar(255)) > 300) { undercutX = Tools.GetLeftPoint(new Point(j, tonghouY[1] - 20), result).X; break; } } } if (i > 10) undercutX = offsetX[0] - 25; else { if (undercutX == 0 || (undercutX > 0 && offsetX[0] - undercutX > 100)) { FanghanUndercut5_2(gray, tonghouY, b, offsetX, LPIHouY, out undercutX, ++i); } } } /// /// 防焊双层铜undercut,采集点位置不同 /// /// /// /// /// /// /// public void FanghanUndercut6(Mat gray, int[] tonghouY, int[] b, int[] offsetX, int[] LPIHouY, out int undercutX) { undercutX = 0; Mat newGray = new Mat(); Cv2.GaussianBlur(gray, newGray, new Size(15, 15), 5, 5); Mat edge = new Mat(); Edge(newGray, out edge); Mat threshEdge = new Mat(); threshEdge = edge.Threshold(25, 255, ThresholdTypes.Binary); Mat threshEdge1 = threshEdge.Clone(); Cv2.Rectangle(threshEdge1, new Rect(0, 0, b[1] + 20, threshEdge1.Rows), new Scalar(255), -1); Mat noMin = new Mat(); GetArea(threshEdge1, out noMin, 2000, true); //Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); //Mat close = new Mat(); //Cv2.MorphologyEx(noMin, close, MorphTypes.Close, seClose); Mat result = noMin.Clone(); //ImageShow(threshEdge1, noMin * 255/*, close * 255*/); int[] x1 = new int[10]; int[] y1 = new int[10]; int count = 0; for (int i = tonghouY[0] - 10; i < tonghouY[0]; i += 1) { for (int j = offsetX[0] + 20; j > offsetX[0] - 100; j--) { if (result.Get(i, j) > 0) { x1[count] = j; y1[count] = i; count++; break; } } if (count == 10) break; } int[] x2 = new int[10]; int[] y2 = new int[10]; count = 0; for (int i = tonghouY[0] + 10; i < tonghouY[0] + 20; i += 1) { for (int j = offsetX[0] + 20; j > offsetX[0] - 100; j--) { if (result.Get(i, j) > 0) { x2[count] = j; y2[count] = i; count++; break; } } if (count == 10) break; } double[] averOrdinate1 = new double[2]; double[] averOrdinate2 = new double[2]; AverOrdinate(x1, y1, out averOrdinate1); AverOrdinate(x2, y2, out averOrdinate2); //LineShow(gray, (int)averOrdinate1[0], (int)averOrdinate1[1], (int)averOrdinate2[0], (int)averOrdinate2[1]); //ImageShow(gray); double slope = ((averOrdinate2[0] - averOrdinate1[0]) == 0) ? 0 : (averOrdinate2[1] - averOrdinate1[1]) / (averOrdinate2[0] - averOrdinate1[0]); double intercept = averOrdinate1[1] - slope * averOrdinate1[0]; undercutX = (slope == 0) ? 0 : (int)((LPIHouY[1] - intercept) / slope); int compensate = 10; undercutX -= compensate; } /// /// 705改,提取undercut /// /// /// /// /// /// /// public void FanghanUndercut6_2(Mat gray, int[] tonghouY, int[] b, int[] offsetX, int[] LPIHouY, out int undercutX) { undercutX = 0; Mat filter = new Mat(); PointEnhancement(gray, out filter); Mat newGray = new Mat(); Cv2.GaussianBlur(filter, newGray, new Size(15, 15), 5, 5); //PointEnhancement(gray, out gray); //Mat crop = gray[tonghouY[0] - 120, tonghouY[0] - 20, LPIHouduX - 10, LPIHouduX + 10]; Mat edge = new Mat(); //Sobel(gray, out edge); Edge(newGray, out edge); Mat threshEdge = new Mat(); threshEdge = edge.Threshold(25, 255, ThresholdTypes.Binary); //Cv2.Rectangle(threshEdge, new Rect(0, tonghouY[0]-100, b[1], tonghouY[1]-tonghouY[0]+100), new Scalar(255), -1); Mat noCircle = new Mat(); RemoveCircles(threshEdge, out noCircle); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); Mat close = new Mat(); Cv2.MorphologyEx(noCircle, close, MorphTypes.Close, seClose); //Mat noMin = new Mat(); //GetArea(threshEdge1, out noMin, 2000, true); //Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); //Mat close = new Mat(); //Cv2.MorphologyEx(noMin, close, MorphTypes.Close, seClose); Mat result = close.Clone(); //ImageShow(threshEdge, noCircle * 255, close * 255); int[] x1 = new int[10]; int[] y1 = new int[10]; int count = 0; for (int i = tonghouY[0] - 10; i < tonghouY[0]; i += 1) { for (int j = offsetX[0] + 20; j > offsetX[0] - 100; j--) { if (result.Get(i, j) > 0) { x1[count] = j; y1[count] = i; count++; break; } } if (count == 10) break; } int[] x2 = new int[10]; int[] y2 = new int[10]; count = 0; for (int i = tonghouY[0] + 10; i < tonghouY[0] + 20; i += 1) { for (int j = offsetX[0] + 20; j > offsetX[0] - 100; j--) { if (result.Get(i, j) > 0) { x2[count] = j; y2[count] = i; count++; break; } } if (count == 10) break; } double[] averOrdinate1 = new double[2]; double[] averOrdinate2 = new double[2]; AverOrdinate(x1, y1, out averOrdinate1); AverOrdinate(x2, y2, out averOrdinate2); //LineShow(gray, (int)averOrdinate1[0], (int)averOrdinate1[1], (int)averOrdinate2[0], (int)averOrdinate2[1]); //ImageShow(gray); double slope = ((averOrdinate2[0] - averOrdinate1[0]) == 0) ? 0 : (averOrdinate2[1] - averOrdinate1[1]) / (averOrdinate2[0] - averOrdinate1[0]); double intercept = averOrdinate1[1] - slope * averOrdinate1[0]; undercutX = (slope == 0) ? 0 : (int)((LPIHouY[1] - intercept) / slope); int compensate = 10; undercutX -= compensate; } //高度差 /// /// 計算含非零點數最大列 /// /// /// public void MaxCol(Mat image, out int maxCol) { maxCol = 0; Scalar sum = new Scalar(0); Scalar max = new Scalar(0); for (int j = 0; j < image.Cols; j++) { sum = image[0, image.Rows, j, j + 1].Sum(); if ((int)sum > (int)max) { max = sum; maxCol = j; } } } /// /// 得到高度差左右的测量区域 /// /// 二值图 /// 高度差B横坐标 /// 高度差B*横坐标 /// 方向,“left”;"right" public void GaoduchaGetDataArea(Mat thresh, out Mat result, out int BX, out int B_X, string direction) { BX = 0; B_X = 0; GetMaxArea(thresh, out thresh); int[] b = new int[3]; MaxCol(thresh, out b[1]); //ceju.ImageShow(thresh * 255); double ordinate1 = 0; double ordinate2 = 0; switch (direction) { case "left": ExtractLines(thresh, out ordinate1, b[1] - 500, b[1] - 400, 1); ExtractLines(thresh, out ordinate2, b[1] - 500, b[1] - 400, ordinate1, -1); break; case "right": ExtractLines(thresh, out ordinate1, b[1] + 400, b[1] + 500, 1); ExtractLines(thresh, out ordinate2, b[1] + 400, b[1] + 500, ordinate1, -1); break; } int[] firstAndTwo = new int[] { (int)ordinate1, (int)ordinate2 }; //int border = 0; //switch (direction) //{ // case "left": // for (int j = b[1]; j>0;j--) // { // if ((int)thresh[(int)ordinate1, (int)ordinate2, j - 1, j].Sum() == 0) // { // border = j; // break; // } // } // break; // case "right": // for (int j = b[1]; j < thresh.Cols; j++) // { // if ((int)thresh[(int)ordinate1, (int)ordinate2, j - 1, j].Sum() == 0) // { // border = j; // break; // } // } // break; //} Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat open = new Mat(); Cv2.MorphologyEx(thresh, open, MorphTypes.Open, se); result = open.Clone(); //ceju.ImageShow(open * 255); Scalar sum = new Scalar(0); Scalar lastSum = new Scalar(0); switch (direction) { case "left": for (int j = b[1] - 600; j > 0; j -= 5) { sum = open[0, (int)ordinate2, j - 10, j].Sum(); if (((int)lastSum - (int)sum) > 60 && (int)lastSum != 0)//不用绝对值差防止凸起 { b[0] = j; break; } lastSum = sum; } if (b[0] == 0) { lastSum = 0; sum = 0; for (int j = b[1] - 600; j > 0; j -= 5) { sum = open[0, (int)ordinate2, j - 10, j].Sum(); if ((int)lastSum - (int)sum > 20 && (int)lastSum != 0) { b[0] = j; break; } lastSum = sum; } } B_X = b[0] + 15; BX = b[0] + 50; break; case "right": for (int j = b[1] + 500; j < open.Cols; j += 5) { sum = open[0, (int)ordinate2, j - 10, j].Sum(); if (Math.Abs((int)sum - (int)lastSum) > 50/*80*/ && (int)lastSum != 0 && Math.Abs((int)lastSum - (int)(open[0, (int)ordinate2, j + 0, j + 10].Sum())) > 50 && (int)sum - (int)(open[0, (int)ordinate2, j + 10, j + 20].Sum()) > 30) { b[2] = j; break; } lastSum = sum; } B_X = b[2] - 15; BX = b[2] - 50; break; } } /// /// 计算高度差左右的测量线的纵坐标 /// /// 测量区域时的结果图 /// 红色通道图 /// 高度差B纵坐标坐标 /// 高度差B*纵坐标坐标 /// 高度差B横坐标 /// 高度差B*横坐标 public void GaoduchaB(Mat image, Mat imageRed, out int[] BY, out int[] B_Y, int BX, int B_X) { BY = new int[2]; B_Y = new int[2]; for (int i = 0; i < image.Rows; i++) { if (image.Get(i, B_X) > 0) { B_Y[1] = i; break; } } for (int i = 0; i < image.Rows; i++) { if (image.Get(i, BX) > 0) { BY[1] = i; break; } } //Cv2.EqualizeHist(imageRed, imageRed); Mat crop = imageRed[BY[1] - 60, BY[1] - 10, B_X - 5, BX + 5]; Mat thresh2 = 1 - crop.Threshold(0, 1, ThresholdTypes.Otsu); //Mat thresh2 = new Mat(); //double t2 = Cv2.Threshold(crop, thresh2, 0, 1, ThresholdTypes.Otsu); //thresh = 1 - crop.Threshold(t + 10, 1, ThresholdTypes.Binary); Mat se2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Cv2.MorphologyEx(thresh2, thresh2, MorphTypes.Close, se2); GetMaxArea(thresh2, out thresh2); //ceju.ImageShow(thresh2 * 255); for (int i = 0; i < thresh2.Rows; i++) //for (int i = thresh2.Rows-5; i >0;i--) { if (thresh2.Get(i, 5) > 0) { B_Y[0] = i + BY[1] - 60 + 5; break; } } for (int i = 0; i < thresh2.Rows; i++) //for (int i = thresh2.Rows - 5; i > 0; i--) { if (thresh2.Get(i, thresh2.Cols - 5) > 0) { BY[0] = i + BY[1] - 60 + 5; break; } } } /// /// 计算高度差纵坐标 /// /// /// /// /// /// /// public void GaoduchaBOrdinateY(Mat thresh, Mat image, out int[] BY, out int[] B_Y, int BX, int B_X) { BY = new int[2]; B_Y = new int[2]; //计算下纵坐标 for (int i = 0; i < thresh.Rows; i++) { if (thresh.Get(i, B_X) > 0) { B_Y[1] = i; break; } } for (int i = 0; i < thresh.Rows; i++) { if (thresh.Get(i, BX) > 0) { BY[1] = i; break; } } //边缘检测 Mat edge = new Mat(); //PointEnhancement(image, out image); Cv2.GaussianBlur(image, image, new Size(9, 9), 5, 5); Cv2.Canny(image, edge, 15, 0); //Mat crop = edge[B_Y[1]-60, edge.Rows, B_X - 5, BX + 5].Clone(); //Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); //Mat open = new Mat(); //Cv2.MorphologyEx(edge, open, MorphTypes.Open, seOpen); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 3)); Mat close = new Mat(); Cv2.MorphologyEx(edge, close, MorphTypes.Close, seClose); //Cv2.MorphologyEx(close, close, MorphTypes.Close, seClose); //Cv2.Rectangle(close, new Rect(B_X-5, B_Y[1]-60, 1, close.Rows-(B_Y[1]-60)), new Scalar(255), -1); //Cv2.Rectangle(close, new Rect(BX+5, B_Y[1] - 60, 1, close.Rows - (B_Y[1] - 60)), new Scalar(255), -1); Mat fill = new Mat(); Fill(close, out fill, 255); Mat maxFill = new Mat(); //Cv2.Rectangle(fill, new Rect(B_X - 5, B_Y[0] - 60, 1, close.Rows - (B_Y[0] - 60)), new Scalar(0), -1); //Cv2.Rectangle(fill, new Rect(BX + 5, B_Y[0] - 60, 1, close.Rows - (B_Y[0] - 60)), new Scalar(0), -1); //GetMaxArea(fill, out maxFill); GetArea(fill, out maxFill, 150, true); //ImageShow(edge, close, fill, maxFill * 255); //计算上纵坐标 for (int i = B_Y[1] - 10; i > 0; i--) { if (maxFill.Get(i, B_X) > 0) { B_Y[0] = i; break; } } for (int i = BY[1] - 10; i > 0; i--) { if (maxFill.Get(i, BX) > 0) { BY[0] = i; break; } } int compensate = 5; BY[0] -= compensate; B_Y[0] -= compensate; } public void GaoduchaBOrdinateY2(Mat thresh, Mat imageRed, Mat image, out int[] BY, out int[] B_Y, int BX, int B_X, string direction) { BY = new int[2]; B_Y = new int[2]; //计算下纵坐标 for (int i = 0; i < thresh.Rows; i++) { if (thresh.Get(i, B_X) > 0) { B_Y[1] = i; break; } } for (int i = 0; i < thresh.Rows; i++) { if (thresh.Get(i, BX) > 0) { BY[1] = i; break; } } #region//法一 //边缘检测 Mat sobelEdge = new Mat(); //PointEnhancement(image, out image); Cv2.GaussianBlur(imageRed, imageRed, new Size(9, 9), 3, 3); PointEnhancement(imageRed, out imageRed); Sobel(imageRed, out sobelEdge); Mat threshEdge = new Mat(); double t = Cv2.Threshold(sobelEdge, threshEdge, 0, 255, ThresholdTypes.Otsu); if (t < 50) threshEdge = sobelEdge.Threshold(10, 255, ThresholdTypes.Binary); //Mat cannyEdge = new Mat(); //Cv2.GaussianBlur(image, image, new Size(9, 9), 5, 5); //Cv2.Canny(image, cannyEdge, 15, 0); //Mat edge = cannyEdge/2 + threshEdge / 2; //Cv2.ConvertScaleAbs(edge, edge); //横向连接 Mat text2 = new Mat(); switch (direction) { case "left": text2 = threshEdge[B_Y[1] - 40, B_Y[1] - 10, B_X, BX] / 255; break; case "right": text2 = threshEdge[B_Y[1] - 40, B_Y[1] - 10, BX, B_X] / 255; break; } Mat seClose1 = new Mat(); if ((int)text2.Sum() < text2.Rows * text2.Cols / 2) { //Mat seClose1 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); seClose1 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9, 1)); } else { seClose1 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); } Mat close1 = new Mat(); Cv2.MorphologyEx(threshEdge, close1, MorphTypes.Close, seClose1); //上方置零 Cv2.Rectangle(close1, new Rect(0, 0, close1.Cols, BY[1] - 60), new Scalar(0), -1); //先将小点去掉 Mat noMin = new Mat(); GetArea(close1, out noMin, 10, true); //闭运算后得到最大连通域 //如果边缘不明显 Mat text = new Mat(); switch (direction) { case "left": text = noMin[B_Y[1] - 40, B_Y[1] - 10, B_X, BX]; break; case "right": text = noMin[B_Y[1] - 40, B_Y[1] - 10, BX, B_X]; break; } Mat result = new Mat(); Mat max = new Mat(); if ((int)text.Sum() < (text.Rows * text.Cols) / 3) { result = noMin.Clone(); } else if ((int)text.Sum() < (text.Rows * text.Cols) / 2) { Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); Mat close = new Mat(); Cv2.MorphologyEx(noMin, close, MorphTypes.Close, se); GetMaxArea(close, out max); result = max.Clone(); } else { Cv2.Rectangle(noMin, new Rect(B_X - 20, B_Y[1] - 40, 10, 60), new Scalar(1), -1); GetMaxArea(noMin, out max); result = max.Clone(); } #endregion //ImageShow(close1, noMin * 255, result * 255); //计算上纵坐标 for (int i = B_Y[1] - 60; i < result.Rows; i++) { if (result.Get(i, B_X) > 0) { B_Y[0] = i; break; } } for (int i = BY[1] - 60; i < result.Rows; i++) { if (result.Get(i, BX) > 0) { BY[0] = i; break; } } int compensate = 5; BY[0] += compensate; B_Y[0] += compensate; } public void GaoduchaBOrdinateY3(Mat thresh, Mat image, out int[] BY, out int[] B_Y, int BX, int B_X, string direction) { BY = new int[2]; B_Y = new int[2]; #region//计算下纵坐标 for (int i = 0; i < thresh.Rows; i++) { if (thresh.Get(i, B_X) > 0) { B_Y[1] = i; break; } } for (int i = 0; i < thresh.Rows; i++) { if (thresh.Get(i, BX) > 0) { BY[1] = i; break; } } #endregion #region//图像处理 //阈值分割,保留最大连通域 Mat crop = new Mat(); switch (direction) { case "left": crop = image[BY[1] - 60, BY[1] - 10, B_X - 10, BX + 10].Clone(); Cv2.Rectangle(image, new Rect(B_X - 10, BY[1] - 60, BX + 10 - (B_X - 10), 50), new Scalar(255), 2); break; case "right": crop = image[BY[1] - 60, BY[1] - 10, BX - 10, B_X + 10].Clone(); break; } Mat thresh2 = new Mat(); //Cv2.ImWrite(@"C:\Users\54434\Desktop\image.png", image * 1); //Cv2.ImWrite(@"C:\Users\54434\Desktop\crop.png", crop * 1); double t = Cv2.Threshold(crop, thresh2, 0, 1, ThresholdTypes.Otsu); Mat fanse = 1 - thresh2; Mat nomin = fanse.Clone();// new Mat(); //GetMaxArea(fanse, out nomin); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 1)); Mat open = new Mat(); Cv2.MorphologyEx(nomin, open, MorphTypes.Open, seOpen); //ImageShow(fanse * 255, nomin * 255, open * 255,crop+open*100); Mat result = new Mat();// open.Clone();// Fill(open, out result, 1); Cv2.ImWrite(@"C:\Users\54434\Desktop\result.png", result * 255); #endregion #region//计算上纵坐标 int[] lower = new int[2]; int[] upper = new int[2]; int compensate = 7; Scalar sum = new Scalar(0); int upper_temp = 0; int upper_max = 0; switch (direction) { case "left": //B* for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 1, 0, 20].Sum(); if ((int)sum > 10) { if (upper_temp == 0) { if (upper[0] == 0 || upper_max < 13) upper_temp = i; else if ((int)(result[i, i + 1, 0, result.Cols - 1].Sum()) > result.Cols - 20) upper_temp = i; } if ((int)sum > upper_max/*13*/) upper_max = (int)sum;// break;//避免找到内部的干扰点 } else if (upper_temp > 0) { upper[0] = upper_temp; upper_temp = 0; } } if (upper_temp > 0) { upper[0] = upper_temp; upper_temp = 0; } upper_max = 0; for (int i = result.Rows - 1; i > 1; i--) { sum = result[i - 1, i, 0, 20].Sum(); if ((int)sum > 10) { lower[0] = i; break; } } //B for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 1, result.Cols - 20, result.Cols].Sum(); if ((int)sum > 10) { if (upper_temp == 0) { if(upper[1] == 0 || upper_max < 13) upper_temp = i; else if ((int)(result[i, i + 1, 0, result.Cols - 1].Sum()) > result.Cols - 20) upper_temp = i; } if ((int)sum > upper_max/*13*/) upper_max = (int)sum;// break;//避免找到内部的干扰点 } else if (upper_temp > 0) { upper[1] = upper_temp; upper_temp = 0; } } if (upper_temp > 0) { upper[1] = upper_temp; upper_temp = 0; } upper_max = 0; for (int i = result.Rows - 1; i > 1; i--) { sum = result[i - 1, i, result.Cols - 20, result.Cols].Sum(); if ((int)sum > 10) { lower[1] = i; break; } } if (lower[0] - upper[0] > 10) { B_Y[0] = upper[0] + compensate + BY[1] - 60; } else { B_Y[0] = (upper[0] + lower[0]) / 2 + BY[1] - 60; } if (lower[1] - upper[1] > 10) { BY[0] = upper[1] + compensate + BY[1] - 60; } else { BY[0] = (upper[1] + lower[1]) / 2 + BY[1] - 60; } break; case "right": //B for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 1, 0, 20].Sum(); if ((int)sum >= 10) { if (upper_temp == 0) { if (upper[0] == 0 || upper_max < 13) upper_temp = i; else if ((int)(result[i, i + 1, 0, result.Cols - 1].Sum()) > result.Cols - 20 || (int)(result[i, i + 1, 0, result.Cols - 1].Sum()) > result.Cols / 2) upper_temp = i; } if ((int)sum > upper_max/*13*/) upper_max = (int)sum;// break;//避免找到内部的干扰点 } else if (upper_temp > 0 && (int)sum < 7) { upper[0] = upper_temp; upper_temp = 0; } } if (upper_temp > 0) { upper[0] = upper_temp; upper_temp = 0; } upper_max = 0; for (int i = result.Rows - 1; i > 1; i--) { sum = result[i - 1, i, 0, 20].Sum(); if ((int)sum > 10) { lower[0] = i; break; } } //B* for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 1, result.Cols - 20, result.Cols].Sum(); if ((int)sum > 10) { if (upper_temp == 0) { if (upper[1] == 0 || upper_max < 13) upper_temp = i; else if ((int)(result[i, i + 1, 0, result.Cols - 1].Sum()) > result.Cols - 20 || (int)(result[i, i + 1, 0, result.Cols - 1].Sum()) > result.Cols / 2) upper_temp = i; } if ((int)sum > upper_max/*13*/) upper_max = (int)sum;// break;//避免找到内部的干扰点 } else if (upper_temp > 0) { upper[1] = upper_temp; upper_temp = 0; } } if (upper_temp > 0) { upper[1] = upper_temp; upper_temp = 0; } upper_max = 0; for (int i = result.Rows - 1; i > 1; i--) { sum = result[i - 1, i, result.Cols - 20, result.Cols].Sum(); if ((int)sum > 10) { lower[1] = i; break; } } if (lower[0] - upper[0] > 10) { BY[0] = upper[0] + compensate + BY[1] - 60; } else { BY[0] = (upper[0] + lower[0]) / 2 + BY[1] - 60; } if (lower[1] - upper[1] > 10) { B_Y[0] = upper[1] + compensate + BY[1] - 60; } else { B_Y[0] = (upper[1] + lower[1]) / 2 + BY[1] - 60; } break; } #endregion } /// /// 得到高度差全的提取区域 /// /// 绿色通道图 /// 输出提取区域图 /// 提取区域 /// 提取区域的上下界 public void GaoduchaQuanGetDataArea(Mat imageGreen, out Mat result, out int[] dataArea, out int[] y) { dataArea = new int[4]; y = new int[2]; Mat edge = new Mat(); Sobel(imageGreen, out edge); Mat thresh = new Mat(); thresh = edge.Threshold(0, 255, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat close = new Mat(); Cv2.MorphologyEx(thresh, close, MorphTypes.Close, seClose); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(1, 3)); Mat open = new Mat(); Cv2.MorphologyEx(close, open, MorphTypes.Open, seOpen); Mat seOpen2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Cv2.MorphologyEx(open, open, MorphTypes.Open, seOpen2); Mat fill = new Mat(); Fill(open, out fill, 255); fill = fill / 255; Mat connect = fill.Clone(); Scalar sum = new Scalar(0); int k = 0; bool flag = true;//真是找大于200的,假时找等于0 的 int border = 0; while (k < connect.Cols - 1) { if (flag) { for (k = border; k < fill.Cols; k++) { sum = fill[0, fill.Rows, k, k + 1].Sum(); if ((int)sum > 200) { Cv2.Rectangle(connect, new Rect(k, 0, 100, fill.Rows), new Scalar(1), -1); border = k + 100; flag = false; break; } } } else { for (k = border; k < fill.Cols; k++) { sum = fill[0, fill.Rows, k, k + 1].Sum(); if ((int)sum == 0) { border = k; flag = true; break; } } } } //Cv2.Rectangle(connect, new Rect(0, 0, fill.Cols, 1), new Scalar(1), -1); //Cv2.Rectangle(connect, new Rect(0, fill.Rows-1, fill.Cols, 1), new Scalar(1), -1); //保留前二大面积 Mat[] contours; Mat hierachy = new Mat(); Cv2.FindContours(connect, out contours, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); double largest = 0, secondLargest = 0; int index1 = 0, index2 = 0; for (int i = 0; i < contours.Count(); i++) { if (Cv2.ContourArea(contours[i]) > largest) { largest = Cv2.ContourArea(contours[i]); index1 = i; } else if (Cv2.ContourArea(contours[i]) > secondLargest) { largest = Cv2.ContourArea(contours[i]); index2 = i; } } result = Mat.Zeros(connect.Rows, connect.Cols, connect.Type()); Cv2.DrawContours(result, contours, index1, new Scalar(1)); Cv2.DrawContours(result, contours, index2, new Scalar(1)); Mat fill2 = new Mat(); Fill(result, out fill2, 1); Cv2.BitwiseAnd(fill, fill2, result); for (int i = 0; i < result.Rows; i++) { sum = result[i, i + 1, 0, result.Cols].Sum(); if ((int)sum > 20) { y[0] = i - 20; break; } } for (int i = result.Rows - 1; i > 0; i--) { sum = result[i - 1, i, 0, result.Cols].Sum(); if ((int)sum > 20) { y[1] = i; break; } } for (int j = 0; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 0) { dataArea[0] = j; break; } } for (int j = dataArea[0]; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { dataArea[1] = j; break; } } for (int j = result.Cols - 1; j > 0; j--) { sum = result[y[0], y[1], j - 1, j].Sum(); if ((int)sum > 0) { dataArea[3] = j; break; } } for (int j = dataArea[3]; j > 0; j--) { sum = result[y[0], y[1], j - 1, j].Sum(); if ((int)sum == 0) { dataArea[2] = j; break; } } //ImageShow(open, connect * 255, result * 255); } public void GaoduchaQuanGetDataArea2(Mat imageRed, out Mat result, out int[] dataArea, out int[] y) { //result = new Mat(); dataArea = new int[4]; y = new int[2]; Mat thresh = new Mat(); double t = Cv2.Threshold(imageRed, thresh, 0, 1, ThresholdTypes.Otsu); if (t > 170) thresh = imageRed.Threshold(t + 30, 1, ThresholdTypes.Binary); //Mat max = new Mat(); //GetMaxArea(thresh, out max); //ImageShow(thresh * 255); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat close = new Mat(); Cv2.MorphologyEx(thresh, close, MorphTypes.Close, seClose); Mat fill = new Mat(); Fill(close, out fill, 255); Mat connect = fill.Clone(); Scalar sum = new Scalar(0); int k = 0; bool flag = true;//真是找大于200的,假时找等于0 的 int border = 0; while (k < connect.Cols - 1) { if (flag) { for (k = border; k < thresh.Cols; k++) { sum = thresh[0, thresh.Rows, k, k + 1].Sum(); if ((int)sum > 200) { Cv2.Rectangle(connect, new Rect(k, 0, 100, thresh.Rows), new Scalar(1), -1); border = k + 100; flag = false; break; } } } else { for (k = border; k < thresh.Cols; k++) { sum = thresh[0, thresh.Rows, k, k + 1].Sum(); if ((int)sum == 0) { border = k; flag = true; break; } } } } //保留前二大面积 Mat[] contours; Mat hierachy = new Mat(); Cv2.FindContours(connect, out contours, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); double largest = 0, secondLargest = 0; int index1 = 0, index2 = 0; for (int i = 0; i < contours.Count(); i++) { if (Cv2.ContourArea(contours[i]) > largest) { largest = Cv2.ContourArea(contours[i]); index1 = i; } else if (Cv2.ContourArea(contours[i]) > secondLargest) { secondLargest = Cv2.ContourArea(contours[i]); index2 = i; } } result = Mat.Zeros(connect.Rows, connect.Cols, connect.Type()); Cv2.DrawContours(result, contours, index1, new Scalar(1)); Cv2.DrawContours(result, contours, index2, new Scalar(1)); Mat fill2 = new Mat(); Fill(result, out fill2, 1); Cv2.BitwiseAnd(fill, fill2, result); //ImageShow(connect * 255, result * 255); for (int i = 0; i < result.Rows; i++) { sum = result[i, i + 1, 0, result.Cols].Sum(); if ((int)sum > 20) { y[0] = i - 20; break; } } for (int i = result.Rows - 1; i > 0; i--) { sum = result[i - 1, i, 0, result.Cols].Sum(); if ((int)sum > 20) { y[1] = i; break; } } for (int j = 0; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum > 0) { dataArea[0] = j; break; } } for (int j = dataArea[0]; j < result.Cols; j++) { sum = result[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { dataArea[1] = j; break; } } for (int j = result.Cols - 1; j > 0; j--) { sum = result[y[0], y[1], j - 1, j].Sum(); if ((int)sum > 0) { dataArea[3] = j; break; } } for (int j = dataArea[3]; j > 0; j--) { sum = result[y[0], y[1], j - 1, j].Sum(); if ((int)sum == 0) { dataArea[2] = j; break; } } } public void GaoduchaQuanGetDataArea3(Mat imageRed, Mat image, out int[] leftTonghou, out int[] rightTonghou, out int[] dataArea, out int[] y) { dataArea = new int[4]; y = new int[2]; leftTonghou = new int[3]; rightTonghou = new int[3]; Mat thresh = new Mat(); double t = Cv2.Threshold(imageRed, thresh, 0, 1, ThresholdTypes.Otsu); if (t > 170) thresh = imageRed.Threshold(240, 1, ThresholdTypes.Binary); //ImageShow(thresh * 255); //当还是太亮时,需要判断,使用边缘检测加填充方法 Mat maxArea = new Mat(); GetMaxArea(thresh, out maxArea); bool flag = false; double maxAreaSum = (double)maxArea.Sum(); if ((int)maxArea.Sum() > 350000) { Mat gray = new Mat(); Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY); thresh = gray.Threshold(200, 1, ThresholdTypes.Binary); //Mat edge = new Mat(); //Sobel(imageRed, out edge); //Mat edgeThresh = new Mat(); //edgeThresh = edge.Threshold(50, 1, ThresholdTypes.Binary); //Mat edgeMax = new Mat(); //GetMaxArea(edgeThresh, out edgeMax); //flag = true; //ImageShow(edgeThresh * 255, edgeMax * 255); } //ImageShow(thresh * 255); Cv2.Rectangle(thresh, new Rect(thresh.Cols - 1, 0, 1, thresh.Rows), new Scalar(1), -1);//当右侧出现非整体铜体时连接 Cv2.Rectangle(thresh, new Rect(0, 0, 1, thresh.Rows), new Scalar(1), -1);//也可能出现在左侧 //闭运算 Mat seClose = new Mat(); if (t < 170) seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9, 9)); else seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat close = new Mat(); Cv2.MorphologyEx(thresh, close, MorphTypes.Close, seClose); Fill(close, out close, 1); //ImageShow(close * 255); //保留前二大区域 Mat hierachy = new Mat(); Mat[] contoursMat; Cv2.FindContours(close, out contoursMat, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); double max1 = 0, max2 = 0; int idx1 = 0, idx2 = 0; for (int i = 0; i < contoursMat.Count(); i++) { if (Cv2.ContourArea(contoursMat[i]) > max1) { max2 = max1; idx2 = idx1; max1 = Cv2.ContourArea(contoursMat[i]); idx1 = i; } else if (Cv2.ContourArea(contoursMat[i]) > max2) { max2 = Cv2.ContourArea(contoursMat[i]); idx2 = i; } } Mat qianerArea = new Mat(thresh.Size(), thresh.Type()); Cv2.DrawContours(qianerArea, contoursMat, idx1, new Scalar(1)); Cv2.DrawContours(qianerArea, contoursMat, idx2, new Scalar(1)); Fill(qianerArea, out qianerArea, 1); thresh = qianerArea; Cv2.Rectangle(thresh, new Rect(thresh.Cols - 1, 0, 1, thresh.Rows), new Scalar(0), -1);//将连接线去掉 Cv2.Rectangle(thresh, new Rect(0, 0, 1, thresh.Rows), new Scalar(0), -1);// // int middle = imageRed.Cols / 2; //ImageShow(thresh * 255); Scalar sum = new Scalar(0); Scalar max = new Scalar(0); //左右列像素最多的地方,并且提取目标区域 int leftBorde = 0, rightBorder = 0; for (int j = 0; j < middle; j++) { sum = thresh[0, thresh.Rows, j, j + 1].Sum(); if ((int)sum > (int)max) { max = sum; leftBorde = j; dataArea[0] = leftBorde; } } max = 0; for (int j = thresh.Cols - 1; j > middle; j--) { sum = thresh[0, thresh.Rows, j - 1, j].Sum(); if ((int)sum > (int)max) { max = sum; rightBorder = j; dataArea[3] = rightBorder; } } //目标区域的上下界 for (int i = 0; i < thresh.Rows; i++) { sum = thresh[i, i + 1, 0, thresh.Cols].Sum(); if ((int)sum > 0) { y[0] = i; break; } } for (int i = thresh.Rows - 1; i > 0; i--) { sum = thresh[i - 1, i, 0, thresh.Cols].Sum(); if ((int)sum > 0) { y[1] = i; break; } } //目标区域中间 if (flag == false) { //Cv2.ImWrite(@"C:\Users\54434\Desktop\thresh.png", thresh * 120); for (int j = leftBorde; j < thresh.Cols; j++) { sum = thresh[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { dataArea[1] = j; break; } } for (int j = rightBorder - 1; j > middle; j--) { sum = thresh[y[0], y[1], j - 1, j].Sum(); if ((int)sum == 0) { dataArea[2] = j; break; } } } //else //{ // Scalar lastSum = new Scalar(0); // for (int j = middle; j > 100; j-=5) // { // sum = thresh[y[0], y[1], j - 3, j].Sum(); // if ((int)sum - (int)lastSum > 100&& lastSum!=0) // { // dataArea[1] = j; // break; // } // lastSum = sum; // } // lastSum = 0; // for (int j = middle; j 150 && lastSum != 0) // { // dataArea[2] = j; // break; // } // lastSum = sum; // } //} //边缘检测并横向腐蚀,去掉小连通域,提取铜厚 Mat sobel = new Mat(); Sobel(thresh, out sobel); Mat result = sobel.Clone(); //Mat sobel = new Mat(); //Cv2.GaussianBlur(imageRed, imageRed, new Size(11, 11), 5, 5); //Cv2.MedianBlur(imageRed, imageRed, 5); //Sobel(imageRed, out sobel); //Mat sobelThresh = new Mat(); //double t2 = Cv2.Threshold(sobel, sobelThresh, 0, 255, ThresholdTypes.Otsu); //sobelThresh = sobel.Threshold(5, 255, ThresholdTypes.Binary); //Mat seErode = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(30, 1)); //Mat erode = new Mat(); //Cv2.Erode(sobelThresh, erode, seErode); //Mat noMinArea = new Mat(); //GetArea(erode, out noMinArea, 500, true); //Mat result = noMinArea.Clone(); //ImageShow(result * 255); leftTonghou[0] = dataArea[0] + 100; rightTonghou[0] = dataArea[3] - 100; //计算线纵坐标 //左 for (int i = y[0]; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) > 0) { leftTonghou[1] = i; break; } } for (int i = leftTonghou[1] + 60; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) > 0) { leftTonghou[2] = i; break; } } for (int i = leftTonghou[2]; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) == 0) { leftTonghou[2] = i; break; } } //右 for (int i = y[0]; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) > 0) { rightTonghou[1] = i; break; } } for (int i = rightTonghou[1] + 60; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) > 0) { rightTonghou[2] = i; break; } } for (int i = rightTonghou[2]; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) == 0) { rightTonghou[2] = i; break; } } if (/*leftTonghou[2] - rightTonghou[2] > 400 && rightTonghou[2] * 3 > result.Rows || */leftTonghou[2] - rightTonghou[2] > 300 && rightTonghou[2] * 3 > result.Rows) { if (leftTonghou[2] - rightTonghou[2] > 400 && rightTonghou[2] * 3 > result.Rows) leftTonghou[0] = leftTonghou[0] + 400; else if (leftTonghou[2] - rightTonghou[2] > 300 && rightTonghou[2] * 3 > result.Rows) leftTonghou[0] = leftTonghou[0] + 430; //计算线纵坐标 //左 for (int i = y[0]; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) > 0) { leftTonghou[1] = i; break; } } for (int i = leftTonghou[1] + 60; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) > 0) { leftTonghou[2] = i; break; } } for (int i = leftTonghou[2]; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) == 0) { leftTonghou[2] = i; break; } } } if (leftTonghou[2] - rightTonghou[2] > 400 && rightTonghou[2] * 3 < result.Rows || rightTonghou[2] - leftTonghou[2] > 300 && leftTonghou[2] * 3 > result.Rows) { if (leftTonghou[2] - rightTonghou[2] > 400 && rightTonghou[2] * 3 < result.Rows) rightTonghou[0] = rightTonghou[0] - 400; else if (rightTonghou[2] - leftTonghou[2] > 300 && leftTonghou[2] * 3 > result.Rows) rightTonghou[0] = rightTonghou[0] - 550; //右 for (int i = y[0]; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) > 0) { rightTonghou[1] = i; break; } } for (int i = rightTonghou[1] + 60; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) > 0) { rightTonghou[2] = i; break; } } for (int i = rightTonghou[2]; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) == 0) { rightTonghou[2] = i; break; } } if (rightTonghou[2] - leftTonghou[2] > 300 && leftTonghou[2] * 3 > result.Rows) rightTonghou[2] = leftTonghou[2]; } //Cv2.ImWrite(@"C:\Users\54434\Desktop\result.png", result * 120); ////ExtractLines(thresh,out left1,leftBorde+200) ////ImageShow(sobelThresh,erode,maxArea*255); } public void GaoduchaQuanGetDataArea3_Center(Mat imageRed, Mat image, out int[] leftTonghou, out int[] rightTonghou, out int[] dataArea, out int[] y, int[] dataArea0) { dataArea = new int[4]; y = new int[2]; leftTonghou = new int[3]; rightTonghou = new int[3]; Mat thresh = new Mat(); double t = Cv2.Threshold(imageRed, thresh, 0, 1, ThresholdTypes.Otsu); if (t > 170) thresh = imageRed.Threshold(240, 1, ThresholdTypes.Binary); //ImageShow(thresh * 255); //当还是太亮时,需要判断,使用边缘检测加填充方法 Mat maxArea = new Mat(); GetMaxArea(thresh, out maxArea); bool flag = false; double maxAreaSum = (double)maxArea.Sum(); if ((int)maxArea.Sum() > 350000) { Mat gray = new Mat(); Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY); thresh = gray.Threshold(200, 1, ThresholdTypes.Binary); //Mat edge = new Mat(); //Sobel(imageRed, out edge); //Mat edgeThresh = new Mat(); //edgeThresh = edge.Threshold(50, 1, ThresholdTypes.Binary); //Mat edgeMax = new Mat(); //GetMaxArea(edgeThresh, out edgeMax); //flag = true; //ImageShow(edgeThresh * 255, edgeMax * 255); } //ImageShow(thresh * 255); Cv2.Rectangle(thresh, new Rect(thresh.Cols - 1, 0, 1, thresh.Rows), new Scalar(1), -1);//当右侧出现非整体铜体时连接 Cv2.Rectangle(thresh, new Rect(0, 0, 1, thresh.Rows), new Scalar(1), -1);//也可能出现在左侧 //闭运算 Mat seClose = new Mat(); if (t < 170) seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9, 9)); else seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat close = new Mat(); Cv2.MorphologyEx(thresh, close, MorphTypes.Close, seClose); Fill(close, out close, 1); //ImageShow(close * 255); //保留前二大区域 Mat hierachy = new Mat(); Mat[] contoursMat; Cv2.FindContours(close, out contoursMat, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); double max1 = 0, max2 = 0; int idx1 = 0, idx2 = 0; for (int i = 0; i < contoursMat.Count(); i++) { if (Cv2.ContourArea(contoursMat[i]) > max1) { max2 = max1; idx2 = idx1; max1 = Cv2.ContourArea(contoursMat[i]); idx1 = i; } else if (Cv2.ContourArea(contoursMat[i]) > max2) { max2 = Cv2.ContourArea(contoursMat[i]); idx2 = i; } } Mat qianerArea = new Mat(thresh.Size(), thresh.Type()); Cv2.DrawContours(qianerArea, contoursMat, idx1, new Scalar(1)); Cv2.DrawContours(qianerArea, contoursMat, idx2, new Scalar(1)); Fill(qianerArea, out qianerArea, 1); thresh = qianerArea; Cv2.Rectangle(thresh, new Rect(thresh.Cols - 1, 0, 1, thresh.Rows), new Scalar(0), -1);//将连接线去掉 Cv2.Rectangle(thresh, new Rect(0, 0, 1, thresh.Rows), new Scalar(0), -1);// // int middle = imageRed.Cols / 2; //ImageShow(thresh * 255); Scalar sum = new Scalar(0); Scalar max = new Scalar(0); //左右列像素最多的地方,并且提取目标区域 int leftBorde = 0, rightBorder = 0; for (int j = 0; j < middle; j++) { sum = thresh[0, thresh.Rows, j, j + 1].Sum(); if ((int)sum > (int)max) { max = sum; leftBorde = dataArea0[0];// j; dataArea[0] = dataArea0[0];// leftBorde; } } max = 0; for (int j = thresh.Cols - 1; j > middle; j--) { sum = thresh[0, thresh.Rows, j - 1, j].Sum(); if ((int)sum > (int)max) { max = sum; rightBorder = dataArea0[3];// j; dataArea[3] = dataArea0[3];// rightBorder; } } //目标区域的上下界 for (int i = 0; i < thresh.Rows; i++) { sum = thresh[i, i + 1, 0, thresh.Cols].Sum(); if ((int)sum > 0) { y[0] = i; break; } } for (int i = thresh.Rows - 1; i > 0; i--) { sum = thresh[i - 1, i, 0, thresh.Cols].Sum(); if ((int)sum > 0) { y[1] = i; break; } } //目标区域中间 if (flag == false) { for (int j = leftBorde; j < thresh.Cols; j++) { sum = thresh[y[0], y[1], j, j + 1].Sum(); if ((int)sum == 0) { dataArea[1] = j - 120; break; } } for (int j = rightBorder - 100; j > middle; j--) { sum = thresh[y[0], y[1], j - 1, j].Sum(); if ((int)sum == 0) { dataArea[2] = j - 120; break; } } } //else //{ // Scalar lastSum = new Scalar(0); // for (int j = middle; j > 100; j-=5) // { // sum = thresh[y[0], y[1], j - 3, j].Sum(); // if ((int)sum - (int)lastSum > 100&& lastSum!=0) // { // dataArea[1] = j; // break; // } // lastSum = sum; // } // lastSum = 0; // for (int j = middle; j 150 && lastSum != 0) // { // dataArea[2] = j; // break; // } // lastSum = sum; // } //} //边缘检测并横向腐蚀,去掉小连通域,提取铜厚 Mat sobel = new Mat(); Sobel(thresh, out sobel); Mat result = sobel.Clone(); //Mat sobel = new Mat(); //Cv2.GaussianBlur(imageRed, imageRed, new Size(11, 11), 5, 5); //Cv2.MedianBlur(imageRed, imageRed, 5); //Sobel(imageRed, out sobel); //Mat sobelThresh = new Mat(); //double t2 = Cv2.Threshold(sobel, sobelThresh, 0, 255, ThresholdTypes.Otsu); //sobelThresh = sobel.Threshold(5, 255, ThresholdTypes.Binary); //Mat seErode = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(30, 1)); //Mat erode = new Mat(); //Cv2.Erode(sobelThresh, erode, seErode); //Mat noMinArea = new Mat(); //GetArea(erode, out noMinArea, 500, true); //Mat result = noMinArea.Clone(); //ImageShow(result * 255); leftTonghou[0] = dataArea[0] + 100; rightTonghou[0] = dataArea[3] - 100; //计算线纵坐标 //左 for (int i = y[0]; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) > 0) { leftTonghou[1] = i; break; } } for (int i = leftTonghou[1] + 60; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) > 0) { leftTonghou[2] = i; break; } } for (int i = leftTonghou[2]; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) == 0) { leftTonghou[2] = i; break; } } //右 for (int i = y[0]; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) > 0) { rightTonghou[1] = i; break; } } for (int i = rightTonghou[1] + 60; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) > 0) { rightTonghou[2] = i; break; } } for (int i = rightTonghou[2]; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) == 0) { rightTonghou[2] = i; break; } } if (/*leftTonghou[2] - rightTonghou[2] > 400 && rightTonghou[2] * 3 > result.Rows || */leftTonghou[2] - rightTonghou[2] > 300 && rightTonghou[2] * 3 > result.Rows) { if (leftTonghou[2] - rightTonghou[2] > 400 && rightTonghou[2] * 3 > result.Rows) leftTonghou[0] = leftTonghou[0] + 400; else if (leftTonghou[2] - rightTonghou[2] > 300 && rightTonghou[2] * 3 > result.Rows) leftTonghou[0] = leftTonghou[0] + 430; //计算线纵坐标 //左 for (int i = y[0]; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) > 0) { leftTonghou[1] = i; break; } } for (int i = leftTonghou[1] + 60; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) > 0) { leftTonghou[2] = i; break; } } for (int i = leftTonghou[2]; i < y[1]; i++) { if (result.Get(i, leftTonghou[0]) == 0) { leftTonghou[2] = i; break; } } } if (leftTonghou[2] - rightTonghou[2] > 400 && rightTonghou[2] * 3 < result.Rows || rightTonghou[2] - leftTonghou[2] > 300 && leftTonghou[2] * 3 > result.Rows) { if (leftTonghou[2] - rightTonghou[2] > 400 && rightTonghou[2] * 3 < result.Rows) rightTonghou[0] = rightTonghou[0] - 400; else if (rightTonghou[2] - leftTonghou[2] > 300 && leftTonghou[2] * 3 > result.Rows) rightTonghou[0] = rightTonghou[0] - 550; //右 for (int i = y[0]; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) > 0) { rightTonghou[1] = i; break; } } for (int i = rightTonghou[1] + 60; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) > 0) { rightTonghou[2] = i; break; } } for (int i = rightTonghou[2]; i < y[1]; i++) { if (result.Get(i, rightTonghou[0]) == 0) { rightTonghou[2] = i; break; } } if (rightTonghou[2] - leftTonghou[2] > 300 && leftTonghou[2] * 3 > result.Rows) rightTonghou[2] = leftTonghou[2]; } //Cv2.ImWrite(@"C:\Users\54434\Desktop\result.png", result * 120); ////ExtractLines(thresh,out left1,leftBorde+200) ////ImageShow(sobelThresh,erode,maxArea*255); } /// /// 计算高度差全的铜厚 /// /// 二值图 /// 左侧铜厚,0:横坐标;1:上纵坐标;2:下纵坐标 /// 右侧铜厚,0:横坐标;1:上纵坐标;2:下纵坐标 /// 提取区域 /// 目标区域上下边界 public void GaoduchaTonghou(Mat contour, out int[] leftTonghou, out int[] rightTonghou, int[] dataArea, int[] y) { leftTonghou = new int[3]; rightTonghou = new int[3]; leftTonghou[0] = dataArea[0] + 200; rightTonghou[0] = dataArea[3] - 200; Mat crop = contour[y[0], y[1], 0, contour.Cols].Clone(); double leftOrdinate1 = 0; ExtractLines(crop, out leftOrdinate1, leftTonghou[0] - 5, leftTonghou[0] + 5, 1); double leftOrdinate2 = 0; ExtractLines(crop, out leftOrdinate2, leftTonghou[0] - 5, leftTonghou[0] + 5, leftOrdinate1, -1); double rightOrdinate1 = 0; ExtractLines(crop, out rightOrdinate1, rightTonghou[0] - 5, rightTonghou[0] + 5, 1); double rightOrdinate2 = 0; ExtractLines(crop, out rightOrdinate2, rightTonghou[0] - 5, rightTonghou[0] + 5, rightOrdinate1, -1); leftTonghou[1] = (int)leftOrdinate1 + y[0]; leftTonghou[2] = (int)leftOrdinate2 + y[0]; rightTonghou[1] = (int)rightOrdinate1 + y[0]; rightTonghou[2] = (int)rightOrdinate2 + y[0]; } /// /// 计算高度差全的防焊厚度 /// /// 绿色通道图 /// 左侧防焊厚度,0:横坐标;1:上纵坐标;2:下纵坐标 /// 右侧防焊厚度,0:横坐标;1:上纵坐标;2:下纵坐标 /// 提取区域 /// 其中一个铜厚坐标 public void GaoduchaFanhanhou(Mat imageGreen, out int[] leftFanghanhou, out int[] rightFanghanhou, int[] dataArea, int[] tonghou) { leftFanghanhou = new int[3]; rightFanghanhou = new int[3]; int range = 30; int range2 = 80; //将目标区域选出来 PointEnhancement(imageGreen, out imageGreen); Cv2.GaussianBlur(imageGreen, imageGreen, new Size(5, 5), 3, 3); Mat crop = imageGreen[tonghou[1] - range, tonghou[2] + range, dataArea[1] + range2, dataArea[2] - range2].Clone(); Mat contour = new Mat(); double t = Cv2.Threshold(crop, contour, 0, 1, ThresholdTypes.Otsu); contour = 255 - crop.Threshold(t - 5, 255, ThresholdTypes.Binary); Mat edge = new Mat(); Sobel(crop, out edge); Mat thresh = edge.Threshold(0, 255, ThresholdTypes.Otsu); //新增 Mat maxArea1 = new Mat(); GetMaxArea(contour, out maxArea1); maxArea1 = maxArea1 * 255; Mat and = new Mat(); Cv2.BitwiseAnd(thresh, maxArea1, and); //ImageShow(contour, thresh,and); //Mat delete = new Mat(); //GetArea(thresh, out delete, 10,true); //delete = delete * 255; // Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 2)); Mat close = new Mat(); Cv2.MorphologyEx(thresh, close, MorphTypes.Close, seClose); Mat fill = new Mat(); Fill(close, out fill, 255); //ImageShow(thresh, close, fill); Mat maxArea = new Mat(); GetMaxArea(fill, out maxArea); Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9, 3)); Cv2.MorphologyEx(maxArea, close, MorphTypes.Close, seClose2); Fill(close, out fill, 255); Mat result = fill.Clone() / 255; //得到提取点 Scalar sum = new Scalar(0); for (int j = 0; j < result.Cols; j++) { sum = result[0, result.Rows, j, j + 40].Sum(); if ((int)sum > 2800) { leftFanghanhou[0] = j + 100; break; } } for (int j = result.Cols - 1; j > 0; j--) { sum = result[0, result.Rows, j - 40, j].Sum(); if ((int)sum > 2800) { rightFanghanhou[0] = j - 100; break; } } //计算高度 double leftOrdinate1 = 0; ExtractLines(and, out leftOrdinate1, leftFanghanhou[0] - 5, leftFanghanhou[0] + 5, 1); double leftOrdinate2 = 0; and = and / 255; for (int i = and.Rows - 1; i > and.Rows / 2; i--) { sum = and[i - 1, i, 0, leftFanghanhou[0]].Sum(); if ((int)sum > 5) { leftOrdinate2 = i; break; } } //ExtractLines(result, out leftOrdinate2, leftFanghanhou[0] - 5, leftFanghanhou[0] + 5,leftOrdinate1, -1); //ExtractLines2(and, out leftOrdinate2, 5, 15, 1); double rightOrdinate1 = 0; ExtractLines(and, out rightOrdinate1, rightFanghanhou[0] - 5, rightFanghanhou[0] + 5, 1); double rightOrdinate2 = 0; for (int i = and.Rows - 1; i > and.Rows / 2; i--) { sum = and[i - 1, i, rightFanghanhou[0], and.Cols].Sum(); if ((int)sum > 5) { rightOrdinate2 = i; break; } } //ExtractLines(result, out rightOrdinate2, rightFanghanhou[0] - 5, rightFanghanhou[0] + 5, rightOrdinate1, -1); //ExtractLines2(and, out rightOrdinate2, and.Cols-15, and.Cols- 5, 1); leftFanghanhou[0] += dataArea[1] + range2; leftFanghanhou[1] = (int)leftOrdinate1 + tonghou[1] - range; leftFanghanhou[2] = (int)leftOrdinate2 + tonghou[1] - range; rightFanghanhou[0] += dataArea[1] + range2; rightFanghanhou[1] = (int)rightOrdinate1 + tonghou[1] - range; rightFanghanhou[2] = (int)rightOrdinate2 + tonghou[1] - range; //ImageShow(close*255, fill, maxArea * 255); //ImageShow(result * 255); } public void GaoduchaFanhanhou2(Mat imageRed, out int[] leftFanghanhou, out int[] rightFanghanhou, int[] dataArea, int[] tonghou) { leftFanghanhou = new int[3]; rightFanghanhou = new int[3]; int range = 30; int range2 = 80; //将目标区域选出来 PointEnhancement(imageRed, out imageRed); Cv2.GaussianBlur(imageRed, imageRed, new Size(9, 9), 3, 3); Mat crop = imageRed[tonghou[1] - range, tonghou[2] + range, dataArea[1] + range2, dataArea[2] - range2].Clone(); Mat sobel = new Mat(); Sobel(crop, out sobel); Mat thresh = new Mat(); double t = Cv2.Threshold(sobel, thresh, 0, 255, ThresholdTypes.Otsu); thresh = sobel.Threshold(5, 255, ThresholdTypes.Binary); Mat tangle = new Mat(); Cv2.Rectangle(thresh, new Rect(0, 0, 10, thresh.Rows), new Scalar(255), -1); Cv2.Rectangle(thresh, new Rect(thresh.Cols - 11, 0, 10, thresh.Rows), new Scalar(255), -1); //清楚小点 Mat noMin = new Mat(); GetArea(thresh, out noMin, 10, true); //闭运算 Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); Mat close = new Mat(); Cv2.MorphologyEx(noMin, close, MorphTypes.Close, seClose); Mat max = new Mat(); GetMaxArea(close, out max); //再次闭运算全连接 Mat seClsoe2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9, 3)); Mat close2 = new Mat(); Cv2.MorphologyEx(max, close2, MorphTypes.Close, seClsoe2); //ImageShow( thresh,noMin*255,max*255,close2*255); Mat result = close2.Clone(); //得到提取点 Scalar sum = new Scalar(0); for (int j = 20; j < result.Cols; j++) { sum = result[0, result.Rows, j, j + 40].Sum(); if ((int)sum > 2800) { leftFanghanhou[0] = j + 100; break; } } for (int j = result.Cols - 21; j > 0; j--) { sum = result[0, result.Rows, j - 40, j].Sum(); if ((int)sum > 2800) { rightFanghanhou[0] = j - 100; break; } } //计算高度 for (int i = 0; i < result.Rows; i++) { sum = result[i, i + 1, leftFanghanhou[0] - 5, leftFanghanhou[0] + 5].Sum(); if ((int)sum > 5) { leftFanghanhou[1] = i; break; } } for (int i = result.Rows - 1; i > 0; i--) { sum = result[i - 1, i, leftFanghanhou[0] - 5, leftFanghanhou[0] + 5].Sum(); if ((int)sum > 5) { leftFanghanhou[2] = i; break; } } for (int i = 0; i < result.Rows; i++) { sum = result[i, i + 1, rightFanghanhou[0] - 5, rightFanghanhou[0] + 5].Sum(); if ((int)sum > 5) { rightFanghanhou[1] = i; break; } } for (int i = result.Rows - 1; i > 0; i--) { sum = result[i - 1, i, rightFanghanhou[0] - 5, rightFanghanhou[0] + 5].Sum(); if ((int)sum > 5) { rightFanghanhou[2] = i; break; } } int compensate = 13; leftFanghanhou[0] += dataArea[1] + range2; leftFanghanhou[1] += tonghou[1] - range; leftFanghanhou[2] += tonghou[1] - range - compensate; rightFanghanhou[0] += dataArea[1] + range2; rightFanghanhou[1] += tonghou[1] - range; rightFanghanhou[2] += tonghou[1] - range - compensate; } public void GaoduchaFanghanhoudu3(Mat image, out int[] leftFanghanhoudu, out int[] rightFanghanhoudu, int[] dataArea, int[] tonghou) { leftFanghanhoudu = new int[3]; rightFanghanhoudu = new int[3]; Mat gray = new Mat(); Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY); Cv2.GaussianBlur(gray, gray, new Size(9, 9), 3, 3); //Cv2.MedianBlur(gray, gray, 5); Mat sobel = new Mat(); //Sobel(gray, out sobel); EdgeY(gray, out sobel); Mat sobelThresh = new Mat(); double t = Cv2.Threshold(sobel, sobelThresh, 0, 255, ThresholdTypes.Otsu); sobelThresh = sobel.Threshold(10, 255, ThresholdTypes.Binary); //Mat seClsoe = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); //Mat close = new Mat(); //Cv2.MorphologyEx(sobelThresh, close, MorphTypes.Close, seClsoe); Mat seErode = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 1)); Mat erode = new Mat(); Cv2.Erode(sobelThresh, erode, seErode); Mat crop = erode[tonghou[1] - 60, tonghou[2] + 40, dataArea[1], dataArea[2]].Clone(); Mat noMinArea = new Mat(); GetArea(crop, out noMinArea, 50, true); Mat result = new Mat(); RemoveCircles(noMinArea, out result); Scalar sum = new Scalar(0); int startBorder = 0; for (int i = 10; i < result.Rows - 2; i++) { sum = result[i, i + 2, 0, result.Cols].Sum(); if ((int)sum > 600) { startBorder = i; break; } } Cv2.Rectangle(result, new Rect(0, 0, result.Cols, startBorder), new Scalar(0), -1); GetArea(result, out result, 2000, true); //ImageShow(result * 255); int middle = crop.Cols / 2; leftFanghanhoudu[0] = middle - 150; rightFanghanhoudu[0] = middle + 150; double left1 = 0, left2 = 0; double right1 = 0, right2 = 0; ExtractLines(result, out left1, leftFanghanhoudu[0] - 10, leftFanghanhoudu[0] + 10, 1); ExtractLines(result, out right1, rightFanghanhoudu[0] - 10, rightFanghanhoudu[0] + 10, 1); //计算防焊下坐标 Mat edgeLower = new Mat(); Sobel(gray, out edgeLower); Mat edgeLowerThresh = edgeLower.Threshold(5, 1, ThresholdTypes.Binary); //ImageShow(edgeLowerThresh * 255); Mat crop2 = edgeLowerThresh[tonghou[2] - 20, tonghou[2] + 40, dataArea[1], dataArea[2]].Clone(); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); Mat close2 = new Mat(); Cv2.MorphologyEx(crop2, close2, MorphTypes.Close, seOpen); Mat open = new Mat(); Cv2.MorphologyEx(close2, open, MorphTypes.Open, seOpen); Mat bigArea = new Mat(); //GetMaxArea(open, out bigArea); GetArea(open, out bigArea, 500, true); //ImageShow(bigArea * 255); //Mat cannyEdge = new Mat(); //Cv2.Canny(gray, cannyEdge, 18, 14); //ImageShow(cannyEdge); int bigAreaSum = (int)bigArea.Sum(); if (bigAreaSum < 5000) bigArea = result[result.Rows - 60, result.Rows, 0, result.Cols].Clone(); ExtractLines2(bigArea, out left2, leftFanghanhoudu[0] - 10, leftFanghanhoudu[0] + 10, 1); ExtractLines2(bigArea, out right2, rightFanghanhoudu[0] - 10, rightFanghanhoudu[0] + 10, 1); int compensate1 = 10; int compensate2 = 0; leftFanghanhoudu[0] += dataArea[1]; leftFanghanhoudu[1] = (int)left1 + tonghou[1] - 60 + compensate1; leftFanghanhoudu[2] = (int)left2 + tonghou[2] - 20 - compensate2; rightFanghanhoudu[0] += dataArea[1]; rightFanghanhoudu[1] = (int)right1 + tonghou[1] - 60 + compensate1; rightFanghanhoudu[2] = (int)right2 + tonghou[2] - 20 - compensate2; //ImageShow(sobelThresh, crop, result * 255); } public void GaoduchaFanghanhoudu4(Mat image_0, out int[] leftFanghanhoudu, out int[] rightFanghanhoudu, int[] dataArea, int[] tonghou) { leftFanghanhoudu = new int[3]; rightFanghanhoudu = new int[3]; //防焊厚上层 Mat gray = new Mat(); Cv2.CvtColor(image_0, gray, ColorConversionCodes.BGR2GRAY); //Mat filter = new Mat(); //PointEnhancement(gray, out filter); Mat newGray = gray.Clone();// new Mat();// //Cv2.GaussianBlur(gray, newGray, new Size(11, 11), 3, 3); Mat blur = new Mat(); Cv2.MedianBlur(newGray, blur, 5); Mat edge; //Cv2.ImWrite(@"C:\Users\54434\Desktop\blur.png", blur); EdgeY(blur, out edge); //Edge(blur, out edge); //Cv2.ImWrite(@"C:\Users\54434\Desktop\edge.png", edge); int meanV = (int)(edge[tonghou[1] - 30, tonghou[2], dataArea[1], dataArea[2]].Mean().Val0); if (meanV > 50) meanV -= 25; else if (meanV > 18) { if ((int)(edge[tonghou[1], tonghou[1] / 2 - 15 + tonghou[2] / 2, dataArea[1], dataArea[2]].Mean().Val0) * 2 < meanV) meanV = (int)(edge[tonghou[1], tonghou[1] / 2 - 15 + tonghou[2] / 2, dataArea[1], dataArea[2]].Mean().Val0) / 2; else if (meanV > 20) meanV /= 2; else meanV -= 5; } //meanV = 2;// (int)(edge[tonghou[1], tonghou[1] / 2 - 15 + tonghou[2] / 2, dataArea[1], dataArea[2]].Mean().Val0)/2;// 2;// (int)(edge[tonghou[1], tonghou[1] / 2 - 15 + tonghou[2] / 2, dataArea[1], dataArea[2]].Mean().Val0); meanV = meanV < 13 ? meanV * 2 : meanV; Mat thresh = edge.Threshold(meanV/*15*/, 255, ThresholdTypes.Binary); Mat thresh2 = thresh.Clone(); //Cv2.ImWrite(@"C:\Users\54434\Desktop\thresh2_0.png", thresh2); Cv2.Rectangle(thresh2, new Rect(0, 0, thresh.Cols, tonghou[1] - 30), new Scalar(0), -1); Cv2.Rectangle(thresh2, new Rect(0, tonghou[2] + 20, thresh.Cols, thresh.Rows - tonghou[2] - 20), new Scalar(0), -1); Cv2.Rectangle(thresh2, new Rect(0, tonghou[1] + 40, thresh.Cols, tonghou[2] - tonghou[1]), new Scalar(255), -1); //Cv2.ImWrite(@"C:\Users\54434\Desktop\thresh2.png", thresh2); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); //Mat close = new Mat(); //Cv2.MorphologyEx(thresh2, close, MorphTypes.Close, seClose); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat open = new Mat(); Cv2.MorphologyEx(thresh2, open, MorphTypes.Open, seOpen); Mat max = new Mat(); //GetMaxArea(thresh2, out max); //Cv2.ImWrite(@"C:\Users\54434\Desktop\open.png", open); //GetMaxArea(open, out max/*thresh, out maxThresh*/); GetArea(open, out max, 500, true); //ImageShow(thresh, thresh2,open, max * 255); Mat result = max.Clone(); int middle = (dataArea[1] + dataArea[2]) / 2; leftFanghanhoudu[0] = middle - 120;// 150; rightFanghanhoudu[0] = middle + 120;// 150; Mat seOpen11 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(70/*15*/, 1/*水平线<--3, 3*/));// 开运算 //Mat open11 = new Mat(); ////OpenCV提取图像中的垂直线(或者水平线) 定义结构元素,开操作 Cv2.MorphologyEx(result, result, MorphTypes.Open, seOpen11); //Cv2.ImWrite(@"C:\Users\54434\Desktop\result.png", result * 120); //if (result.Get(tonghou[2] - 10, leftFanghanhoudu[0]) > 0) //{ // for (int i = tonghou[2] - 10; i > tonghou[1] - 30; i--) // { // if (result.Get(i, leftFanghanhoudu[0]) == 0) // { // leftFanghanhoudu[1] = i; // break; // } // } //} //else { for (int i = tonghou[1] - 30; i < tonghou[2]; i++) { if (result/*result*/.Get(i, leftFanghanhoudu[0]) > 0) { leftFanghanhoudu[1] = i; if (max[i - 1, i, leftFanghanhoudu[0], rightFanghanhoudu[0]].Sum().Val0 > (rightFanghanhoudu[0] - leftFanghanhoudu[0]) / 2 + 15 || Cv2.FloodFill(max, new Point(leftFanghanhoudu[0], i), new Scalar(1/*255*/)) > 3500) break;//对弧形的判定! } } } int upperLine = leftFanghanhoudu[1]; for (int i = leftFanghanhoudu[1]; i > leftFanghanhoudu[1] - 5; i--) { if (max.Get(i, leftFanghanhoudu[0]) > 0) upperLine = i; else break; } leftFanghanhoudu[1] = upperLine; //if (result.Get(tonghou[2] - 10, rightFanghanhoudu[0]) > 0) //{ // for (int i = tonghou[2] - 10; i > tonghou[1] - 30; i--) // { // if (result.Get(i, rightFanghanhoudu[0]) == 0) // { // rightFanghanhoudu[1] = i; // break; // } // } //} //else { for (int i = tonghou[1] - 30; i < tonghou[2]; i++) { if (result/*result*/.Get(i, rightFanghanhoudu[0]) > 0) { rightFanghanhoudu[1] = i; if (max[i - 1, i, leftFanghanhoudu[0], rightFanghanhoudu[0]].Sum().Val0 > (rightFanghanhoudu[0] - leftFanghanhoudu[0]) / 2 + 15 || Cv2.FloodFill(max, new Point(rightFanghanhoudu[0], i), new Scalar(1/*255*/)) > 3500) break;//对弧形的判定! } } } upperLine = rightFanghanhoudu[1]; for (int i = rightFanghanhoudu[1]; i > rightFanghanhoudu[1] - 5; i--) { if (max.Get(i, rightFanghanhoudu[0]) > 0) upperLine = i; else break; } rightFanghanhoudu[1] = upperLine; Scalar color = new Scalar(255/*2*//*127*//*255*/); //颜色 Cv2.Line(gray, new Point(leftFanghanhoudu[0], leftFanghanhoudu[1]), new Point(leftFanghanhoudu[0], leftFanghanhoudu[2]), color, 2, LineTypes.Link8); Cv2.Line(gray, new Point(rightFanghanhoudu[0], rightFanghanhoudu[1]), new Point(rightFanghanhoudu[0], rightFanghanhoudu[2]), color, 2, LineTypes.Link8); Rect rectMin = new Rect(Math.Max(0, leftFanghanhoudu[0] - 130), Math.Max(0, leftFanghanhoudu[1] - 200), Math.Min(max.Cols-1, rightFanghanhoudu[0]+130)- Math.Max(0, leftFanghanhoudu[0] - 130), Math.Min(max.Rows-1, leftFanghanhoudu[1]+30)- Math.Max(0, leftFanghanhoudu[1] - 200)); Cv2.Rectangle(gray, rectMin, color, 1); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray.png", gray/*max * 127*//*1*//*120*/); int[] compensate1 = new int[] { 10, 10 }; //去掉球 以及 微调补偿数值 Mat roundTemp = image_0[Math.Max(0, leftFanghanhoudu[1] - 200), Math.Min(max.Rows - 1, leftFanghanhoudu[1] + 30), Math.Max(0, leftFanghanhoudu[0] - 130), Math.Min(max.Cols - 1, rightFanghanhoudu[0] + 130)].CvtColor(ColorConversionCodes.BGR2GRAY); //meanV = (int)(roundTemp.Mean().Val0); //Mat mat_er = roundTemp.Threshold(meanV/*15*/, 255, ThresholdTypes.Binary); CircleSegment[] circles = Cv2.HoughCircles(roundTemp, HoughMethods.Gradient, 1, 30, 70, 30, 10, 60/*60*/);//, dp, minDist, param1, param2, minRadius, maxRadius); //CircleSegment[] circleSegment; //Base.AutoMeasure.Ceju.RemoveCircles(image1, image2, out result, 1, 30, 70, 30, 10, 60); if (circles.Length > 0) { int range = 10;// 5;// 10; for (int ic = 0; ic < circles.Length; ic++) { Point center = (Point)circles[ic].Center; int radius = (int)circles[ic].Radius; //for(int j=1;j 0) { int range = 0;// 5;// 10; for (int ic = 0; ic < circles.Length; ic++) { Point center = (Point)circles[ic].Center; int radius = (int)circles[ic].Radius; //for(int j=1;j(i, leftFanghanhoudu[0]) > 0) // { // leftFanghanhoudu[1] = i; // if (max[i - 1, i, leftFanghanhoudu[0], rightFanghanhoudu[0]].Sum().Val0 > // (rightFanghanhoudu[0] - leftFanghanhoudu[0]) / 2 + 15 // || Cv2.FloodFill(max, new Point(leftFanghanhoudu[0], i), new Scalar(1/*255*/)) > 3500) // break;//对弧形的判定! // } // } //} int comp = 5; if (rightFanghanhoudu[1] > leftFanghanhoudu[1] + 10) comp = 10; upperLine = leftFanghanhoudu[1] + comp; for (int i = leftFanghanhoudu[1]; i < leftFanghanhoudu[1] + comp; i++) { if (max.Get(i, leftFanghanhoudu[0]) > 0) { upperLine = i; break; } } leftFanghanhoudu[1] = upperLine; if (rightFanghanhoudu[1] < leftFanghanhoudu[1]) { comp = 5; upperLine = rightFanghanhoudu[1] + 5; for (int i = rightFanghanhoudu[1]; i < rightFanghanhoudu[1] + 5; i++) { if (max.Get(i, rightFanghanhoudu[0]) > 0) { upperLine = i; break; } } rightFanghanhoudu[1] = upperLine; } //{ // for (int i = tonghou[1] - 30; i < tonghou[2]; i++) // { // if (result/*result*/.Get(i, rightFanghanhoudu[0]) > 0) // { // rightFanghanhoudu[1] = i; // if (max[i - 1, i, leftFanghanhoudu[0], rightFanghanhoudu[0]].Sum().Val0 > // (rightFanghanhoudu[0] - leftFanghanhoudu[0]) / 2 + 15 // || Cv2.FloodFill(max, new Point(rightFanghanhoudu[0], i), new Scalar(1/*255*/)) > 3500) // break;//对弧形的判定! // } // } //} ////Mat roundGray = new Mat(); ////Cv2.CvtColor(roundTemp, roundGray, ColorConversionCodes.BGR2GRAY); ////int mean0; Scalar mean_rgb; //////去掉圆并灰度化,怎么能更快? ////Scalar mean = roundGray.Mean(/*gray*/); ////mean0 = (int)mean[0]; ////mean_rgb = roundTemp/*srcImage*/.Mean(); /////*final = */ ////bool foundCircle; ////roundTemp = FangHanTools.RemoveCircle(roundTemp, mean0, mean_rgb, out foundCircle);//.CvtColor(ColorConversionCodes.BGR2GRAY); ///////*Mat roundTemp = */FangHanTools.RemoveCircle(roundTemp, out mean0, out roundTemp); //Cv2.ImWrite(@"C:\Users\54434\Desktop\gray.png", roundTemp/*max * 127*//*1*//*120*/); ////通过连接区域的大小判定是否在圆球范围内 //int fillArea1 = 0; //for (int i = tonghou[1] - 30; i < tonghou[2]; i++) //{ // if (result.Get(i, leftFanghanhoudu[0]) > 0) // { // fillArea1 = Cv2.FloodFill(result.Clone()/*, mask1*/, new Point(leftFanghanhoudu[0], i), new Scalar(255/*127*//*255*/)); // leftFanghanhoudu[1] = i; // break; // } //} //Console.WriteLine("fillArea1:" + fillArea1); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\result.png", result * 120); ////通过连接区域的大小判定是否在圆球范围内 //int fillArea2 = 0; //for (int i = tonghou[1] - 30; i < tonghou[2]; i++) //{ // if (result.Get(i, rightFanghanhoudu[0]) > 0) // { // fillArea2 = Cv2.FloodFill(result.Clone()/*, mask1*/, new Point(rightFanghanhoudu[0], i), new Scalar(255/*127*//*255*/)); // rightFanghanhoudu[1] = i; // break; // } //} //Console.WriteLine("fillArea2:" + fillArea2); if (Math.Abs(leftFanghanhoudu[1] - rightFanghanhoudu[1]) > 100) { if (leftFanghanhoudu[1] < rightFanghanhoudu[1]) leftFanghanhoudu[1] = rightFanghanhoudu[1]; else rightFanghanhoudu[1] = leftFanghanhoudu[1]; } //if (fillArea1 != fillArea2) //{ // if (leftFanghanhoudu[1] < rightFanghanhoudu[1]) // leftFanghanhoudu[1] = rightFanghanhoudu[1]; // else // rightFanghanhoudu[1] = leftFanghanhoudu[1]; //} //防焊厚下层 Mat newGray2 = new Mat(); Cv2.GaussianBlur(gray, newGray2, new Size(15, 15), 5, 5); Mat filter2 = new Mat(); Cv2.MedianBlur(newGray2, filter2, 3); Mat edge2 = new Mat(); Edge(filter2, out edge2); Mat thresh3 = new Mat(); thresh3 = edge2.Threshold(15, 255, ThresholdTypes.Binary); Mat thresh4 = thresh3.Clone(); Cv2.Rectangle(thresh4, new Rect(0, 0, thresh.Cols, tonghou[2] - 30), new Scalar(255), -1); Cv2.Rectangle(thresh4, new Rect(0, tonghou[2] + 40, thresh.Cols, thresh.Rows - tonghou[2] - 40), new Scalar(0), -1); Mat seOpen2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); Mat open2 = new Mat(); Cv2.MorphologyEx(thresh4, open2, MorphTypes.Open, seOpen2); Mat crop2 = open2[tonghou[2] - 20, tonghou[2] + 20, leftFanghanhoudu[0], rightFanghanhoudu[0]] / 255; int openSum = (int)crop2.Sum(); int compensate2 = 8; if (openSum < 3000) { compensate2 = 0; Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 3)); Cv2.MorphologyEx(thresh4, open2, MorphTypes.Close, seClose2); } Mat max2 = new Mat(); GetMaxArea(thresh2, out max2); GetArea(open2, out max2, 500, true); //ImageShow(thresh3, thresh4, max2 * 255); //Cv2.ImWrite(@"C:\Users\54434\Desktop\max2.png", max2 * 255); Mat result2 = max2.Clone(); //防焊厚上层 Mat gray_1 = new Mat(); Cv2.CvtColor(image_0, gray_1, ColorConversionCodes.BGR2GRAY); Scalar sum2 = new Scalar(0); for (int i = tonghou[2] + 20; i > tonghou[2] - 20; i--) { sum2 = result2[i - 1, i, leftFanghanhoudu[0] - 50, leftFanghanhoudu[0] + 50].Sum(); if ((int)sum2 > 70) //if(result2.Get(i,leftFanghanhoudu[0])>0) { leftFanghanhoudu[2] = i; break; } } if (leftFanghanhoudu[2] == 0) leftFanghanhoudu[2] = tonghou[2]; for (int i = tonghou[2] + 20; i > tonghou[2] - 20; i--) { sum2 = result2[i - 1, i, rightFanghanhoudu[0] - 50, rightFanghanhoudu[0] + 50].Sum(); if ((int)sum2 > 70) //if(result2.Get(i, rightFanghanhoudu[0]) > 0) { rightFanghanhoudu[2] = i; break; } } if (rightFanghanhoudu[2] == 0) rightFanghanhoudu[2] = tonghou[2]; //for (int i = tonghou[2] + 20; i > tonghou[2] - 20; i--) //{ // sum2 = result2[i - 1, i, rightFanghanhoudu[0] - 50, rightFanghanhoudu[0] + 50].Sum(); // if ((int)sum2 > 60) // { // rightFanghanhoudu[2] = i; // break; // } //} //int compensate1 = 10; leftFanghanhoudu[1] += compensate1[0]; rightFanghanhoudu[1] += compensate1[1]; int fanghanX1 = rightFanghanhoudu[0] - 15;// 10;// += 140;// 145; int fanghanX2 = rightFanghanhoudu[0] + 15;// 10;// -= 140;// 145; int leftY0 = leftFanghanhoudu[1]; int rightY0 = rightFanghanhoudu[1]; { int fanghanhouduY1 = leftFanghanhoudu[1]; int minGray__2 = 255 * 300;// minGray; int fanghanTop = fanghanhouduY1 - 25;// 20;// 25;// 20;// 10; int fanghanhouduY_0 = fanghanhouduY1 + 60/*50*/ + 20; Mat grayRect = gray_1[fanghanTop, fanghanhouduY_0 - 20/*50*/, fanghanX1, fanghanX2]; int fanghanhouduY1__2_bottom; fanghanhouduY1 -= fanghanTop; int fanghanhouduY1__2 = fanghanhouduY1; Gaoduchahoudu_ACC(grayRect, fanghanhouduY1 - 0/*19*//*15*//*5*//*(isLeft ? 8 : 1)*/, out fanghanhouduY1__2, out fanghanhouduY1__2_bottom, out minGray__2, 0); if (true && Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 10/* <<15 16*//*11*//*<-10*//*20*//*10*/ || (fanghanhouduY1 - fanghanhouduY1__2 > 0 && fanghanhouduY1 - fanghanhouduY1__2 < 12/* <<15.12 <<10 *//*10*//*20*/)) //|| (!isLeft && Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 25/*20*/)) fanghanhouduY1 = fanghanhouduY1__2/*fanghanhouduY1__2_bottom*//*fanghanhouduY1__2*/ + fanghanTop;// +5; else fanghanhouduY1 = fanghanhouduY1 + fanghanTop; Console.WriteLine("leftFanghanhoudu[1]:" + leftFanghanhoudu[1] + ";fanghanhouduY1:" + fanghanhouduY1); leftFanghanhoudu[1] = fanghanhouduY1; } { int fanghanhouduY1 = rightFanghanhoudu[1]; int minGray__2 = 255 * 300;// minGray; int fanghanTop = fanghanhouduY1 - 25;// 20;// 25;// 20;// 10; int fanghanhouduY_0 = fanghanhouduY1 + 60/*50*/ + 20; Mat grayRect = gray_1[fanghanTop, fanghanhouduY_0 - 20/*50*/, fanghanX1, fanghanX2]; int fanghanhouduY1__2_bottom; fanghanhouduY1 -= fanghanTop; int fanghanhouduY1__2 = fanghanhouduY1; Gaoduchahoudu_ACC(grayRect, fanghanhouduY1 - 0/*19*//*15*//*5*//*(isLeft ? 8 : 1)*/, out fanghanhouduY1__2, out fanghanhouduY1__2_bottom, out minGray__2, 1); if (true && Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 10/* <<15 16*//*11*//*<-10*//*20*//*10*/ || (fanghanhouduY1 - fanghanhouduY1__2 > 0 && fanghanhouduY1 - fanghanhouduY1__2 < 12/* <<15.12 <<10 *//*10*//*20*/)) //|| (!isLeft && Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 25/*20*/)) fanghanhouduY1 = fanghanhouduY1__2/*fanghanhouduY1__2_bottom*//*fanghanhouduY1__2*/ + fanghanTop;// +5; else fanghanhouduY1 = fanghanhouduY1 + fanghanTop; Console.WriteLine("rightFanghanhoudu[1]:" + rightFanghanhoudu[1] + ";fanghanhouduY1:" + fanghanhouduY1); rightFanghanhoudu[1] = fanghanhouduY1; } if (Math.Abs(leftFanghanhoudu[1] - rightFanghanhoudu[1]) - Math.Abs(leftY0 - rightY0) > 2) {//纠错2(1).JPG if (leftY0 == leftFanghanhoudu[1]) rightFanghanhoudu[1] = rightY0; else if (rightY0 == rightFanghanhoudu[1]) if (Math.Abs(rightY0 - leftY0) > 10) { leftFanghanhoudu[1] = rightY0;// leftY0; } else leftFanghanhoudu[1] = leftY0; } //Mat grayRect = gray_1[leftFanghanhoudu[1] - 10/*fanghanTop*/, leftFanghanhoudu[1] + 50/*fanghanhouduY_0 - 50*/, leftFanghanhoudu[0] - 10, leftFanghanhoudu[0] + 10]; //Gaoduchahoudu_ACC(grayRect/*gray*/, y, marginTop/*150*//*fanghanhouduX*/, tonghouY, out fanghanhouduY1, out minGray); //int fanghanhouduY1__2 = fanghanhouduY1; //int minGray__2 = minGray; //fanghanX1 += 140;// 145; //fanghanX2 -= 140;// 145; //grayRect = gray[fanghanTop, fanghanhouduY_0 - 20/*50*/, fanghanX1, fanghanX2]; //int fanghanhouduY1__2_bottom; //FanghanhouduForYouKaiKou_ACC(grayRect, y, marginTop, fanghanhouduY1 - (isLeft ? 8/*5*/ : 1), out fanghanhouduY1__2, out fanghanhouduY1__2_bottom, out minGray__2); //if (true && (Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 16/*11*//*<-10*//*20*//*10*/ // || (!isLeft && Math.Abs(fanghanhouduY1 - fanghanhouduY1__2) < 25/*20*/))) // fanghanhouduY1 = fanghanhouduY1__2/*fanghanhouduY1__2_bottom*//*fanghanhouduY1__2*/ + fanghanTop;// +5; //else // fanghanhouduY1 = fanghanhouduY1 + fanghanTop; leftFanghanhoudu[2] -= compensate2; rightFanghanhoudu[2] -= compensate2; } /// /// 防焊 有开口 厚度 精确计算 /// /// /// /// /// /// /// private void Gaoduchahoudu_ACC(Mat gray0, int fanghanhouduY1__0, out int fanghanhouduY1, out int fanghanhouduY1Bottom, out int minGray, int a = 0) { int bottomYDistance = 15;// 30; int fanghanhouduY1__noSharp = -1;// fanghanhouduY1; { minGray = 300 * 255; int minRowIndex = 0; int colEnd = gray0.Cols - 1; int curGray; List curGrayList = new List(); fanghanhouduY1Bottom = 0; for (int i = Math.Max(0, fanghanhouduY1__0 - 19/*1*//*5*//*10*/); i < Math.Min(fanghanhouduY1__0 + bottomYDistance/*25*/, gray0.Rows) - 5; i++) { curGray = this.FanghanhouduForAreaMin(gray0, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; curGrayList.Add(curGray); if (curGray < minGray) { minRowIndex = i; fanghanhouduY1Bottom = i; minGray = curGray; } } for (int i = minRowIndex - Math.Max(0, fanghanhouduY1__0 - 19/*1*//*5*//*10*/) + 2; i < curGrayList.Count; i += 2) { if (Math.Abs(curGrayList[i] - minGray) < 10/*100*/) { minRowIndex += 1; fanghanhouduY1Bottom += 2; } else break; } fanghanhouduY1__noSharp = minRowIndex;// 84;// 72;// minRowIndex; } { minGray = 300 * 255; //锐化 //Mat left_small_sharp = BinaryTools.BlurMaskFunction(left_small).CvtColor(ColorConversionCodes.BGRA2GRAY); Mat gray = BinaryTools.BlurMaskFunction(gray0.Clone()/*grayRect*/, 4f * 3.14f, 1, 10f).CvtColor(ColorConversionCodes.BGRA2GRAY); //Cv2.ImWrite(@"C:\Users\win10SSD\Desktop\BlurMask" + a + "_.jpg", gray); int minRowIndex = 0; int colEnd = gray.Cols - 1; int curGray; List curGrayList = new List(); fanghanhouduY1Bottom = 0; for (int i = Math.Max(0, fanghanhouduY1__0 - 19/*1*//*5*//*10*/); i < Math.Min(fanghanhouduY1__0 + bottomYDistance/*25*/, gray.Rows) - 5; i++) { curGray = this.FanghanhouduForAreaMin(gray, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; curGrayList.Add(curGray); if (curGray < minGray) { minRowIndex = i; fanghanhouduY1Bottom = i; minGray = curGray; } } for (int i = minRowIndex - Math.Max(0, fanghanhouduY1__0 - 19/*1*//*5*//*10*/) + 2; i < curGrayList.Count; i += 2) { if (Math.Abs(curGrayList[i] - minGray) < 10/*100*/) { minRowIndex += 1; fanghanhouduY1Bottom += 2; } else break; } //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); fanghanhouduY1 = minRowIndex;// 84;// 72;// minRowIndex; } Console.Write("noSharp:" + fanghanhouduY1__noSharp + ";fanghanhouduY1:" + fanghanhouduY1 +"..."); if (Math.Abs(fanghanhouduY1__noSharp - fanghanhouduY1) < 7/* <<7 8*//* << 6 *//*5*/ || (fanghanhouduY1__noSharp - fanghanhouduY1 > 0 && fanghanhouduY1__noSharp - fanghanhouduY1 < 20)) { fanghanhouduY1 = fanghanhouduY1__noSharp; } else Console.WriteLine("fanghanhouduY1 far away from fanghanhouduY1__noSharp."); } //叠构 /// /// 得到叠构有导电布时铜层的数量以及当铜层大于二时的平均厚度 /// /// /// /// public void GetTongCengShuliang(Mat gray, out int tongshu, out int tonghou, out int jianhou) { tongshu = 0; tonghou = 0; jianhou = 0; Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); //ImageShow(thresh * 255); Mat nomin = new Mat();//去除小点防止干扰 GetArea(thresh, out nomin, 500, true); Mat result = nomin.Clone(); int[] y = new int[8]; int middle = thresh.Cols / 2;//根据中间选取部分范围防止倾斜的干扰 Scalar sum = new Scalar(0); for (int i = 0; i < thresh.Rows; i++) { sum = result[i, i + 1, middle - 100, middle + 100].Sum(); if ((int)sum > 0) { y[0] = i; break; } } for (int i = y[0]; i < thresh.Rows; i++) { sum = result[i, i + 1, middle - 100, middle + 100].Sum(); if ((int)sum == 0) { y[1] = i; break; } } for (int i = y[1]; i < thresh.Rows; i++) { sum = result[i, i + 1, middle - 100, middle + 100].Sum(); if ((int)sum > 0) { y[2] = i; break; } } if (y[2] != 0) { for (int i = y[2]; i < thresh.Rows; i++) { sum = result[i, i + 1, middle - 100, middle + 100].Sum(); if ((int)sum == 0) { y[3] = i; break; } } for (int i = y[3]; i < thresh.Rows; i++) { sum = result[i, i + 1, middle - 100, middle + 100].Sum(); if ((int)sum > 0) { y[4] = i; break; } } if (y[4] != 0) { for (int i = y[4]; i < thresh.Rows; i++) { sum = result[i, i + 1, middle - 100, middle + 100].Sum(); if ((int)sum == 0) { y[5] = i; break; } } for (int i = y[5]; i < thresh.Rows; i++) { sum = result[i, i + 1, middle - 100, middle + 100].Sum(); if ((int)sum > 0) { y[6] = i; break; } } if (y[6] != 0) { for (int i = y[6]; i < thresh.Rows; i++) { sum = result[i, i + 1, middle - 100, middle + 100].Sum(); if ((int)sum == 0) { y[7] = i; break; } } } } } if (y[2] == 0) tongshu = 1; else if (y[4] == 0) tongshu = 2; else if (y[6] == 0) tongshu = 3; else tongshu = 4; if (tongshu == 1) { tonghou = y[1] - y[0]; } else if (tongshu == 2) { tonghou = (y[1] - y[0] + y[3] - y[2]) / 2; jianhou = y[2] - y[1]; } } /// /// 提取有导电布时单层铜的坐标 /// /// /// public void DaoidanbuDanceng(Mat gray, out List ordinates) { ordinates = new List(); //图片处理 //无预处理图片边缘检测+阈值分割+去小面积用来提取导电布 //高斯滤波+边缘检测+阈值分割+铜区域闭运算-反色-掩膜-+掩膜+去小面积提取中间线条 //无预处理 Mat sobel1 = new Mat(); EdgeY2(gray, out sobel1); Mat threshSobel1 = new Mat(); threshSobel1 = sobel1.Threshold(100, 1, ThresholdTypes.Binary); Mat nomin1 = new Mat(); GetArea(threshSobel1, out nomin1, 500, true); Mat result1 = nomin1.Clone(); //ImageShow(result1 * 255); //有预处理高斯滤波 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(5, 5), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(80, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fanse = 1 - thresh; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); Mat nomin = new Mat(); GetArea(and, out nomin, 500, true); //ImageShow(threshSobel * 255, thresh * 255, and * 255,nomin*255); //提取坐标 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate); i += 30; } } if (ordinates[1] - ordinates[0] < 50) ordinates.RemoveAt(1); for (int i = ordinates[0] + 10; i < result.Rows; i++) { sum = result1[i, i + 1, middle - 10, middle + 10].Sum(); if ((int)sum == 0) { int newOrdinate = i; ordinates.Insert(1, newOrdinate); break; } } //if (ordinates[ordinates.Count - 1] - ordinates[ordinates.Count - 2] < 40) if (ordinates.Count == 7 || ordinates.Count == 9) ordinates.RemoveAt(ordinates.Count - 1); for (int i = ordinates[ordinates.Count - 1] + 10; i < result.Rows; i++) { sum = result1[i, i + 1, middle - 10, middle + 10].Sum(); if ((int)sum == 0) { int newOrdinate = i; ordinates.Add(newOrdinate); break; } } } /// /// 得到叠构的总厚 /// /// /// public void DiegouGetZonghou(Mat gray, out int zonghou) { zonghou = 0; Mat sobel = new Mat(); EdgeY2(gray, out sobel); Mat thresh = sobel.Threshold(100, 1, ThresholdTypes.Binary); Mat nomin = new Mat(); GetArea(thresh, out nomin, 500, true); Scalar sum = new Scalar(); int[] y = new int[2]; int middle = nomin.Cols / 2; for (int i = 0; i < thresh.Rows - 1; i++) { sum = nomin[i, i + 1, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { y[0] = i; break; } } for (int i = thresh.Rows - 1; i > 1; i--) { sum = nomin[i - 1, i, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { y[1] = i; break; } } zonghou = y[1] - y[0]; } /// /// 无导电布单层时测总厚 /// /// /// public void DiegouGetZonghou2(Mat gray, out int zonghou) { zonghou = 0; Mat sobel = new Mat(); EdgeY2(gray, out sobel); Mat thresh = sobel.Threshold(40, 1, ThresholdTypes.Binary); Mat nomin = new Mat(); GetArea(thresh, out nomin, 500, true); //ImageShow(nomin * 255); Scalar sum = new Scalar(); int[] y = new int[2]; int middle = nomin.Cols / 2; for (int i = 0; i < thresh.Rows - 1; i++) { sum = nomin[i, i + 1, 0, nomin.Cols].Sum(); if ((int)sum > 100) { y[0] = i; break; } } for (int i = thresh.Rows - 1; i > 1; i--) { sum = nomin[i - 1, i, 0, nomin.Cols].Sum(); if ((int)sum > 100) { y[1] = i; break; } } zonghou = y[1] - y[0]; if (zonghou > 600)//如果大于600,说明是亮图由于阈值太低而出现干扰,划到亮图里面去 { zonghou = 200; } } /// /// 提取有导电布双层铜总厚大时的坐标 /// /// /// public void DaodianbuShuangcengZongHou(Mat gray, out List ordinates) { ordinates = new List(); //图片处理 //无预处理图片边缘检测+阈值分割+去小面积用来提取导电布 //高斯滤波+边缘检测+阈值分割+铜区域闭运算-反色-掩膜-+掩膜+去小面积提取中间线条 //无预处理 Mat sobel1 = new Mat(); EdgeY2(gray, out sobel1); Mat threshSobel1 = new Mat(); threshSobel1 = sobel1.Threshold(100, 1, ThresholdTypes.Binary); Mat nomin1 = new Mat(); GetArea(threshSobel1, out nomin1, 500, true); Mat result1 = nomin1.Clone(); //ImageShow(result1 * 255); //有预处理高斯滤波 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(5, 5), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(100, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fanse = 1 - thresh; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); Mat nomin = new Mat(); GetArea(and, out nomin, 500, true); //ImageShow(threshSobel * 255, thresh * 255, and * 255, nomin * 255+gray); //提取坐标 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate); i += 30; } } if (ordinates[5] - ordinates[4] < 50) ordinates.RemoveAt(5); for (int i = ordinates[4] + 10; i < result.Rows; i++) { sum = result1[i, i + 1, middle - 10, middle + 10].Sum(); if ((int)sum == 0) { int newOrdinate = i; ordinates.Insert(5, newOrdinate); break; } } if (ordinates[ordinates.Count - 1] - ordinates[ordinates.Count - 2] < 40) ordinates.RemoveAt(ordinates.Count - 1); for (int i = ordinates[ordinates.Count - 1] + 10; i < result.Rows; i++) { sum = result1[i, i + 1, middle - 10, middle + 10].Sum(); if ((int)sum == 0) { int newOrdinate = i; ordinates.Add(newOrdinate); break; } } } /// /// 提取有导电布时三层铜时的坐标 /// /// /// public void DaodianbuSanceng(Mat gray, out List ordinates) { ordinates = new List(); //图片处理 //无预处理图片边缘检测+阈值分割+去小面积用来提取导电布 //高斯滤波+边缘检测+阈值分割+铜区域闭运算-反色-掩膜-+掩膜+去小面积提取中间线条 //无预处理 Mat sobel1 = new Mat(); EdgeY2(gray, out sobel1); Mat threshSobel1 = new Mat(); threshSobel1 = sobel1.Threshold(100, 1, ThresholdTypes.Binary); Mat nomin1 = new Mat(); GetArea(threshSobel1, out nomin1, 500, true); Mat result1 = nomin1.Clone(); //ImageShow(result1 * 255); //有预处理高斯滤波 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(5, 5), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(80, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fanse = 1 - thresh; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); Mat nomin = new Mat(); GetArea(and, out nomin, 500, true); //ImageShow(threshSobel * 255, thresh * 255, and * 255, nomin * 255 + gray); //提取坐标 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate); i += 30; } } //第一层 if (ordinates[1] - ordinates[0] < 50) ordinates.RemoveAt(1); for (int i = ordinates[0] + 10; i < result.Rows; i++) { sum = result1[i, i + 1, middle - 10, middle + 10].Sum(); if ((int)sum == 0) { int newOrdinate = i; ordinates.Insert(1, newOrdinate); break; } } //倒数第三层和倒数第四层,求倒数第四层 if (ordinates[ordinates.Count - 3] - ordinates[ordinates.Count - 4] < 40) ordinates.RemoveAt(ordinates.Count - 3); for (int i = ordinates[ordinates.Count - 3] + 10; i < result.Rows; i++) { sum = result1[i, i + 1, middle - 10, middle + 10].Sum(); if ((int)sum == 0) { int newOrdinate = i; ordinates.Insert(ordinates.Count - 2, newOrdinate); break; } } } /// /// 提取无导电布时单层铜厚大时的坐标 /// /// /// public void WuDaodianbuDancengHou(Mat gray, out List ordinates) { ordinates = new List(); //图像处理 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(5, 5), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(80, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fanse = 1 - thresh; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); Mat nomin = new Mat(); GetArea(and, out nomin, 500, true); //ImageShow(threshSobel * 255, thresh * 255, and * 255, nomin * 255 + gray); //坐标提取 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate); i += 100; } } } /// /// 提取无导电布时,单层铜,总厚较窄时的坐标 /// /// /// public void WuDaodianbuDancengZhaiZonghouZhai(Mat gray, out List ordinates) { ordinates = new List(); //图像处理 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(5, 5), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(60, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fanse = 1 - thresh; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); //Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); //Mat close2 = new Mat(); //Cv2.MorphologyEx(and, close2, MorphTypes.Close, seClose2); Mat nomin = new Mat(); GetArea(and, out nomin, 500, true); //ImageShow(threshSobel * 255, thresh * 255, and * 255, nomin * 255 + gray); //坐标提取 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate); i += 30; } } int compensate = 5; ordinates[ordinates.Count - 1] += compensate; } /// /// 提取无导电布时,单层铜,总厚较宽时的坐标 /// /// /// public void WuDaodianbuDancengZhaiZonghouKuan(Mat gray, out List ordinates) { ordinates = new List(); //图像处理 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(5, 5), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(20, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fill = new Mat(); Fill(thresh, out fill, 1); Mat fanse = 1 - fill; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); Mat close2 = new Mat(); Cv2.MorphologyEx(and, close2, MorphTypes.Close, seClose2); Mat nomin = new Mat(); GetArea(close2, out nomin, 2000, true); //ImageShow(threshSobel * 255, thresh * 255, and * 255, nomin * 255 + gray); //坐标提取 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); int count = 0; for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate); i += 30; count++; } if (count == 3) break; } //最后一行 for (int i = result.Rows - 1; i > 2; i--) { sum = result[i - 1, i, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate); break; } } for (int i = ordinates[ordinates.Count - 1] - 30; i > 2; i--) { sum = result[i - 2, i, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Insert(ordinates.Count - 1, newOrdinate); break; } } int compensate = 5; ordinates[0] += compensate; //ordinates[ordinates.Count - 1] += compensate; //提取中间线 Mat crop = gray[ordinates[0], ordinates[1], middle - 100, middle + 100].Clone(); //Mat threshCrop = crop.Threshold(160, 1, ThresholdTypes.Binary); Mat cropSobel = new Mat(); EdgeY2(crop, out cropSobel); Mat threshCropSobel = 1 - cropSobel.Threshold(40, 1, ThresholdTypes.Binary); Mat result2 = threshCropSobel.Clone(); for (int i = 20; i < result2.Rows - 1; i++) { sum = result2[i, i + 2, 0, result2.Cols].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Insert(1, newOrdinate + ordinates[0] + 20); break; } } //ImageShow(crop, threshCropSobel * 255); } /// /// 提取无导电布双层铜层厚较大时 /// /// /// public void WuDaodianbuShuangcengCenghou(Mat gray, out List ordinates) { ordinates = new List(); //图像处理 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(9, 9), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(80, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fill = new Mat(); Fill(thresh, out fill, 1); Mat fanse = 1 - fill; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); //Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); //Mat close2 = new Mat(); //Cv2.MorphologyEx(and, close2, MorphTypes.Close, seClose2); Mat nomin = new Mat(); GetArea(and, out nomin, 2000, true); //ImageShow(threshSobel * 255, thresh * 255, and * 255, nomin * 255 + gray); //坐标提取 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate + 5); i += 100; } } } public void WudaodianbuShuangcengD(Mat gray, out List ordinates) { ordinates = new List(); //图像处理 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(9, 9), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(40, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fill = new Mat(); Fill(thresh, out fill, 1); Mat fanse = 1 - fill; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); Mat close2 = new Mat(); Cv2.MorphologyEx(and, close2, MorphTypes.Close, seClose2); Mat nomin = new Mat(); GetArea(close2, out nomin, 3000, true); //Mat noCircle = new Mat(); //RemoveCircles(nomin, out noCircle); //ImageShow(thresh * 255, and * 255,close2*255, nomin * 255 + gray); //坐标提取 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate + 5); i += 30; } } //迭代 if (ordinates.Count < 11) { for (int i = 0; i < ordinates[0]; i++) { sum = result[i, i + 2, 0, result.Cols].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Insert(0, newOrdinate + 5); break; } } } if (ordinates.Count == 12) ordinates.RemoveAt(11); if (ordinates.Count == 11) { ordinates[6] += 6; ordinates[8] += 6; ordinates[10] += 10; } } public void WudaodianbuShuangcengQita(Mat gray, out List ordinates) { ordinates = new List(); //图像处理 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(9, 9), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(80, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fill = new Mat(); Fill(thresh, out fill, 1); Mat fanse = 1 - fill; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); //Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); //Mat close2 = new Mat(); //Cv2.MorphologyEx(and, close2, MorphTypes.Close, seClose2); Mat nomin = new Mat(); GetArea(and, out nomin, 2000, true); //ImageShow(threshSobel * 255, thresh * 255, and * 255, nomin * 255 + gray); //坐标提取 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate + 5); i += 30; } } } /// /// 提取无导电布三层坐标 /// /// /// public void WudaodianbuSanceng(Mat gray, out List ordinates) { ordinates = new List(); //图像处理 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(9, 9), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(80, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fill = new Mat(); Fill(thresh, out fill, 1); Mat fanse = 1 - fill; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); //Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); //Mat close2 = new Mat(); //Cv2.MorphologyEx(and, close2, MorphTypes.Close, seClose2); Mat nomin = new Mat(); GetArea(and, out nomin, 2000, true); //ImageShow(threshSobel * 255, thresh * 255, and * 255, nomin * 255 + gray); //坐标提取 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate + 5); i += 30; } } if (ordinates[1] - ordinates[0] > 300) { if (ordinates[2] - ordinates[1] > 120) { for (int i = ordinates[1] + 30; i < ordinates[2]; i++) { sum = result[i, i + 2, 0, result.Cols].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Insert(2, newOrdinate); break; } } } } else { if (ordinates[3] - ordinates[2] > 120) { for (int i = ordinates[2] + 30; i < ordinates[3]; i++) { sum = result[i, i + 2, 0, result.Cols].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Insert(3, newOrdinate); break; } } } } ////添加超出范围的线条 //Mat stright = new Mat(); //List strights = new List(); //KeepStraight(result, out stright, out strights); ////插入原坐标没有的点 //for (int i = 0; i < strights.Count; i++) //{ // for (int j = 0; j < ordinates.Count - 1; j++) // { // if (Math.Abs(strights[i] - ordinates[j]) < 30 || Math.Abs(strights[i] - ordinates[j + 1]) < 30) // break; // else if (strights[i] > ordinates[j] && strights[i] < ordinates[j + 1]) // { // ordinates.Insert(j + 1, strights[i]); // break; // } // } //} ////删除过近的坐标 //List ordinatesCopy = ordinates.ToList(); //int count = 0; //for (int i = 0; i < ordinates.Count - 1; i++) //{ // if (ordinates[i + 1] - ordinates[i] < 10) // { // ordinatesCopy.RemoveAt(i - count); // count++; // } //} //ordinates = ordinatesCopy.ToList(); //增加最下层坐标 if (ordinates.Count < 10) { Mat bottom = gray.Clone(); Cv2.Rectangle(bottom, new Rect(0, 0, bottom.Cols, ordinates[ordinates.Count - 1]), new Scalar(0), -1); Cv2.GaussianBlur(bottom, bottom, new Size(5, 5), 3); Mat edge = new Mat(); EdgeY(bottom, out edge); Mat threshEdge = new Mat(); threshEdge = edge.Threshold(30, 1, ThresholdTypes.Binary); Mat seClose3 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); Mat close = new Mat(); Cv2.MorphologyEx(threshEdge, close, MorphTypes.Close, seClose3); Mat nomin3 = new Mat(); GetArea(close, out nomin3, 500, true); //Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 1)); //Mat open = new Mat(); //Cv2.MorphologyEx(threshEdge, open, MorphTypes.Open, seOpen); //ImageShow(threshEdge * 255,close*255,nomin3*255); Mat result2 = nomin3.Clone(); for (int i = ordinates[ordinates.Count - 1] + 30; i < result2.Rows - 1; i++) { sum = result2[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate); break; } } } //else //{ //} } /// /// 提取无导电布四层铜的坐标 /// /// /// public void WuDaodianbuSiceng(Mat gray, out List ordinates) { ordinates = new List(); //图像处理 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(5, 5), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(60, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fill = new Mat(); Fill(thresh, out fill, 1); Mat fanse = 1 - fill; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); Mat seClose2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); Mat close2 = new Mat(); Cv2.MorphologyEx(and, close2, MorphTypes.Close, seClose2); Mat nomin = new Mat(); GetArea(close2, out nomin, 2000, true); //ImageShow(threshSobel * 255, thresh * 255, and * 255, nomin * 255 + gray); //坐标提取 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate + 5); i += 30; } } } /// /// 提取有内部线条的坐标 /// /// /// public void WuDaodianbuQicengtong(Mat gray, out List ordinates) { ordinates = new List(); //图像处理 Mat filter = new Mat(); Cv2.GaussianBlur(gray, filter, new Size(9, 9), 3); Mat sobel = new Mat(); EdgeY2(filter, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(80, 1, ThresholdTypes.Binary); Mat thresh = new Mat(); thresh = gray.Threshold(0, 1, ThresholdTypes.Otsu); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 7)); Cv2.MorphologyEx(thresh, thresh, MorphTypes.Close, seClose); Mat fill = new Mat(); Fill(thresh, out fill, 1); Mat fanse = 1 - fill; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshSobel, and); Mat nomin = new Mat(); GetArea(and, out nomin, 2000, true); Mat threshSobel2 = new Mat(); threshSobel2 = sobel.Threshold(180, 1, ThresholdTypes.Binary); //ImageShow(threshSobel * 255, and * 255, nomin * 255 + gray,threshSobel2*255); //坐标提取 Mat result = nomin.Clone(); int middle = result.Cols / 2; Scalar sum = new Scalar(); for (int i = 0; i < result.Rows - 1; i++) { sum = result[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Add(newOrdinate + 5); i += 30; } } //对内部线进行提取 //对内部进行阈值分割 int start1 = ordinates[0]; int start2 = ordinates[2]; Mat crop1 = gray[ordinates[0], ordinates[1], middle - 100, middle + 100].Clone(); Mat crop2 = gray[ordinates[2], ordinates[3], middle - 100, middle + 100].Clone(); Mat threshCrop1 = 1 - crop1.Threshold(0, 1, ThresholdTypes.Otsu); Mat threshCrop2 = 1 - crop2.Threshold(0, 1, ThresholdTypes.Otsu); //ImageShow(threshCrop1 * 255, threshCrop2 * 255); for (int i = 10; i < threshCrop1.Rows - 1; i++) { sum = threshCrop1[i, i + 2, 0, threshCrop1.Cols].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Insert(1, newOrdinate + ordinates[0]); break; } } for (int i = threshCrop1.Rows - 30; i > 2; i--) { sum = threshCrop1[i - 2, i, 0, threshCrop1.Cols].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Insert(2, newOrdinate + ordinates[0]); break; } } for (int i = 30; i < threshCrop2.Rows - 2; i++) { sum = threshCrop2[i, i + 2, 0, threshCrop2.Cols].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Insert(5, newOrdinate + start2); break; } } for (int i = threshCrop2.Rows - 10; i > 2; i--) { sum = threshCrop2[i - 2, i, 0, threshCrop2.Cols].Sum(); if ((int)sum > 100) { int newOrdinate = i; ordinates.Insert(6, newOrdinate + start2); break; } } } /// /// 通过计算二值图最集中的区域来得到叠构的提取区域 /// /// /// public void DiegouDataArea(Mat contour, out int dataArea) { Scalar sum = new Scalar(0); Scalar max = new Scalar(0); int maxArea = 0; for (int j = contour.Cols / 5; j < contour.Cols / 5 * 4 && j < contour.Cols - 40; j++) { sum = contour[0, contour.Rows, j, j + 40].Sum(); if ((int)sum > (int)max) { max = sum; maxArea = j; } } dataArea = maxArea + 20; } /// /// 得到去噪后的边缘线 /// /// /// public void GetEdge(Mat image, out Mat edge) { Mat filter = new Mat(); Cv2.GaussianBlur(image, filter, new Size(11, 11), 5, 5); edge = new Mat(); Cv2.Canny(filter, edge, 10, 10); //去除小连通域噪声 Mat[] contours; Mat hierachy = new Mat(); Cv2.FindContours(edge, out contours, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); int area = 2; Mat noise = Mat.Zeros(edge.Rows, edge.Cols, edge.Type()); for (int i = 0; i < contours.Count(); i++) { if (Cv2.ContourArea(contours[i]) > area) { Cv2.DrawContours(noise, contours, i, new Scalar(1)); } } //减去噪声+开运算 Mat noNoise = edge - noise * 255; //Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); //Mat close = new Mat(); //Cv2.MorphologyEx(noNoise, close, MorphTypes.Close, seClose); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 1)); Mat open = new Mat(); Cv2.MorphologyEx(noNoise, open, MorphTypes.Open, seOpen); edge = open; } /// /// 计算线的坐标,当10行内点的数量大于10时记录平均坐标,用的是非膨胀后开运算结果图 /// /// /// /// public void GetOrdinate(Mat edge, int dataArea, out List ordinates) { int upper = 0; int lower = 0; int upperBound = 0, lowerBound = 0; int count = 0; int meanOrdinate = 0; ordinates = new List(); Scalar sum = new Scalar(0); for (int i = 0; i < edge.Rows; i++) { sum = edge[i, i + 3, 0, edge.Cols].Sum(); if ((int)sum > 50) { upper = i; break; } } for (int i = edge.Rows - 1; i > 0; i--) { sum = edge[i - 3, i, 0, edge.Cols].Sum(); if ((int)sum > 40) { lower = i; break; } } upperBound = upper - 10; while (lowerBound < lower + 50) { count = 0; meanOrdinate = 0; while (count < 10 /*&& lowerBound + 20 < edge.Rows*/) { upperBound += 5; lowerBound = upperBound + 5; for (int i = upperBound; i < lowerBound; i++) { for (int j = dataArea - 25; j < dataArea + 25; j++) { if (edge.Get(i, j) > 0) { meanOrdinate += i; count++; } } } } if (count > 5) { int newOrdinate = new int(); newOrdinate = meanOrdinate / count; if (ordinates.Count > 0 && newOrdinate > ordinates[ordinates.Count - 1] + 40) { ordinates.Add(newOrdinate); upper += 10; } else if (ordinates.Count == 0) { ordinates.Add(newOrdinate); upper += 10; } } } } public void GetOrdinate2(Mat edge, int dataArea, out List ordinates) { int upper = 0; int lower = 0; int upperBound = 0, lowerBound = 0; int count = 0; int meanOrdinate = 0; ordinates = new List(); Scalar sum = new Scalar(0); for (int i = 0; i < edge.Rows; i++) { sum = edge[i, i + 3, 0, edge.Cols].Sum(); if ((int)sum > 70) { upper = i; break; } } for (int i = edge.Rows - 1; i > 0; i--) { sum = edge[i - 3, i, 0, edge.Cols].Sum(); if ((int)sum > 40) { lower = i; break; } } upperBound = upper - 10; int j = 0; while (upperBound + 20 < lower) { for (int i = upperBound; i < lower + 50; i += 1) { sum = edge[i, i + 5, dataArea - 50, dataArea + 50].Sum(); if ((int)sum > 10) { meanOrdinate = i + 1; if (ordinates.Count == 0) { ordinates.Add(meanOrdinate); upperBound = i + 10; break; } else if (ordinates.Count > 0 && meanOrdinate > ordinates[ordinates.Count - 1] + 40) { ordinates.Add(meanOrdinate); upperBound = (i + 10); break; } } j = i; } if (j == lower + 49) break; } } /// /// 对叠构的上区域重新进行处理并判断是否有线条存在 /// /// /// /// public void UpperProcess(Mat image, out int ordinate, int[] border) { ordinate = 0; Mat result = new Mat(); Mat crop = image[border[0], border[1], 0, image.Cols].Clone(); //ImageShow(crop); Cv2.GaussianBlur(crop, crop, new Size(11, 11), 5, 5); //ImageShow(crop); //Cv2.MedianBlur(image, image, 11); //ImageShow(image); Mat edgeSobel = new Mat(); EdgeY(crop, out edgeSobel); //Sobel(image, out edgeSobel); Mat threshEdge = new Mat(); double t2 = Cv2.Threshold(edgeSobel, threshEdge, 0, 255, ThresholdTypes.Otsu); threshEdge = edgeSobel.Threshold(15, 255, ThresholdTypes.Binary); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9, 1)); Mat close = new Mat(); Cv2.MorphologyEx(threshEdge, close, MorphTypes.Close, seClose); close = close / 255; Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9, 1)); Mat open = new Mat(); Cv2.MorphologyEx(close, open, MorphTypes.Open, seOpen); GetArea(open, out close, 400, true); result = close.Clone(); //ImageShow(crop, edgeSobel, threshEdge, result * 255); Scalar sum = new Scalar(0); for (int i = 0; i < crop.Rows - 5; i++) { sum = result[i, i + 2, result.Cols / 3, result.Cols / 3 * 2].Sum(); if ((int)sum > result.Cols / 2) { ordinate = i; break; } } } public void DiegouImageProcess(Mat gray, out Mat result) { result = new Mat(); //大致轮廓线 Mat newGray = new Mat(); Cv2.GaussianBlur(gray, newGray, new Size(15, 15), 5, 5); Mat filter = new Mat(); //Cv2.MedianBlur(newGray, filter, 9); PointEnhancement(newGray, out filter); //Mat blur = new Mat(); //Cv2.MedianBlur(filter, blur, 7); Mat edgeSobel = new Mat(); Edge(filter, out edgeSobel); Mat threshEdge = new Mat(); double t2 = Cv2.Threshold(edgeSobel, threshEdge, 0, 255, ThresholdTypes.Otsu); threshEdge = edgeSobel.Threshold(20, 255, ThresholdTypes.Binary); //Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 1)); //Mat close = new Mat(); //Cv2.MorphologyEx(threshEdge, close, MorphTypes.Close, seClose); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(11, 1)); Mat open = new Mat(); Cv2.MorphologyEx(threshEdge, open, MorphTypes.Open, seOpen); Mat sobel4 = new Mat(); Sobel(open, out sobel4); //Mat nomin = new Mat(); //GetArea(open, out nomin, 20, true); //Mat nocircle = new Mat(); //RemoveCircles(open, out nocircle); //ImageShow(edgeSobel, threshEdge, open/*, nocircle*255*/); //铜线 Mat thresh = new Mat(); thresh = gray.Threshold(0, 255, ThresholdTypes.Otsu); Mat fill = new Mat(); Fill(thresh, out fill, 255); Mat edge2 = new Mat(); Sobel(fill, out edge2); //铜内部线 Mat edge3 = new Mat(); Sobel(filter, out edge3); Mat thresh3 = edge3.Threshold(10, 255, ThresholdTypes.Binary); Mat and = new Mat(); Cv2.BitwiseAnd(thresh, thresh3, and); Mat seErode = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(15, 3)); Mat erode = new Mat(); Cv2.Erode(and, erode, seErode); Mat seOpen2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 3)); Mat open2 = new Mat(); Cv2.MorphologyEx(and, open2, MorphTypes.Open, seOpen2); Mat nomin2 = new Mat(); GetArea(open2, out nomin2, 200, true); //ImageShow( and,erode,open2,nomin2*255); //铜内部线2 Mat and2 = new Mat(); Cv2.BitwiseAnd(gray, thresh, and2); Scalar sum = and2.Sum(); int num = 0; Mat idx = new Mat(); Cv2.FindNonZero(and2, idx); num = idx.Rows; int T = (int)sum / num; Mat thresh4 = and2.Threshold(T, 255, ThresholdTypes.Binary); Mat seClose3 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); Mat close3 = new Mat(); Cv2.MorphologyEx(thresh4, close3, MorphTypes.Close, seClose3); Mat fill2 = new Mat(); Fill(close3, out fill2, 255); Mat nomin3 = new Mat(); GetArea(fill2, out nomin3, 10000, true); Mat fanse = 255 - nomin3 * 255; Mat edge4 = new Mat(); Sobel(fanse, out edge4); //ImageShow(thresh4, edge4); //最终 Mat fanse2 = 255 - thresh; Mat and3 = new Mat(); Cv2.BitwiseAnd(fanse2, sobel4, and3); result = and3 + edge2 + edge4;/*nomin2 * 255;*/ //ImageShow(result); } public void DiegouImageProcess2(Mat gray, out Mat result) { result = new Mat(); Mat filter = new Mat(); Mat junheng = new Mat(); Mat blur = new Mat(); Mat zengqiang = new Mat(); Mat edge = new Mat(); Mat thresh = new Mat(); //PointEnhancement(gray, out zengqiang); //Cv2.EqualizeHist(zengqiang, junheng); //Cv2.GaussianBlur(junheng, filter, new Size(15,15), 5, 5); ////PointEnhancement(filter, out zengqiang); //Cv2.Blur(filter, blur, new Size (3,3)); //Cv2.GaussianBlur(gray, filter, new Size(15, 15), 5, 5); Cv2.Blur(gray, blur, new Size(3, 3)); PointEnhancement(blur, out zengqiang); //Cv2.EqualizeHist(zengqiang, junheng); //ImageShow(gray, zengqiang, junheng, /*filter,*/blur); Edge(zengqiang, out edge); Mat threshEdge = edge.Threshold(30, 255, ThresholdTypes.Binary); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); Mat open = new Mat(); Cv2.MorphologyEx(threshEdge, open, MorphTypes.Open, seOpen); double t = Cv2.Threshold(gray, thresh, 0, 255, ThresholdTypes.Otsu); thresh = gray.Threshold(t - 20, 255, ThresholdTypes.Binary); Mat fill = new Mat(); Fill(thresh, out fill, 255); Mat fanse = 255 - fill; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, open, and); //Mat seOpen2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 1)); //Mat open2 = new Mat(); //Cv2.MorphologyEx(and, open2, MorphTypes.Open, seOpen2); Mat nomin = new Mat(); GetArea(and, out nomin, 500, true); gray = gray + nomin * 100; ImageShow(thresh, fill, fanse); ImageShow(and, nomin * 255, gray); //Cv2.Canny(filter, edge, 7, 0); //Mat nomin = new Mat(); //GetArea(edge, out nomin, 5, true); //ImageShow(edge, nomin * 255); //CvTrackbarCallback cvTrackbarCallback = new CvTrackbarCallback(Text); //CvTrackbarCallback cvTrackbarCallback2 = new CvTrackbarCallback(Text2); //Window window = new Window("tbar");//创建一个新窗口"tbar" //CvTrackbar cvTrackbarV = new CvTrackbar("bar1", "tbar", 25, 500, cvTrackbarCallback); //CvTrackbar cvTrackbar2 = new CvTrackbar("bar2", "tbar", 35, 500, cvTrackbarCallback2); //Cv2.WaitKey(); //void Text(int value) //{ // minValue = value; // Cv2.Canny(filter, edge, minValue, maxValue); // new Window("tbar", edge); //} //void Text2(int value) //{ // maxValue = value; // Cv2.Canny(filter, edge, minValue, maxValue); // new Window("tbar", edge); //} //CvTrackbarCallback cvTrackbarCallback = new CvTrackbarCallback(Text); //CvTrackbarCallback cvTrackbarCallback2 = new CvTrackbarCallback(Text2); //CvTrackbar cvTrackbarV = new CvTrackbar("bar1", "tbar", 25, 225, cvTrackbarCallback); //CvTrackbar cvTrackbar2 = new CvTrackbar("bar2", "tbar", 35, 225, cvTrackbarCallback2); //Cv2.WaitKey(); //void Text(int value) //{ // color = value; // Cv2.BilateralFilter(gray, filter, d, color, 3); // PointEnhancement(filter, out zengqiang); // Sobel(zengqiang, out edge); // thresh = edge.Threshold(5, 255, ThresholdTypes.Binary); // new Window("tbar", WindowMode.Normal, thresh); //} //void Text2(int value) //{ // d = value; // Cv2.BilateralFilter(gray, filter, d, color, 3); // PointEnhancement(filter, out zengqiang); // Sobel(zengqiang, out edge); // thresh = edge.Threshold(5, 255, ThresholdTypes.Binary); // new Window("tbar", WindowMode.Normal, thresh); //} } public void DiegouImageProcess3(Mat gray, out Mat result, out Mat edgeSobel) { result = new Mat(); //大致轮廓线 Mat newGray = new Mat(); Cv2.GaussianBlur(gray, newGray, new Size(11, 11), 3, 3); Mat blur = new Mat(); Cv2.Blur(newGray, blur, new Size(3, 3)); Mat filter = new Mat(); PointEnhancement(blur, out filter); edgeSobel = new Mat(); //Edge(filter, out edgeSobel); EdgeY2(filter, out edgeSobel); Mat threshEdge = new Mat(); double t2 = Cv2.Threshold(edgeSobel, threshEdge, 0, 255, ThresholdTypes.Otsu); threshEdge = edgeSobel.Threshold(80, 255, ThresholdTypes.Binary); Mat thresh = gray.Threshold(0, 255, ThresholdTypes.Otsu); Mat fill = new Mat(); Fill(thresh, out fill, 255); Mat sobel2 = new Mat(); Sobel(fill, out sobel2); Mat fanse = 255 - fill; Mat and = new Mat(); Cv2.BitwiseAnd(fanse, threshEdge, and); //ImageShow( threshEdge,sobel2, and,gray+and); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); Mat close = new Mat(); Cv2.MorphologyEx(and, close, MorphTypes.Close, seClose); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 1)); Mat open = new Mat(); Cv2.MorphologyEx(close, open, MorphTypes.Open, seOpen); Mat nomin4 = new Mat(); GetArea(open, out nomin4, 2000, true); Mat sobel4 = new Mat(); Sobel(nomin4, out sobel4); //ImageShow(open,close,nomin4*255); result = sobel4 * 100 + sobel2;/*nomin2 * 255;*/ //ImageShow(open,nomin4*255+gray ,result+gray); } public void DiegouImageProcess4(Mat gray, out Mat result) { result = new Mat(gray.Size(), gray.Type()); int middle = gray.Cols / 2; Scalar sum = new Scalar(); Scalar lastSum = new Scalar(0); byte[] cha = new byte[gray.Rows]; for (int i = 0; i < gray.Rows; i++) { sum = gray[i, i + 1, middle - 200, middle + 200].Sum(); if (i == 0) { cha[i] = 0; } else { cha[i] = (byte)Math.Abs((int)sum - (int)lastSum); } lastSum = sum; } for (int i = 0; i < gray.Rows; i++) { for (int j = 0; j < gray.Cols; j++) { result.Set(i, j, cha[i]); } } ImageShow(result); } public void DiegouOrdinates(Mat image, Mat gray, Mat edgeSobel, bool daodianbu, out List ordinates) { ordinates = new List(); Scalar sum = new Scalar(0); int middle = image.Cols / 2; image = image.Threshold(10, 1, ThresholdTypes.Binary); //Mat hierachy = new Mat(); //Mat[] contoursMat; //Cv2.FindContours(image, out contoursMat, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); Mat thresh = gray.Threshold(0, 255, ThresholdTypes.Otsu); //ImageShow(thresh); int[] y = new int[4]; int b = 0; for (int i = 0; i < thresh.Rows; i++) { sum = thresh[i, i + 1, 0, thresh.Cols].Sum(); if ((int)sum > 50) { y[0] = i; break; } } for (int i = y[0] + 50; i < thresh.Rows; i++) { sum = thresh[i, i + 1, 0, thresh.Cols].Sum(); if ((int)sum == 0) { y[1] = i; break; } } for (int i = y[1] + 50; i < thresh.Rows; i++) { sum = thresh[i, i + 1, 0, thresh.Cols].Sum(); if ((int)sum > 50) { y[2] = i; break; } } for (int i = y[2]; i < thresh.Rows; i++) { sum = thresh[i, i + 1, 0, thresh.Cols].Sum(); if ((int)sum == 0) { y[3] = i; break; } } Mat newThresh = thresh / 255; for (int j = 0; j < thresh.Cols; j++) { sum = newThresh[0, thresh.Rows, j, j + 1].Sum(); if ((int)sum > 300) { b = j; break; } } int type = 0; int[] cha = new int[] { y[1] - y[0], y[3] - y[2], y[2] - y[1] }; if ((y[1] - y[0]) > 180 && (y[3] - y[2]) > 180) { type = 1;//单独两个铜 } else if (((cha[0] > 300) && y[2] == 0 && y[3] == 0 && b < thresh.Cols / 3) || ((cha[0] > 100 && cha[0] < 180) && (cha[1] > 100 && cha[1] < 180) && (cha[2] > 150))) { type = 2;//有内部线 } if (type == 1)//当是只有两层铜的时候 { for (int i = 0; i < image.Rows - 20; i++) { sum = image[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 150) { int newOrdinate = i; ordinates.Add(newOrdinate /*+ 10*/); i += 150; } } if (ordinates.Count <= 3) { ordinates.Clear(); for (int i = 0; i < image.Rows - 20; i++) { sum = image[i, i + 5, middle - 100, middle + 100].Sum(); if ((int)sum > 150) { int newOrdinate = i; ordinates.Add(newOrdinate /*+ 10*/); i += 150; } } } } else if (type == 2) { Mat threshEdge = edgeSobel.Threshold(180, 255, ThresholdTypes.Binary); Mat fanse = 255 - threshEdge; //ImageShow(threshEdge, fanse); for (int i = 0; i < image.Rows - 20; i++) { sum = image[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 150) { int newOrdinate = i; ordinates.Add(newOrdinate + 10); i += 30; } } for (int i = ordinates[0]; i < ordinates[0] + 30; i++) { sum = fanse[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 50) { ordinates.Insert(1, i + 7); break; } } for (int i = ordinates[0] + 40; i < ordinates[2]; i++) { sum = threshEdge[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 150) { ordinates.Insert(2, i + 10); break; } } for (int i = ordinates[0] + 350; i < threshEdge.Rows; i++) { sum = threshEdge[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > 150) { ordinates.Insert(5, i + 12); break; } } for (int i = ordinates[6] - 15; i > 0; i--) { sum = fanse[i - 2, i, middle - 100, middle + 100].Sum(); if ((int)sum > 50) { ordinates.Insert(6, i - 7); break; } } } else { int t = 2; for (int i = 0; i < image.Rows - 20; i++) { if (ordinates.Count == 0 && daodianbu) t = 180; else t = 150; sum = image[i, i + 2, middle - 100, middle + 100].Sum(); if ((int)sum > t) { int newOrdinate = i; ordinates.Add(newOrdinate + 5); i += 30; //if (ordinates.Count == 1) // i += 10; //else // i += 30; } } ordinates[0] += 5; //ordinates[1] -= 5; Mat threshEdge = edgeSobel.Threshold(40, 1, ThresholdTypes.Binary); //ImageShow(threshEdge * 255); if (daodianbu) { for (int i = ordinates[0] - 40; i < ordinates[0] - 10; i++) { sum = threshEdge[i, i + 2, middle - 50, middle + 50].Sum(); if ((int)sum > 75) { int newOrdinate = i; ordinates.Insert(0, i); break; } } for (int i = ordinates[ordinates.Count - 1] + 40; i > ordinates[ordinates.Count - 1] + 10; i--) { sum = threshEdge[i - 2, i, middle - 50, middle + 50].Sum(); if ((int)sum > 75) { int newOrdinate = i; ordinates.Add(i); break; } } } //for (int i = ordinates[ordinates.Count-1] + 40; i > ordinates[ordinates.Count-1] + 5&&i 100) // { // int newOrdinate = i; // ordinates.Add(newOrdinate /*+ 10*/); // break; // } //} //for (int i = ordinates[0] - 40; i < ordinates[0] - 5; i++) //{ // sum = image[i , i+5, middle - 100, middle + 100].Sum(); // if ((int)sum > 100) // { // ordinates.Insert(0, i); // break; // } //} if (ordinates.Count <= 3) { ordinates.Clear(); for (int i = 0; i < image.Rows - 20; i++) { sum = image[i, i + 5, middle - 100, middle + 100].Sum(); if ((int)sum > 150) { int newOrdinate = i; ordinates.Add(newOrdinate /*+ 10*/); i += 150; } } } } } public void DieGouTopBottom(Mat gray, out int ordinate, int[] range, string direction) { ordinate = 0; Mat crop = gray[range[0], range[1], gray.Cols / 2 - 100, gray.Cols / 2 + 100].Clone(); Cv2.GaussianBlur(crop, crop, new Size(11, 11), 5, 5); Mat edgeSobel = new Mat(); EdgeY(crop, out edgeSobel); Mat threshEdge = new Mat(); double t2 = Cv2.Threshold(edgeSobel, threshEdge, 0, 255, ThresholdTypes.Otsu); threshEdge = edgeSobel.Threshold(15, 255, ThresholdTypes.Binary); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); Mat close = new Mat(); Cv2.MorphologyEx(threshEdge, close, MorphTypes.Close, seClose); close = close / 255; Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); Mat open = new Mat(); Cv2.MorphologyEx(close, open, MorphTypes.Open, seOpen); GetArea(open, out close, 1000, true); Mat result = close.Clone(); //ImageShow(crop, edgeSobel, threshEdge, result * 255); Scalar sum = new Scalar(0); switch (direction) { case "top": for (int i = 0; i < crop.Rows - 10; i++) { sum = result[i, i + 2, 0, result.Cols].Sum(); if ((int)sum > 100) { ordinate = i; break; } } break; case "bottom": for (int i = crop.Rows - 1; i > 2; i--) { sum = result[i - 2, i, 0, result.Cols].Sum(); if ((int)sum > 100) { ordinate = i; break; } } break; } } //锡膏 //锡膏H public void XigaoKaikouXiangnei(Mat gray, int[] dataArea, int start, out int[] leftShangOrdinates, out int[] rightShangOrdinates, out int[] leftXiaOrdinates, out int[] rightXiaOrdinates) { leftShangOrdinates = new int[3]; rightShangOrdinates = new int[3]; leftXiaOrdinates = new int[3]; rightXiaOrdinates = new int[3]; #region//找上下边界 int[] leftExtractionRange = new int[2]; int[] rightExtractionRange = new int[2]; Mat thresh = new Mat(); double t = Cv2.Threshold(gray, thresh, 0, 1, ThresholdTypes.Otsu); thresh = gray.Threshold(t - 30, 1, ThresholdTypes.Binary); //ImageShow(thresh * 255); Scalar sum = new Scalar(); Mat result1 = thresh.Clone(); //for (int i = start; i < result1.Rows; i++)//左侧上界 //{ // sum = result1[i, i + 1, dataArea[1]-350, dataArea[1] - 100].Sum(); // if ((int)sum > 100) // { // leftExtractionRange[0] = i; // break; // } //} for (int i = start; i < result1.Rows; i++)//左侧上界 { //sum = result1[i, i + 1, dataArea[1] - 350, dataArea[1] - 100].Sum(); if (result1.Get(i, dataArea[1] - 100) > 0) { leftExtractionRange[0] = i; break; } } for (int i = leftExtractionRange[0] + 50; i < result1.Rows; i++)//左侧下界 { sum = result1[i, i + 1, dataArea[1] - 200, dataArea[1] - 100].Sum(); if ((int)sum == 0) { leftExtractionRange[1] = i; break; } } //for (int i = start; i < result1.Rows; i++)//右侧上界 //{ // sum = result1[i, i + 1, dataArea[2] + 100, dataArea[2]+350].Sum(); // if ((int)sum > 100) // { // rightExtractionRange[0] = i; // break; // } //} for (int i = start; i < result1.Rows; i++)//右侧上界 { //sum = result1[i, i + 1, dataArea[2] + 100, dataArea[2] + 350].Sum(); if (result1.Get(i, dataArea[2] + 100) > 0) { rightExtractionRange[0] = i; break; } } for (int i = rightExtractionRange[0] + 50; i < result1.Rows; i++)//右侧下界 { sum = result1[i, i + 1, dataArea[2] + 100, dataArea[2] + 200].Sum(); if ((int)sum == 0) { rightExtractionRange[1] = i; break; } } //LineShow(gray, dataArea[1], leftExtractionRange[0], dataArea[1], leftExtractionRange[1]); //LineShow(gray, dataArea[2], rightExtractionRange[0], dataArea[2], rightExtractionRange[1]); //ImageShow(gray); #endregion #region//找质量好的位置 int[] maxSpacing = new int[2]; Scalar max = new Scalar(0); for (int j = dataArea[1] - 300; j < dataArea[1]; j += 40) { sum = result1[leftExtractionRange[0], leftExtractionRange[1], j - 20, j + 20].Sum(); if ((int)max < (int)sum) { max = sum; maxSpacing[0] = j; } } max = new Scalar(0); for (int j = dataArea[2]; j < dataArea[2] + 300; j += 40) { sum = result1[rightExtractionRange[0], rightExtractionRange[1], j - 20, j + 20].Sum(); if ((int)max < (int)sum) { max = sum; maxSpacing[1] = j; } } //LineShow(gray, dataArea[0], start, dataArea[1], start); //LineShow(gray, dataArea[2], start, dataArea[3], start); //LineShow(gray, maxSpacing[0], leftExtractionRange[0], maxSpacing[0], leftExtractionRange[1]); //LineShow(gray, maxSpacing[1], rightExtractionRange[0], maxSpacing[1], rightExtractionRange[1]); //ImageShow(gray); #endregion Mat sobel = new Mat(); Sobel(thresh, out sobel); Mat nomin = new Mat(); GetArea(sobel, out nomin, 500, true); Mat result = nomin.Clone(); #region//左上 for (int i = leftExtractionRange[0] - 30; i < leftExtractionRange[0]; i++) { sum = result[i, i + 1, dataArea[1] - 350, dataArea[1] - 100].Sum(); if ((int)sum > 0) { leftShangOrdinates[1] = i; break; } } //if (leftExtractionRange[0] - leftShangOrdinates[1] < 5) // leftShangOrdinates[1] = 0; if (leftShangOrdinates[1] != 0) { for (int j = dataArea[1] - 350; j < dataArea[1] - 100; j++) { if (result.Get(leftShangOrdinates[1], j) > 0) { leftShangOrdinates[0] = j; leftShangOrdinates[2] = leftExtractionRange[0]; break; } } } #endregion #region //右上 for (int i = rightExtractionRange[0] - 30; i < rightExtractionRange[0]; i++) { sum = result[i, i + 1, dataArea[2] + 100, dataArea[2] + 350].Sum(); if ((int)sum > 0) { rightShangOrdinates[1] = i; break; } } //if (rightExtractionRange[0] - rightShangOrdinates[1] < 5) // rightShangOrdinates[1] = 0; if (rightShangOrdinates[1] != 0) { for (int j = dataArea[2] + 100; j < dataArea[2] + 350; j++) { if (result.Get(rightShangOrdinates[1], j) > 0) { rightShangOrdinates[0] = j; rightShangOrdinates[2] = rightExtractionRange[0]; break; } } } #endregion Mat zengqiang = new Mat(); PointEnhancement(gray, out zengqiang); Mat sobel2 = new Mat(); //EdgeY2(gray, out sobel2); EdgeY2(zengqiang, out sobel2); Mat thresh2 = new Mat(); thresh2 = sobel2.Threshold(200, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[0], 0, 1, thresh2.Rows), new Scalar(0), -1); Cv2.Rectangle(thresh2, new Rect(maxSpacing[1], 0, 1, thresh2.Rows), new Scalar(0), -1); Mat nomin2 = new Mat(); GetArea(thresh2, out nomin2, 50, true); Mat result2 = nomin2.Clone(); //ImageShow(nomin2 * 255); #region//左下 int compensate = 5; for (int i = leftExtractionRange[0] + 20; i < leftExtractionRange[1] - 20; i++) { sum = result2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[1] = i; break; } } for (int i = leftXiaOrdinates[1] + 20; i < leftExtractionRange[1] - 20; i++) { sum = result2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[2] = i; break; } } leftXiaOrdinates[0] = maxSpacing[0]; leftXiaOrdinates[1] += compensate; #endregion #region//右下 for (int i = rightExtractionRange[0] + 20; i < rightExtractionRange[1] - 20; i++) { sum = result2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[1] = i; break; } } for (int i = rightXiaOrdinates[1] + 20; i < rightExtractionRange[1] - 20; i++) { sum = result2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[2] = i; break; } } rightXiaOrdinates[0] = maxSpacing[1]; rightXiaOrdinates[1] += compensate; #endregion #region//下层迭代 if (leftXiaOrdinates[2] == 0 || rightXiaOrdinates[2] == 0) { int leftThresh = 200, rightThresh = 200; while (leftXiaOrdinates[2] == 0) { if (leftThresh == 0) break; leftThresh -= 10; thresh2 = sobel2.Threshold(leftThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[0], 0, 1, thresh2.Rows), new Scalar(0), -1); GetArea(thresh2, out nomin2, 500, true); for (int i = leftXiaOrdinates[1] + 20; i < leftExtractionRange[1] - 10; i++) { sum = nomin2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[2] = i; break; } } } while (rightXiaOrdinates[2] == 0) { if (rightThresh == 0) break; rightThresh -= 10; thresh2 = sobel2.Threshold(rightThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[1], 0, 1, thresh2.Rows), new Scalar(0), -1); GetArea(thresh2, out nomin2, 500, true); for (int i = rightXiaOrdinates[1] + 20; i < rightExtractionRange[1] - 10; i++) { sum = nomin2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[2] = i; break; } } } } #endregion if (leftShangOrdinates[2] - leftShangOrdinates[1] < 5) { leftShangOrdinates[0] = 0; leftShangOrdinates[1] = 0; leftShangOrdinates[2] = 0; } if (rightShangOrdinates[2] - rightShangOrdinates[1] < 5) { rightShangOrdinates[0] = 0; rightShangOrdinates[1] = 0; rightShangOrdinates[2] = 0; } //LineShow(gray, leftXiaOrdinates[0], leftXiaOrdinates[1], leftXiaOrdinates[0], leftXiaOrdinates[2]); //LineShow(gray, rightXiaOrdinates[0], rightXiaOrdinates[1], rightXiaOrdinates[0], rightXiaOrdinates[2]); //ImageShow(gray); } public void XigaoYouheikuai(Mat gray, int[] dataArea, int start, out int[] leftShangOrdinates, out int[] rightShangOrdinates, out int[] leftXiaOrdinates, out int[] rightXiaOrdinates) { leftShangOrdinates = new int[3]; rightShangOrdinates = new int[3]; leftXiaOrdinates = new int[3]; rightXiaOrdinates = new int[3]; #region//提取上下边界与黑框边界 int[] leftExtractionRange = new int[2]; int[] rightExtractionRange = new int[2]; int[] blackBorder = new int[2]; Mat thresh = new Mat(); double t = Cv2.Threshold(gray, thresh, 0, 1, ThresholdTypes.Otsu); thresh = gray.Threshold(t - 30, 1, ThresholdTypes.Binary); Scalar sum = new Scalar(); Mat result1 = thresh.Clone(); for (int i = start; i < result1.Rows; i++)//左侧上界 { sum = result1[i, i + 1, dataArea[0], dataArea[1] - 100].Sum(); if ((int)sum > 100) { leftExtractionRange[0] = i; break; } } for (int i = leftExtractionRange[0]; i < result1.Rows; i++)//左侧下界 { sum = result1[i, i + 1, dataArea[0], dataArea[1] - 100].Sum(); if ((int)sum == 0) { leftExtractionRange[1] = i; break; } } for (int i = start; i < result1.Rows; i++)//右侧上界 { sum = result1[i, i + 1, dataArea[2] + 100, dataArea[3]].Sum(); if ((int)sum > 100) { rightExtractionRange[0] = i; break; } } for (int i = rightExtractionRange[0]; i < result1.Rows; i++)//右侧下界 { sum = result1[i, i + 1, dataArea[2] + 100, dataArea[3]].Sum(); if ((int)sum == 0) { rightExtractionRange[1] = i; break; } } Mat sobel = new Mat(); Sobel(gray, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(10, 1, ThresholdTypes.Binary); Mat nomin4 = new Mat(); GetArea(threshSobel, out nomin4, 500, true); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat open = new Mat(); Cv2.MorphologyEx(threshSobel, open, MorphTypes.Open, seOpen); //ImageShow(threshSobel*255, nomin4 * 255); Mat result2 = nomin4.Clone(); for (int j = dataArea[0]; j < dataArea[1]; j++)//提取左黑块边界 { sum = result2[leftExtractionRange[0] - 100, leftExtractionRange[0] - 10, j, j + 1].Sum(); if ((int)sum > 20) { blackBorder[0] = j; break; } } for (int j = dataArea[3]; j > dataArea[2]; j--)//提取右黑块边界 { sum = result2[rightExtractionRange[0] - 100, rightExtractionRange[0] - 10, j - 1, j].Sum(); if ((int)sum > 20) { blackBorder[1] = j; break; } } //LineShow(gray, dataArea[0], leftExtractionRange[0], dataArea[0], leftExtractionRange[1]); //LineShow(gray, dataArea[2], rightExtractionRange[0], dataArea[2], rightExtractionRange[1]); //LineShow(gray, blackBorder[0], leftExtractionRange[0] - 100, blackBorder[0], leftExtractionRange[0] - 10); //LineShow(gray, blackBorder[1], rightExtractionRange[0] - 100, blackBorder[1], rightExtractionRange[0] - 10); //ImageShow(gray, threshSobel * 255,open*255); #endregion Mat thresh2 = new Mat(); thresh2 = gray.Threshold(t - 30, 1, ThresholdTypes.Binary); Mat sobel2 = new Mat(); Sobel(thresh2, out sobel2); Mat nomin3 = new Mat(); GetArea(sobel2, out nomin3, 500, true); Mat result3 = nomin3.Clone(); //ImageShow(nomin3 * 255); #region//左上 for (int i = leftExtractionRange[0] - 30; i < leftExtractionRange[0]; i++) { sum = result3[i, i + 1, dataArea[0], blackBorder[0]].Sum(); if ((int)sum > 0) { leftShangOrdinates[1] = i; break; } } if (leftShangOrdinates[1] != 0) { for (int j = dataArea[0]; j < blackBorder[0]; j++) { if (result3.Get(leftShangOrdinates[1], j) > 0) { leftShangOrdinates[0] = j; leftShangOrdinates[2] = leftExtractionRange[0]; break; } } } #endregion #region//右上 for (int i = rightExtractionRange[0] - 30; i < rightExtractionRange[0]; i++) { sum = result3[i, i + 1, blackBorder[1], dataArea[3]].Sum(); if ((int)sum > 0) { rightShangOrdinates[1] = i; break; } } if (rightShangOrdinates[1] != 0) { for (int j = blackBorder[1]; j < dataArea[3]; j++) { if (result3.Get(rightShangOrdinates[1], j) > 0) { rightShangOrdinates[0] = j; rightShangOrdinates[2] = rightExtractionRange[0]; break; } } } #endregion //LineShow(gray, leftShangOrdinates[0], leftShangOrdinates[1], leftShangOrdinates[0], leftShangOrdinates[2]); //LineShow(gray, rightShangOrdinates[0], rightShangOrdinates[1], rightShangOrdinates[0], rightShangOrdinates[2]); //ImageShow(gray, sobel2 * 255); #region //提取最大间距的位置 int[] maxSpacing = new int[2]; Scalar max = new Scalar(0); for (int j = blackBorder[0]; j < dataArea[1]; j += 40) { sum = result1[leftExtractionRange[0], leftExtractionRange[1], j - 20, j + 20].Sum(); if ((int)max < (int)sum) { max = sum; maxSpacing[0] = j; } } max = new Scalar(0); for (int j = dataArea[2]; j < blackBorder[1]; j += 40) { sum = result1[rightExtractionRange[0], rightExtractionRange[1], j - 20, j + 20].Sum(); if ((int)max < (int)sum) { max = sum; maxSpacing[1] = j; } } //LineShow(gray, maxSpacing[0], leftExtractionRange[0], maxSpacing[0], leftExtractionRange[1]); //LineShow(gray, maxSpacing[1], rightExtractionRange[0], maxSpacing[1], rightExtractionRange[1]); //ImageShow(gray); #endregion Mat sobel3 = new Mat(); EdgeY2(gray, out sobel3); Mat thresh3 = new Mat(); thresh3 = sobel3.Threshold(200, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh3, new Rect(maxSpacing[0], 0, 1, thresh3.Rows), new Scalar(0), -1); Cv2.Rectangle(thresh3, new Rect(maxSpacing[1], 0, 1, thresh3.Rows), new Scalar(0), -1); Mat nomin2 = new Mat(); GetArea(thresh3, out nomin2, 500, true); //ImageShow(gray, thresh3 * 255,nomin2*255,gray+nomin2*100); #region//左下 int compensate = 5; Mat result4 = nomin2.Clone(); for (int i = leftExtractionRange[0] + 20; i < leftExtractionRange[1] - 20; i++) { sum = result4[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[1] = i; break; } } for (int i = leftXiaOrdinates[1] + 20; i < leftExtractionRange[1] - 20; i++) { sum = result4[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[2] = i; break; } } leftXiaOrdinates[0] = maxSpacing[0]; leftXiaOrdinates[1] += compensate; #endregion #region//右下 for (int i = rightExtractionRange[0] + 20; i < rightExtractionRange[1] - 20; i++) { sum = result4[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[1] = i; break; } } for (int i = rightXiaOrdinates[1] + 20; i < rightExtractionRange[1] - 20; i++) { sum = result4[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[2] = i; break; } } rightXiaOrdinates[0] = maxSpacing[1]; rightXiaOrdinates[1] += compensate; #endregion #region//下层迭代 if (leftXiaOrdinates[2] == 0 || rightXiaOrdinates[2] == 0) { int leftThresh = 200, rightThresh = 200; while (leftXiaOrdinates[2] == 0) { if (leftThresh == 0) break; leftThresh -= 10; thresh3 = sobel3.Threshold(leftThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh3, new Rect(maxSpacing[0], 0, 1, thresh3.Rows), new Scalar(0), -1); GetArea(thresh3, out nomin2, 500, true); for (int i = leftXiaOrdinates[1] + 20; i < leftExtractionRange[1] - 20; i++) { sum = nomin2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[2] = i; break; } } } while (rightXiaOrdinates[2] == 0) { if (rightThresh == 0) break; rightThresh -= 10; thresh3 = sobel3.Threshold(rightThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh3, new Rect(maxSpacing[1], 0, 1, thresh3.Rows), new Scalar(0), -1); GetArea(thresh3, out nomin2, 500, true); for (int i = rightXiaOrdinates[1] + 20; i < rightExtractionRange[1] - 20; i++) { sum = nomin2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[2] = i; break; } } } } #endregion //LineShow(gray, leftXiaOrdinates[0], leftXiaOrdinates[1], leftXiaOrdinates[0], leftXiaOrdinates[2]); //LineShow(gray, rightXiaOrdinates[0], rightXiaOrdinates[1], rightXiaOrdinates[0], rightXiaOrdinates[2]); //ImageShow(gray,nomin2*255); } public void XigaoXiangShangWanqu(Mat gray, int[] dataArea, int start, out int[] leftShangOrdinates, out int[] rightShangOrdinates, out int[] leftXiaOrdinates, out int[] rightXiaOrdinates) { leftShangOrdinates = new int[3]; rightShangOrdinates = new int[3]; leftXiaOrdinates = new int[3]; rightXiaOrdinates = new int[3]; #region//上下边界 int[] leftExtractionRange = new int[2]; int[] rightExtractionRange = new int[2]; Mat thresh = new Mat(); double t = Cv2.Threshold(gray, thresh, 0, 1, ThresholdTypes.Otsu); thresh = gray.Threshold(t - 30, 1, ThresholdTypes.Binary); //ImageShow(thresh * 255); Scalar sum = new Scalar(); Mat result1 = thresh.Clone(); for (int i = start + 300; i < result1.Rows; i++)//左侧上界 { //sum = result1[i, i + 1, dataArea[1] - 350, dataArea[1] - 100].Sum(); if (result1.Get(i, dataArea[1] + 50) > 0) { leftExtractionRange[0] = i; break; } } for (int i = leftExtractionRange[0] + 50; i < result1.Rows; i++)//左侧下界 { sum = result1[i, i + 1, dataArea[1] - 200, dataArea[1] - 100].Sum(); if ((int)sum == 0) { leftExtractionRange[1] = i; break; } } for (int i = start + 300; i < result1.Rows; i++)//右侧上界 { //sum = result1[i, i + 1, dataArea[2] + 100, dataArea[2] + 350].Sum(); if (result1.Get(i, dataArea[2] - 50) > 0) { rightExtractionRange[0] = i; break; } } for (int i = rightExtractionRange[0] + 50; i < result1.Rows; i++)//右侧下界 { sum = result1[i, i + 1, dataArea[2] + 100, dataArea[2] + 200].Sum(); if ((int)sum == 0) { rightExtractionRange[1] = i; break; } } //LineShow(gray, dataArea[1] + 50, leftExtractionRange[0], dataArea[1] + 50, leftExtractionRange[1]); //LineShow(gray, dataArea[2] - 50, rightExtractionRange[0], dataArea[2] - 50, rightExtractionRange[1]); //ImageShow(gray); #endregion #region//找质量好的位置 int[] maxSpacing = new int[2]; Scalar max = new Scalar(0); for (int j = dataArea[1] - 250; j < dataArea[1]; j += 40) { sum = result1[leftExtractionRange[0], leftExtractionRange[1], j - 20, j + 20].Sum(); if ((int)max < (int)sum) { max = sum; maxSpacing[0] = j; } } max = new Scalar(0); for (int j = dataArea[2]; j < dataArea[2] + 250; j += 40) { sum = result1[rightExtractionRange[0], rightExtractionRange[1], j - 20, j + 20].Sum(); if ((int)max < (int)sum) { max = sum; maxSpacing[1] = j; } } //LineShow(gray, dataArea[0], start, dataArea[1], start); //LineShow(gray, dataArea[2], start, dataArea[3], start); //LineShow(gray, maxSpacing[0], leftExtractionRange[0], maxSpacing[0], leftExtractionRange[1]); //LineShow(gray, maxSpacing[1], rightExtractionRange[0], maxSpacing[1], rightExtractionRange[1]); //ImageShow(gray); #endregion #region//左上 for (int i = leftExtractionRange[0] - 50; i < leftExtractionRange[0]; i++) { sum = thresh[i, i + 1, dataArea[1] - 350, dataArea[1] - 100].Sum(); if ((int)sum > 0) { leftShangOrdinates[1] = i; break; } } if (leftShangOrdinates[1] != 0) { for (int j = dataArea[1] - 350; j < dataArea[1] - 100; j++) { if (thresh.Get(leftShangOrdinates[1], j) > 0) { leftShangOrdinates[0] = j; leftShangOrdinates[2] = leftExtractionRange[0]; break; } } } #endregion #region //右上 for (int i = rightExtractionRange[0] - 50; i < rightExtractionRange[0]; i++) { sum = thresh[i, i + 1, dataArea[2] + 100, dataArea[2] + 350].Sum(); if ((int)sum > 0) { rightShangOrdinates[1] = i; break; } } //if (rightExtractionRange[0] - rightShangOrdinates[1] < 5) // rightShangOrdinates[1] = 0; if (rightShangOrdinates[1] != 0) { for (int j = dataArea[2] + 100; j < dataArea[2] + 350; j++) { if (thresh.Get(rightShangOrdinates[1], j) > 0) { rightShangOrdinates[0] = j; rightShangOrdinates[2] = rightExtractionRange[0]; break; } } } #endregion //LineShow(gray, leftShangOrdinates[0], leftShangOrdinates[1], leftShangOrdinates[0], leftShangOrdinates[2]); //LineShow(gray, rightShangOrdinates[0], rightShangOrdinates[1], rightShangOrdinates[0], rightShangOrdinates[2]); //ImageShow(gray); Mat zengqiang = new Mat(); PointEnhancement(gray, out zengqiang); Mat sobel2 = new Mat(); //EdgeY2(gray, out sobel2); EdgeY2(zengqiang, out sobel2); Mat thresh2 = new Mat(); thresh2 = sobel2.Threshold(200, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[0], 0, 1, thresh2.Rows), new Scalar(0), -1); Cv2.Rectangle(thresh2, new Rect(maxSpacing[1], 0, 1, thresh2.Rows), new Scalar(0), -1); Mat nomin2 = new Mat(); GetArea(thresh2, out nomin2, 50, true); Mat result2 = nomin2.Clone(); //ImageShow(nomin2 * 255); #region//左下 int compensate = 5; for (int i = leftExtractionRange[0] + 20; i < leftExtractionRange[1] - 40; i++) { sum = result2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[1] = i; break; } } for (int i = leftXiaOrdinates[1] + 20; i < leftExtractionRange[1] - 20; i++) { sum = result2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[2] = i; break; } } leftXiaOrdinates[0] = maxSpacing[0]; leftXiaOrdinates[1] += compensate; #endregion #region//右下 for (int i = rightExtractionRange[0] + 20; i < rightExtractionRange[1] - 40; i++) { sum = result2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[1] = i; break; } } for (int i = rightXiaOrdinates[1] + 20; i < rightExtractionRange[1] - 20; i++) { sum = result2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[2] = i; break; } } rightXiaOrdinates[0] = maxSpacing[1]; rightXiaOrdinates[1] += compensate; #endregion #region//下层迭代 if (leftXiaOrdinates[1] < 10 || rightXiaOrdinates[1] < 10) { int leftThresh = 200, rightThresh = 200; while (leftXiaOrdinates[1] < 10) { if (leftThresh == 0) break; leftThresh -= 10; thresh2 = sobel2.Threshold(leftThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[0], 0, 1, thresh2.Rows), new Scalar(0), -1); GetArea(thresh2, out nomin2, 500, true); for (int i = leftExtractionRange[0] + 20; i < leftExtractionRange[1] - 30; i++) { sum = nomin2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[1] = i; break; } } } for (int i = leftXiaOrdinates[1] + 20; i < leftExtractionRange[1] - 10; i++) { sum = result2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[2] = i; break; } } while (rightXiaOrdinates[1] < 10) { if (rightThresh == 0) break; rightThresh -= 10; thresh2 = sobel2.Threshold(rightThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[1], 0, 1, thresh2.Rows), new Scalar(0), -1); GetArea(thresh2, out nomin2, 500, true); for (int i = rightExtractionRange[0] + 20; i < rightExtractionRange[1] - 30; i++) { sum = nomin2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[1] = i; break; } } } for (int i = rightXiaOrdinates[1] + 20; i < rightExtractionRange[1] - 10; i++) { sum = result2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[2] = i; break; } } } if (leftXiaOrdinates[2] == 0 || rightXiaOrdinates[2] == 0) { int leftThresh = 200, rightThresh = 200; while (leftXiaOrdinates[2] == 0) { if (leftThresh == 0) break; leftThresh -= 10; thresh2 = sobel2.Threshold(leftThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[0], 0, 1, thresh2.Rows), new Scalar(0), -1); GetArea(thresh2, out nomin2, 500, true); for (int i = leftXiaOrdinates[1] + 20; i < leftExtractionRange[1] - 10; i++) { sum = nomin2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[2] = i; break; } } } while (rightXiaOrdinates[2] == 0) { if (rightThresh == 0) break; rightThresh -= 10; thresh2 = sobel2.Threshold(rightThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[1], 0, 1, thresh2.Rows), new Scalar(0), -1); GetArea(thresh2, out nomin2, 500, true); for (int i = rightXiaOrdinates[1] + 20; i < rightExtractionRange[1] - 10; i++) { sum = nomin2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[2] = i; break; } } } } #endregion //LineShow(gray, leftXiaOrdinates[0], leftXiaOrdinates[1], leftXiaOrdinates[0], leftXiaOrdinates[2]); //LineShow(gray, rightXiaOrdinates[0], rightXiaOrdinates[1], rightXiaOrdinates[0], rightXiaOrdinates[2]); //ImageShow(gray); } public void XigaoXiangXiaWanqu(Mat gray, int[] dataArea, int start, out int[] leftShangOrdinates, out int[] rightShangOrdinates, out int[] leftXiaOrdinates, out int[] rightXiaOrdinates) { leftShangOrdinates = new int[3]; rightShangOrdinates = new int[3]; leftXiaOrdinates = new int[3]; rightXiaOrdinates = new int[3]; #region//上下边界 int[] leftExtractionRange = new int[2]; int[] rightExtractionRange = new int[2]; Mat thresh = new Mat(); double t = Cv2.Threshold(gray, thresh, 0, 1, ThresholdTypes.Otsu); thresh = gray.Threshold(t - 30, 1, ThresholdTypes.Binary); //ImageShow(thresh * 255); Scalar sum = new Scalar(); Mat result1 = thresh.Clone(); for (int i = start + 300; i < result1.Rows; i++)//左侧上界 { //sum = result1[i, i + 1, dataArea[1] - 350, dataArea[1] - 100].Sum(); if (result1.Get(i, dataArea[1] - 50) > 0) { leftExtractionRange[0] = i; break; } } for (int i = leftExtractionRange[0] + 50; i < result1.Rows; i++)//左侧下界 { sum = result1[i, i + 1, dataArea[0], dataArea[1] - 100].Sum(); if ((int)sum < 100) { leftExtractionRange[1] = i; break; } } for (int i = start + 300; i < result1.Rows; i++)//右侧上界 { //sum = result1[i, i + 1, dataArea[2] + 100, dataArea[2] + 350].Sum(); if (result1.Get(i, dataArea[2] + 50) > 0) { rightExtractionRange[0] = i; break; } } for (int i = rightExtractionRange[0] + 50; i < result1.Rows; i++)//右侧下界 { sum = result1[i, i + 1, dataArea[2] + 100, dataArea[3]].Sum(); if ((int)sum < 100) { rightExtractionRange[1] = i; break; } } //LineShow(gray, dataArea[1] + 50, leftExtractionRange[0], dataArea[1] + 50, leftExtractionRange[1]); //LineShow(gray, dataArea[2] - 50, rightExtractionRange[0], dataArea[2] - 50, rightExtractionRange[1]); //ImageShow(gray); #endregion #region//找质量好的位置 int[] maxSpacing = new int[2]; Scalar max = new Scalar(0); for (int j = dataArea[1] - 300; j < dataArea[1]; j += 40) { sum = result1[leftExtractionRange[0], leftExtractionRange[1], j - 20, j + 20].Sum(); if ((int)max < (int)sum) { max = sum; maxSpacing[0] = j; } } max = new Scalar(0); for (int j = dataArea[2]; j < dataArea[2] + 300; j += 40) { sum = result1[rightExtractionRange[0], rightExtractionRange[1], j - 20, j + 20].Sum(); if ((int)max < (int)sum) { max = sum; maxSpacing[1] = j; } } //LineShow(gray, dataArea[0], start, dataArea[1], start); //LineShow(gray, dataArea[2], start, dataArea[3], start); //LineShow(gray, maxSpacing[0], leftExtractionRange[0], maxSpacing[0], leftExtractionRange[1]); //LineShow(gray, maxSpacing[1], rightExtractionRange[0], maxSpacing[1], rightExtractionRange[1]); //ImageShow(gray); #endregion //Mat zengqiang = new Mat(); //PointEnhancement(gray, out zengqiang); Mat sobel3 = new Mat(); EdgeY2(gray, out sobel3); Mat thresh3 = new Mat(); thresh3 = sobel3.Threshold(200, 1, ThresholdTypes.Binary); Mat nomin3 = new Mat(); GetArea(thresh3, out nomin3, 500, true); //ImageShow(thresh3 * 255,nomin3*255); Mat result3 = nomin3.Clone(); #region//左上 for (int i = leftExtractionRange[0] - 50; i < result3.Rows; i++) { if (result3.Get(i, dataArea[1] - 250) > 0) { leftShangOrdinates[1] = i; break; } } for (int i = leftShangOrdinates[1] + 50; i > leftShangOrdinates[1] + 5; i--) { if (result3.Get(i, dataArea[1] - 200) > 0) { leftShangOrdinates[2] = i; break; } } if (leftShangOrdinates[2] != 0) leftShangOrdinates[0] = dataArea[1] - 250; #endregion #region//右上 for (int i = rightExtractionRange[0] - 50; i < result3.Rows; i++) { if (result3.Get(i, dataArea[2] + 250) > 0) { rightShangOrdinates[1] = i; break; } } for (int i = rightShangOrdinates[1] + 50; i > rightShangOrdinates[1] + 5; i--) { if (result3.Get(i, dataArea[2] + 200) > 0) { rightShangOrdinates[2] = i; break; } } if (rightShangOrdinates[2] != 0) rightShangOrdinates[0] = dataArea[2] + 250; #endregion maxSpacing[0] = dataArea[1] - 100; maxSpacing[1] = dataArea[2] + 100; //LineShow(gray, leftShangOrdinates[0], leftShangOrdinates[1], leftShangOrdinates[0], leftShangOrdinates[2]); //LineShow(gray, rightShangOrdinates[0], rightShangOrdinates[1], rightShangOrdinates[0], rightShangOrdinates[2]); //LineShow(gray, maxSpacing[0], leftExtractionRange[0], maxSpacing[0], leftExtractionRange[1]); //LineShow(gray, maxSpacing[1], rightExtractionRange[0], maxSpacing[1], rightExtractionRange[1]); //ImageShow(gray); Mat zengqiang = new Mat(); PointEnhancement(gray, out zengqiang); Mat sobel2 = new Mat(); EdgeY2(gray, out sobel2); //EdgeY2(zengqiang, out sobel2); //Sobel(zengqiang, out sobel2); Mat thresh2 = new Mat(); thresh2 = sobel2.Threshold(200, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[0], 0, 1, thresh2.Rows), new Scalar(0), -1); Cv2.Rectangle(thresh2, new Rect(maxSpacing[1], 0, 1, thresh2.Rows), new Scalar(0), -1); Cv2.Rectangle(thresh2, new Rect(0, 0, thresh2.Cols, leftExtractionRange[0]), new Scalar(0), -1); Cv2.Rectangle(thresh2, new Rect(0, leftExtractionRange[1] + 20, thresh2.Cols, thresh2.Rows - leftExtractionRange[1] - 20), new Scalar(0), -1); Mat nomin2 = new Mat(); GetArea(thresh2, out nomin2, 10, true); Mat result2 = nomin2.Clone(); //ImageShow(thresh2*255, nomin2 * 255,nomin2*100+gray); #region//左下 int compensate = 5; for (int i = leftExtractionRange[0] + 20; i < leftExtractionRange[1] - 40; i++) { sum = result2[i, i + 1, maxSpacing[0] - 10, maxSpacing[0] + 10].Sum(); if ((int)sum > 10) { leftXiaOrdinates[1] = i; break; } } for (int i = leftXiaOrdinates[1] + 20; i < leftExtractionRange[1] - 20; i++) { sum = result2[i, i + 1, maxSpacing[0] - 10, maxSpacing[0] + 10].Sum(); if ((int)sum > 10) { leftXiaOrdinates[2] = i; break; } } leftXiaOrdinates[0] = maxSpacing[0]; leftXiaOrdinates[1] += compensate; #endregion #region//右下 for (int i = rightExtractionRange[0] + 20; i < rightExtractionRange[1] - 40; i++) { sum = result2[i, i + 1, maxSpacing[1] - 10, maxSpacing[1] + 10].Sum(); if ((int)sum > 20) { rightXiaOrdinates[1] = i; break; } } for (int i = rightXiaOrdinates[1] + 20; i < rightExtractionRange[1] - 20; i++) { sum = result2[i, i + 1, maxSpacing[1] - 10, maxSpacing[1] + 10].Sum(); if ((int)sum > 10) { rightXiaOrdinates[2] = i; break; } } rightXiaOrdinates[0] = maxSpacing[1]; rightXiaOrdinates[1] += compensate; #endregion #region//下层迭代 if (leftXiaOrdinates[1] < 10 || rightXiaOrdinates[1] < 10) { int leftThresh = 200, rightThresh = 200; while (leftXiaOrdinates[1] < 10) { if (leftThresh == 0) break; leftThresh -= 10; thresh2 = sobel2.Threshold(leftThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[0], 0, 1, thresh2.Rows), new Scalar(0), -1); GetArea(thresh2, out nomin2, 500, true); for (int i = leftExtractionRange[0] + 20; i < leftExtractionRange[1] - 30; i++) { sum = nomin2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[1] = i; break; } } } for (int i = leftXiaOrdinates[1] + 20; i < leftExtractionRange[1] - 10; i++) { sum = result2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[2] = i; break; } } while (rightXiaOrdinates[1] < 10) { if (rightThresh == 0) break; rightThresh -= 10; thresh2 = sobel2.Threshold(rightThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[1], 0, 1, thresh2.Rows), new Scalar(0), -1); GetArea(thresh2, out nomin2, 500, true); for (int i = rightExtractionRange[0] + 20; i < rightExtractionRange[1] - 30; i++) { sum = nomin2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[1] = i; break; } } } for (int i = rightXiaOrdinates[1] + 20; i < rightExtractionRange[1] - 10; i++) { sum = result2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[2] = i; break; } } } if (leftXiaOrdinates[2] == 0 || rightXiaOrdinates[2] == 0) { int leftThresh = 200, rightThresh = 200; while (leftXiaOrdinates[2] == 0) { if (leftThresh == 0) break; leftThresh -= 10; thresh2 = sobel2.Threshold(leftThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[0], 0, 1, thresh2.Rows), new Scalar(0), -1); GetArea(thresh2, out nomin2, 500, true); for (int i = leftXiaOrdinates[1] + 20; i < leftExtractionRange[1] - 10; i++) { sum = nomin2[i, i + 1, maxSpacing[0] - 20, maxSpacing[0] + 20].Sum(); if ((int)sum > 20) { leftXiaOrdinates[2] = i; break; } } } while (rightXiaOrdinates[2] == 0) { if (rightThresh == 0) break; rightThresh -= 10; thresh2 = sobel2.Threshold(rightThresh, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh2, new Rect(maxSpacing[1], 0, 1, thresh2.Rows), new Scalar(0), -1); GetArea(thresh2, out nomin2, 500, true); for (int i = rightXiaOrdinates[1] + 20; i < rightExtractionRange[1] - 10; i++) { sum = nomin2[i, i + 1, maxSpacing[1] - 20, maxSpacing[1] + 20].Sum(); if ((int)sum > 20) { rightXiaOrdinates[2] = i; break; } } } } #endregion //LineShow(gray, leftShangOrdinates[0], leftShangOrdinates[1], leftShangOrdinates[0], leftShangOrdinates[2]); //LineShow(gray, rightShangOrdinates[0], rightShangOrdinates[1], rightShangOrdinates[0], rightShangOrdinates[2]); //LineShow(gray, leftXiaOrdinates[0], leftXiaOrdinates[1], leftXiaOrdinates[0], leftXiaOrdinates[2]); //LineShow(gray, rightXiaOrdinates[0], rightXiaOrdinates[1], rightXiaOrdinates[0], rightXiaOrdinates[2]); //ImageShow(gray); } public void GetXigaoArea0(Mat image, out int[] dataArea, out int start) { dataArea = new int[4]; start = 0; Scalar leftMax = new Scalar(0); Scalar rightMax = new Scalar(0); int thresh1 = 120, thresh2 = 200; for (int j = 0; j < image.Cols; j++) { leftMax = image[0, image.Rows, j, j + 1].Sum(); if ((int)leftMax > thresh1) { dataArea[0] = j; break; } } for (int j = dataArea[0]; j < image.Cols; j++) { leftMax = image[0, image.Rows, j, j + 1].Sum(); if ((int)leftMax > thresh2) { dataArea[1] = j; break; } } for (int j = image.Cols - 1; j > 0; j--) { rightMax = image[0, image.Rows, j - 1, j].Sum(); if ((int)rightMax > thresh1) { dataArea[3] = j; break; } } for (int j = dataArea[3]; j > 0; j--) { rightMax = image[0, image.Rows, j - 1, j].Sum(); if ((int)rightMax > thresh2) { dataArea[2] = j; break; } } Scalar sum = new Scalar(0); for (int i = 0; i < image.Rows; i++) { sum = image[i, i + 1, dataArea[0], dataArea[3]].Sum(); if ((int)sum > 0) { start = i; break; } } } public void GetXigaoArea(Mat image, out int[] dataArea, out int start) { dataArea = new int[4]; start = 0; Scalar leftMax = new Scalar(0); Scalar rightMax = new Scalar(0); int thresh1 = 140, thresh2 = 300; for (int j = 0; j < image.Cols; j++) { leftMax = image[0, image.Rows, j, j + 1].Sum(); if ((int)leftMax > thresh1) { dataArea[0] = j; break; } } for (int j = dataArea[0]; j < image.Cols; j++) { leftMax = image[0, image.Rows, j, j + 1].Sum(); if ((int)leftMax > thresh2) { dataArea[1] = j; break; } } for (int j = image.Cols - 1; j > 0; j--) { rightMax = image[0, image.Rows, j - 1, j].Sum(); if ((int)rightMax > thresh1) { dataArea[3] = j; break; } } for (int j = dataArea[3]; j > 0; j--) { rightMax = image[0, image.Rows, j - 1, j].Sum(); if ((int)rightMax > thresh2) { dataArea[2] = j; break; } } Scalar sum = new Scalar(0); for (int i = 0; i < image.Rows; i++) { sum = image[i, i + 1, dataArea[0], dataArea[3]].Sum(); if ((int)sum > 0) { start = i; break; } } } /// /// 判断正向黑块是否突出 /// /// 原图 /// 二值图 /// 黑块是否突出,true:突出;false:不突出; /// 提取区域 /// 上像素边界 /// public void HeiKuai(Mat image, Mat contour, out bool tuchu, int[] dataArea, int start, out int[] Hang) { tuchu = new bool(); Scalar sum = new Scalar(0); Hang = new int[4]; Mat imageBlur = new Mat(); Cv2.GaussianBlur(image, imageBlur, new Size(11, 11), 5, 5);//模糊 int minThresh = 18; int maxThresh = 20; Mat edge = new Mat(); Cv2.Canny(imageBlur, edge, minThresh, maxThresh);//边缘检测 ////闭运算 Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat close = new Mat(); Cv2.MorphologyEx(edge, edge, MorphTypes.Close, se); //new Window("edge", WindowMode.Normal, edge * 255); //左侧 for (int i = start; i < edge.Rows; i++)//求左边缘检测图行 { sum = edge[i, i + 1, 500, dataArea[1] - 50].Sum(); if ((int)sum > 255) { Hang[0] = i; break; } } for (int i = start; i < contour.Rows; i++)//求左二值图行 { sum = contour[i, i + 1, 500, dataArea[1] - 50].Sum(); if ((int)sum > 5) { Hang[1] = i; break; } } for (int i = start; i < edge.Rows; i++)//求右边缘检测图行 { sum = edge[i, i + 1, dataArea[2] + 50, dataArea[3] - 200].Sum(); if ((int)sum > 255) { Hang[2] = i; break; } } for (int i = start; i < contour.Rows; i++)//求右二值图行 { sum = contour[i, i + 1, dataArea[2] + 50, dataArea[3] - 200].Sum(); if ((int)sum > 5) { Hang[3] = i; break; } } if (Hang[1] - Hang[0] > 20 & Hang[3] - Hang[2] > 20) { tuchu = true; } else { tuchu = false; } } public void Heikuai2(Mat gray, int start, int[] dataArea, out bool tuchu) { tuchu = false; #region//測試 //Mat thresh4 = new Mat(); //double t3 = Cv2.Threshold(gray, thresh4, 0, 1, ThresholdTypes.Otsu); //Mat sobel4 = new Mat(); //Sobel(thresh4, out sobel4); //Mat zengqiang2 = new Mat(); //Cv2.EqualizeHist(gray, zengqiang2); ////ceju.ImageShow(sobel2 * 255); //CvTrackbarCallback cvTrackbarCallback = new CvTrackbarCallback(Text); //Window window = new Window("tbar", WindowMode.Normal);//创建一个新窗口"tbar" //CvTrackbar cvTrackbarV = new CvTrackbar("bar1", "tbar", 100, 255, cvTrackbarCallback); //Cv2.WaitKey(); //void Text(int value) //{ // //thresh4 = gray.Threshold(t3 - value, 1, ThresholdTypes.Binary); // //sobel4 = new Mat(); // //ceju.Sobel(thresh4, out sobel4); // //new Window("tbar", WindowMode.Normal, sobel4 * 255); // //EdgeY(zengqiang2, out sobel4); // Sobel(gray, out sobel4); // thresh4 = sobel4.Threshold(value, 1, ThresholdTypes.Binary); // new Window("tbar", WindowMode.Normal, thresh4 * 255); //} #endregion Scalar sum = new Scalar(); Mat thresh2 = new Mat(); double t = Cv2.Threshold(gray, thresh2, 0, 1, ThresholdTypes.Otsu); thresh2 = gray.Threshold(t - 30, 1, ThresholdTypes.Binary); Mat sobel2 = new Mat(); Sobel(thresh2, out sobel2); Mat result2 = sobel2.Clone(); int leftStart = 0; for (int i = start - 300; i < result2.Rows; i++) { sum = result2[i, i + 1, dataArea[0], dataArea[1]].Sum(); if ((int)sum > 50) { leftStart = i; break; } } Mat sobel = new Mat(); Sobel(gray, out sobel); Mat thresh = new Mat(); thresh = sobel.Threshold(10, 1, ThresholdTypes.Binary); Cv2.Rectangle(thresh, new Rect(dataArea[1] - 50, 0, thresh.Cols - dataArea[1] + 100, thresh.Rows), new Scalar(0), -1); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); Mat close = new Mat(); Cv2.MorphologyEx(thresh, close, MorphTypes.Close, seClose); //ImageShow(close * 255); Mat nomin = new Mat(); GetArea(close, out nomin, 100, true); Mat result1 = nomin.Clone(); //ImageShow(nomin * 255); int heixian = 0; for (int i = start + 300; i < leftStart; i++) { sum = result1[i, i + 1, dataArea[0], dataArea[1]].Sum(); if ((int)sum > 30) { heixian = i; break; } } //LineShow(gray, 0, leftStart, gray.Cols, leftStart); //LineShow(gray, 0, heixian, gray.Cols, heixian); //ImageShow(gray); if ((leftStart - heixian) > 30 && heixian != 0) tuchu = true; } public void Heikuai3(Mat gray, int start, int[] dataArea, out bool tuchu) { tuchu = false; Mat thresh = new Mat(); double t = Cv2.Threshold(gray, thresh, 0, 1, ThresholdTypes.Otsu); thresh = gray.Threshold(t - 30, 1, ThresholdTypes.Binary); Mat result1 = thresh.Clone(); Mat sobel = new Mat(); Sobel(gray, out sobel); Mat threshSobel = new Mat(); threshSobel = sobel.Threshold(10, 1, ThresholdTypes.Binary); Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat open = new Mat(); Cv2.MorphologyEx(threshSobel, open, MorphTypes.Open, seOpen); //Mat nomin = new Mat(); //GetArea(open, out nomin, 500, true); Mat result2 = open.Clone(); //ImageShow(result2 * 255); int leftStart = 0; Scalar sum = new Scalar(0); for (int i = start + 300; i < result1.Rows; i++) { sum = result1[i, i + 1, dataArea[0], dataArea[1] - 100].Sum(); if ((int)sum > 20) { leftStart = i; break; } } //LineShow(gray, dataArea[1] - 400, leftStart - 100, dataArea[1] - 100, leftStart - 10); //ImageShow(gray, result2 * 255,result1*255); int leftBlackBorder = 0; for (int j = dataArea[1] - 400; j < dataArea[1] - 100; j++) { sum = result2[leftStart - 100, leftStart - 10, j, j + 1].Sum(); if ((int)sum > 20) { leftBlackBorder = j; break; } } if (leftBlackBorder != 0) tuchu = true; } //判断是否弯曲 public void WanQu(Mat contour, out bool wanQu, int[] dataArea, int start, out int[] a) { a = new int[3]; wanQu = new bool(); //int max=new int(); for (int i = start; i < contour.Rows; i++) { if (contour.Get(i, dataArea[1] - 150) > 0) { a[0] = i; break; } } for (int i = start; i < contour.Rows; i++) { if (contour.Get(i, dataArea[1] - 50) > 0) { a[1] = i; break; } } //int[] zongzuobiao = new int[150 - 51]; int[] zongzuobiao = new int[dataArea[1] - dataArea[0] - 200]; int count = 0; //for (int j = dataArea[1] - 149; j < dataArea[1] - 51; j++) for (int j = dataArea[0] + 100; j < dataArea[1] - 100; j++) { for (int i = start; i < contour.Rows; i++) { if (contour.Get(i, j) > 0) { zongzuobiao[count] = i; count++; break; } } } int max = zongzuobiao.Max(); int min = zongzuobiao.Min(); int idxMax = 0, idxMin = 0; for (int i = 0; i < zongzuobiao.Length; i++) { if (zongzuobiao[i] == max) idxMax = i; if (zongzuobiao[i] == min) idxMin = i; } //判断是否在中间 if (idxMax > zongzuobiao.Length / 3 && idxMax < zongzuobiao.Length / 3 * 2) { wanQu = false; } else { wanQu = true; } } public void WanQu2(Mat gray, out bool wanQu, int[] dataArea, int start, out int[] a) { a = new int[3]; wanQu = false; int leftStart = 0; Mat thresh = new Mat(); double t = Cv2.Threshold(gray, thresh, 0, 1, ThresholdTypes.Otsu); thresh = gray.Threshold(t - 30, 1, ThresholdTypes.Binary); for (int i = start + 300; i < thresh.Rows; i++) { if (thresh.Get(i, dataArea[1] + 50) > 0) { leftStart = i; break; } } Scalar sum = new Scalar(); for (int i = start + 300; i < leftStart; i++) { sum = thresh[i, i + 1, dataArea[1] - 200, dataArea[1] - 100].Sum(); if ((int)sum > 0) { wanQu = true; } } //LineShow(gray, dataArea[1] + 50, leftStart, dataArea[1] + 50, start); //ImageShow(gray,thresh*255); } public void youCexiangsu(Mat contour, out bool cunzai, out int lowrow, out int[] zuidalie, int[] dataArea) { cunzai = new bool(); zuidalie = new int[2]; lowrow = new int(); //左最大列 Scalar max = new Scalar(0); for (int j = 0; j < contour.Cols / 2; j++) { Scalar sum = new Scalar(0); sum = contour[0, contour.Rows, j, j + 1].Sum(); if ((int)sum > (int)max) { max = sum; zuidalie[0] = j; } } ////右最大列 //Scalar max1 = new Scalar(0); //for (int j = contour.Cols; j > contour.Cols / 2; j--) //{ // Scalar sum = new Scalar(0); // sum = contour[0, contour.Rows, j-1, j].Sum(); // if ((int)sum > (int)max1) // { // max1 = sum; // zuidalie[1] = j; // } //} //左底行 for (int i = 0; i < contour.Rows; i++) { if (contour.Get(i, dataArea[1] - 150) > 0) { lowrow = i; break; } } Scalar sum1 = new Scalar(0); sum1 = contour[0, lowrow - 150, zuidalie[0] + 100, zuidalie[0] + 101].Sum(); //Console.WriteLine(sum1); if ((int)sum1 > 0) { cunzai = true; } else { cunzai = false; } } /// /// 计算锡膏的上层坐标 /// /// 二值图 /// 红色通道增强后图 /// 左边上层坐标,0:横坐标;1:上纵坐标;2:下纵坐标 /// 右边上层坐标,0:横坐标;1:上纵坐标;2:下纵坐标 /// 上界 /// 数据提取区域 public void Shang(Mat contour, Mat filter, out int[] leftShang, out int[] rightShang, int upperBorder, int[] dataArea) { leftShang = new int[3];//0:横坐标;1:上纵坐标;2:下纵坐标 rightShang = new int[3]; Scalar sum = new Scalar(0); //左侧 for (int i = upperBorder; i < contour.Rows; i++)//求上纵坐标 { sum = contour[i, i + 1, dataArea[0], dataArea[1] - 50].Sum(); if ((int)sum > 0) { leftShang[1] = i; break; } } for (int j = dataArea[1] - 50; j > dataArea[0]; j--)//求横坐标 { if (contour.Get(leftShang[1], j) > 0) { leftShang[0] = j; break; } } Mat cropLeft = filter[leftShang[1] + 2, leftShang[1] + 20, leftShang[0] - 1, leftShang[0] + 1].Clone(); Mat threshLeft = cropLeft.Threshold(0, 1, ThresholdTypes.Otsu); for (int i = 0; i < threshLeft.Rows; i++)//求下纵坐标 { sum = threshLeft[i, i + 1, 0, threshLeft.Cols].Sum(); if ((int)sum == 0) { leftShang[2] = i + leftShang[1] + 2; break; } } //右侧 for (int i = upperBorder; i < contour.Rows; i++)//求上纵坐标 { sum = contour[i, i + 1, dataArea[2] + 50, dataArea[3]].Sum(); if ((int)sum > 0) { rightShang[1] = i; break; } } for (int j = dataArea[2] + 50; j < dataArea[3]; j++)//求横坐标 { if (contour.Get(rightShang[1], j) > 0) { rightShang[0] = j; break; } } Mat cropRight = filter[rightShang[1] + 2, rightShang[1] + 20, rightShang[0] - 1, rightShang[0] + 1].Clone(); Mat threshRight = cropRight.Threshold(0, 1, ThresholdTypes.Otsu); for (int i = 0; i < threshRight.Rows; i++)//求下纵坐标 { sum = threshRight[i, i + 1, 0, threshRight.Cols].Sum(); if ((int)sum == 0) { rightShang[2] = i + rightShang[1] + 2; break; } } } /// /// 计算锡膏下层坐标 /// /// 原图 /// 二值图 /// 左边坐标,0:横坐标;1:上纵坐标;2:下纵坐标 /// 右边坐标,0:横坐标;1:上纵坐标;2:下纵坐标 /// 提取区域 /// 左边上层,leftShangOrdinate[1] /// 右边上层,rightShangOrdinate[1] public void Xia(Mat image, Mat contour, out int[] leftXia, out int[] rightXia, int[] dataArea, int leftUpper, int rightUpper) { leftXia = new int[3]; rightXia = new int[3]; //leftXia[0] = dataArea[1] - 50; //rightXia[0] = dataArea[2] + 50; //找下界 Scalar sum = new Scalar(0); int leftLower = 0, rightLower = 0; for (int i = leftUpper; i < contour.Rows; i++) { sum = contour[i, i + 1, dataArea[0], dataArea[1]].Sum(); if ((int)sum == 0) { leftLower = i; break; } } for (int i = rightUpper; i < contour.Rows; i++) { sum = contour[i, i + 1, dataArea[2], dataArea[3]].Sum(); if ((int)sum == 0) { rightLower = i; break; } } //找到中间画线处,局部最大值 int rangeInside = 30; int rangeOutside = 100; Scalar max = new Scalar(0); for (int j = dataArea[0] + rangeOutside; j < dataArea[1] - rangeInside; j++) { sum = contour[leftUpper + 20, leftLower - 5, j, j + 50].Sum(); if ((int)sum > (int)max) { leftXia[0] = j + 25; max = sum; } } max = 0; for (int j = dataArea[2] + rangeInside; j < dataArea[3] - rangeInside; j++) { sum = contour[rightUpper + 20, rightLower - 5, j, j + 50].Sum(); if ((int)sum > (int)max) { max = sum; rightXia[0] = j + 25; } } //边缘检测 int minThresh = 30; int maxThresh = 55; Mat edge = new Mat(); Cv2.Canny(image, edge, minThresh, maxThresh); Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Mat close = new Mat(); Cv2.MorphologyEx(edge, close, MorphTypes.Close, se); Mat se2 = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); Mat erode = new Mat(); Cv2.Erode(close, erode, se2); //ImageShow(edge,close,erode); erode = erode / 255; //计算高度 for (int i = leftUpper + 20; i < leftLower - 5; i++)//左边坐标上层 { sum = erode[i, i + 1, leftXia[0] - 10, leftXia[0] + 10].Sum(); if ((int)sum > 5) { leftXia[1] = i; break; } } for (int i = leftXia[1] + 10; i < leftLower - 5; i++)//左边坐标下层 { sum = erode[i, i + 1, leftXia[0] - 10, leftXia[0] + 10].Sum(); if ((int)sum > 10) { leftXia[2] = i; break; } } for (int i = rightUpper + 20; i < rightLower - 5; i++)//右边坐标上层 { sum = erode[i, i + 1, rightXia[0] - 10, rightXia[0] + 10].Sum(); if ((int)sum > 10) { rightXia[1] = i; break; } } for (int i = rightXia[1] + 10; i < rightLower - 5; i++)//右边坐标下层 { sum = erode[i, i + 1, rightXia[0] - 10, rightXia[0] + 10].Sum(); if ((int)sum > 5) { rightXia[2] = i; break; } } //Mat cropLeft = erode[leftUpper + 20, leftLower - 5, leftXia[0] - 10, leftXia[0] + 10].Clone(); //Mat cropRight = erode[rightUpper + 20, rightLower - 5, rightXia[0] - 10, rightXia[0] + 10].Clone(); //ImageShow(cropLeft, cropRight); //CvTrackbarCallback cvTrackbarCallback = new CvTrackbarCallback(Text); //CvTrackbarCallback cvTrackbarCallback2 = new CvTrackbarCallback(Text2); //Window window = new Window("tbar");//创建一个新窗口"tbar" //CvTrackbar cvTrackbarV = new CvTrackbar("bar1", "tbar", 20, 100, cvTrackbarCallback); //CvTrackbar cvTrackbar2 = new CvTrackbar("bar2", "tbar", 50, 100, cvTrackbarCallback2); //Cv2.WaitKey(); //LineShow(image, leftXia[0], leftXia[1], leftXia[0], leftXia[2]); //LineShow(image, rightXia[0], rightXia[1], rightXia[0], rightXia[2]); //ImageShow(image); //ImageShow(threshLeft, threshRight); //ImageShow(sobelLeft, sobelRight); //void Text(int value) //{ // minThresh = value; // Cv2.Canny(image, edge, minThresh, maxThresh); // new Window("tbar", edge); //} //void Text2(int value) //{ // maxThresh = value; // Cv2.Canny(image, edge, minThresh, maxThresh); // new Window("tbar", edge); //} } /// /// 锡膏z 上面测量线的 精确计算 /// /// /// /// /// /// /// public void Xigaozhoudu_ACC_upLines(Mat gray0, out int xigaohouduY1, out int xigaohouduY2, out int existOneTwoPoint, out int xigaoTopY) { xigaohouduY1 = 0;// 30; xigaohouduY2 = 40; xigaoTopY = 0; existOneTwoPoint = 0; { int minGray = 300 * 255; int minRowIndex = 0; int minRowInStart = 0; int colEnd = gray0.Cols - 1; int curGray; List curGrayList = new List(); xigaohouduY1 = 15;// 10; for (int i = Math.Min(55/*65*//*55*/, gray0.Rows) - 5; i > xigaohouduY1; i--) { curGray = this.XigaohouduForAreaMin(gray0, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; curGrayList.Insert(0, curGray); if (curGray < minGray) { minRowIndex = i; minGray = curGray; } else if (curGray - minGray > 100/*400*//*参数调试-阈值*/) { minRowInStart = i; break; } } if (minRowIndex < 30)//继续往下多走10个像素 { minRowInStart = 0; curGrayList.Clear(); minGray = 300 * 255; for (int i = Math.Min(65/*55*/, gray0.Rows) - 5; i > xigaohouduY1; i--) { curGray = this.XigaohouduForAreaMin(gray0, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; curGrayList.Insert(0, curGray); if (curGray < minGray) { minRowIndex = i; minGray = curGray; } else if (curGray - minGray > 400/*100*//*400*//*参数调试-阈值*/) { minRowInStart = i; break; } } } if (minRowIndex < 30 && minRowInStart > 5)//继续往上走找上端点用于最后的优化,以便找到模糊的 { List upGrays = new List(); int upMinG = 300 * 255; for (int i = minRowIndex - 5; i > 5; i--) { curGray = this.XigaohouduForAreaMin(gray0, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; upGrays.Insert(0, curGray); if (curGray < minGray) { xigaoTopY = i; break; } //if (curGray < minGray) //{ // minRowIndex = i; // minGray = curGray; //} //else if (curGray - minGray > 400/*100*//*400*//*参数调试-阈值*/) //{ // minRowInStart = i; // break; //} } upMinG = upGrays.Min(); } List upGrayList = new List(); for (int i = 0; i < minRowIndex; i ++) { curGray = this.XigaohouduForAreaMin(gray0, i); upGrayList.Add(curGray); } xigaohouduY2 = minRowIndex; if (xigaohouduY2 > 30) { existOneTwoPoint = 1; } } if (false) { int minGray = 300 * 255; int minRowIndex = 0; int colEnd = gray0.Cols - 1; int curGray; List curGrayList = new List(); xigaohouduY1 = 10; for (int i = xigaohouduY1; i < Math.Min(50, gray0.Rows) - 5; i++) { int v = gray0.Row[i].CountNonZero(); if (v > colEnd / 2) { xigaohouduY1 = i; break; } } if (xigaohouduY1 < 36) { for (int i = xigaohouduY1 + 5/*10*//*5*/; i < Math.Min(55, gray0.Rows) - 5; i++) { curGray = this.XigaohouduForAreaMin(gray0, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; curGrayList.Add(curGray); if (curGray < minGray) { minRowIndex = i; minGray = curGray; } } for (int i = (minRowIndex - xigaohouduY1 - 5/*10*/) + 2; i < curGrayList.Count; i += 2) { if (Math.Abs(curGrayList[i] - minGray) < 10/*100*/) { minRowIndex += 1; } else break; } } else minRowIndex = xigaohouduY1 + 1; xigaohouduY2 = minRowIndex;// 84;// 72;// minRowIndex; } Console.WriteLine("noSharp:" + xigaohouduY2 + ";xigaohouduY1:" + xigaohouduY1 + "..."); } /// /// 锡膏z 上面测量线的 精确计算 /// /// /// /// /// /// /// public void Xigaozhoudu_ACC_upLines__0(Mat gray0, out int xigaohouduY1, out int xigaohouduY2) { xigaohouduY1 = 30; xigaohouduY2 = 40; { int minGray = 300 * 255; int minRowIndex = 0; int colEnd = gray0.Cols - 1; int curGray; List curGrayList = new List(); xigaohouduY1 = 10; for (int i = xigaohouduY1; i < Math.Min(50, gray0.Rows) - 5; i++) { int v = gray0.Row[i].CountNonZero(); if (v > colEnd / 2) { xigaohouduY1 = i; break; } } if (xigaohouduY1 < 36) { for (int i = xigaohouduY1 + 5/*10*//*5*/; i < Math.Min(55, gray0.Rows) - 5; i++) { curGray = this.XigaohouduForAreaMin(gray0, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; curGrayList.Add(curGray); if (curGray < minGray) { minRowIndex = i; minGray = curGray; } } for (int i = (minRowIndex - xigaohouduY1 - 5/*10*/) + 2; i < curGrayList.Count; i += 2) { if (Math.Abs(curGrayList[i] - minGray) < 10/*100*/) { minRowIndex += 1; } else break; } } else minRowIndex = xigaohouduY1 + 1; xigaohouduY2 = minRowIndex;// 84;// 72;// minRowIndex; } Console.WriteLine("noSharp:" + xigaohouduY2 + ";xigaohouduY1:" + xigaohouduY1 + "..."); } //获取当前行附件最暗的总和 private int XigaohouduForAreaMin(Mat gray, int rowIndex) { int areaMin = 0; for (int i = 0; i < gray.Cols; i++) { int colMin = 255; for (int j = rowIndex - 0/*1*//*Math.Max(0, rowIndex - 5)*/; j < rowIndex + 1; j++) if (gray.At(j, i) < colMin) colMin = gray.At(j, i); areaMin += colMin; } return areaMin; } /// /// 锡膏z 有开口 厚度 精确计算 /// /// /// /// /// /// /// public void Xigaozhoudu_ACC(Mat gray0, int fanghanhouduY1__0, out int fanghanhouduY1, out int fanghanhouduY1Bottom, out int minGray, out bool skipUpLine, int a = 0) { int bottomYDistance = 20;// 25;// 15;// 30; int fanghanhouduY1__noSharp = -1;// fanghanhouduY1; skipUpLine = false; { minGray = 300 * 255; int minRowIndex = 0; int colEnd = gray0.Cols - 1; int curGray; List curGrayList = new List(); fanghanhouduY1Bottom = 0; for (int i = Math.Max(0, fanghanhouduY1__0 - 4/*1*//*4*//*19*//*1*//*5*//*10*/); i < Math.Min(fanghanhouduY1__0 + bottomYDistance/*25*/, gray0.Rows) - 5; i++) { curGray = this.FanghanhouduForAreaMin(gray0, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; curGrayList.Add(curGray); if (curGray < minGray) { minRowIndex = i; fanghanhouduY1Bottom = i; minGray = curGray; } } while (minRowIndex <= 6 && minRowIndex > 1) { curGray = this.FanghanhouduForAreaMin(gray0, minRowIndex - 1); if (curGray < minGray || Math.Abs(curGray - minGray) < 10) minRowIndex -= 1; else break; } for (int i = Math.Max(0, minRowIndex - Math.Max(0, fanghanhouduY1__0 - 4)) + 2; i < curGrayList.Count; i += 2) { if (Math.Abs(curGrayList[i] - minGray) < 10/*100*/) { minRowIndex += 1; fanghanhouduY1Bottom += 2; } else break; } fanghanhouduY1__noSharp = minRowIndex;// 84;// 72;// minRowIndex; } { minGray = 300 * 255; //锐化 //Mat left_small_sharp = BinaryTools.BlurMaskFunction(left_small).CvtColor(ColorConversionCodes.BGRA2GRAY); Mat gray = BinaryTools.BlurMaskFunction(gray0.Clone()/*grayRect*/, 4f * 3.14f, 1, 10f).CvtColor(ColorConversionCodes.BGRA2GRAY); //Cv2.ImWrite(@"C:\Users\win10SSD\Desktop\BlurMask" + a + "_.jpg", gray); int minRowIndex = 0; int colEnd = gray.Cols - 1; int curGray; List curGrayList = new List(); fanghanhouduY1Bottom = 0; for (int i = Math.Max(0, fanghanhouduY1__0 - 4/*1*//*4*//*19*//*1*//*5*//*10*/); i < Math.Min(fanghanhouduY1__0 + bottomYDistance/*25*/, gray.Rows) - 5; i++) { curGray = this.FanghanhouduForAreaMin(gray, i);// (int)thresh[i - 1, i, 0, colEnd].Sum().Val0; curGrayList.Add(curGray); if (curGray < minGray) { minRowIndex = i; fanghanhouduY1Bottom = i; minGray = curGray; } } while (minRowIndex <= 6 && minRowIndex > 1) { curGray = this.FanghanhouduForAreaMin(gray0, minRowIndex - 1); if (curGray < minGray || Math.Abs(curGray - minGray) < 10) minRowIndex -= 1; else break; } for (int i = Math.Max(0, minRowIndex - Math.Max(0, fanghanhouduY1__0 - 4)) + 2; i < curGrayList.Count; i += 2) { if (Math.Abs(curGrayList[i] - minGray) < 10/*100*/) { minRowIndex += 1; fanghanhouduY1Bottom += 2; } else break; } //Console.WriteLine("fanghanhouduY1_1:" + minRowIndex); ////Cv2.ImWrite(@"C:\Users\54434\Desktop\thres_3.png", gray); fanghanhouduY1 = minRowIndex;// 84;// 72;// minRowIndex; } Console.Write("noSharp:" + fanghanhouduY1__noSharp + ";fanghanhouduY1:" + fanghanhouduY1 + "..."); if (fanghanhouduY1__noSharp < 8 && fanghanhouduY1 < 8 || fanghanhouduY1__noSharp == 1 && fanghanhouduY1 > 10) { skipUpLine = true;// false;// true; } if (Math.Abs(fanghanhouduY1__noSharp - fanghanhouduY1) < 7/* <<7 8*//* << 6 *//*5*/ || (fanghanhouduY1__noSharp - fanghanhouduY1 */ 0 && fanghanhouduY1__noSharp - fanghanhouduY1 >/*<*/ -10/*20*/)) { fanghanhouduY1 = fanghanhouduY1__noSharp; } else Console.WriteLine("fanghanhouduY1 far away from fanghanhouduY1__noSharp."); } //锡膏Z /// /// 得到锡膏Z的数据提取区域 /// /// /// /// public void GetXigaoZArea(Mat contour, Mat imageRed, out Mat resulet, out int[] dataArea, out int upperBorder, out int lowerBorder) { resulet = new Mat(); //闭运算 Mat close = new Mat(); Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(27, 27)); Cv2.MorphologyEx(contour, close, MorphTypes.Open, seClose); if ((int)close.Sum() < 200000) { seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)); Cv2.MorphologyEx(contour, close, MorphTypes.Open, seClose); } contour = close; //将中间目标区域通过掩膜弄出来 int leftBorder = 0, rightBorder = 0; upperBorder = 0; lowerBorder = 0; Scalar sum = new Scalar(0); for (int i = 0; i < contour.Rows; i++) { sum = contour[i, i + 1, 0, contour.Cols].Sum(); if ((int)sum > 200) { upperBorder = i - 20; break; } } for (int i = upperBorder + 100; i < contour.Rows; i++) { sum = contour[i, i + 1, 0, contour.Cols].Sum(); if ((int)sum < 200) { lowerBorder = i; break; } } contour = imageRed.Threshold(0, 1, ThresholdTypes.Otsu); Mat delete = contour.Clone(); Cv2.Rectangle(delete, new Rect(0, upperBorder, contour.Cols, lowerBorder - upperBorder), new Scalar(0), -1); contour = contour - delete; Mat seOpen = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); Cv2.MorphologyEx(contour, contour, MorphTypes.Open, seOpen); resulet = contour.Clone(); //选出两个目标的提取区域 dataArea = new int[4]; int middle = contour.Cols / 2; sum = contour[0, contour.Rows, middle, middle + 1].Sum(); if ((int)sum > 0) { for (int j = middle; j > 0; j--) { sum = contour[0, contour.Rows, j - 1, j].Sum(); if ((int)sum == 0) { dataArea[1] = j; break; } } for (int j = middle; j < contour.Cols; j++) { sum = contour[0, contour.Rows, j, j + 1].Sum(); if ((int)sum == 0) { dataArea[1] = j; break; } } for (int j = dataArea[1] + 10; j < contour.Cols; j++) { sum = contour[0, contour.Rows, j, j + 1].Sum(); if ((int)sum > 0) { dataArea[2] = j; break; } } for (int j = dataArea[2] + 10; j < contour.Cols; j++) { sum = contour[0, contour.Rows, j, j + 1].Sum(); if ((int)sum == 0) { dataArea[3] = j; break; } } } else { for (int j = middle; j < contour.Cols; j++) { sum = contour[0, contour.Rows, j, j + 1].Sum(); if ((int)sum > 0) { dataArea[0] = j; break; } } for (int j = dataArea[0] + 10; j < contour.Cols; j++) { sum = contour[0, contour.Rows, j, j + 1].Sum(); if ((int)sum == 0) { dataArea[1] = j; break; } } for (int j = dataArea[1] + 10; j < contour.Cols; j++) { sum = contour[0, contour.Rows, j, j + 1].Sum(); if ((int)sum > 0) { dataArea[2] = j; break; } } for (int j = dataArea[2] + 10; j < contour.Cols; j++) { sum = contour[0, contour.Rows, j, j + 1].Sum(); if ((int)sum == 0) { dataArea[3] = j; break; } } } } /// /// 得到所求的坐标 /// /// /// /// 0:横坐标;1:上纵坐标;2:下纵坐标 /// 0:横坐标;1:上纵坐标;2:下纵坐标 /// /// /// public void GetXigaoZOrdinate(Mat image, Mat contour, out int[] leftOrdinate, out int[] rightOrdinate, int upperBorder, int lowerBorder, int[] dataArea) { //边缘检测 //ceju.ImageShow(image); LineEnhancement(image, out image); //ceju.ImageShow(image); Cv2.GaussianBlur(image, image, new Size(9, 9), 3, 3); Mat edge = new Mat(); Cv2.Canny(image, edge, 20, 25); edge = edge / 255; //ceju.ImageShow(edge * 255); Mat se = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 1)); Cv2.MorphologyEx(edge, edge, MorphTypes.Close, se); //每个目标的第一条线 int leftFirstLine = 0, rightFirstLine = 0; Scalar sum = new Scalar(0); for (int i = upperBorder; i < lowerBorder; i++) { sum = contour[i, i + 1, dataArea[0], dataArea[1]].Sum(); if ((int)sum > 0) { leftFirstLine = i; break; } } for (int i = upperBorder; i < lowerBorder; i++) { sum = contour[i, i + 1, dataArea[2], dataArea[3]].Sum(); if ((int)sum > 0) { rightFirstLine = i; break; } } //通过最大值找出测距点 int leftPoint = 0, rightPoint = 0; Scalar max = new Scalar(0); int middle1 = (dataArea[0] + dataArea[1]) / 2; int middle2 = (dataArea[2] + dataArea[3]) / 2; for (int j = middle1 - 40; j < middle1 + 40; j++) { sum = contour[leftFirstLine + 20, lowerBorder, j, j + 40].Sum(); if ((int)sum > (int)max) { max = sum; leftPoint = j + 20; } } max = 0; for (int j = middle2 - 40; j < middle2 + 40; j++) { sum = contour[rightFirstLine + 20, lowerBorder, j, j + 40].Sum(); if ((int)sum > (int)max) { max = sum; rightPoint = j + 20; } } //测距 leftOrdinate = new int[3]; rightOrdinate = new int[3]; int range = 5; for (int i = leftFirstLine + 40; i < lowerBorder; i++) { sum = edge[i, i + 3, leftPoint - range - 5, leftPoint + range + 5].Sum(); if ((int)sum > 5) { leftOrdinate[1] = i; break; } } for (int i = leftOrdinate[0] + 20; i < lowerBorder; i++) { sum = edge[i, i + 3, leftPoint - range, leftPoint + range].Sum(); if ((int)sum > 5) { leftOrdinate[2] = i; break; } } for (int i = rightFirstLine + 40; i < lowerBorder; i++) { sum = edge[i, i + 3, rightPoint - range - 5, rightPoint + range + 5].Sum(); if ((int)sum > 5) { rightOrdinate[1] = i; break; } } for (int i = rightOrdinate[0] + 20; i < lowerBorder; i++) { sum = edge[i, i + 3, rightPoint - range, rightPoint + range].Sum(); if ((int)sum > 5) { rightOrdinate[2] = i; break; } } leftOrdinate[0] = leftPoint; rightOrdinate[0] = rightPoint; } public void GetXigaoZOrdinate2(Mat gray, out int[] leftUpprOrdinate, out int[] rightUpperOrdinate, out int[] leftLwerOrdinate, out int[] rightLowerOrdinate, int upperBorder, int lowerBorder, int[] dataArea) { if (upperBorder < 0) upperBorder = 0; leftUpprOrdinate = new int[3]; rightUpperOrdinate = new int[3]; leftLwerOrdinate = new int[3]; rightLowerOrdinate = new int[3]; Mat zengqiang = new Mat(); PointEnhancement(gray, out zengqiang); Mat thresh = new Mat(); double t = Cv2.Threshold(zengqiang, thresh, 0, 255, ThresholdTypes.Otsu); thresh = zengqiang.Threshold(t + 65, 1, ThresholdTypes.Binary); Scalar sum = new Scalar(0); int[] b = new int[2]; //尋找質量好的位置 for (int j = 300; j < thresh.Cols - 200; j++) { sum = thresh[upperBorder, lowerBorder, j, j + 150].Sum(); if ((int)sum > 4000) { b[0] = j; break; } } if (b[0] == 0) { for (int j = 300; j < thresh.Cols - 200; j++) { sum = thresh[upperBorder, lowerBorder, j, j + 150].Sum(); if ((int)sum > 3000) { b[0] = j; break; } } } for (int j = b[0] + 300; j < thresh.Cols - 200; j++) { sum = thresh[upperBorder, lowerBorder, j, j + 150].Sum(); if ((int)sum > 4000) { b[1] = j; break; } } if (b[1] == 0) { for (int j = b[0] + 300; j < thresh.Cols - 200; j++) { sum = thresh[upperBorder, lowerBorder, j, j + 150].Sum(); if ((int)sum > 3000) { b[1] = j; break; } } } //精確目標邊界 int[] border = new int[4]; for (int j = b[0]; j < thresh.Cols; j += 5) { sum = thresh[upperBorder, lowerBorder, j, j + 1].Sum(); if ((int)sum > 0) { border[0] = j; break; } } for (int j = border[0] + 50; j < thresh.Cols; j += 5) { sum = thresh[upperBorder, lowerBorder, j, (j + 10)>= thresh.Width ? thresh.Width-1: (j + 10)].Sum(); if ((int)sum == 0) { border[1] = j; break; } } for (int j = b[1]; j < thresh.Cols; j += 5) { sum = thresh[upperBorder, lowerBorder, j, j + 1].Sum(); if ((int)sum > 0) { border[2] = j; break; } } for (int j = border[2] + 50; j < thresh.Cols; j += 5) { sum = thresh[upperBorder, lowerBorder, j, (j + 10) >= thresh.Width ? thresh.Width - 1 : (j + 10)].Sum(); if ((int)sum == 0) { border[3] = j; break; } } //LineShow(gray, b[0], upperBorder, b[0], lowerBorder); //LineShow(gray, b[1], upperBorder, b[1], lowerBorder); //LineShow(gray, border[0], upperBorder, border[0], lowerBorder); //LineShow(gray, border[1], upperBorder, border[1], lowerBorder); //LineShow(gray, border[2], upperBorder, border[2], lowerBorder); //LineShow(gray, border[3], upperBorder, border[3], lowerBorder); //ImageShow(gray, thresh * 255); //Mat seClose = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); //Mat close = new Mat(); //Cv2.MorphologyEx(thresh, close, MorphTypes.Close, seClose); Mat sobel = new Mat(); Sobel(thresh, out sobel); Mat result = sobel.Clone(); //ImageShow(sobel * 255); int leftMiddle = (border[0] + border[1]) / 2; int rightMiddle = (border[2] + border[3]) / 2; int compensate = 5; //計算下層測量綫長度 for (int i = upperBorder + 50; i < upperBorder + 70; i++) { sum = result[i, i + 1, leftMiddle - 40<0?0: leftMiddle - 40, leftMiddle + 40].Sum(); if ((int)sum > 50) { leftLwerOrdinate[1] = i + compensate; break; } } if (leftLwerOrdinate[1] == 0) { for (int i = upperBorder + 50; i < upperBorder + 70; i++) { sum = result[i, i + 2, leftMiddle - 40 < 0 ? 0 : leftMiddle - 40, leftMiddle + 40].Sum(); if ((int)sum > 20) { leftLwerOrdinate[1] = i + compensate; break; } } } for (int i = leftLwerOrdinate[1] + 15; i < lowerBorder + 20; i++) { sum = result[i, i + 1, leftMiddle - 40 < 0 ? 0 : leftMiddle - 40, leftMiddle + 40].Sum(); if ((int)sum > 50) { leftLwerOrdinate[2] = i + compensate; break; } } if (leftLwerOrdinate[2] == 0) { for (int i = leftLwerOrdinate[1] + 20; i < lowerBorder + 20; i++) { sum = result[i, i + 1, leftMiddle - 40 < 0 ? 0 : leftMiddle - 40, leftMiddle + 40].Sum(); if ((int)sum > 20) { leftLwerOrdinate[2] = i + compensate; break; } } } leftLwerOrdinate[0] = (border[0] + border[1]) / 2; for (int i = upperBorder + 50; i < upperBorder + 70; i++) { sum = result[i, i + 1, leftMiddle - 40 < 0 ? 0 : leftMiddle - 40, rightMiddle + 40].Sum(); if ((int)sum > 50) { rightLowerOrdinate[1] = i + compensate; break; } } if (rightLowerOrdinate[1] == 0) { for (int i = upperBorder + 50; i < upperBorder + 70; i++) { sum = result[i, i + 2, leftMiddle - 40 < 0 ? 0 : leftMiddle - 40, rightMiddle + 40].Sum(); if ((int)sum > 20) { rightLowerOrdinate[1] = i + compensate; break; } } } for (int i = rightLowerOrdinate[1] + 15; i < lowerBorder + 20; i++) { sum = result[i, i + 1, leftMiddle - 40 < 0 ? 0 : leftMiddle - 40, rightMiddle + 40].Sum(); if ((int)sum > 50) { rightLowerOrdinate[2] = i + compensate; break; } } rightLowerOrdinate[0] = (border[2] + border[3]) / 2; //LineShow(gray, leftLwerOrdinate[0], leftLwerOrdinate[1], leftLwerOrdinate[0], leftLwerOrdinate[2]); //LineShow(gray, rightLowerOrdinate[0], rightLowerOrdinate[1], rightLowerOrdinate[0], rightLowerOrdinate[2]); //ImageShow(gray, sobel * 255); //計算上層測量綫距離 Mat thresh2 = zengqiang.Threshold(t - 20, 1, ThresholdTypes.Binary); Mat sobel2 = new Mat(); Sobel(thresh2, out sobel2); Mat thresh3 = zengqiang.Threshold(t - 10, 1, ThresholdTypes.Binary); Mat sobel3 = new Mat(); Sobel(thresh3, out sobel3); for (int i = upperBorder; i < lowerBorder; i++) { sum = sobel2[i, i + 1, leftMiddle - 60<0?0: leftMiddle - 60, leftMiddle + 60].Sum(); //if ((int)sum > 5) //{ // leftUpprOrdinate[1] = 0; // break; //} //else if ((int)sum > 0) { leftUpprOrdinate[1] = i; break; } } for (int i = leftUpprOrdinate[1] + 30; i > leftUpprOrdinate[1] + 7; i--) { sum = sobel3[i - 1, i, leftMiddle - 60 < 0 ? 0 : leftMiddle - 60, leftMiddle + 60].Sum(); if ((int)sum > 50) { leftUpprOrdinate[2] = i; break; } } leftUpprOrdinate[0] = (border[0] + border[1]) / 2; for (int i = upperBorder; i < lowerBorder; i++) { sum = sobel2[i, i + 1, rightMiddle - 60<0?0 : rightMiddle - 60, rightMiddle + 60].Sum(); //if ((int)sum > 5) //{ // rightUpperOrdinate[1] = 0; // break; //} //else if ((int)sum > 0) { rightUpperOrdinate[1] = i; break; } } for (int i = rightUpperOrdinate[1] + 30; i > rightUpperOrdinate[1] + 7; i--) { sum = sobel3[i - 1, i, rightMiddle - 60 < 0 ? 0 : rightMiddle - 60, rightMiddle + 60].Sum(); if ((int)sum > 50) { rightUpperOrdinate[2] = i; break; } } rightUpperOrdinate[0] = (border[2] + border[3]) / 2; //LineShow(gray, leftUpprOrdinate[0], leftUpprOrdinate[1], leftUpprOrdinate[0], leftUpprOrdinate[2]); //LineShow(gray, rightUpperOrdinate[0], rightUpperOrdinate[1], rightUpperOrdinate[0], rightUpperOrdinate[2]); //ImageShow(gray, (sobel2+sobel3) * 100,sobel3*255); if (leftUpprOrdinate[1] == 0 || leftUpprOrdinate[2] == 0) { leftUpprOrdinate[0] = 0; leftUpprOrdinate[1] = 0; leftUpprOrdinate[2] = 0; } if (rightUpperOrdinate[1] == 0 || rightUpperOrdinate[2] == 0) { rightUpperOrdinate[0] = 0; rightUpperOrdinate[1] = 0; rightUpperOrdinate[2] = 0; } if (leftUpprOrdinate[1] != 0 || rightUpperOrdinate[1] != 0) { for (int i = upperBorder - 10; i < lowerBorder; i++) { sum = sobel2[i, i + 1, leftMiddle - 60, leftMiddle + 60].Sum(); //if ((int)sum > 5) //{ // leftUpprOrdinate[1] = 0; // break; //} //else if ((int)sum > 0) { leftUpprOrdinate[1] = i; break; } } for (int i = leftUpprOrdinate[1] + 30; i > leftUpprOrdinate[1] + 7; i--) { sum = sobel3[i - 1, i, leftMiddle - 60, leftMiddle + 60].Sum(); if ((int)sum > 50) { leftUpprOrdinate[2] = i; break; } } leftUpprOrdinate[0] = (border[0] + border[1]) / 2; for (int i = upperBorder - 10; i < lowerBorder; i++) { sum = sobel2[i, i + 1, rightMiddle - 60, rightMiddle + 60].Sum(); //if ((int)sum > 5) //{ // rightUpperOrdinate[1] = 0; // break; //} //else if ((int)sum > 0) { rightUpperOrdinate[1] = i; break; } } for (int i = rightUpperOrdinate[1] + 30; i > rightUpperOrdinate[1] + 7; i--) { sum = sobel3[i - 1, i, rightMiddle - 60, rightMiddle + 60].Sum(); if ((int)sum > 50) { rightUpperOrdinate[2] = i; break; } } } //CvTrackbarCallback cvTrackbarCallback = new CvTrackbarCallback(Text); //Window window = new Window("tbar");//创建一个新窗口"tbar" //CvTrackbar cvTrackbarV = new CvTrackbar("bar1", "tbar", 0, 255, cvTrackbarCallback); //Cv2.WaitKey(); //void Text(int value) //{ // thresh = zengqiang.Threshold(t - value, 255, ThresholdTypes.Binary); // new Window("tbar", thresh); //} } //公用 /// /// 去除圓形 /// /// /// /// /// 累加器分辨率与图像分辨率的反比。默认=1 /// 检测到的圆的中心之间的最小距离。 /// 第一个方法特定的参数 /// 第二个方法特定于参数 /// 最小半径 /// 最大半径 public void RemoveCircles(Mat image1, Mat image2, out Mat result, double dp, double minDist, double param1, double param2, int minRadius, int maxRadius) { result = 1 - image2.Clone(); int range = 10; //ImageShow(result*255); //dp = 1; //minDist = 30; //param1 = 70; //param2 = 30; //minRadius = 10; //maxRadius = 60; CircleSegment[] circles = Cv2.HoughCircles(image1, HoughMethods.Gradient, dp, minDist, param1, param2, minRadius, maxRadius); for (int i = 0; i < circles.Length; i++) { Point center = (Point)circles[i].Center; int radius = (int)circles[i].Radius; //for(int j=1;j 1.8 || hengzongbi < 0.5) { Cv2.DrawContours(result, contoursMat, i, new Scalar(1)); } } } Fill(result, out result, 1); } /// /// 保留近似直线 /// /// /// public void KeepStraight(Mat image, out Mat result, out List ordinates) { result = new Mat(image.Size(), image.Type()); ordinates = new List(); Mat hierachy = new Mat(); Mat[] contoursMat; Cv2.FindContours(image, out contoursMat, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); Point[][] contours; HierarchyIndex[] hierarchyIndices; Cv2.FindContours(image, out contours, out hierarchyIndices, RetrievalModes.External, ContourApproximationModes.ApproxNone); for (int i = 0; i < contours.Count(); i++) { if (contours[i].Count() < 10) continue; else { int[] x = new int[contours[i].Count()]; int[] y = new int[contours[i].Count()]; for (int j = 0; j < contours[i].Count(); j++) { x[j] = contours[i][j].X; y[j] = contours[i][j].Y; } double maxY = y.Max(); double minY = y.Min(); double maxX = x.Max(); double minX = x.Min(); double hengzongbi = (double)((maxX - minX) / (maxY - minY)); if (hengzongbi > 20 || hengzongbi < 0.1) { Cv2.DrawContours(result, contoursMat, i, new Scalar(1)); //int newOrdinate = (int)(maxY+minY)/2; int newOrdinate = (int)minY + 5; ordinates.Add(newOrdinate); } } } //Fill(result, out result, 1); } /// /// 保留最大连通域为1,其余为0 /// /// /// public void GetMaxArea(Mat image, out Mat result) { Mat[] contours; Mat hierachy = new Mat(); Cv2.FindContours(image, out contours, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); double max_area = 0; int index = 0; for (int i = 0; i < contours.Count(); i++) { if (Cv2.ContourArea(contours[i]) > max_area) { max_area = Cv2.ContourArea(contours[i]); index = i; } } result = Mat.Zeros(image.Rows, image.Cols, image.Type()); Cv2.DrawContours(result, contours, index, new Scalar(1)); Fill(result, out result, 1); //ImageShow(image*255,result * 255); } /// /// 保留面积大于或小于某个值的连通域 /// /// /// /// /// true:大于;false:小于 public void GetArea(Mat contour, out Mat result, int value, bool compare) { result = Mat.Zeros(contour.Rows, contour.Cols, contour.Type()); Mat[] contours; Mat hierachy = new Mat(); Cv2.FindContours(contour, out contours, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); for (int i = 0; i < contours.Count(); i++) { switch (compare) { case true: if (Cv2.ContourArea(contours[i]) > value) { Cv2.DrawContours(result, contours, i, new Scalar(1)); } break; case false: if (Cv2.ContourArea(contours[i]) < value) { Cv2.DrawContours(result, contours, i, new Scalar(1)); } break; } } Fill(result, out result, 1); } public void GetAreaNoFill(Mat contour, out Mat result, int value, bool compare) { result = Mat.Zeros(contour.Rows, contour.Cols, contour.Type()); Mat[] contours; Mat hierachy = new Mat(); Cv2.FindContours(contour, out contours, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); for (int i = 0; i < contours.Count(); i++) { switch (compare) { case true: if (Cv2.ContourArea(contours[i]) > value) { Cv2.DrawContours(result, contours, i, new Scalar(1)); } break; case false: if (Cv2.ContourArea(contours[i]) < value) { Cv2.DrawContours(result, contours, i, new Scalar(1)); } break; } } //Fill(result, out result, 1); } /// /// 得到最大连通域的轮廓图 /// /// /// public void GetMaxContour(Mat image, out Mat result) { Mat[] contours; Mat hierachy = new Mat(); Cv2.FindContours(image, out contours, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); double max_area = 0; int index = 0; for (int i = 0; i < contours.Count(); i++) { if (Cv2.ContourArea(contours[i]) > max_area) { max_area = Cv2.ContourArea(contours[i]); index = i; } } result = Mat.Zeros(image.Rows, image.Cols, image.Type()); Cv2.DrawContours(result, contours, index, new Scalar(1)); } /// /// 得到图像中非零点的坐标 /// /// /// public void FindContourOrdinate(Mat image, out Point[] ordinates) { int nonZeroNumber = Cv2.CountNonZero(image); ordinates = new Point[nonZeroNumber]; int count = 0; for (int i = 0; i < image.Rows; i++) { for (int j = 0; j < image.Cols; j++) { if (image.Get(i, j) > 0) { ordinates[count].X = j; ordinates[count].Y = i; } } } } /// /// 填充图片孔洞 /// /// 输入二值图像 /// 输出图像 /// 填充像素值 public void Fill(Mat image, out Mat result, int value) { Size imageSize = image.Size(); Mat kuozhan = Mat.Zeros(imageSize.Height + 2, imageSize.Width + 2, image.Type()); image.CopyTo(kuozhan[1, imageSize.Height + 1, 1, imageSize.Width + 1]); Cv2.FloodFill(kuozhan, new Point(0, 0), new Scalar(value)); Mat crop = kuozhan[1, imageSize.Height + 1, 1, imageSize.Width + 1]; result = image + value - crop; } /// /// 对图片进行sobel边缘检测 /// /// /// public void Sobel(Mat imageContour, out Mat imageSobel) { //横向检测 Mat grad_x = new Mat(); Mat grad_x2 = new Mat(); Cv2.Sobel(imageContour, grad_x, MatType.CV_16S, 1, 0); Cv2.ConvertScaleAbs(grad_x, grad_x2); //纵向检测 Mat grad_y = new Mat(); Mat grad_y2 = new Mat(); Cv2.Sobel(imageContour, grad_y, MatType.CV_16S, 0, 1); Cv2.ConvertScaleAbs(grad_y, grad_y2); //横纵向混合平均 imageSobel = new Mat(); Cv2.AddWeighted(grad_x2, 0.5, grad_y2, 0.5, 0, imageSobel); } /// /// 比较两个数的大小 /// /// /// /// 输入选项,big,small /// 输出大值或小值 public void ChooseSize(double a, double b, string world, out double result) { result = 0; switch (world) { case "big": if (a > b) { result = a; } else { result = b; } break; case "small": if (a < b) { result = a; } else { result = b; } break; } } /// /// 判断是否有水平直线 /// /// /// 输出直线纵坐标 /// 判断区域 public void DetectStraightLine(Mat image, out int ordinate, int[] border) { /* * 得到每个连通域的坐标集 * 求每个连通域坐标集最大最小横纵坐标 * 求横纵长度 * 同时满足左右长度和上下长度的阈值条件,判定为直线 */ ordinate = 0; Mat crop = image[border[0], border[1], 0, image.Cols].Clone(); //Mat hierachy = new Mat(); //Mat[] contours; //Cv2.FindContours(crop, out contours, hierachy, RetrievalModes.External, ContourApproximationModes.ApproxNone); Point[][] contours; HierarchyIndex[] hierarchyIndices; Cv2.FindContours(crop, out contours, out hierarchyIndices, RetrievalModes.External, ContourApproximationModes.ApproxNone); Mat idx = new Mat(); for (int i = 0; i < contours.Count(); i++) { if (contours[i].Count() < 200 || contours[i].Count() > 4000) continue; else { int[] x = new int[contours[i].Count()]; int[] y = new int[contours[i].Count()]; for (int j = 0; j < contours[i].Count(); j++) { x[j] = contours[i][j].X; y[j] = contours[i][j].Y; } int maxY = y.Max(); int minY = y.Min(); int maxX = x.Max(); int minX = x.Min(); if ((maxY - minY) < 25 && (maxX - minX) > 250) { ordinate = (maxY + minY) / 2 + border[0]; break; } } } } public void LineShow(Mat image, int x1, int y1, int x2, int y2) { Point p1 = new Point(); Point p2 = new Point(); p1.X = x1; p1.Y = y1; p2.X = x2; p2.Y = y2; Scalar color = new Scalar(0, 0, 255); //颜色 Cv2.Line(image, p1, p2, color, 2, LineTypes.Link8); } /// /// 图像画线,线颜色是红色 /// /// /// /// public void LineShow(Mat image, Point point1, Point point2) { Scalar color = new Scalar(0, 0, 255); //颜色 Cv2.Line(image, point1, point2, color, 2, LineTypes.Link8); } /// /// 图像画线,线条颜色可以选择红,绿,蓝 /// /// 画线图像 /// /// /// /// /// 颜色选择,red、blue、green public void LineShow(Mat image, int x1, int y1, int x2, int y2, string colorChoose) { Point p1 = new Point(); Point p2 = new Point(); p1.X = x1; p1.Y = y1; p2.X = x2; p2.Y = y2; Scalar color = new Scalar();//颜色 switch (colorChoose) { case "blue": color = new Scalar(255, 0, 0); break; case "green": color = new Scalar(0, 255, 0); break; case "red": color = new Scalar(0, 0, 255); break; default: break; } Cv2.Line(image, p1, p2, color, 2, LineTypes.Link8); } /// /// 图像画线,线条颜色可以选择红,绿,蓝 /// /// /// /// /// 颜色选择,red、blue、green public void LineShow(Mat image, Point point1, Point point2, string colorChoose) { Scalar color = new Scalar();//颜色 switch (colorChoose) { case "blue": color = new Scalar(255, 0, 0); break; case "green": color = new Scalar(0, 255, 0); break; case "red": color = new Scalar(0, 0, 255); break; default: break; } Cv2.Line(image, point1, point2, color, 2, LineTypes.Link8); } /// /// 图片显示数字,两位小数 /// /// /// /// /// public void TextShow(Mat image, double data, int x, int y) { data = Math.Round(data, 2); Scalar color = new Scalar(255, 0, 0); Point p = new Point(); p.X = x; p.Y = y; Cv2.PutText(image, data.ToString() + "um", p, HersheyFonts.HersheyComplex, 0.8, color, 2, LineTypes.Link8); } /// /// 图像线条标记(竖向) /// /// /// /// /// public void LabelVertical(Mat image, Point point1, Point point2, double data) { double proportion = 0.2689; data = data * proportion; double middle = (point1.Y + point2.Y) / 2; LineShow(image, point1, point2, "blue"); LineShow(image, point1.X - 5, point1.Y, point1.X + 5, point1.Y, "blue"); LineShow(image, point2.X - 5, point2.Y, point2.X + 5, point2.Y, "blue"); TextShow(image, data, point1.X, (int)middle); } /// /// 图像线条标记(橫向) /// /// /// /// /// public void LabelHorizontal(Mat image, Point point1, Point point2, double data) { double proportion = 0.2689; data = data * proportion; double middle = (point1.X + point2.X) / 2; LineShow(image, point1, point2, "blue"); LineShow(image, point1.X, point1.Y - 5, point1.X, point1.Y + 5, "blue"); LineShow(image, point2.X, point2.Y - 5, point2.X, point2.Y + 5, "blue"); TextShow(image, data, (int)middle, point1.Y); } public void ImageShow(Mat image1) { new Window("image1", WindowMode.Normal, image1); Cv2.WaitKey(); } public void ImageShow(Mat image1, Mat image2) { new Window("image1", WindowMode.Normal, image1); new Window("image2", WindowMode.Normal, image2); Cv2.WaitKey(); } public void ImageShow(Mat image1, Mat image2, Mat image3) { new Window("image1", WindowMode.Normal, image1); new Window("image2", WindowMode.Normal, image2); new Window("image3", WindowMode.Normal, image3); Cv2.WaitKey(); } public void ImageShow(Mat image1, Mat image2, Mat image3, Mat image4) { new Window("image1", WindowMode.Normal, image1); new Window("image2", WindowMode.Normal, image2); new Window("image3", WindowMode.Normal, image3); new Window("image4", WindowMode.Normal, image4); Cv2.WaitKey(); } public void ImageShow(Mat image1, Mat image2, Mat image3, Mat image4, Mat image5) { new Window("image1", WindowMode.Normal, image1); new Window("image2", WindowMode.Normal, image2); new Window("image3", WindowMode.Normal, image3); new Window("image4", WindowMode.Normal, image4); new Window("image5", WindowMode.Normal, image5); Cv2.WaitKey(); } /// /// 点增强 /// /// /// public void PointEnhancement(Mat image, out Mat result) { result = new Mat(image.Size(), image.Type()); InputArray kernel = InputArray.Create(new int[3, 3] { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } }); Cv2.Filter2D(image, result, -1, kernel); Cv2.ConvertScaleAbs(result, result); } public void LineEnhancement(Mat image, out Mat result) { result = new Mat(image.Size(), image.Type()); InputArray kernel = InputArray.Create(new int[3, 3] { { -1, -1, -1 }, { 1, 5, 1 }, { -1, -1, -1 } }); Cv2.Filter2D(image, result, -1, kernel); //result += 100; Cv2.ConvertScaleAbs(result, result); } /// /// 纵向边缘检测 /// /// /// public void EdgeY(Mat image, out Mat result) { InputArray kernel1 = InputArray.Create(new int[3, 3] { { -5, -10, -5 }, { 0, 0, 0 }, { 5, 10, 5 } }); InputArray kernel2 = InputArray.Create(new int[3, 3] { { 5, 10, 5 }, { 0, 0, 0 }, { -5, -10, -5 } }); Mat result1 = new Mat(); Mat result2 = new Mat(); Cv2.Filter2D(image, result1, MatType.CV_16SC1, kernel1); Cv2.Filter2D(image, result2, MatType.CV_16SC1, kernel2); Cv2.ConvertScaleAbs(result1, result1); Cv2.ConvertScaleAbs(result2, result2); result = new Mat(); Cv2.AddWeighted(result1, 0.5, result2, 0.5, 0, result); } public void EdgeY2(Mat image, out Mat result) { InputArray kernel1 = InputArray.Create(new int[3, 9] { { -5, -5, -5, -5, -5, -5, -5, -5, -5 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 5, 5, 5, 5, 5, 5, 5, 5, 5 } }); InputArray kernel2 = InputArray.Create(new int[3, 9] { { 5, 5, 5, 5, 5, 5, 5, 5, 5 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { -5, -5, -5, -5, -5, -5, -5, -5, -5 } }); Mat result1 = new Mat(); Mat result2 = new Mat(); Cv2.Filter2D(image, result1, MatType.CV_16SC1, kernel1); Cv2.Filter2D(image, result2, MatType.CV_16SC1, kernel2); Cv2.ConvertScaleAbs(result1, result1); Cv2.ConvertScaleAbs(result2, result2); result = new Mat(); Cv2.AddWeighted(result1, 0.5, result2, 0.5, 0, result); } /// /// 横向边缘检测 /// /// /// public void EdgeX(Mat image, out Mat result) { InputArray kernel1 = InputArray.Create(new int[3, 3] { { -5, 0, 5 }, { -10, 0, 10 }, { -5, 0, 5 } }); InputArray kernel2 = InputArray.Create(new int[3, 3] { { 5, 0, -5 }, { 10, 0, -10 }, { 5, 0, -5 } }); Mat result1 = new Mat(); Mat result2 = new Mat(); Cv2.Filter2D(image, result1, MatType.CV_16SC1, kernel1); Cv2.Filter2D(image, result2, MatType.CV_16SC1, kernel2); Cv2.ConvertScaleAbs(result1, result1); Cv2.ConvertScaleAbs(result2, result2); result = new Mat(); Cv2.AddWeighted(result1, 0.5, result2, 0.5, 0, result); } /// /// 边缘检测,横向边缘检测与纵向边缘检测的均值 /// /// /// public void Edge(Mat image, out Mat result) { result = new Mat(); Mat result1 = new Mat(); Mat result2 = new Mat(); EdgeX(image, out result1); EdgeY(image, out result2); Cv2.AddWeighted(result1, 0.5, result2, 0.5, 0, result); } /// /// 求一组坐标点的平均坐标值,去掉最大横纵坐标和最小横纵坐标 /// /// /// /// public void AverOrdinate(int[] x, int[] y, out double[] averOrdinate) { averOrdinate = new double[2]; int length = x.Length; int maxX = 0, minX = 0, maxY = 0, minY = 0; maxX = x.Max(); minX = x.Min(); maxY = y.Max(); minY = y.Min(); int[] newX = new int[length - 2]; int[] newY = new int[length - 2]; bool maxTag = false; bool minTag = false; int count = 0; int zeroX = 0; int zeroY = 0; for (int i = 0; i < length; i++) { if (x[i] == maxX && maxTag == false) { maxTag = true; continue; } else if (x[i] == minX && minTag == false) { minTag = true; continue; } else if (x[i] != 0) { newX[count] = x[i]; count++; } else if (x[i] == 0) zeroX++; } maxTag = false; minTag = false; count = 0; for (int i = 0; i < length; i++) { if (y[i] == maxY && maxTag == false) { maxTag = true; continue; } else if (y[i] == minY && minTag == false) { minTag = true; continue; } else if (y[i] != 0) { newY[count] = y[i]; count++; } else if (y[i] == 0) zeroY++; } double averX = ((newX.Length - zeroX) == 0) ? 0 : newX.Sum() / (newX.Length - zeroX); double averY = ((newY.Length - zeroY) == 0) ? 0 : newY.Sum() / (newY.Length - zeroY); averOrdinate[0] = averX; averOrdinate[1] = averY; } /// /// 得到图中非零点的坐标 /// /// /// public void FindNonZeros(Mat image, out Point[] idx) { Mat thresh = image.Threshold(0, 1, ThresholdTypes.Binary); int num = (int)thresh.Sum();//不为0点的数量 idx = new Point[num]; int count = 0; for (int i = 0; i < image.Rows; i++) { if ((int)image[i, i + 1, 0, image.Cols].Sum() != 0) { for (int j = 0; j < image.Cols; j++) { if (image.Get(i, j) > 0) { idx[count].X = j; idx[count].Y = i; count++; } } } } } /// /// 得到图中非零点最左上角的坐标 /// /// /// public void FindLeftTop(Mat image, out Point leftTop) { leftTop = new Point(); Point[] idx; FindNonZeros(image, out idx); int min = 1000000; for (int i = 0; i < idx.Length; i++) { if (min > (idx[i].X + idx[i].Y)) { min = idx[i].X + idx[i].Y; leftTop.X = idx[i].X; leftTop.Y = idx[i].Y; } } } } }