/// <summary> /// /// </summary> /// <param name="image"></param> /// <param name="sides"></param> /// <returns></returns> public static FoundItem[] FindNSidedElement(System.Drawing.Bitmap image, int sides, bool debugMode = false) { List <FoundItem> itemsFound = new List <FoundItem>(); bool closed = false; using (Mat srcColor = image.ToMat()) using (Mat mOutput = new Mat(srcColor.Rows, srcColor.Cols, MatType.CV_8UC4)) using (var grey = srcColor.CvtColor(ColorConversionCodes.BGRA2GRAY)) using (var blueMask = srcColor.InRange(new Scalar(204, 72, 63), new Scalar(204, 72, 63))) { //TODO:This may need to be refactored not sure if objects that need to be disposed are missing var src = grey.SetTo(new Scalar(0, 0, 0), blueMask); int maximumTargetWidth = (int)Math.Round(srcColor.Width * .9, 0); int overAllImageArcLength = src.Width * 2 + src.Height * 2; if (debugMode) { Console.WriteLine($"overAllImageArcLength {overAllImageArcLength}"); } srcColor.CopyTo(mOutput); Cv2.FindContours( image: src, contours: out OpenCvSharp.Point[][] contours, hierarchy: out HierarchyIndex[] outputArray, mode: RetrievalModes.Tree, method: ContourApproximationModes.ApproxTC89KCOS); for (int i = 0; i < contours.Length; i++) { var mat = contours[i]; double distance = 0.01 * Cv2.ArcLength(mat, closed); var approx = Cv2.ApproxPolyDP(mat, distance, closed); double sidesLength = Cv2.ArcLength(approx, closed); if (sidesLength > 1.0 && outputArray[i].Child == -1) { if (debugMode) { Console.WriteLine($"i: {i} mat.Length:{mat.Length} sidesLength: {sidesLength} mat length {Cv2.ArcLength(mat, closed)} distance {distance}"); Console.WriteLine($"outputArray[i].Child:{outputArray[i].Child} outputArray[i].Next:{outputArray[i].Next} outputArray[i].Parent:{outputArray[i].Parent}outputArray[i].Previous: {outputArray[i].Previous}"); } string additionalDescriptor = ""; Scalar scalar = new Scalar(); scalar = Scalar.Red; Rect rect = Cv2.BoundingRect(mat); if (mat.Length == sides && rect.Width <= maximumTargetWidth) { itemsFound.Add(new FoundItem() { Arc = mat, Width = rect.Width, Height = rect.Height }); additionalDescriptor = "Target"; scalar = Scalar.Pink; if (debugMode) { Console.WriteLine("Target Found"); } } if (debugMode) { Cv2.DrawContours( mOutput, contours, contourIdx: i, color: scalar, thickness: 2, lineType: LineTypes.Link8, hierarchy: outputArray, maxLevel: 0); Point middle = new Point(); middle.X = mat[0].X + 10; middle.Y = mat[0].Y + 30; Cv2.PutText(mOutput, $"{i} {additionalDescriptor}", middle, HersheyFonts.HersheyPlain, 1.0, Scalar.Black, 2); } } } if (debugMode) { srcColor.SaveImage(@"c:\drop\source.png"); mOutput.SaveImage(@"c:\drop\moutput.png"); src.SaveImage(@"c:\drop\greyscale.png"); using (new Window("Contour Source", srcColor)) using (new Window("Contours Found", mOutput)) using (new Window("Modified grey scale", src)) Cv2.WaitKey(); } src.Dispose(); return(itemsFound.ToArray()); } }
public async void Contours(SoftwareBitmap input, SoftwareBitmap output, Algorithm algorithm) { if (algorithm.AlgorithmName == "Contours") { using Mat mInput = SoftwareBitmap2Mat(input); using Mat mOutput = new Mat(mInput.Rows, mInput.Cols, MatType.CV_8UC4); mInput.CopyTo(mOutput); using Mat gray = mInput.CvtColor(ColorConversionCodes.BGRA2GRAY); using Mat edges = gray.Canny((double)algorithm.AlgorithmProperties[6].CurrentValue, (double)algorithm.AlgorithmProperties[7].CurrentValue); Cv2.FindContours( image: edges, contours: out OpenCvSharp.Point[][] contours, hierarchy: out HierarchyIndex[] outputArray, mode: (RetrievalModes)algorithm.AlgorithmProperties[0].CurrentValue, method: (ContourApproximationModes)algorithm.AlgorithmProperties[1].CurrentValue, offset: (Point)algorithm.AlgorithmProperties[2].CurrentValue); int maxLen = 0; int maxIdx = -1; for (int i = 0; i < contours.Length; i++) { if (contours[i].Length > maxLen) { maxIdx = i; maxLen = contours[i].Length; } if (contours[i].Length > (int)algorithm.AlgorithmProperties[8].CurrentValue) { Cv2.DrawContours( mOutput, contours, contourIdx: i, color: (Scalar)algorithm.AlgorithmProperties[3].CurrentValue, thickness: (int)algorithm.AlgorithmProperties[4].CurrentValue, lineType: (LineTypes)algorithm.AlgorithmProperties[5].CurrentValue, hierarchy: outputArray, maxLevel: 0); } } if (maxIdx != -1) { var res = Cv2.ApproxPolyDP(contours[maxIdx], 1, true); //Cv2.DrawContours( // mOutput, // contours, // maxIdx, // (Scalar)algorithm.algorithmProperties[3].CurrentValue, // (int)algorithm.algorithmProperties[4].CurrentValue, // (LineTypes)algorithm.algorithmProperties[5].CurrentValue, // outputArray, // 0); ////return Cv2.ContourArea(res); } Mat2SoftwareBitmap(mOutput, output); // Must run on UI thread. The winrt container also needs to be set. if (App.container != null) { await App.container.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { Cv2.ImShow("Contours", mOutput); }); } } }
/// <summary> /// 对外函数,用于识别一个图片 detect one frame /// </summary> /// <param name="frame">一个彩色图片; a RGB picture</param> /// <returns>一个ArrayList,包含结果;results of detections</returns> public ArrayList detect(Mat frame) { Mat gray = new Mat(); Cv2.CvtColor(frame, gray, ColorConversionCodes.RGB2GRAY); Mat dst = new Mat(); Mat gauss = new Mat(); Cv2.GaussianBlur(gray, gauss, new Size(3, 3), this.sigma); switch (this.threshold) { case "canny": Cv2.Canny(gauss, dst, 150, 400, 3); break; case "adaptive": Cv2.AdaptiveThreshold(gauss, dst, 255, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.BinaryInv, 9, 5); break; default: Cv2.Canny(gauss, dst, 150, 400, 3); break; } Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(dst, out contours, out hierarchy, OpenCvSharp.RetrievalModes.CComp, ContourApproximationModes.ApproxSimple, null); if (this.debug == true) { Mat copyimg = new Mat(); frame.CopyTo(copyimg); copyimg.DrawContours(contours, -1, new Scalar(0, 255, 0)); using (new Window("contours image", copyimg)) { Cv2.WaitKey(); } } ArrayList hulls = new ArrayList(); ArrayList quads = new ArrayList(); for (int i = 0; i < contours.Length; i++) { var contour = contours[i];//取出多边形 get polygon if (contour.Length >= 4 && hierarchy[i].Previous < 0) { var area = Cv2.ContourArea(contour);//求多边形面积 get contour`s area if (area > this.minarea) { var hull = Cv2.ConvexHull(contour);//求出凸包 get hull if ((area / Cv2.ContourArea(hull)) > 0.8) { hulls.Add(hull); var quad = Cv2.ApproxPolyDP(hull, 9, true);//根据凸包计算出四边形 get quad if (quad.Length == 4) { var areaqued = Cv2.ContourArea(quad); var areahull = Cv2.ContourArea(hull); if (areaqued / areahull > 0.8 && areahull >= areaqued) { quads.Add(quad); } } } } } } if (this.debug == true) { Mat copyimg = new Mat(); frame.CopyTo(copyimg); foreach (Point[] item in quads) { Point[][] temp = new Point[1][]; temp[0] = item; copyimg.DrawContours(temp, -1, new Scalar(0, 255, 0)); } using (new Window("contours image", copyimg)) { Cv2.WaitKey(); } Console.WriteLine("quads count" + quads.Count); } ArrayList detections = new ArrayList(); ArrayList points = new ArrayList(); ArrayList whitepoints = new ArrayList(); //进行点quad点的提取 foreach (Point[] quad in quads) { int dd = this.tagFamily.getBlackBorder() * 2 + this.tagFamily.getEdge(); ArrayList blackvalue = new ArrayList(); ArrayList whitevalue = new ArrayList(); for (int iy = 0; iy < dd; iy++) { for (int ix = 0; ix < dd; ix++) { double x = (ix + 0.5) / (dd * 1.0); double y = (iy + 0.5) / (dd * 1.0); var polatepoint = _interpolate(quad, new Point2d(x, y)); points.Add(polatepoint); var value = gray.At <byte>(polatepoint.X, polatepoint.Y); if ((iy == 0 || iy == dd - 1) || (ix == 0 || ix == dd - 1)) { blackvalue.Add(value); } else if ((iy == 1 || iy == dd - 2) || (ix == 1 || ix == dd - 2)) { whitevalue.Add(value); } else { continue; } } } long tagcode = 0; var threshold = 0.5 * (_average(blackvalue) + _average(whitevalue)); for (int iy = 0; iy < dd; iy++) { for (int ix = 0; ix < dd; ix++) { if ((iy == 0 || iy == dd - 1) || (ix == 0 || ix == dd - 1)) { continue; } double newx = (ix + 0.5) / dd * 1.0; double newy = (iy + 0.5) / dd * 1.0; Point point = _interpolate(quad, new Point2d(newx, newy)); int grayvalue = gray.At <byte>(point.X, point.Y); tagcode = tagcode << 1; if (grayvalue > threshold) { tagcode |= 1; whitepoints.Add(point); } } } Detector decoderesult = this.tagFamily._decode(tagcode); if (decoderesult.good == true) { decoderesult.addPoint(quad); detections.Add(decoderesult); } } if (this.debug == true) { Mat copyimg = new Mat(); frame.CopyTo(copyimg); foreach (Point item in points) { Point tpoint = new Point(item.Y, item.X); copyimg.Circle(tpoint, 1, new Scalar(0, 0, 255)); } using (new Window("quad", copyimg)) { Cv2.WaitKey(); } Mat copyimg2 = new Mat(); frame.CopyTo(copyimg2); foreach (Point item in whitepoints) { Point tpoint = new Point(item.Y, item.X); copyimg2.Circle(tpoint, 1, new Scalar(0, 0, 255)); } using (new Window("quad", copyimg2)) { Cv2.WaitKey(); } } return(detections); }
static void Main(string[] args) { var afWindow = new Window("Annotated Frame"); var cdWindow = new Window("Contour Delta"); VideoCapture capture = new VideoCapture("rtsp://10.0.0.104:554/1/h264major"); int frameIndex = 0; Mat lastFrame = new Mat(); VideoWriter writer = null; while (capture.IsOpened()) { Mat frame = new Mat(); if (!capture.Read(frame)) { break; } Mat grayFrame, dilatedFrame, edges, deltaCopyFrame = new Mat(); Mat deltaFrame = new Mat(); try { frame = frame.Resize(new Size(0, 0), 0.33, 0.33); } catch (Exception e) { } grayFrame = frame.CvtColor(ColorConversionCodes.BGR2GRAY); grayFrame = grayFrame.GaussianBlur(new Size(21, 21), 0); if (frameIndex == 0) { frameIndex++; afWindow.Move(0, 0); cdWindow.Move(0, grayFrame.Size().Height); string fileName = "C:\\temp\\capture.avi"; string fcc = capture.FourCC; double fps = capture.Get(CaptureProperty.Fps); Size frameSize = new Size(grayFrame.Size().Width, grayFrame.Size().Height); writer = new VideoWriter(fileName, fcc, fps, frameSize); Console.Out.WriteLine("Frame Size = " + grayFrame.Size().Width + " x " + grayFrame.Size().Height); if (!writer.IsOpened()) { Console.Out.WriteLine("Error Opening Video File For Write"); return; } lastFrame = grayFrame; continue; } else if (frameIndex % 50 == 0) { frameIndex = 0; lastFrame = grayFrame; } frameIndex++; Cv2.Absdiff(lastFrame, grayFrame, deltaFrame); Cv2.Threshold(deltaFrame, deltaFrame, 50, 255, ThresholdTypes.Binary); int iterations = 2; Cv2.Dilate(deltaFrame, deltaFrame, new Mat(), new Point(), iterations); Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(deltaFrame, out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple, new Point(0, 0)); var countorsPoly = new Point[contours.Length][]; List <Rect> boundRect = new List <Rect>(); List <Point2f> center = new List <Point2f>(); List <float> radius = new List <float>(); for (int i = 0; i < contours.Length; i++) { countorsPoly[i] = Cv2.ApproxPolyDP(contours[i], 3, true); if (countorsPoly.Length != 0) { boundRect.Insert(i, Cv2.BoundingRect(countorsPoly[i])); Cv2.MinEnclosingCircle(countorsPoly[i], out Point2f centerObj, out float radiusObj); center.Insert(i, centerObj); radius.Insert(i, radiusObj); } } for (int i = 0; i < contours.Length; i++) { if (countorsPoly.Length != 0) { Scalar color = new Scalar(54, 67, 244); //Cv2.DrawContours(frame, countorsPoly, i, color, 1, LineTypes.Link8, new HierarchyIndex[] { }, 0, new Point()); Cv2.Rectangle(frame, boundRect[i].TopLeft, boundRect[i].BottomRight, color, 2, LineTypes.Link8, 0); //Cv2.Circle(frame, (int)center[i].X, (int)center[i].Y, (int)radius[i], color, 2, LineTypes.Link8, 0); } } afWindow.ShowImage(frame); cdWindow.ShowImage(deltaFrame); writer.Write(frame); switch (Cv2.WaitKey(1)) { case 27: capture.Release(); writer.Release(); return; } } }
//MyMSER static List <Point[][]> My_MSER(int my_delta, int my_minArea, int my_maxArea, double my_maxVariation, Mat img, ref Mat img_rgb, int big_flag) { //img.SaveImage("img_detected.jpg"); List <Point[][]> final_area = new List <Point[][]>(); Point[][] contours; Rect[] bboxes; MSER mser = MSER.Create(delta: my_delta, minArea: my_minArea, maxArea: my_maxArea, maxVariation: my_maxVariation); mser.DetectRegions(img, out contours, out bboxes); //====================================Local Majority Vote // to speed up, create four shift image first var shift_mat = set_shift_image(ref img); Mat[] neighbor_img = new Mat[4]; for (int i = 0; i < 4; i++) { neighbor_img[i] = new Mat(); var imageCenter = new Point2f(img.Cols / 2f, img.Rows / 2f); var rotationMat = Cv2.GetRotationMatrix2D(imageCenter, 100, 1.3); Cv2.WarpAffine(img, neighbor_img[i], shift_mat[i], img.Size()); //neighbor_img[i].SaveImage("./shift_image" + i + ".jpg"); } //for each contour, apply local majority vote foreach (Point[] now_contour in contours) { OpenCvSharp.Point[][] temp = new Point[1][]; Point[] Convex_hull = Cv2.ConvexHull(now_contour); Point[] Approx = Cv2.ApproxPolyDP(now_contour, 0.5, true); RotatedRect rotateRect = Cv2.MinAreaRect(Approx); //Debug //Console.WriteLine(Cv2.ContourArea(Approx)+" "+ rotateRect.Size.Height / rotateRect.Size.Width+ " "+rotateRect.Size.Width / rotateRect.Size.Height); if (Cv2.ContourArea(Approx) > 10000 || (Cv2.ContourArea(Approx) < stop1_inner_defect_size_min || ((rotateRect.Size.Height / rotateRect.Size.Width)) > stop1_arclength_area_ratio || ((rotateRect.Size.Width / rotateRect.Size.Height)) > stop1_arclength_area_ratio)) { continue; } //======================intensity in the area temp[0] = Approx; double mean_in_area_temp = 0, min_in_area_temp = 0; Mat mask_img_temp = Mat.Zeros(img.Size(), MatType.CV_8UC1); Cv2.DrawContours(mask_img_temp, temp, -1, 255, thickness: -1);//notice the difference between temp = Approx and Convex_hull mean_in_area_temp = img.Mean(mask_img_temp)[0]; img.MinMaxLoc(out min_in_area_temp, out _, out _, out _, mask_img_temp); //Console.WriteLine(min_in_area_temp + " " + mean_in_area_temp); if (min_in_area_temp > 100 || mean_in_area_temp > 130) { continue; } // Convex hull temp[0] = Approx; if (big_flag == 0)//small area: local majority vote { //Cv2.Polylines(img_rgb, temp, true, new Scalar(0, 0, 255), 1); //inside the area double mean_in_area = 0, min_in_area = 0; Mat mask_img = Mat.Zeros(img.Size(), MatType.CV_8UC1); Cv2.DrawContours(mask_img, temp, -1, 255, thickness: -1);//notice the difference between temp = Approx and Convex_hull mean_in_area = img.Mean(mask_img)[0]; img.MinMaxLoc(out min_in_area, out _, out _, out _, mask_img); //Console.WriteLine(min_in_area + " " + mean_in_area); //test /* * Mat mask2 = img.LessThan(230); * for (int i = 0; i < img.Cols; i++) { * for (int j = 0; j < img.Rows; j++) * if(mask2.At<bool>(i, j)==false) * Console.Write(mask2.At<bool>(i,j)+ " "); * * Console.Write("\n"); * * } */ //neighbor double[] mean_neighbor = { 255, 255, 255, 255 }; double[] min_neighbor = { 255, 255, 255, 255 }; for (int i = 0; i < 4; i++) { //先把 img > 230 的變成 0,再餵進 shift 裡面 //先把 mask 乘上另一個mask(>230的mask) //Mat mask_neighbor_img = neighbor_img[i].GreaterThan(0); //Console.WriteLine(mask_neighbor_img.At<int>(0,1)); // create final mask Mat mask2 = neighbor_img[i].LessThan(225).ToMat(); mask2.ConvertTo(mask2, MatType.CV_8U, 1.0 / 255.0); Mat mask_final = Mat.Zeros(img.Size(), MatType.CV_8UC1); mask_img.CopyTo(mask_final, mask2); //mask_final.SaveImage("./mask" + i + ".jpg"); mean_neighbor[i] = neighbor_img[i].Mean(mask_final)[0]; //compute min: //neighbor_img[i].MinMaxLoc(out min_neighbor[i], out _, out _, out _, mask_img); //Console.WriteLine(min_neighbor[i] + " " + mean_neighbor[i]); } int vote = 0; for (int i = 0; i < 4; i++) { if (mean_in_area > mean_neighbor[i]) { vote++; } } if (vote > 2 || min_in_area > 100 || mean_in_area > 130) { //Debug //Console.WriteLine(vote + " " + min_in_area + " ", min_in_area); continue; } else { //Cv2.Polylines(img_rgb, temp, true, new Scalar(0, 0, 255), 1); //Console.WriteLine("--"); final_area.Add(temp); } } else { //Console.WriteLine("--"); //Cv2.Polylines(img_rgb, temp, true, new Scalar(0, 0, 255), 1); final_area.Add(temp); } } Console.WriteLine(final_area.Count); return(final_area); }
public List <Contorno> Procesar(Mat matImagenFuente, Texture2D[] texturesObserve = null) { var contornos = new List <Contorno>(); Iniciar(); var escalaReduccionImagen = 1f; if (matImagenFuente.Width > SizeLimit || matImagenFuente.Height > SizeLimit) { escalaReduccionImagen = Mathf.Min(SizeLimit / matImagenFuente.Width, SizeLimit / matImagenFuente.Height); Cv2.Resize(matImagenFuente, matImagenLowRes, new Size(matImagenFuente.Width * escalaReduccionImagen, matImagenFuente.Height * escalaReduccionImagen)); } else { Cv2.Resize(matImagenFuente, matImagenLowRes, matImagenFuente.Size()); } Cv2.CvtColor(matImagenLowRes, matImagenLowRes, ColorConversionCodes.RGB2GRAY); if (UsarCanny) { Cv2.Canny(matImagenLowRes, matBin, CannyBajo, CannyAlto, ApertureCanny, CannyL2); } else { Cv2.Threshold(matImagenLowRes, matBin, Threshold, 255, ThreshType); } if (CannyDilate) { Cv2.Dilate(matBin, matBin, matClean); } if (CannyErode) { Cv2.Erode(matBin, matBin, matClean); } //borde extra por las dudas si hay ruido en lso bordes Cv2.Rectangle(matBin, new Point(0, 0), new Point(matBin.Width, matBin.Height), new Scalar(0), Border); if (texturesObserve != null) { texturesObserve[0] = OpenCvSharp.Unity.MatToTexture(matBin, texturesObserve[0]); } Point[][] puntos; HierarchyIndex[] jerarquia; Cv2.FindContours(matBin, out puntos, out jerarquia, RetrievalModes.Tree, ContourApproximationModes.ApproxTC89KCOS); if (EpsilonDeAproximacion != ConfigExtraerContornoFlor.EpsilonDeAproximacion.NoAproximar) { var epsilon = ValorDeEpsilon; for (int i = 0, n = puntos.Length; i < n; i++) { if (EpsilonDeAproximacion == ConfigExtraerContornoFlor.EpsilonDeAproximacion.EpsilonRelativoArcLen) { epsilon *= Cv2.ArcLength(puntos[i], true); } puntos[i] = Cv2.ApproxPolyDP(puntos[i], epsilon, true); epsilon = ValorDeEpsilon; } } if (jerarquia.Length == 0) { return(null); } contornos = OrdenarContornosEvitandoCanny(puntos, jerarquia, 0, contornos); if (texturesObserve != null) { Cv2.CvtColor(matImagenLowRes, matImagenLowRes, ColorConversionCodes.GRAY2RGB); foreach (var cont in contornos) { var dibujar = new[] { cont.vertices.Select(v => new Point(v.x, v.y)) }; Cv2.DrawContours(matImagenLowRes, dibujar, -1, new Scalar(cont.color.b * 255, cont.color.g * 255, cont.color.r * 255), Mathf.CeilToInt(Mathf.Min(matImagenLowRes.Width * 0.005f, 1))); dibujar = cont.contornosInternos.Select(c => c.vertices.Select(v => new Point(v.x, v.y))).ToArray(); Cv2.DrawContours(matImagenLowRes, dibujar, -1, new Scalar(cont.color.b * 100, cont.color.g * 100, cont.color.r * 100), Mathf.CeilToInt(Mathf.Min(matImagenLowRes.Width * 0.005f, 1))); } texturesObserve[1] = OpenCvSharp.Unity.MatToTexture(matImagenLowRes, texturesObserve[1]); } return(contornos); }
/// <summary> /// Takes blobs information based on colors in <see cref="hsv"/> list and then sends the info through UDP. /// </summary> /// <param name="sourceImage">Image in Mat format.</param> /// <returns>Image in Mat format.</returns> private Mat Renderer(Mat sourceImage) { Mat dstNoisy = src; Mat dstClear = new Mat(); Mat dst = new Mat(); Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(2 * MorphValue + 1, 2 * MorphValue + 1)); Cv2.Blur(dstNoisy, dstClear, new Size(9, 9)); Cv2.CvtColor(dstClear, dst, ColorConversionCodes.BGR2HSV); // Convert BGR to HSV. Mat dstThreshed = new Mat(); Mat dstPreview = new Mat(); if (hsv.Count > 0) { int blobCount = 1; bool theFirst = true; foreach (int[] scal in hsv) { if (theFirst) { Cv2.InRange(dst, new Scalar(scal[0] - 10, scal[1], scal[3]), new Scalar(scal[0] + 10, scal[2], scal[4]), dstPreview); theFirst = false; } else { Mat dstPreview2 = new Mat(); Cv2.InRange(dst, new Scalar(scal[0] - 10, scal[1], scal[3]), new Scalar(scal[0] + 10, scal[2], scal[4]), dstPreview2); Cv2.AddWeighted(dstThreshed, 1.0, dstPreview2, 1.0, 0.0, dstPreview); } Cv2.InRange(dst, new Scalar(scal[0] - 10, scal[1], scal[3]), new Scalar(scal[0] + 10, scal[2], scal[4]), dstThreshed); // Morphologic transformation to close the gaps inside the blob. Cv2.MorphologyEx(src: dstThreshed, dst: dstThreshed, op: MorphTypes.Close, element: element ); blobDetection.Label(dstThreshed); blobDetection.FilterByArea(MinBlobArea, MaxBlobArea); blobDetection.RenderBlobs(dstThreshed, src); CircleSegment[] circles = Cv2.HoughCircles(dstThreshed, HoughMethods.Gradient, 1, dstThreshed.Rows / 8); // Creates all udp datagrams---------------------------------------------------- if (blobDetection.Count != 0) { for (int i = 0; i < blobDetection.Count; i++) { int processKey = blobDetection.ElementAt(i).Key; udpDatagram_1 = "[$]tracking|id=" + data_id + "|label=" + blobCount + "|[$$]" + deviceName + ",[$$$]mesh,sample,"; for (int j = 0; j < blobDetection[processKey].Contour.ConvertToPolygon().Simplify(1).Count; j++) { if (orientation) { udpDatagram_1 += Math.Round((float)blobDetection[processKey].Contour.ConvertToPolygon().Simplify(1).ElementAt(j).X / dst.Cols, 4).ToString().Replace(',', '.'); udpDatagram_1 += "," + (1 - Math.Round((float)blobDetection[processKey].Contour.ConvertToPolygon().Simplify(1).ElementAt(j).Y / dst.Rows, 4)).ToString().Replace(',', '.'); udpDatagram_1 += ","; } else { udpDatagram_1 += (1 - Math.Round((float)blobDetection[processKey].Contour.ConvertToPolygon().Simplify(1).ElementAt(j).X / dst.Cols, 4)).ToString().Replace(',', '.'); udpDatagram_1 += "," + Math.Round((float)blobDetection[processKey].Contour.ConvertToPolygon().Simplify(1).ElementAt(j).Y / dst.Rows, 4).ToString().Replace(',', '.'); udpDatagram_1 += ","; } } udpDatagram_1 += ";"; udpDatagram_2 = "[$]tracking|id=" + data_id + "|label=" + blobCount + "|[$$]" + deviceName + ",[$$$]area,"; udpDatagram_2 += "value," + blobDetection[processKey].Contour.ConvertToPolygon().Simplify(1).Area().ToString().Replace(',', '.') + ";"; udpDatagram_3 = "[$]tracking|id=" + data_id + "|label=" + blobCount + "|[$$]" + deviceName + ",[$$$]place,"; if (orientation) { udpDatagram_3 += "position," + (Math.Round(blobDetection[processKey].Centroid.X / dst.Cols, 3)).ToString().Replace(',', '.') + "," + (Math.Round(1 - (blobDetection[processKey].Centroid.Y / dst.Rows), 3)).ToString().Replace(',', '.') + ";"; } else { udpDatagram_3 += "position," + (Math.Round(1 - (blobDetection[processKey].Centroid.X / dst.Cols), 3)).ToString().Replace(',', '.') + "," + (Math.Round(blobDetection[processKey].Centroid.Y / dst.Rows, 3)).ToString().Replace(',', '.') + ";"; } udpDatagram_4 = "[$]tracking|id=" + data_id + "|label=" + blobCount + "|[$$]" + deviceName + ",[$$$]color,"; udpDatagram_4 += "hsv," + scal[0] + "-" + (scal[1] + scal[2]) / 2 + "-" + (scal[3] + scal[4]) / 2 + ";"; //Geometry udpDatagram_5 = "[$]tracking|id=" + data_id + "|label=" + blobCount + "|[$$]" + deviceName + ",[$$$]form,geometry,"; CvContourPolygon poly = blobDetection[processKey].Contour.ConvertToPolygon(); double epsilon = 0.04 * Cv2.ArcLength(poly, true); Point[] counterResult = Cv2.ApproxPolyDP(poly, epsilon, closed: true); int contourSimple_counter = counterResult.Length; string geometry = ""; switch (contourSimple_counter) { case 3: geometry = "triangle"; break; case 4: Rect rect = Cv2.BoundingRect(poly); float aspectRatio = 0; if (rect.Y != 0) { aspectRatio = rect.X / rect.Y; } if (aspectRatio >= 0.95 && aspectRatio <= 1.05) { geometry = "square"; } else { geometry = "rectangle"; } break; default: geometry = "unidentified" + contourSimple_counter; break; } udpDatagram_5 += geometry + ";"; if (BlobLabel) { Cv2.PutText(src, geometry, blobDetection[processKey].Centroid, HersheyFonts.HersheySimplex, 0.5, new Scalar(0, 255, 0), 2); Cv2.PutText(src, "[" + scal[0] + ", " + ((scal[1] + scal[2]) / 2) + ", " + ((scal[3] + scal[4]) / 2) + "]", new Point(blobDetection[processKey].Centroid.X, blobDetection[processKey].Centroid.Y + 20), HersheyFonts.HersheySimplex, 0.45, new Scalar(0, 255, 0), 2); } udpDatagram_6 = "[$]tracking|id=" + data_id + "|label=" + blobCount + "|[$$]" + deviceName + ",[$$$]perimeter,value,"; udpDatagram_6 += blobDetection[processKey].Contour.Perimeter().ToString().Replace(',', '.') + ";"; // UDP sender--------------------------------------------------------------------- try { byte[] sendBytes_1 = Encoding.ASCII.GetBytes(udpDatagram_1); byte[] sendBytes_2 = Encoding.ASCII.GetBytes(udpDatagram_2); byte[] sendBytes_3 = Encoding.ASCII.GetBytes(udpDatagram_3); byte[] sendBytes_4 = Encoding.ASCII.GetBytes(udpDatagram_4); byte[] sendBytes_5 = Encoding.ASCII.GetBytes(udpDatagram_5); byte[] sendBytes_6 = Encoding.ASCII.GetBytes(udpDatagram_6); udpClient.Send(sendBytes_1, sendBytes_1.Length, IP_udp, Port_udp); udpClient.Send(sendBytes_2, sendBytes_2.Length, IP_udp, Port_udp); udpClient.Send(sendBytes_3, sendBytes_3.Length, IP_udp, Port_udp); udpClient.Send(sendBytes_4, sendBytes_4.Length, IP_udp, Port_udp); udpClient.Send(sendBytes_5, sendBytes_5.Length, IP_udp, Port_udp); udpClient.Send(sendBytes_6, sendBytes_6.Length, IP_udp, Port_udp); } catch (Exception e) { Console.WriteLine(e.ToString()); } udpDatagram_1 = ""; udpDatagram_2 = ""; udpDatagram_3 = ""; udpDatagram_4 = ""; blobCount++; } } } blobCount = 1; } // Same morphologic transformation but this time for the output image. Cv2.MorphologyEx(src: dstPreview, dst: dstPreview, op: MorphTypes.Close, element: element ); return(dstPreview); }
private void detectShapeCandidates(ref Bitmap bitmap, Boolean saveShapes) { Debug.WriteLine("Running OpenCV"); string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); Mat colorMat = BitmapConverter.ToMat(bitmap); MatOfDouble mu = new MatOfDouble(); MatOfDouble sigma = new MatOfDouble(); Cv2.MeanStdDev(colorMat, mu, sigma); double mean = mu.GetArray(0, 0)[0]; mu.Dispose(); sigma.Dispose(); Mat greyMat = new Mat(); Cv2.CvtColor(colorMat, greyMat, ColorConversion.BgraToGray, 0); greyMat = greyMat.GaussianBlur(new OpenCvSharp.CPlusPlus.Size(1, 1), 5, 5, BorderType.Default); greyMat = greyMat.Canny(0.5 * mean, 1.2 * mean, 3, true); Mat contourMat = new Mat(greyMat.Size(), colorMat.Type()); greyMat.CopyTo(contourMat); var contours = contourMat.FindContoursAsArray(ContourRetrieval.List, ContourChain.ApproxSimple); for (int j = 0; j < contours.Length; j++) { var poly = Cv2.ApproxPolyDP(contours[j], 0.01 * Cv2.ArcLength(contours[j], true), true); int num = poly.Length; if (num >= 4 && num < 20) { var color = Scalar.Blue; var rect = Cv2.BoundingRect(poly); if (rect.Height < 20 || rect.Width < 20) { continue; } if (saveShapes) { string path = Path.Combine(myPhotos, "shape_samples"); path = Path.Combine(path, "shape_sample_" + Path.GetRandomFileName() + ".png"); var matRect = new OpenCvSharp.CPlusPlus.Rect(0, 0, greyMat.Width, greyMat.Height); rect.Inflate((int)(rect.Width * 0.1), (int)(rect.Height * 0.1)); rect = rect.Intersect(matRect); Mat shapeMat = greyMat.SubMat(rect); var size = new OpenCvSharp.CPlusPlus.Size(128, 128); shapeMat = shapeMat.Resize(size); Bitmap shape = shapeMat.ToBitmap(); shape.Save(path); shape.Dispose(); shapeMat.Dispose(); continue; } Cv2.Rectangle(colorMat, rect, color, 2); } } bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(colorMat); colorMat.Dispose(); greyMat.Dispose(); contourMat.Dispose(); }
private string getOMRString(OpenCvSharp.Point wh) { String[] chars = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" }; String res = ""; const int SMALL_OBJECT_MIN_AREA = 12; const int SMALL_OBJECT_THREADHOLD = 7; Mat src, gray, binary, canny; src = OpenCvSharp.Extensions.BitmapConverter.ToMat(bitmapPerspective); gray = new Mat(); binary = new Mat(); canny = new Mat(); Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY); Cv2.Threshold(gray, binary, 150, 255, ThresholdTypes.Binary); Cv2.Canny(binary, canny, 0, 0, 3); OpenCvSharp.Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(canny, out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxTC89KCOS); List <OpenCvSharp.Point> smallObjectList = new List <OpenCvSharp.Point>(); List <int> yList = new List <int>(); List <OpenCvSharp.Point[]> rectObjectList = new List <OpenCvSharp.Point[]>(); foreach (OpenCvSharp.Point[] p in contours) { double length = Cv2.ArcLength(p, true); double area = Cv2.ContourArea(p, true); if (length < 100 && area < 1000 || p.Length < 5) { continue; } OpenCvSharp.Point[] hull = Cv2.ConvexHull(p, true); OpenCvSharp.Point[] pp = Cv2.ApproxPolyDP(p, 0.02 * length, true); if (pp.Length > SMALL_OBJECT_THREADHOLD && Math.Abs(area) < SMALL_OBJECT_MIN_AREA) { OpenCvSharp.Point ppCenter = Util.getCenterPoint(pp); smallObjectList.Add(ppCenter); bool isExist = false; foreach (int y in yList) { if (Math.Abs(y - ppCenter.Y) < SMALL_OBJECT_MIN_AREA * 2) { isExist = true; } } if (isExist == false) { yList.Add(ppCenter.Y); } } } int minExamineeRectX = 0; int maxExamineeRectX = wh.X; int maxExamineeRectY = wh.Y; int widthExamineeRectItem = (maxExamineeRectX - minExamineeRectX) / 6; try { for (int i = 0; i < 6; i++) { int minIndex = 0, minCount = int.MaxValue; for (int k = 0; k < 10; k++) { int x = minExamineeRectX + widthExamineeRectItem * i + widthExamineeRectItem / 2; int y = yList[k]; OpenCvSharp.Rect rect = new OpenCvSharp.Rect(x - 12, y - 12, 24, 24); // x, y, width, height Mat matCircle = binary.SubMat(rect); int nonzeroCount = Cv2.CountNonZero(matCircle); matCircle.Dispose(); if (nonzeroCount < minCount) { minCount = nonzeroCount; minIndex = 9 - k; } } if (i == 0) { res = chars[minIndex]; } else { res += minIndex; } //Console.WriteLine("i" + i + " index:" + minIndex); } } catch (Exception e) { Console.WriteLine(e.ToString()); res = null; } finally { if (bitmapPerspective != null) { bitmapPerspective.Dispose(); } } return(res); }
public Window1() { InitializeComponent(); Mat src = new Mat(@"./desktop.jpg"); Cv2.ImShow("src", src); //src = src.Resize(new Size(src.Width / 2, src.Height / 2)); for (var y = 0; y < src.Height; y++) { for (var x = 0; x < src.Width; x++) { var color = src.Get <Vec3b>(y, x); //if (color.Item2 < 175) if (color.Item2 < 225) { color.Item0 = 255; color.Item1 = 0; color.Item2 = 0; } src.Set(y, x, color); } } Cv2.ImShow("fade", src); Mat gray = new Mat(); Mat binary = new Mat(); Cv2.CvtColor(src, gray, ColorConversionCodes.RGB2GRAY); gray = gray.GaussianBlur(new Size(5, 5), 0); gray = gray.Blur(new Size(5, 5)); gray = gray.BoxFilter(-1, new Size(10, 10), normalize: true); Cv2.ImShow("gray", gray); Cv2.Threshold(gray, binary, 100, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary); var element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)); binary = binary.Erode(element); binary = binary.MorphologyEx(MorphTypes.Close, element); Cv2.ImShow("bin", binary); //var line = binary.Canny(100, 200); //Cv2.ImShow("line", line); //Cv2.WaitKey(); //建立轮廓接受数组 Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(binary, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxTC89KCOS); //最小外接矩形接收数组 MessageBox.Show(contours.Length.ToString()); RotatedRect[] rotateRect = new RotatedRect[contours.Length]; Point[][] contours_poly = new Point[contours.Length][]; for (int i = 0; i < contours.Length; i++) { contours_poly[i] = Cv2.ApproxPolyDP(contours[i], 30, true); //返回凸包,单线长大于30过滤 rotateRect[i] = Cv2.MinAreaRect(contours_poly[i]); //最小外接矩形集合 Point2f[] pot = new Point2f[4]; //新建点集合接收点集合 //for (int i = 0; i < rotateRect.Length; i++) //{ var angle = rotateRect[i].Angle; //矩形角度 pot = rotateRect[i].Points(); //矩形的4个角 var line1 = Math.Sqrt((pot[0].X - pot[1].X) * (pot[0].X - pot[1].X) + (pot[0].Y - pot[1].Y) * (pot[0].Y - pot[1].Y)); var line2 = Math.Sqrt((pot[0].X - pot[3].X) * (pot[0].X - pot[3].X) + (pot[0].Y - pot[3].Y) * (pot[0].Y - pot[3].Y)); if (line1 * line2 < 1000)//过滤,太小的矩形直接pass { continue; } if (line1 > line2)//依据实际情况进行判断 { angle += 90; } Mat Roi = new Mat(src.Size(), MatType.CV_8UC3); Roi.SetTo(0);//全黑 //Cv2.DrawContours(binary, contours, -1, Scalar.White, -1);//在二值图像中圈出轮廓区域并染白 Cv2.DrawContours(binary, contours, -1, Scalar.White, 1); Cv2.ImShow("bin", binary); src.CopyTo(Roi, binary);//将原图通过mask抠图到Roi Cv2.ImShow("Roi", Roi); Mat afterRotato = new Mat(src.Size(), MatType.CV_8UC3); afterRotato.SetTo(0); Point2f center = rotateRect[i].Center; Mat M = Cv2.GetRotationMatrix2D(center, angle, 1); //计算变换矩阵 Cv2.WarpAffine(Roi, afterRotato, M, Roi.Size(), InterpolationFlags.Linear, BorderTypes.Wrap); //得到变换后的图像,滤除其他信息 Cv2.ImShow("旋转后", afterRotato); Mat bin2 = new Mat(); Cv2.ImShow("after", afterRotato); Cv2.CvtColor(afterRotato, bin2, ColorConversionCodes.RGB2GRAY); Cv2.Threshold(bin2, bin2, 50, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu); Point[][] con; HierarchyIndex[] temp;//接收矫正后的轮廓信息 Cv2.FindContours(bin2, out con, out temp, RetrievalModes.External, ContourApproximationModes.ApproxSimple); for (int j = 0; j < con.Length; j++) { Rect rect = Cv2.BoundingRect(con[j]); //直接使用矫正矩形,因为矫正后不需要再旋转 if (rect.Height * rect.Width < 8000) //过滤干扰信息 { continue; } Mat dstImg = new Mat(afterRotato, rect); dstImg = dstImg.CvtColor(ColorConversionCodes.RGB2GRAY); dstImg = dstImg.Threshold(50, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary); Cv2.BitwiseNot(dstImg, dstImg, new Mat()); dstImg = new Mat(dstImg, new Rect(100, 100, dstImg.Width - 200, dstImg.Height - 200)); Cv2.ImShow("dst", dstImg); dstImg.SaveImage("dst1.jpg"); var engine = new TesseractEngine("./tessdata", "eng", EngineMode.Default); var resProcess = engine.Process(Pix.LoadTiffFromMemory(dstImg.ToBytes(".tiff"))); MessageBox.Show(resProcess.GetText()); ////string name = "dst" + i;//主要看调试的时候有几个结果 //dstImg = dstImg.CvtColor(ColorConversionCodes.RGB2GRAY); //dstImg = dstImg.Threshold(10, 255, ThresholdTypes.Otsu); //Cv2.ImShow("chan", dstImg.Canny(100, 200)); //dstImg.FindContours(out var con1, out var hie1, RetrievalModes.External, // ContourApproximationModes.ApproxNone); //dstImg.DrawContours(con1, -1, Scalar.Green, 3); //Cv2.ImShow("dst2", dstImg); } } Cv2.WaitKey(); Console.ReadLine(); }
static void Stop4_Detect(Mat Src, int fileindex, string filename) { Mat vis_rgb = Src.CvtColor(ColorConversionCodes.GRAY2RGB); int OK_NG_Flag = 0; int stop4_black_defect_area_min = 220; int stop4_black_defect_area_max = 20000; double stop4_arclength_area_ratio = 0.35; int stop4_ignore_radius = 5; //==================================================find real oring=============================================== Point[][] contours; HierarchyIndex[] hierarchly; Mat thresh1 = Src.Threshold(240, 255, ThresholdTypes.Binary); Cv2.FindContours(thresh1, out contours, out hierarchly, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple); // find final circle List <Point[]> contours_final = new List <Point[]>(); List <Point[]> approx_list = new List <Point[]>(); foreach (Point[] contour_now in contours) { if (Cv2.ContourArea(contour_now) > 300000 && Cv2.ContourArea(contour_now) < 800000) { contours_final.Add(contour_now); Point[] approx = Cv2.ApproxPolyDP(contour_now, 0.5, true); approx_list.Add(approx); } } //==================================================outer contour - inner contour===================================== // variable OpenCvSharp.Point[][] temp = new Point[1][]; // inner contour Mat inner_contour_img = Mat.Zeros(Src.Size(), MatType.CV_8UC1); Point[] inner_contour = Cv2.ConvexHull(approx_list[1]); temp[0] = inner_contour; Cv2.DrawContours(inner_contour_img, temp, -1, 255, -1); // outer contour Mat outer_contour_img = Mat.Zeros(Src.Size(), MatType.CV_8UC1); Mat outer_contour_img2 = new Mat(Src.Size(), MatType.CV_8UC1, new Scalar(255));//initilize Mat with the value 255 temp[0] = approx_list[0]; Cv2.DrawContours(outer_contour_img, temp, -1, 255, -1); //outer contour2 in order to make mask area = 255 Cv2.DrawContours(outer_contour_img2, temp, -1, 0, -1); //outer - inner Mat diff_mask = outer_contour_img - inner_contour_img; Mat diff_mask2 = inner_contour_img + outer_contour_img2; Mat image = Mat.Zeros(Src.Size(), MatType.CV_8UC1); Src.CopyTo(image, diff_mask); //in order to make mask area = 255 image = image + diff_mask2; //=======================circle ignore========================= Point2f center; float radius; Mat circle_mask = new Mat(Src.Size(), MatType.CV_8UC1, new Scalar(255)); Cv2.MinEnclosingCircle(approx_list[0], out center, out radius); Cv2.Circle(circle_mask, (OpenCvSharp.Point)center, (int)(radius - stop4_ignore_radius), 0, thickness: -1); circle_mask.CopyTo(image, circle_mask); //image.SaveImage("./mask.jpg"); //================================use threshold to find defect========================================== Point[][] contours2; HierarchyIndex[] hierarchly2; Mat thresh2 = image.Threshold(95, 255, ThresholdTypes.BinaryInv); //thresh2.SaveImage("./thresh2.jpg"); Mat kernel = Mat.Ones(7, 7, MatType.CV_8UC1);//改變凹角大小 thresh2 = thresh2.MorphologyEx(MorphTypes.Dilate, kernel); //thresh2.SaveImage("./thresh2_Dilate.jpg"); Cv2.FindContours(thresh2, out contours2, out hierarchly2, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple); foreach (OpenCvSharp.Point[] contour_now in contours2) { if (Cv2.ContourArea(contour_now) > stop4_black_defect_area_min && Cv2.ContourArea(contour_now) < 20000 && Cv2.ContourArea(contour_now) < stop4_black_defect_area_max && (Cv2.ArcLength(contour_now, true) / Cv2.ContourArea(contour_now)) < stop4_arclength_area_ratio) { //Console.WriteLine("Arc Length: " + (Cv2.ArcLength(contour_now, true) + " Area: " + Cv2.ContourArea(contour_now))+" Length/Area:" +(Cv2.ArcLength(contour_now, true) / Cv2.ContourArea(contour_now))); OpenCvSharp.Point[] approx = Cv2.ApproxPolyDP(contour_now, 0.000, true); temp[0] = approx; Cv2.Polylines(vis_rgb, temp, true, new Scalar(0, 0, 255), 1); OK_NG_Flag = 1; } } if (OK_NG_Flag == 0) { Console.WriteLine("OK"); } else { Console.WriteLine("NG"); } //vis_rgb.SaveImage("./result.jpg"); vis_rgb.SaveImage("./result/test" + filename); }
public void find_polygon(int polygon_type, double threadhold, Point[][] contours, Mat result_mat) { int idx, i; Point[] poly = new Point[100]; Point center_pos = new Point(); center_pos.X = 0; center_pos.Y = 0; for (idx = 0; idx < contours.Length; idx++) { poly = Cv2.ApproxPolyDP(contours[idx], 10, true); if (polygon_type == 10000) { int left = 10000, right = -10000, top = 10000, bottom = -10000; for (i = 0; i < poly.Length; i++) { if (left > poly[i].X) { left = poly[i].X; } if (right < poly[i].X) { right = poly[i].X; } if (top > poly[i].Y) { top = poly[i].Y; } if (bottom < poly[i].Y) { bottom = poly[i].Y; } center_pos.X += poly[i].X; center_pos.Y += poly[i].Y; Cv2.Line(result_mat, poly[i], poly[(i + 1) % poly.Length], Scalar.Blue, 2); } if (right - left > 30) { center_pos.X = (left + right) / 2; center_pos.Y = (top + bottom) / 2; bool bfound = false; foreach (Polygon_T s in polygon_array) { if (center_pos.X > 0 && center_pos.Y > 0) { double dist = Math.Sqrt((center_pos.X - s.center_pos.X) * (center_pos.X - s.center_pos.X) + (center_pos.Y - s.center_pos.Y) * (center_pos.Y - s.center_pos.Y)); if (dist < threadhold) { bfound = true; } } } if (bfound == false) { Polygon_T p = new Polygon_T(); p.center_pos = center_pos; p.gt = GraphicType.GT_Polygon; polygon_array.Add(p); Cv2.Circle(result_mat, center_pos, 5, Scalar.Red, 2); } } } else { if (poly.Length == polygon_type) { int left = 10000, right = -10000, top = 10000, bottom = -10000; for (i = 0; i < poly.Length; i++) { if (left > poly[i].X) { left = poly[i].X; } if (right < poly[i].X) { right = poly[i].X; } if (top > poly[i].Y) { top = poly[i].Y; } if (bottom < poly[i].Y) { bottom = poly[i].Y; } center_pos.X += poly[i].X; center_pos.Y += poly[i].Y; Cv2.Line(result_mat, poly[i], poly[(i + 1) % poly.Length], Scalar.Blue, 2); } center_pos.X = (left + right) / 2; center_pos.Y = (top + bottom) / 2; bool bfound = false; foreach (Polygon_T s in polygon_array) { if (center_pos.X > 0 && center_pos.Y > 0) { double dist = Math.Sqrt((center_pos.X - s.center_pos.X) * (center_pos.X - s.center_pos.X) + (center_pos.Y - s.center_pos.Y) * (center_pos.Y - s.center_pos.Y)); if (dist < threadhold) { bfound = true; } } } if (bfound == false) { Polygon_T p = new Polygon_T(); p.center_pos = center_pos; if (polygon_type == 3) { p.gt = GraphicType.GT_Triangularity; } if (polygon_type == 4) { p.gt = GraphicType.GT_Rectangle; } polygon_array.Add(p); Cv2.Circle(result_mat, center_pos, 5, Scalar.Red, 2); } } } } }
/// <summary> /// The magic is here /// </summary> private void CalculateOutput() { Mat matGray = null; // instead of regular Grayscale, we use BGR -> HSV and take Hue channel as // source if (Settings.GrayMode == ScannerSettings.ColorMode.HueGrayscale) { var matHSV = matInput_.CvtColor(ColorConversionCodes.RGB2HSV); Mat[] hsvChannels = matHSV.Split(); matGray = hsvChannels[0]; } // Alternative: just plain BGR -> Grayscale else { matGray = matInput_.CvtColor(ColorConversionCodes.BGR2GRAY); } // scale down if necessary var matScaled = matGray; float sx = 1, sy = 1; if (Settings.Scale != 0) { if (matGray.Width > Settings.Scale) { sx = (float)Settings.Scale / matGray.Width; } if (matGray.Height > Settings.Scale) { sy = (float)Settings.Scale / matGray.Height; } matScaled = matGray.Resize(new Size(Math.Min(matGray.Width, Settings.Scale), Math.Min(matGray.Height, Settings.Scale))); } // reduce noise var matBlur = matScaled; if (Settings.NoiseReduction != 0) { int medianKernel = 11; // calculate kernel scale double kernelScale = Settings.NoiseReduction; if (0 == Settings.Scale) { kernelScale *= Math.Max(matInput_.Width, matInput_.Height) / 512.0; } // apply scale medianKernel = (int)(medianKernel * kernelScale + 0.5); medianKernel = medianKernel - (medianKernel % 2) + 1; if (medianKernel > 1) { matBlur = matScaled.MedianBlur(medianKernel); } } // detect edges with our 'adaptive' algorithm that computes bounds automatically with // image's mean value var matEdges = matBlur.AdaptiveEdges(Settings.EdgesTight); // now find contours Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(matEdges, out contours, out hierarchy, RetrievalModes.List, ContourApproximationModes.ApproxNone, null); // check contours and drop those we consider "noise", all others put into a single huge "key points" map // also, detect all almost-rectangular contours with big area and try to determine whether they're exact match List <Point> keyPoints = new List <Point>(); List <Point[]> goodCandidates = new List <Point[]>(); double referenceArea = matScaled.Width * matScaled.Height; foreach (Point[] contour in contours) { double length = Cv2.ArcLength(contour, true); // drop mini-contours if (length >= 25.0) { Point[] approx = Cv2.ApproxPolyDP(contour, length * 0.01, true); keyPoints.AddRange(approx); if (approx.Length >= 4 && approx.Length <= 6) { double area = Cv2.ContourArea(approx); if (area / referenceArea >= Settings.ExpectedArea) { goodCandidates.Add(approx); } } } } // compute convex hull, considering we presume having an image of a document on more or less // homogeneous background, this accumulated convex hull should be the document bounding contour Point[] hull = Cv2.ConvexHull(keyPoints); Point[] hullContour = Cv2.ApproxPolyDP(hull, Cv2.ArcLength(hull, true) * 0.01, true); // find best guess for our contour Point[] paperContour = GetBestMatchingContour(matScaled.Width * matScaled.Height, goodCandidates, hullContour); if (null == paperContour) { shape_ = null; dirty_ = false; matOutput_ = matInput_; return; } // exact hit - we have 4 corners if (paperContour.Length == 4) { paperContour = SortCorners(paperContour); } // some hit: we either have 3 points or > 4 which we can try to make a 4-corner shape else if (paperContour.Length > 2) { // yet contour might contain too much points: along with calculation inaccuracies we might face a // bended piece of paper, missing corner etc. // the solution is to use bounding box RotatedRect bounds = Cv2.MinAreaRect(paperContour); Point2f[] points = bounds.Points(); Point[] intPoints = Array.ConvertAll(points, p => new Point(Math.Round(p.X), Math.Round(p.Y))); Point[] fourCorners = SortCorners(intPoints); // array.ClosestElement is not efficient but we can live with it since it's quite few // elements to search for System.Func <Point, Point, double> distance = (Point x, Point y) => Point.Distance(x, y); Point[] closest = new Point[4]; for (int i = 0; i < fourCorners.Length; ++i) { closest[i] = paperContour.ClosestElement(fourCorners[i], distance); } paperContour = closest; } // scale contour back to input image coordinate space - if necessary if (sx != 1 || sy != 1) { for (int i = 0; i < paperContour.Length; ++i) { Point2f pt = paperContour[i]; paperContour[i] = new Point2f(pt.X / sx, pt.Y / sy); } } // un-wrap var matUnwrapped = matInput_; bool needConvertionToBGR = true; if (paperContour.Length == 4) { matUnwrapped = matInput_.UnwrapShape(Array.ConvertAll(paperContour, p => new Point2f(p.X, p.Y))); // automatic color converter bool convertColor = (ScannerSettings.DecolorizationMode.Always == Settings.Decolorization); if (ScannerSettings.DecolorizationMode.Automatic == Settings.Decolorization) { convertColor = !IsColored(matUnwrapped); } // perform color conversion to b&w if (convertColor) { matUnwrapped = matUnwrapped.CvtColor(ColorConversionCodes.BGR2GRAY); // we have some constants for Adaptive, but this can be improved with some 'educated guess' for the constants depending on input image if (ScannerSettings.ScanType.Adaptive == Settings.ColorThreshold) { matUnwrapped = matUnwrapped.AdaptiveThreshold(255, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 47, 25); } // Otsu doesn't need our help, decent on it's own else { matUnwrapped = matUnwrapped.Threshold(0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu); } } else { needConvertionToBGR = false; } } // assign result shape_ = paperContour; matOutput_ = matUnwrapped; if (needConvertionToBGR) { matOutput_ = matOutput_.CvtColor(ColorConversionCodes.GRAY2BGR); // to make it compatible with input texture } // mark we're good dirty_ = false; }
public static List <Unit> FindUnits(Img img) { var src = img.ToMat().Clone(); var blurred = src.GaussianBlur(new OpenCvSharp.Size(3, 3), 0); var gray = blurred.ToGray(); var canny = gray.Canny(30, 100); CvPoint[][] contours; HierarchyIndex[] hierarchy; canny.FindContours(out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple); var list = new List <FindUnitIconMatTempInfo>(); for (var i = 0; i < contours.Length; i++) { var contour = contours[i]; var borderLen = Cv2.ArcLength(contour, true); var approx = Cv2.ApproxPolyDP(contour, 0.02 * borderLen, true); if (approx.Length == 4 && Cv2.IsContourConvex(approx)) { if (borderLen > 100 && IsSquare(approx)) { list.Add(new FindUnitIconMatTempInfo() { Index = i, BorderLength = borderLen, Points = approx, CenterPoint = GetCenterPoint(approx), }); } } } if (list.Count == 0) { return(new List <Unit>()); } list.Sort((a, b) => { return(a.BorderLength.CompareTo(b.BorderLength)); }); var listList = new List <List <FindUnitIconMatTempInfo> >(); var tempList = new List <FindUnitIconMatTempInfo>() { list[0] }; for (var i = 1; i < list.Count; i++) { var ratio = list[i].BorderLength / list[i - 1].BorderLength; if (ratio > 1.1) { listList.Add(tempList); tempList = new List <FindUnitIconMatTempInfo>(); } tempList.Add(list[i]); } listList.Add(tempList); var maxCount = listList.Max(x => x.Count); var maxCountList = listList.Where(x => x.Count == maxCount).FirstOrDefault(); //根据FindContours的索引重新排序 maxCountList.Sort((a, b) => { return(a.Index.CompareTo(b.Index)); }); //过滤掉重复的 var centerPointList = new List <CvPoint>(); tempList = new List <FindUnitIconMatTempInfo>(); var hasSame = new Func <CvPoint, bool>((point) => { foreach (var pt in centerPointList) { if (Math.Abs(point.X - pt.X) < 10 && Math.Abs(point.Y - pt.Y) < 10) { return(true); } } return(false); }); foreach (var item in maxCountList) { var center = item.CenterPoint; if (!hasSame(center)) { tempList.Add(item); centerPointList.Add(center); } } maxCountList = tempList; var iconSources = new List <Img>(); for (var i = 0; i < maxCountList.Count; i++) { var item = maxCountList[i]; var wid = item.BorderLength * 0.25 * 1.1; var center = item.CenterPoint; var rect = new Rect(center - new CvPoint(wid / 2, wid / 2), new CvSize(wid, wid)); var mat = new Mat(src, rect); iconSources.Add(new Img(mat)); //Cv2.ImShow(i.ToString(), mat); } var averBorderLen = maxCountList.Average(x => x.BorderLength); var r = FindUnits(iconSources, averBorderLen * 0.25); r.Reverse(); return(r); }
private Bitmap CreateObjectMaskMelee(Bitmap image, out Mat image_mask, out double mask_length, out double mask_area, out double mask_width, out double mask_height, out double mask_pvheight, bool useKthresholdLab = false) { Bitmap dst = null; image_mask = null; mask_length = mask_area = mask_width = mask_height = mask_pvheight = 0; try { Mat src = BitmapConverter.ToMat(image); Mat src_kirsch = BitmapConverter.ToMat(image.KirschFilter()); Mat kirsch_gray = new Mat(); Cv2.CvtColor(src_kirsch, kirsch_gray, ColorConversionCodes.RGB2GRAY); Mat kirsch_threshold = new Mat(); if (!useKthresholdLab) { Cv2.Threshold(kirsch_gray, kirsch_threshold, kThreshold, 255, ThresholdTypes.Binary); } else { Cv2.Threshold(kirsch_gray, kirsch_threshold, kThresholdLab, 255, ThresholdTypes.Binary); } Mat[] contours; List <OpenCvSharp.Point> hierarchy; List <Mat> hulls; Mat morph_element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new OpenCvSharp.Size(2, 2), new OpenCvSharp.Point(1, 1)); #region morphology Mat kirsch_threshold_copy = new Mat(); kirsch_threshold.CopyTo(kirsch_threshold_copy); int hullCount = 0, numLoops = 0; do { numLoops++; Mat kirsch_morph = kirsch_threshold_copy.MorphologyEx(MorphTypes.Gradient, morph_element); hierarchy = new List <OpenCvSharp.Point>(); Cv2.FindContours(kirsch_morph, out contours, OutputArray.Create(hierarchy), RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0)); hulls = new List <Mat>(); for (int j = 0; j < contours.Length; j++) { Mat hull = new Mat(); Cv2.ConvexHull(contours[j], hull); hulls.Add(hull); } Mat drawing = Mat.Zeros(src.Size(), MatType.CV_8UC1); Cv2.DrawContours(drawing, hulls, -1, Scalar.White); if (hulls.Count != hullCount && numLoops < 100) { hullCount = hulls.Count; kirsch_threshold_copy = drawing; } else { break; } } while (true); #endregion if (numLoops >= 100) { throw new Exception("Could not find hull"); } #region bestHull //try and filter out dust near to stone double largestArea = hulls.Max(m => Cv2.ContourArea(m)); var bestHulls = hulls.Where(m => Cv2.ContourArea(m) == largestArea).ToList(); Mat hulls_mask = Mat.Zeros(src.Size(), MatType.CV_8UC1); Cv2.DrawContours(hulls_mask, bestHulls, -1, Scalar.White, -1); //hulls_mask is the convex hull of main outline excluding nearby dust Cv2.Threshold(kirsch_gray, kirsch_threshold, hullThreshold, 255, ThresholdTypes.Binary); Mat kirsch_mask = Mat.Zeros(kirsch_threshold.Size(), kirsch_threshold.Type()); kirsch_threshold.CopyTo(kirsch_mask, hulls_mask); #endregion hierarchy = new List <OpenCvSharp.Point>();; Cv2.FindContours(kirsch_mask, out contours, OutputArray.Create(hierarchy), RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0)); List <OpenCvSharp.Point> points = new List <OpenCvSharp.Point>(); foreach (Mat contour in contours) { int m2Count = (contour.Rows % 2 > 0) ? contour.Rows + 1 : contour.Rows; OpenCvSharp.Point[] p2 = new OpenCvSharp.Point[m2Count]; contour.GetArray(0, 0, p2); Array.Resize(ref p2, contour.Rows); points.AddRange(p2.ToList()); } Mat finalHull = new Mat(); Cv2.ConvexHull(InputArray.Create(points), finalHull); List <Mat> finalHulls = new List <Mat>(); finalHulls.Add(finalHull); Cv2.DrawContours(src, finalHulls, -1, new Scalar(128, 0, 128, 255), 2); hulls_mask = Mat.Zeros(src.Size(), MatType.CV_8UC1); Cv2.DrawContours(hulls_mask, finalHulls, -1, Scalar.White, -1); image_mask = hulls_mask; #region bounding Mat poly = new Mat(); Cv2.ApproxPolyDP(finalHull, poly, 3, true); Rect boundaryRect = Cv2.BoundingRect(poly); mask_width = boundaryRect.Width; mask_height = boundaryRect.Height; mask_area = Cv2.ContourArea(poly); mask_length = Cv2.ArcLength(finalHull, true); List <OpenCvSharp.Point> finalPoints = new List <OpenCvSharp.Point>(); int m1Count = (finalHull.Rows % 2 > 0) ? finalHull.Rows + 1 : finalHull.Rows; OpenCvSharp.Point[] p1 = new OpenCvSharp.Point[m1Count]; finalHull.GetArray(0, 0, p1); Array.Resize(ref p1, finalHull.Rows); finalPoints.AddRange(p1.ToList()); double y_min = boundaryRect.Bottom; double y_x_min = finalPoints.Where(p => p.X == boundaryRect.Left).ToList()[0].Y; double y_x_max = finalPoints.Where(p => p.X == boundaryRect.Right).ToList()[0].Y; mask_pvheight = ((double)y_x_max + (double)y_x_min) / 2 - (double)y_min; #endregion //dst = BitmapConverter.ToBitmap(src); using (var ms = src.ToMemoryStream()) { dst = (Bitmap)Image.FromStream(ms); } try { if (saveMaskDataPath.Length > 0) { StringBuilder sb = new StringBuilder(); sb.AppendLine("mask_length,mask_area,mask_width,mask_height,mask_pvheight"); sb.AppendLine(mask_length + "," + mask_area + "," + mask_width + "," + mask_height + "," + mask_pvheight); image_mask.SaveImage(saveMaskDataPath + @"\image_mask.jpg"); File.WriteAllText(saveMaskDataPath + @"\mask_vals.csv", sb.ToString()); } } catch { } } catch { dst = null; } return(dst); }
/// <summary> /// 2値化 /// </summary> /// <param name="picture">Image画像データ</param> /// <returns> /// 成功時:Imageデータ /// 失敗時:null /// </returns> public List <Image> Binarization(Image picture) { List <Image> img = new List <Image>(); try { //元画像(Image)データをMatデータにする。 Mat Moto = new Mat(); Moto = BitmapConverter.ToMat((Bitmap)picture); //グレースケール Mat Gray = new Mat(); Cv2.CvtColor(Moto, Gray, ColorConversionCodes.BGRA2GRAY); //2値化 Mat Binari = Gray.Threshold(0.0, 255.0, ThresholdTypes.Binary | ThresholdTypes.Otsu); //輪郭検出 OpenCvSharp.Point[][] edgesArray = Binari.Clone().FindContoursAsArray(RetrievalModes.List, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0)); //輪郭ごとに処理を加える foreach (OpenCvSharp.Point[] item1 in edgesArray) { //直線近似にする OpenCvSharp.Point[] normalizedEdges = Cv2.ApproxPolyDP(item1, 10, true); //近似結果から四角のみを対象 if (normalizedEdges.Count() == 4) { //輪郭が内接する四角形を作り、長辺に合わせて正方形にしておく Rect rect = Cv2.BoundingRect(normalizedEdges); if (rect.Width < rect.Height) { rect.Width = rect.Height; } else if (rect.Height < rect.Width) { rect.Height = rect.Width; } //四角形のサイズが一定の範囲以外は無視する if ((Moto.Width * 0.1) < rect.Width && (Moto.Width * 0.6) > rect.Width && (Moto.Width * 0.1) < rect.Height && (Moto.Width * 0.6) > rect.Height) { //見つけた輪郭を、上記にて作った正方形に補正するための行列を作り、元画像に補正をかける。 //補正準備(補正元の輪郭) List <Point2f> srcEdges = new List <Point2f>(); foreach (OpenCvSharp.Point edge in normalizedEdges) { srcEdges.Add(new Point2f(edge.X, edge.Y)); } srcEdges.Add(new Point2f(normalizedEdges[0].X, normalizedEdges[0].Y)); //補正準備(補正先の輪郭) List <Point2f> dstEdges = new List <Point2f>(); dstEdges.Add(new Point2f(rect.X, rect.Y)); dstEdges.Add(new Point2f(rect.X + rect.Width, rect.Y)); dstEdges.Add(new Point2f(rect.X + rect.Width, rect.Y + rect.Height)); dstEdges.Add(new Point2f(rect.X, rect.Y + rect.Height)); dstEdges.Add(new Point2f(rect.X, rect.Y)); //変換行列の作成 Mat t = Cv2.GetPerspectiveTransform(srcEdges, dstEdges); //元画像に補正をかける Mat mat = Gray; mat = mat.WarpPerspective(t, new OpenCvSharp.Size(mat.Width, mat.Height)); //画像をリストへ追加 img.Add(BitmapConverter.ToBitmap(mat)); } } } if (img.Count == 0) { img = null; } } catch (Exception ex) { img = null; throw ex; } return(img); }
private Bitmap CreateObjectMaskNew(Bitmap image, out Mat image_mask, out double mask_length, out double mask_area, out double mask_width, out double mask_height, out double mask_pvheight, double kThresh, double hThresh, double canny1, double canny2, out Mat image_mask_spc, out double mask2_area, int brightAreaThreshold = -1, int darkAreaThreshold = -1) { Bitmap dst = null; image_mask = null; image_mask_spc = null; mask_length = mask_area = mask_width = mask_height = mask_pvheight = mask2_area = 0; try { Mat src = BitmapConverter.ToMat(image); Mat src_kirsch = BitmapConverter.ToMat(image.KirschFilter()); Mat kirsch_gray = new Mat(); Cv2.CvtColor(src_kirsch, kirsch_gray, ColorConversionCodes.RGB2GRAY); Mat kirsch_threshold = new Mat(); Cv2.Threshold(kirsch_gray, kirsch_threshold, kThresh, 255, ThresholdTypes.Binary); Mat[] contours; List <OpenCvSharp.Point> hierarchy; List <Mat> hulls; Mat morph_element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new OpenCvSharp.Size(2, 2), new OpenCvSharp.Point(1, 1)); #region morphology Mat kirsch_threshold_copy = new Mat(); kirsch_threshold.CopyTo(kirsch_threshold_copy); int hullCount = 0, numLoops = 0; do { numLoops++; Mat kirsch_morph = kirsch_threshold_copy.MorphologyEx(MorphTypes.Gradient, morph_element); hierarchy = new List <OpenCvSharp.Point>(); Cv2.FindContours(kirsch_morph, out contours, OutputArray.Create(hierarchy), RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0)); hulls = new List <Mat>(); for (int j = 0; j < contours.Length; j++) { Mat hull = new Mat(); Cv2.ConvexHull(contours[j], hull); hulls.Add(hull); } Mat drawing = Mat.Zeros(src.Size(), MatType.CV_8UC1); Cv2.DrawContours(drawing, hulls, -1, Scalar.White); if (hulls.Count != hullCount && numLoops < 100) { hullCount = hulls.Count; kirsch_threshold_copy = drawing; } else { break; } } while (true); #endregion if (numLoops >= 100) { throw new Exception("Could not find hull"); } #region bestHull //try and filter out dust near to stone double largestArea = hulls.Max(m => Cv2.ContourArea(m)); var bestHulls = hulls.Where(m => Cv2.ContourArea(m) == largestArea).ToList(); Mat hulls_mask = Mat.Zeros(src.Size(), MatType.CV_8UC1); Cv2.DrawContours(hulls_mask, bestHulls, -1, Scalar.White, -1); //hulls_mask is the convex hull of outline, now look for clefts Cv2.Threshold(kirsch_gray, kirsch_threshold, hThresh, 255, ThresholdTypes.Binary); Mat kirsch_mask = Mat.Zeros(kirsch_threshold.Size(), kirsch_threshold.Type()); kirsch_threshold.CopyTo(kirsch_mask, hulls_mask); Mat kirsch_mask_canny = new Mat(); Cv2.Canny(kirsch_mask, kirsch_mask_canny, canny1, canny2, 3); morph_element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new OpenCvSharp.Size(5, 5), new OpenCvSharp.Point(2, 2)); Mat kirsch_filled = new Mat(); Cv2.Dilate(kirsch_mask_canny, kirsch_filled, morph_element); Cv2.Dilate(kirsch_filled, kirsch_filled, morph_element); Cv2.Erode(kirsch_filled, kirsch_filled, morph_element); Cv2.Erode(kirsch_filled, kirsch_filled, morph_element); hierarchy = new List <OpenCvSharp.Point>();; Cv2.FindContours(kirsch_filled, out contours, OutputArray.Create(hierarchy), RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0)); #endregion hulls_mask = Mat.Zeros(src.Size(), MatType.CV_8UC1); Cv2.DrawContours(hulls_mask, contours, -1, Scalar.White, -1); Cv2.Erode(hulls_mask, hulls_mask, morph_element); Cv2.Erode(hulls_mask, hulls_mask, morph_element); image_mask = hulls_mask; //remove bright areas if ((brightAreaThreshold > -1) || (darkAreaThreshold > -1)) { Mat src_mask = new Mat(); Mat hulls_mask_spc = hulls_mask.Clone(); src.CopyTo(src_mask, hulls_mask_spc); Mat gray = new Mat(); Cv2.CvtColor(src_mask, gray, ColorConversionCodes.BGR2GRAY); if (brightAreaThreshold > -1) { Mat bright = new Mat(); Cv2.Threshold(gray, bright, brightAreaThreshold, 255, ThresholdTypes.BinaryInv); Cv2.ImWrite(@"C:\gColorFancy\Image\bright.jpg", bright); Mat t = new Mat(); hulls_mask_spc.CopyTo(t, bright); hulls_mask_spc = t.Clone(); } if (darkAreaThreshold > -1) { Mat dark = new Mat(); Cv2.Threshold(gray, dark, darkAreaThreshold, 255, ThresholdTypes.Binary); Cv2.ImWrite(@"C:\gColorFancy\Image\dark.jpg", dark); Mat t = new Mat(); hulls_mask_spc.CopyTo(t, dark); hulls_mask_spc = t.Clone(); } image_mask_spc = hulls_mask_spc; var hierarchy2 = new List <OpenCvSharp.Point>();; Cv2.FindContours(hulls_mask_spc, out contours, OutputArray.Create(hierarchy2), RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0)); largestArea = contours.Max(m => Cv2.ContourArea(m)); Mat finalHullSpc = contours.Where(m => Cv2.ContourArea(m) == largestArea).ToList()[0]; if (ConvexHullOnMask) { Mat hull = new Mat(); Cv2.ConvexHull(finalHullSpc, hull); Mat polySpc = new Mat(); Cv2.ApproxPolyDP(hull, polySpc, 3, true); mask2_area = Cv2.ContourArea(polySpc); } else { mask2_area = largestArea; } } /////////////////////////// hierarchy = new List <OpenCvSharp.Point>();; Cv2.FindContours(hulls_mask, out contours, OutputArray.Create(hierarchy), RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0)); largestArea = contours.Max(m => Cv2.ContourArea(m)); Mat finalHull = contours.Where(m => Cv2.ContourArea(m) == largestArea).ToList()[0]; if (ConvexHullOnMask) { var hull = new Mat(); Cv2.ConvexHull(finalHull, hull); finalHull = hull; } List <Mat> finalHulls = new List <Mat>(); finalHulls.Add(finalHull); Cv2.DrawContours(src, finalHulls, -1, new Scalar(128, 0, 128, 255), 3); #region bounding Mat poly = new Mat(); Cv2.ApproxPolyDP(finalHull, poly, 3, true); Rect boundaryRect = Cv2.BoundingRect(poly); mask_width = boundaryRect.Width; mask_height = boundaryRect.Height; if (ConvexHullOnMask) { mask_area = Cv2.ContourArea(poly); } else { mask_area = largestArea; } mask_length = Cv2.ArcLength(finalHull, true); List <OpenCvSharp.Point> finalPoints = new List <OpenCvSharp.Point>(); int m1Count = (finalHull.Rows % 2 > 0) ? finalHull.Rows + 1 : finalHull.Rows; OpenCvSharp.Point[] p1 = new OpenCvSharp.Point[m1Count]; finalHull.GetArray(0, 0, p1); Array.Resize(ref p1, finalHull.Rows); finalPoints.AddRange(p1.ToList()); double y_min = boundaryRect.Bottom; double y_x_min = finalPoints.Where(p => p.X == boundaryRect.Left).ToList()[0].Y; double y_x_max = finalPoints.Where(p => p.X == boundaryRect.Right).ToList()[0].Y; mask_pvheight = ((double)y_x_max + (double)y_x_min) / 2 - (double)y_min; #endregion //dst = BitmapConverter.ToBitmap(src); using (var ms = src.ToMemoryStream()) { dst = (Bitmap)Image.FromStream(ms); } try { if (saveMaskDataPath.Length > 0) { //StringBuilder sb = new StringBuilder(); //sb.AppendLine("mask_length,mask_area,mask_width,mask_height,mask_pvheight"); //sb.AppendLine(mask_length + "," + mask_area + "," + mask_width + "," + mask_height + "," + mask_pvheight); image_mask.SaveImage(saveMaskDataPath + @"\image_mask.jpg"); if (image_mask_spc != null) { image_mask_spc.SaveImage(saveMaskDataPath + @"\image_mask_spc.jpg"); } BitmapConverter.ToMat(image).SaveImage(saveMaskDataPath + @"\src.jpg"); //File.WriteAllText(saveMaskDataPath + @"\mask_vals.csv", sb.ToString()); //File.AppendAllText(saveMaskDataPath + @"\exception.txt", DateTime.Now + ":" + av.Message); //File.AppendAllText(saveMaskDataPath + @"\exception.txt", DateTime.Now + ":" + av.StackTrace); //File.AppendAllText(saveMaskDataPath + @"\exception.txt", DateTime.Now + ":" + av.Source); } } catch { } } catch (Exception ex) { dst = null; } return(dst); }
Point2d[] FindTemp(OpenCvSharp.Point[] contours) { //tempCount = contours.Length; //Cv2.PutText(frame_out, tempCount.ToString(), new OpenCvSharp.Point(20, 20), //HersheyFonts.HersheyDuplex, 0.5, new Scalar(255, 255, 0)); OpenCvSharp.Point[] approxedRow; OpenCvSharp.Point[] approxed = new OpenCvSharp.Point[4]; approxedRow = Cv2.ApproxPolyDP(contours, 4, false); if (approxedRow.Length > 4) { int[] indexDel = new int[20]; int k = -1; for (int i = 0; i < approxedRow.Length; i++) { int pl = i + 1; int mi = i - 1; if (mi == -1) { mi = approxedRow.Length - 1; } if (pl == approxedRow.Length) { pl = 0; } if ((Math.Abs(approxedRow[pl].Y - approxedRow[i].Y) < 30) && (Math.Abs(approxedRow[mi].Y - approxedRow[i].Y) < 30)) { k++; indexDel[k] = i; } } int n = -1; for (int i = 0; i < approxedRow.Length; i++) { if (Array.IndexOf(indexDel, i) == -1) { n++; approxed[n] = approxedRow[i]; } } } else { approxed[0] = approxedRow[0]; approxed[1] = approxedRow[1]; approxed[2] = approxedRow[2]; approxed[3] = approxedRow[3]; } //тут мы расставляем точки по местам Point2d[] pointsList = new Point2d[4]; IEnumerable <Point2d> points = new List <Point2d>(); Point2d[] pointsShow = new Point2d[4]; for (int p = 0; p < 4; p++) { int indexL = 0; double maxL = 0; for (int q = 0; q < 4; q++) { if (p != q) { double l = Math.Sqrt(Math.Pow(approxed[p].X - approxed[q].X, 2) + Math.Pow(approxed[p].Y - approxed[q].Y, 2)); if (maxL < l) { maxL = l; indexL = q; } } } if ((approxed[indexL].X - approxed[p].X < 0) && (approxed[indexL].Y - approxed[p].Y > 0)) { pointsList[0] = approxed[p]; pointsShow[0] = approxed[p]; } if ((approxed[indexL].X - approxed[p].X > 0) && (approxed[indexL].Y - approxed[p].Y > 0)) { pointsList[1] = approxed[p]; pointsShow[1] = approxed[p]; } if ((approxed[indexL].X - approxed[p].X > 0) && (approxed[indexL].Y - approxed[p].Y < 0)) { pointsList[2] = approxed[p]; pointsShow[2] = approxed[p]; } if ((approxed[indexL].X - approxed[p].X < 0) && (approxed[indexL].Y - approxed[p].Y < 0)) { pointsList[3] = approxed[p]; pointsShow[3] = approxed[p]; } } points = pointsList; for (int i = 0; i < 4; i++) { Cv2.PutText(frame_out, Convert.ToString(i), new OpenCvSharp.Point(Convert.ToInt32(pointsShow[i].X), Convert.ToInt32(pointsShow[i].Y)), HersheyFonts.HersheyDuplex, 0.3, new Scalar(0, 255, 0)); } return(pointsList); }
private void detectShapeCandidates(ref Bitmap bitmap, Boolean saveShapes) { string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); Mat colorMat = BitmapConverter.ToMat(bitmap); MatOfDouble mu = new MatOfDouble(); MatOfDouble sigma = new MatOfDouble(); Cv2.MeanStdDev(colorMat, mu, sigma); double mean = mu.GetArray(0, 0)[0]; mu.Dispose(); sigma.Dispose(); Mat greyMat = new Mat(); Cv2.CvtColor(colorMat, greyMat, ColorConversion.BgraToGray, 0); greyMat = greyMat.GaussianBlur(new OpenCvSharp.CPlusPlus.Size(1, 1), 5, 5, BorderType.Default); greyMat = greyMat.Canny(0.5 * mean, 1.2 * mean, 3, true); Mat contourMat = new Mat(greyMat.Size(), colorMat.Type()); greyMat.CopyTo(contourMat); var contours = contourMat.FindContoursAsArray(ContourRetrieval.List, ContourChain.ApproxSimple); this.controls.Clear(); for (int j = 0; j < contours.Length; j++) { var poly = Cv2.ApproxPolyDP(contours[j], 0.01 * Cv2.ArcLength(contours[j], true), true); int num = poly.Length; if (num >= 4 && num < 20) { var color = Scalar.Blue; var rect = Cv2.BoundingRect(poly); if (rect.Height < 20 || rect.Width < 20) { continue; } if (saveShapes) { string path = Path.Combine(myPhotos, "shape_samples"); path = Path.Combine(path, "shape_sample_" + Path.GetRandomFileName() + ".png"); Mat shapeMat = preprocessShape(rect, greyMat); Bitmap shape = shapeMat.ToBitmap(); shape.Save(path); shape.Dispose(); shapeMat.Dispose(); continue; } if (shapeSVM != null) { Mat shapeMat = preprocessShape(rect, greyMat); float shapeClass = classifyShape(shapeMat, shapeSVM); if (shapeClass >= 0) { Shape shape = null; switch ((int)shapeClass) { case 0: color = Scalar.Red; shape = new Shape(Shape.ShapeType.SQUARE, rect); break; case 1: color = Scalar.Yellow; shape = new Shape(Shape.ShapeType.CIRCLE, rect); break; case 2: color = Scalar.Green; shape = new Shape(Shape.ShapeType.SLIDER, rect); break; } Cv2.Rectangle(colorMat, rect, color, 2); this.controls.Add(shape); } shapeMat.Dispose(); } else { Cv2.Rectangle(colorMat, rect, color, 2); } } } bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(colorMat); colorMat.Dispose(); greyMat.Dispose(); contourMat.Dispose(); }
//mask the inner part of circle static List <Point[]> Mask_innercicle(ref Mat img) { Mat img_gaussian = Mat.Zeros(img.Size(), MatType.CV_8UC1); Cv2.GaussianBlur(img, img_gaussian, new OpenCvSharp.Size(21, 21), 0, 0); Mat thresh1 = img_gaussian.Threshold(180, 255, ThresholdTypes.Binary); thresh1.SaveImage("threshold.jpg"); Point[][] contours; HierarchyIndex[] hierarchly; Cv2.FindContours(thresh1, out contours, out hierarchly, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple); // find final circle List <Point[]> contours_final = new List <Point[]>(); foreach (OpenCvSharp.Point[] contour_now in contours) { if (Cv2.ContourArea(contour_now) > 1000000 && Cv2.ContourArea(contour_now) < 2500000) { contours_final.Add(contour_now); } } ///OpenCvSharp.Point[][] temp = new Point[1][];//for draw on image Point[] contours_approx_innercircle; var contour_innercircle = contours_final[1]; //temp[0] = contour_now; Point2f center; float radius; //Cv2.DrawContours(vis_rgb, temp, -1, Scalar.Green, thickness: -1); contours_approx_innercircle = Cv2.ApproxPolyDP(contour_innercircle, 0.001, true);//speedup Cv2.MinEnclosingCircle(contours_approx_innercircle, out center, out radius); //Cv2.Circle(img, (Point)center, (int)radius+ stop1_inner_circle_radius, 255, thickness: -1); //Cv2.Circle(vis_rgb, (Point)center, (int)radius, Scalar.White, thickness: -1); //==================================================outer contour - inner contour===================================== // variable OpenCvSharp.Point[][] temp = new Point[1][]; // inner contour Mat inner_contour_img = Mat.Zeros(img.Size(), MatType.CV_8UC1); //Point[] inner_contour = Cv2.ConvexHull(contours_final[1]); temp[0] = contours_final[1]; //Cv2.DrawContours(inner_contour_img, temp, -1, 255, -1); Cv2.DrawContours(inner_contour_img, temp, -1, 255, -1); //Cv2.Circle(inner_contour_img, (Point)center, (int)radius + stop1_inner_circle_radius, 255, thickness: -1); // outer contour Mat outer_contour_img = Mat.Zeros(img.Size(), MatType.CV_8UC1); Mat outer_contour_img2 = new Mat(img.Size(), MatType.CV_8UC1, new Scalar(255));//initilize Mat with the value 255 temp[0] = contours_final[0]; Cv2.DrawContours(outer_contour_img, temp, -1, 255, -1); //outer contour2 in order to make mask area = 255 Cv2.DrawContours(outer_contour_img2, temp, -1, 0, -1); //outer - inner Mat diff_mask = outer_contour_img - inner_contour_img; Mat diff_mask2 = inner_contour_img + outer_contour_img2; Mat image = Mat.Zeros(img.Size(), MatType.CV_8UC1); img.CopyTo(image, diff_mask); //in order to make mask area = 255 img = image + diff_mask2; return(contours_final); }
private static void SegmentationCannyFilledPolygons(Camera camera, out List <Point2f> v_center, out List <float> v_radius) { RenderTexture activeRenderTexture = RenderTexture.active; RenderTexture.active = camera.targetTexture; camera.Render(); Texture2D currentFrame = new Texture2D(camera.targetTexture.width, camera.targetTexture.height); currentFrame.ReadPixels(new UnityEngine.Rect(0, 0, camera.targetTexture.width, camera.targetTexture.height), 0, 0); currentFrame.Apply(); RenderTexture.active = activeRenderTexture; Mat image = OpenCvSharp.Unity.TextureToMat(currentFrame); UnityEngine.Object.Destroy(currentFrame); Mat grayImage = new Mat(); Cv2.CvtColor(image, grayImage, ColorConversionCodes.BGR2GRAY); Cv2.EqualizeHist(grayImage, grayImage); Cv2.GaussianBlur(grayImage, grayImage, new Size(9, 9), 2, 2); Mat edgesImage = new Mat(); Cv2.Canny(grayImage, edgesImage, 40, 20); Point[][] contours_canny; HierarchyIndex[] hierarchy_canny; Cv2.FindContours(edgesImage, out contours_canny, out hierarchy_canny, RetrievalModes.List, ContourApproximationModes.ApproxSimple, null); Mat img_all_contours_and_filled = Mat.Zeros(edgesImage.Height, edgesImage.Width, MatType.CV_8UC1); Mat img_all_contours = Mat.Zeros(edgesImage.Height, edgesImage.Width, MatType.CV_8UC1); for (int j = 0; j < contours_canny.Length; j++) { Scalar color = new Scalar(255, 255, 255); Cv2.DrawContours(img_all_contours_and_filled, contours_canny, j, color, -1, LineTypes.Link8, hierarchy_canny); Cv2.DrawContours(img_all_contours, contours_canny, j, color, 1, LineTypes.Link8, hierarchy_canny); } Mat img_only_closed_contours = new Mat(); Cv2.Absdiff(img_all_contours_and_filled, img_all_contours, img_only_closed_contours); Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(img_only_closed_contours, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxTC89L1, null); Point[][] contours_poly = new Point[contours.Length][]; OpenCvSharp.Rect[] boundRect = new OpenCvSharp.Rect[contours.Length]; List <Point2f> contours_center = new List <Point2f> { }; List <float> contours_radius = new List <float> { }; int i_contour = 0; foreach (Point[] contour in contours) { Point2f contour_center; float contour_radius; contours_poly[i_contour] = Cv2.ApproxPolyDP(contour, 3, true); Cv2.MinEnclosingCircle(contours_poly[i_contour], out contour_center, out contour_radius); //currentFrame = DrawCircle(currentFrame, (int)contour_center.X, (int)contour_center.Y, (int)contour_radius); contours_center.Add(contour_center); contours_radius.Add(contour_radius); i_contour++; } v_center = contours_center; v_radius = contours_radius; //TextureToPNG(currentFrame); }
private void LoadImage(string filePath) { //using (Mat mat1 = Mat.Zeros(2048, 1536, MatType.CV_8UC1)) //using (Mat mat2 = Mat.Zeros(2048, 1536, MatType.CV_8UC1)) //using (var intersection = new Mat(2048, 1536, MatType.CV_8UC1)) //using (var union = new Mat(2048, 1536, MatType.CV_8UC1)) //{ // mat1.FillPoly(new[] { new[] // { // new Point(565, 267), // new Point(1210, 207), // new Point(1275, 1720), // new Point(568, 1688) // } }, Scalar.All(255)); // AddImage(mat1); // mat2.FillPoly(new[] { new[] // { // new Point(564, 268), // new Point(1208, 208), // new Point(1272, 1716), // new Point(572, 1688) // } }, Scalar.All(255)); // AddImage(mat2); // Cv2.BitwiseAnd(mat1, mat2, intersection); // int intersectionPixels = Cv2.CountNonZero(intersection); // AddImage(intersection); // Cv2.BitwiseOr(mat1, mat2, union); // int unionPixels = Cv2.CountNonZero(union); // AddImage(union); // double iou = (double) intersectionPixels / unionPixels; //} // //return; try { using (Mat image = new Mat(filePath)) using (Mat resized = image.Resize(GetTargetSize(image.Size()))) //Scale the image, so we are working with something consistent { AddImage(resized); using (Mat gray = resized.CvtColor(ColorConversionCodes.BGRA2GRAY)) //Convert to gray scale since we don't want the color data using (Mat blur = gray.GaussianBlur(new Size(5, 5), 0, borderType: BorderTypes.Replicate)) //Smooth the image to eliminate noise using (Mat autoCanny = blur.AutoCanny(0.75)) //Apply canny edge filter to find edges { AddImage(blur); AddImage(autoCanny); Point[][] contours = autoCanny.FindContoursAsArray(RetrievalModes.List, ContourApproximationModes.ApproxSimple); //Just get the external hull of the contours for (int i = 0; i < contours.Length; i++) { contours[i] = Cv2.ConvexHull(contours[i]); } //Draw all of the found polygons. This is just for reference using (Mat allFound = resized.Clone()) { for (int i = 0; i < contours.Length; i++) { Cv2.DrawContours(allFound, contours, i, Scalar.RandomColor(), 2); } AddImage(allFound); } //Find the largest polygons that four corners var found = (from contour in contours let permimiter = Cv2.ArcLength(contour, true) let approx = Cv2.ApproxPolyDP(contour, 0.02 * permimiter, true) where IsValidRectangle(approx, 0.2) let area = Cv2.ContourArea(contour) orderby area descending //We are looking for the biggest thing select contour).Take(3).ToArray(); //Grabbing three just for comparison //Colors the found polygons Green->Yellow->Red to indicate best matches. for (int i = found.Length - 1; i >= 0; i--) { Scalar color; switch (i) { case 0: color = Scalar.Green; break; case 1: color = Scalar.Yellow; break; case 2: color = Scalar.Red; break; default: color = Scalar.RandomColor(); break; } resized.DrawContours(found, i, color, 3); } AddImage(resized); } } } catch (Exception e) { Debug.WriteLine(e.ToString()); } bool IsValidRectangle(Point[] contour, double minimum) { if (contour.Length != 4) { return(false); } double side1 = GetLength(contour[0], contour[1]); double side2 = GetLength(contour[1], contour[2]); double side3 = GetLength(contour[2], contour[3]); double side4 = GetLength(contour[3], contour[0]); if (Math.Abs(side1 - side3) / Math.Max(side1, side3) > minimum) { return(false); } if (Math.Abs(side2 - side4) / Math.Max(side2, side4) > minimum) { return(false); } return(true); double GetLength(Point p1, Point p2) => Math.Abs(p1.X - p2.X) + Math.Abs(p1.Y - p2.Y); } Size GetTargetSize(Size size, int longSize = 512) { if (size.Width > size.Height) { return(new Size(longSize, (int)(longSize * (double)size.Height / size.Width))); } return(new Size((int)(longSize * (double)size.Width / size.Height), longSize)); } }
static void Main(string[] args) { UdpClient client = new UdpClient(); List <byte> data = new List <byte>(); int x2 = 0; int y2 = 0; int a2 = 0; HttpCamera skyCam = new HttpCamera("HTTPCam", "http://192.168.1.121:1181/stream.mjpg"); MjpegServer mjpeg = new MjpegServer("MjpegServer", 9000); mjpeg.Source = skyCam; CvSink skySink = new CvSink("Sky"); skySink.Source = mjpeg.Source; skySink.Enabled = true; CvSource cvSource1 = new CvSource("Source 1", PixelFormat.Mjpeg, 1920, 1080, 30); MjpegServer source1Server = new MjpegServer("Source 1 server", 9001); source1Server.Source = cvSource1; CvSource cvSource2 = new CvSource("Source 2", PixelFormat.Mjpeg, 1920, 1080, 30); MjpegServer inRangeServer = new MjpegServer("Source 2 server", 9002); inRangeServer.Source = cvSource2; cvSource2.CreateProperty("HLow", PropertyKind.Integer, 0, 180, 1, 75, 75); cvSource2.CreateProperty("HHigh", PropertyKind.Integer, 0, 180, 1, 80, 80); cvSource2.CreateProperty("SLow", PropertyKind.Integer, 0, 255, 1, 21, 21); cvSource2.CreateProperty("SHigh", PropertyKind.Integer, 0, 255, 1, 255, 255); cvSource2.CreateProperty("VLow", PropertyKind.Integer, 0, 255, 1, 131, 131); cvSource2.CreateProperty("VHigh", PropertyKind.Integer, 0, 255, 1, 255, 255); //IPEndPoint EP = new IPEndPoint(IPAddress.Any, 0); //UdpClient reciever = new UdpClient(9003, AddressFamily.InterNetwork); //while (true) //{ // byte[] received = reciever.Receive(ref EP); // Console.Write("{ "); // for (int i = 0; i < received.Length; i++) // { // Console.Write($"{received[i]}{(i < received.Length - 1 ? "," : "")}"); // } // Console.WriteLine($" }} (from: {EP})"); //} Mat input = new Mat(); Mat hsv = new Mat(); Mat inRange = new Mat(); Mat inRangeCopy = new Mat(); double angle1 = 0; double angle2 = 0; Stopwatch sw = new Stopwatch(); while (true) { sw.Restart(); if (skySink.GrabFrame(input) == 0) { continue; } //Cv2.Resize(input, input, new Size(640, 360)); Cv2.CvtColor(input, hsv, ColorConversionCodes.BGR2HSV); int hlow = cvSource2.GetProperty("HLow").Get(); int hhigh = cvSource2.GetProperty("HHigh").Get(); int slow = cvSource2.GetProperty("SLow").Get(); int shigh = cvSource2.GetProperty("SHigh").Get(); int vlow = cvSource2.GetProperty("VLow").Get(); int vhigh = cvSource2.GetProperty("VHigh").Get(); Cv2.InRange(hsv, new Scalar(hlow, slow, vlow), new Scalar(hhigh, shigh, vhigh), inRange); inRange.CopyTo(inRangeCopy); Point[][] contours = Cv2.FindContoursAsArray(inRangeCopy, RetrievalModes.List, ContourApproximationModes.ApproxTC89KCOS); List <int> averages = new List <int>(); List <Point[]> polyPoints = new List <Point[]>(); foreach (var contour in contours) { Point[] hull = Cv2.ConvexHull(contour); Point[] poly = Cv2.ApproxPolyDP(hull, 5, true); if (poly.Length == 3) { if (Cv2.ContourArea(hull) < 580) { #region OtherTriangle if (Cv2.ContourArea(hull) < 520) { continue; } double yAv = 0; double xAv = 0; int ct = 0; for (int i = 0; i < poly.Length; i++) { ct++; xAv += poly[i].X; yAv += poly[i].Y; } double zO = poly[0].DistanceTo(poly[1]); double oT = poly[1].DistanceTo(poly[2]); double tZ = poly[2].DistanceTo(poly[0]); double op = 0; double adj = 0; bool rQ = false; if (zO < oT && zO < tZ) { Point p = new Point((poly[0].X + poly[1].X) / 2, (poly[0].Y + poly[1].Y) / 2); input.Line(p, poly[2], Scalar.White, 2); op = poly[2].Y - p.Y; adj = poly[2].X - p.X; if (adj >= 0) { rQ = true; } } else if (oT < zO && oT < tZ) { Point p = new Point((poly[1].X + poly[2].X) / 2, (poly[1].Y + poly[2].Y) / 2); input.Line(p, poly[0], Scalar.White, 2); op = poly[0].Y - p.Y; adj = poly[0].X - p.X; if (adj >= 0) { rQ = true; } } else { Point p = new Point((poly[2].X + poly[0].X) / 2, (poly[2].Y + poly[0].Y) / 2); input.Line(p, poly[1], Scalar.White, 2); op = poly[1].Y - p.Y; adj = poly[1].X - p.X; if (adj >= 0) { rQ = true; } } xAv /= ct; yAv /= ct; x2 = (int)(xAv * 100); y2 = (int)(yAv * 100); a2 = (int)((Math.Atan(op / adj) * 180 / Math.PI)); if (rQ) { a2 = a2 + 270; rQ = false; } else { a2 += 90; } #endregion continue; } double yAverage = 0; double xAverage = 0; int count = 0; for (int i = 0; i < poly.Length; i++) { count++; xAverage += poly[i].X; yAverage += poly[i].Y; } double zeroOne = poly[0].DistanceTo(poly[1]); double oneTwo = poly[1].DistanceTo(poly[2]); double twoZero = poly[2].DistanceTo(poly[0]); double opposite = 0; double adjacent = 0; bool rightQuadrants = false; if (zeroOne < oneTwo && zeroOne < twoZero) { Point p = new Point((poly[0].X + poly[1].X) / 2, (poly[0].Y + poly[1].Y) / 2); input.Line(p, poly[2], Scalar.White, 2); opposite = poly[2].Y - p.Y; adjacent = poly[2].X - p.X; if (adjacent >= 0) { rightQuadrants = true; } } else if (oneTwo < zeroOne && oneTwo < twoZero) { Point p = new Point((poly[1].X + poly[2].X) / 2, (poly[1].Y + poly[2].Y) / 2); input.Line(p, poly[0], Scalar.White, 2); opposite = poly[0].Y - p.Y; adjacent = poly[0].X - p.X; if (adjacent >= 0) { rightQuadrants = true; } } else { Point p = new Point((poly[2].X + poly[0].X) / 2, (poly[2].Y + poly[0].Y) / 2); input.Line(p, poly[1], Scalar.White, 2); opposite = poly[1].Y - p.Y; adjacent = poly[1].X - p.X; if (adjacent >= 0) { rightQuadrants = true; } } xAverage /= count; yAverage /= count; int x = (int)(xAverage * 100); int y = (int)(yAverage * 100); int angle = (int)((Math.Atan(opposite / adjacent) * 180 / Math.PI)); if (rightQuadrants) { angle = angle + 270; rightQuadrants = false; } else { angle += 90; } //Console.WriteLine(angle); AddData(x, data); AddData(y, data); AddData(angle, data); } else if (poly.Length == 4) { if (Cv2.ContourArea(hull) < 300) { continue; } polyPoints.Add(poly); Rect boundingRect = Cv2.BoundingRect(poly); Point centerPoint = new Point(boundingRect.X + boundingRect.Width / 2, boundingRect.Y + boundingRect.Height / 2); if (boundingRect.X < 540) { Cv2.Circle(input, centerPoint, 10, Scalar.AliceBlue); Point difference = centerPoint - new Point(421, 372); angle1 = Math.Atan2(difference.X, difference.Y) * 180 / Math.PI; } else { Cv2.Circle(input, centerPoint, 10, Scalar.HotPink); Point difference = centerPoint - new Point(876, 369); angle2 = Math.Atan2(difference.X, difference.Y) * 180 / Math.PI; } } } input.PutText("Angle1: " + angle1.ToString(), new Point(421, 400), HersheyFonts.HersheyComplex, 0.5f, Scalar.AliceBlue); input.PutText("Angle2: " + angle2.ToString(), new Point(876, 400), HersheyFonts.HersheyComplex, 0.5f, Scalar.HotPink); Cv2.Circle(input, new Point(421, 372), 1, Scalar.AliceBlue); Cv2.Circle(input, new Point(876, 369), 1, Scalar.AliceBlue); AddData((int)Math.Round(angle1, 0), data); AddData((int)Math.Round(angle2, 0), data); AddData(x2, data); AddData(y2, data); AddData(a2, data); input.DrawContours(polyPoints, -1, Scalar.Blue, -1); cvSource1.PutFrame(input); cvSource2.PutFrame(inRange); client.Send(data.ToArray(), data.Count, new IPEndPoint(IPAddress.Loopback, 9003)); data.Clear(); Console.WriteLine(sw.Elapsed); //Thread.Sleep(20); } }