public static void Run(Options options) { //load the image and compute the ratio of the old height //to the new height, clone it, and resize it using (var disposer = new Disposer()) { var image = new Image <Bgr, byte>(options.Image); disposer.Add(image); Image <Bgr, byte> orig = image.Clone(); disposer.Add(orig); double ratio = image.Height / 500.0; image = ImageUtil.Resize(image, height: 500); disposer.Add(image); Image <Gray, byte> gray = image.Convert <Gray, byte>(); disposer.Add(gray); gray = gray.SmoothGaussian(5); disposer.Add(gray); Image <Gray, byte> edged = gray.Canny(75, 200); disposer.Add(edged); Console.WriteLine("STEP 1: Edge Detection"); CvInvoke.Imshow("Image", image); CvInvoke.Imshow("Edged", edged); CvInvoke.WaitKey(); CvInvoke.DestroyAllWindows(); //find the contours in the edged image, keeping only the //largest ones, and initialize the screen contour VectorOfVectorOfPoint cnts = new VectorOfVectorOfPoint(); disposer.Add(cnts); using (Image <Gray, byte> edgedClone = edged.Clone()) { CvInvoke.FindContours(edgedClone, cnts, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); } Point[] screenCnt = null; foreach (VectorOfPoint c in Enumerable.Range(0, cnts.Size).Select(i => cnts[i]).OrderByDescending(c => CvInvoke.ContourArea(c)).Take(5)) { //approximate the contour double peri = CvInvoke.ArcLength(c, true); using (VectorOfPoint approx = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(c, approx, 0.02 * peri, true); if (approx.Size == 4) { screenCnt = approx.ToArray(); break; } } } if (screenCnt == null) { Console.WriteLine("Failed to find polygon with four points"); return; } //show the contour (outline) of the piece of paper Console.WriteLine("STEP 2: Find contours of paper"); image.Draw(screenCnt, new Bgr(0, 255, 0), 2); CvInvoke.Imshow("Outline", image); CvInvoke.WaitKey(); CvInvoke.DestroyAllWindows(); //apply the four point transform to obtain a top-down //view of the original image Image <Bgr, byte> warped = FourPointTransform(orig, screenCnt.Select(pt => new PointF((int)(pt.X * ratio), (int)(pt.Y * ratio)))); disposer.Add(warped); //convert the warped image to grayscale, then threshold it //to give it that 'black and white' paper effect Image <Gray, byte> warpedGray = warped.Convert <Gray, byte>(); disposer.Add(warpedGray); warpedGray = warpedGray.ThresholdAdaptive(new Gray(251), AdaptiveThresholdType.GaussianC, ThresholdType.Binary, 251, new Gray(10)); disposer.Add(warpedGray); Console.WriteLine("STEP 3: Apply perspective transform"); Image <Bgr, byte> origResized = ImageUtil.Resize(orig, height: 650); disposer.Add(origResized); CvInvoke.Imshow("Original", origResized); Image <Gray, byte> warpedResized = ImageUtil.Resize(warpedGray, height: 650); disposer.Add(warpedResized); CvInvoke.Imshow("Scanned", warpedResized); CvInvoke.WaitKey(); CvInvoke.DestroyAllWindows(); } }
public Form1() { InitializeComponent(); //Mat picture = new Mat(@"C:\Users\flore\Desktop\OK.png", Emgu.CV.CvEnum.LoadImageType.AnyColor); // Pick some path on your disk! //CvInvoke.Imshow("Hello World!", picture); // Open window with image Capture capture = new Capture(); //create a camera captue // var inImage = new Image<Bgr, byte>(@"PhotosCube\cube3.jpg"); var processViewer = new ImageBox(); //create an image viewer this.pnl.Controls.Add(processViewer); processViewer.Dock = DockStyle.Top; processViewer.Height = capture.Height; var cannyViewer = new ImageBox(); //create an image viewer this.pnl.Controls.Add(cannyViewer); cannyViewer.Dock = DockStyle.Top; cannyViewer.Height = capture.Height; var contourViewer = new ImageBox(); //create an image viewer this.pnl.Controls.Add(contourViewer); contourViewer.Dock = DockStyle.Top; contourViewer.Height = capture.Height; var viewer = new ImageBox(); //create an image viewer this.pnl.Controls.Add(viewer); viewer.Dock = DockStyle.Top; viewer.Height = capture.Height; Vector2 vect1; Vector2 vect2; for (int i = 0; i < Colors.Count - 1; i++) { for (int j = i + 1; j < Colors.Count; j++) { var dist = (Colors.Values.ElementAt(i) - Colors.Values.ElementAt(j)).LengthFast; if (dist < MaxColorDistance) { MaxColorDistance = dist; vect1 = Colors.Values.ElementAt(i); vect2 = Colors.Values.ElementAt(j); } } } Application.Idle += new EventHandler(delegate(object sender, EventArgs e) { //run this until application closed (close button click on image viewer) var frame = capture.QueryFrame(); var inImage = frame.ToImage <Bgr, byte>(); //draw the image obtained from camera var contourImage = inImage.Clone(); // Mat outImage = new Mat(); //CvInvoke.MedianBlur(frame, outImage, 5); var processsImageChannels = new Image <Bgr, byte>(inImage.Size); CvInvoke.CvtColor(frame, processsImageChannels, ColorConversion.Rgb2Hsv); // var processsImage = new Mat(); // CvInvoke.ExtractChannel(inImage, processsImage, 1); processViewer.Image = processsImageChannels; Mat canny = new Mat(); CvInvoke.Canny(inImage, canny, barCanny1.Value, barCanny2.Value, 3, true); cannyViewer.Image = canny; //CvInvoke.DrawContours(outImage, contours,-1, new MCvScalar(0,0,255)); using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.FindContours(canny, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); var lstParallelogram = new List <Quadrilateral>(); for (int i = 0; i < contours.Size; i++) { using (VectorOfPoint contour = contours[i]) using (VectorOfPoint approxContour = new VectorOfPoint()) { var arc = CvInvoke.ArcLength(contour, true); // éliminer les objets les plus petits if (arc / 4 < inImage.Width / 30) { continue; } CvInvoke.ApproxPolyDP(contour, approxContour, arc * 0.1, true); if (approxContour.Size == 4) { var pts = approxContour.ToArray(); contourImage.DrawPolyline(pts, true, new Bgr(Color.Green)); var quadri = new Quadrilateral(pts, 0.1, 0.1); if (quadri.IsParallelogram) { lstParallelogram.Add(quadri); } } } } contourViewer.Image = contourImage; // suppression des doublons var comparer = new QuadrilateralCenterComparer(0.3); lstParallelogram = lstParallelogram.Distinct(comparer).ToList(); var lstSquares = lstParallelogram.Where((x) => x.IsSquare).ToList(); // nombre minimal de cube if (lstSquares.Count > 5) { //var circle = CvInvoke.MinEnclosingCircle(lstCube.SelectMany((x) => x.Points).Select((x) => new PointF(x.X, x.Y)).ToArray()); //inImage.Draw(circle, new Bgr(255, 255, 0)); var minX = lstSquares.Min((x) => x.Center.X); var maxX = lstSquares.Max((x) => x.Center.X); var minY = lstSquares.Min((x) => x.Center.Y); var maxY = lstSquares.Max((x) => x.Center.Y); //inImage.Draw(new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY)), new Bgr(Color.Bisque), 1); lstSquares.Min((x) => x.Center.X); var averageLength = lstSquares.Average((x) => x.AverageLength); var centerDistance = averageLength * 1.4; var bottom = new Vector2(lstSquares.Average((x) => x.Bottom.X), lstSquares.Average((x) => x.Bottom.Y)); bottom.Normalize(); var right = new Vector2(bottom.Y, -bottom.X); var pastilles = new List <Pastille>(); var pastilleOrigine = new Pastille(); pastilleOrigine.m = 0; pastilleOrigine.n = 0; pastilleOrigine.Quadrilateral = lstSquares[0]; pastilleOrigine.Center = lstSquares[0].Center; pastilles.Add(pastilleOrigine); var origine = lstSquares[0].Center; for (int i = 1; i < lstSquares.Count; i++) { var u = lstSquares[i].Center - origine; var pastille = new Pastille(); pastille.Quadrilateral = lstSquares[i]; //inImage.DrawPolyline(quadri.Points, true, new Bgr(Color.Blue), 3); pastille.n = (int)Math.Round(Vector2.Dot(u, bottom) / centerDistance); pastille.m = (int)Math.Round(Vector2.Dot(u, right) / centerDistance); pastille.Center = lstSquares[i].Center; pastilles.Add(pastille); } var xMax = pastilles.Max((x) => x.m); var xMin = pastilles.Min((x) => x.m); var yMax = pastilles.Max((x) => x.n); var yMin = pastilles.Min((x) => x.n); if (xMax - xMin != 3 || yMax - yMin != 3) { return; // ce n'est pas un cube 4x4 } // x et y entre 0 et 3 pastilles.ForEach((x) => { x.m -= xMin; x.n -= yMin; }); // recalcul de centerDistance centerDistance = 0; for (int i = 0; i < pastilles.Count - 1; i++) { var dm = pastilles[i + 1].m - pastilles[i].m; var dn = pastilles[i + 1].n - pastilles[i].n; centerDistance += (pastilles[i].Center - pastilles[i + 1].Center).LengthFast / Math.Sqrt(dm * dm + dn * dn); } centerDistance /= pastilles.Count - 1; Pastille[,] pastilleMatrix = new Pastille[4, 4]; //http://www.wolframalpha.com/input/?i=x%3Dx1%2Bk1*u1,x%3Dx2%2Bk2*u2,y%3Dy1%2Bk1*v1,y%3Dy2%2Bk2*v2+for+x,y for (int m = 0; m < 4; m++) { for (int n = 0; n < 4; n++) { var pastille = pastilles.FirstOrDefault((x) => x.m == m && x.n == n); if (pastille == null) { pastille = new Pastille(); pastille.m = m; pastille.n = n; // calcul de la position des pastilles non détéctées foreach (var p in pastilles) { pastille.Center += p.Center + (float)centerDistance * ((m - p.m) * right + (n - p.n) * bottom); } pastille.Center /= pastilles.Count; } pastilleMatrix[m, n] = pastille; var ptRect = pastille.Center - new Vector2(averageLength / 4); if (ptRect.X < 0) { ptRect.X = 0; } else if (ptRect.X + averageLength / 2 >= inImage.Width) { ptRect.X = inImage.Width - 1 - (int)averageLength / 2; } if (ptRect.Y < 0) { ptRect.Y = 0; } else if (ptRect.Y + averageLength / 2 >= inImage.Height) { ptRect.Y = inImage.Height - 1 - (int)averageLength / 2; } var rectangle = new Rectangle((int)ptRect.X, (int)ptRect.Y, (int)averageLength / 2, (int)averageLength / 2); var rectMat = processsImageChannels.GetSubRect(rectangle); var color = CvInvoke.Mean(rectMat); pastille.MeanColor.MCvScalar = color; var minDist = float.MaxValue; foreach (var elt in Colors) { var dist = (elt.Value - new Vector2((float)color.V0, (float)color.V1)).Length; if (dist < minDist) { minDist = dist; pastille.Color = elt.Key; } } } } // inImage.Draw(pastille.X + ";" + pastille.Y, new Point((int)lstSquares[i].Center.X - 10, (int)lstSquares[i].Center.Y + 10), FontFace.HersheyComplex, 0.5, new Bgr(Color.Aquamarine), 1); // int n = 0; h.Add(pastilleMatrix[0, 0].MeanColor.Hue); s.Add(pastilleMatrix[0, 0].MeanColor.Satuation); lblH.Text = h.Average().ToString(); lblS.Text = s.Average().ToString(); foreach (var pastille in pastilleMatrix) { if (pastille.Quadrilateral != null) { inImage.DrawPolyline(pastille.Quadrilateral.Points, true, new Bgr(Color.Blue), 3); inImage.Draw(new LineSegment2D(new Point((int)(pastille.Quadrilateral.Center.X), (int)(pastille.Quadrilateral.Center.Y)), new Point((int)(pastille.Quadrilateral.Center.X + right.X * 20), (int)(pastille.Quadrilateral.Center.Y + right.Y * 20))), new Bgr(Color.SeaGreen), 3); inImage.Draw(new LineSegment2D(new Point((int)(pastille.Quadrilateral.Center.X), (int)(pastille.Quadrilateral.Center.Y)), new Point((int)(pastille.Quadrilateral.Center.X + bottom.X * 20), (int)(pastille.Quadrilateral.Center.Y + bottom.Y * 20))), new Bgr(Color.Red), 3); inImage.Draw(pastille.m + ";" + pastille.n, new Point((int)pastille.Quadrilateral.Center.X - 10, (int)pastille.Quadrilateral.Center.Y + 10), FontFace.HersheyComplex, 0.5, new Bgr(Color.Aquamarine), 1); } else { var circle = new CircleF(new PointF(pastille.Center.X, pastille.Center.Y), averageLength / 4); inImage.Draw(circle, new Bgr(Color.Pink), (int)averageLength / 4); //inImage.Draw(circle, new Bgr(Color.Pink), 3); } var l = 20; var rect = new Rectangle(pastille.m * l + l, pastille.n * l + l, l / 2, l / 2); inImage.Draw(rect, new Bgr(pastille.Color), l / 2, LineType.AntiAlias); // n++; // inImage.Draw(n.ToString(), new Point(quadri.Points.Sum((x) => x.X) / 4 - 10, quadri.Points.Sum((x) => x.Y) / 4 + 10), FontFace.HersheyComplex, 0.5, new Bgr(Color.Aquamarine), 1); } inImage.Draw(new CircleF(new PointF(origine.X, origine.Y), 5), new Bgr(Color.Purple), 10); //var angles = lstParallelogram.SelectMany((x) => x.Angles).ToList(); //angles.Sort(); //var derivateAngle = new List<double>(angles.Count-1); //for (int a=0;a<angles.Count-1;a++) //{ // derivateAngle.Add(angles[a + 1] - angles[a]); //} //derivateAngle.Sort(); //lblNbFace.Text = derivateAngle.Count((x) => x > 0.5).ToString(); } else { h.Clear(); s.Clear(); } } // CvInvoke.inra // CvInvoke.CvtColor(inImage, outImage, ColorConversion.Rgb2Hsv); //var hue = outImage.Split()[0]; //CvInvoke.Laplacian(inImage, outImage, DepthType.Default, 3); // CvInvoke.Erode(inImage, outImage, null, new Point(-1, -1), 3, BorderType.Default, new MCvScalar(1)); viewer.Image = inImage; }); /* * Mat outImage = new Mat(); * * CvInvoke.MedianBlur(inImage, outImage, 5); * * Mat canny = new Mat(); * * CvInvoke.Canny(outImage, canny, barCanny1.Value, barCanny2.Value); * * * var contours = new VectorOfVectorOfPoint(); * var hierarchy = new Mat(); * * CvInvoke.FindContours(canny, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxNone); * * * CvInvoke.DrawContours(outImage, contours, -1, new MCvScalar(0, 0, 255), 1, LineType.FourConnected, hierarchy); * * * var area = new List<double>(); * * for(int i=0;i<contours.Size;i++) * { * var contour = contours[i]; * * area.Add( CvInvoke.ContourArea(contour)); * } * * area.Sort(); * * richTextBox1.Text = String.Join("\r\n", area.Select((x) => x.ToString()).ToArray()); * * * * viewer.Image = outImage; */ return; StringBuilder msgBuilder = new StringBuilder("Performance: "); //Load the image from file and resize it for display Image <Bgr, Byte> img = new Image <Bgr, byte>(@"PhotosCube\cube3.jpg"); //Convert the image to grayscale and filter out the noise UMat uimage = new UMat(); CvInvoke.CvtColor(img, uimage, ColorConversion.Bgr2Gray); //use image pyr to remove noise // UMat pyrDown = new UMat(); //CvInvoke.PyrDown(uimage, pyrDown); //CvInvoke.PyrUp(pyrDown, uimage); //Image<Gray, Byte> gray = img.Convert<Gray, Byte>().PyrDown().PyrUp(); //#region circle detection Stopwatch watch = Stopwatch.StartNew(); double cannyThreshold = 30; /* * double circleAccumulatorThreshold = 100; * CircleF[] circles = CvInvoke.HoughCircles(uimage, HoughType.Gradient, 2.0, 20.0, cannyThreshold, circleAccumulatorThreshold, 5); * * watch.Stop(); * msgBuilder.Append(String.Format("Hough circles - {0} ms; ", watch.ElapsedMilliseconds)); #endregion */ #region Canny and edge detection watch.Reset(); watch.Start(); double cannyThresholdLinking = 100; UMat cannyEdges = new UMat(); CvInvoke.Canny(uimage, cannyEdges, cannyThreshold, cannyThresholdLinking); LineSegment2D[] lines = CvInvoke.HoughLinesP( cannyEdges, 1, //Distance resolution in pixel-related units Math.PI / 45.0, //Angle resolution measured in radians. 20, //threshold 30, //min Line width 10); //gap between lines watch.Stop(); msgBuilder.Append(String.Format("Canny & Hough lines - {0} ms; ", watch.ElapsedMilliseconds)); #endregion #region Find triangles and rectangles watch.Reset(); watch.Start(); List <Triangle2DF> triangleList = new List <Triangle2DF>(); List <RotatedRect> boxList = new List <RotatedRect>(); //a box is a rotated rectangle using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.FindContours(cannyEdges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); CvInvoke.DrawContours(img, contours, -1, new MCvScalar(0, 0, 255)); int count = contours.Size; for (int i = 0; i < count; i++) { using (VectorOfPoint contour = contours[i]) using (VectorOfPoint approxContour = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true); var a = new VectorOfVectorOfPoint(); // img.Draw(approxContour, new Bgr(Color.DarkOrange), 2); CvInvoke.DrawContours(img, approxContour, 0, new MCvScalar(0, 255, 0)); if (CvInvoke.ContourArea(approxContour, false) > 2) //only consider contours with area greater than 250 { if (approxContour.Size == 3) //The contour has 3 vertices, it is a triangle { Point[] pts = approxContour.ToArray(); triangleList.Add(new Triangle2DF( pts[0], pts[1], pts[2] )); } else if (approxContour.Size == 4) //The contour has 4 vertices. { /* #region determine if all the angles in the contour are within [80, 100] degree * bool isRectangle = true; * Point[] pts = approxContour.ToArray(); * LineSegment2D[] edges = PointCollection.PolyLine(pts, true); * * for (int j = 0; j < edges.Length; j++) * { * double angle = Math.Abs( * edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j])); * if (angle < 80 || angle > 100) * { * isRectangle = false; * break; * } * } #endregion * * if (isRectangle) */ // boxList.Add(CvInvoke.MinAreaRect(approxContour)); } } } } } watch.Stop(); msgBuilder.Append(String.Format("Triangles & Rectangles - {0} ms; ", watch.ElapsedMilliseconds)); #endregion this.Text = msgBuilder.ToString(); #region draw triangles and rectangles //Image<Bgr, Byte> triangleRectangleImage = img.CopyBlank(); //foreach (Triangle2DF triangle in triangleList) //img.Draw(triangle, new Bgr(Color.DarkBlue), 2); foreach (RotatedRect box in boxList) { img.Draw(box, new Bgr(Color.DarkOrange), 2); } #endregion /* #region draw circles * // Image<Bgr, Byte> circleImage = img.CopyBlank(); * // foreach (CircleF circle in circles) * // img.Draw(circle, new Bgr(Color.Brown), 2); #endregion * * #region draw lines * //Image<Bgr, Byte> lineImage = img.CopyBlank(); * foreach (LineSegment2D line in lines) * img.Draw(line, new Bgr(Color.Green), 2); #endregion */ viewer.Image = img; }
private void FindStopSign(Mat img, List <Mat> stopSignList, List <Rectangle> boxList, VectorOfVectorOfPoint contours, int[,] hierachy, int idx) { for (; idx >= 0; idx = hierachy[idx, 0]) { using (VectorOfPoint c = contours[idx]) using (VectorOfPoint approx = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(c, approx, CvInvoke.ArcLength(c, true) * 0.02, true); double area = CvInvoke.ContourArea(approx); if (area > 200) { double ratio = CvInvoke.MatchShapes(_octagon, approx, Emgu.CV.CvEnum.ContoursMatchType.I3); if (ratio > 0.1) //not a good match of contour shape { //check children if (hierachy[idx, 2] >= 0) { FindStopSign(img, stopSignList, boxList, contours, hierachy, hierachy[idx, 2]); } continue; } Rectangle box = CvInvoke.BoundingRectangle(c); Mat candidate = new Mat(); using (Mat tmp = new Mat(img, box)) CvInvoke.CvtColor(tmp, candidate, ColorConversion.Bgr2Gray); //set the value of pixels not in the contour region to zero using (Mat mask = new Mat(candidate.Size.Height, candidate.Width, DepthType.Cv8U, 1)) { mask.SetTo(new MCvScalar(0)); CvInvoke.DrawContours(mask, contours, idx, new MCvScalar(255), -1, LineType.EightConnected, null, int.MaxValue, new Point(-box.X, -box.Y)); double mean = CvInvoke.Mean(candidate, mask).V0; CvInvoke.Threshold(candidate, candidate, mean, 255, ThresholdType.Binary); CvInvoke.BitwiseNot(candidate, candidate); CvInvoke.BitwiseNot(mask, mask); candidate.SetTo(new MCvScalar(0), mask); } int minMatchCount = 8; double uniquenessThreshold = 0.8; VectorOfKeyPoint _observeredKeypoint = new VectorOfKeyPoint(); Mat _observeredDescriptor = new Mat(); _detector.DetectAndCompute(candidate, null, _observeredKeypoint, _observeredDescriptor, false); if (_observeredKeypoint.Size >= minMatchCount) { int k = 2; Mat mask; using (VectorOfVectorOfDMatch matches = new VectorOfVectorOfDMatch()) { _modelDescriptorMatcher.KnnMatch(_observeredDescriptor, matches, k, null); mask = new Mat(matches.Size, 1, DepthType.Cv8U, 1); mask.SetTo(new MCvScalar(255)); Features2DToolbox.VoteForUniqueness(matches, uniquenessThreshold, mask); } int nonZeroCount = CvInvoke.CountNonZero(mask); if (nonZeroCount >= minMatchCount) { boxList.Add(box); stopSignList.Add(candidate); } } } } } }
void DetectPolygons(UMat cannyEdgesImg, bool detectTriangles, bool detectRectangles, bool detectHexagons, int area) { triangles = new List <Triangle2DF>(); rectangles = new List <RotatedRect>(); hexagons = new List <LineSegment2D[]>(); //Find contours VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); CvInvoke.FindContours(cannyEdgesImg, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); //Check all contours for (int i = 0; i < contours.Size; i++) { VectorOfPoint contour = contours[i]; //Approximate a polygon VectorOfPoint approxContour = new VectorOfPoint(); CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.025, true); //Contours bigger than defined area if (CvInvoke.ContourArea(approxContour, false) > 250) { int areaTresshold = 1000; if (area != 0) { if (CvInvoke.ContourArea(approxContour, false) < area - areaTresshold || CvInvoke.ContourArea(approxContour, false) > area + areaTresshold) { //Consider contours near defined area //If area is smaller or bigger than defined -> continue to next countour as this one doesn't fit continue; } } //Add triangle if (approxContour.Size == 3 && detectTriangles) { Point[] pts = approxContour.ToArray(); triangles.Add(new Triangle2DF(pts[0], pts[1], pts[2])); } //Add rectangle else if (approxContour.Size == 4 && detectRectangles) { //Determine if all angles in the contour are within [80, 100] degree bool isRectangle = true; Point[] pts = approxContour.ToArray(); LineSegment2D[] edges = PointCollection.PolyLine(pts, true); for (int j = 0; j < edges.Length; j++) { double angle = Math.Abs(edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j])); if (angle < 80 || angle > 100) { isRectangle = false; break; } } if (isRectangle) { rectangles.Add(CvInvoke.MinAreaRect(approxContour)); } } //Add hexagon else if (approxContour.Size == 6 && detectHexagons) { // Determine if all the angles in the contour are within [50, 70] degree bool isHexagon = true; Point[] pts = approxContour.ToArray(); LineSegment2D[] edges = PointCollection.PolyLine(pts, true); for (int j = 0; j < edges.Length; j++) { double angle = Math.Abs(edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j])); if (angle < 50 || angle > 70) { isHexagon = false; break; } } if (isHexagon) { hexagons.Add(edges); } } } } }
private static void FindRectangle(int min, int max) { Image <Rgb, Byte> img = new Image <Rgb, byte>(ori_img); Image <Gray, Byte> edgeImage = new Image <Gray, byte>(show_img); #region Find rectangles boxList = new List <RotatedRect>(); //a box is a rotated rectangle double rate = img.Width * img.Height / 3864714.0; bool isIDPExist = false, isUseExist = false, isAddressExist = false; using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.FindContours(edgeImage, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); int count = contours.Size; for (int i = 0; i < count; i++) { using (VectorOfPoint contour = contours[i]) using (VectorOfPoint approxContour = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true); double area = CvInvoke.ContourArea(contour, false); if (area > 100000 * rate && area < 142000 * rate && !isIDPExist) { // eid, date, price Point[] pts = contour.ToArray(); PointF[] ptfs = new PointF[pts.Length]; for (int pi = 0; pi < pts.Length; pi++) { ptfs[pi] = new PointF(pts[pi].X, pts[pi].Y); } Rectangle rec = PointCollection.BoundingRectangle(ptfs); img.Draw(rec, new Rgb(Color.DarkOrange), 2); rects.Add(rec); isIDPExist = true; } else if (area > 350000 * rate && area < 450000 * rate) { // use Point[] pts = contour.ToArray(); PointF[] ptfs = new PointF[4]; int minx = int.MaxValue, miny = int.MaxValue, maxx = 0, maxy = 0; for (int pi = 0; pi < pts.Length; pi++) { if (pts[pi].X < minx) { minx = pts[pi].X; } if (pts[pi].Y < miny) { miny = pts[pi].Y; } if (pts[pi].X > maxx) { maxx = pts[pi].X; } if (pts[pi].Y > maxy) { maxy = pts[pi].Y; } } ptfs[0] = new PointF(minx, miny); ptfs[1] = new PointF(minx, (miny + maxy) / 2); ptfs[2] = new PointF(maxx, miny); ptfs[3] = new PointF(maxx, (miny + maxy) / 2); Rectangle rec = PointCollection.BoundingRectangle(ptfs); img.Draw(PointCollection.BoundingRectangle(ptfs), new Rgb(Color.DarkOrange), 2); if (!isUseExist) { rects.Add(rec); isUseExist = true; } PointF[] ptfks = new PointF[4]; ptfks[0] = new PointF(maxx * 1.5f, maxy); ptfks[1] = new PointF(maxx * 1.5f, (float)(maxy + 32 * rate)); ptfks[2] = new PointF(minx, maxy); ptfks[3] = new PointF(minx, (float)(maxy + 32 * rate)); Rectangle rec2 = PointCollection.BoundingRectangle(ptfks); img.Draw(PointCollection.BoundingRectangle(ptfks), new Rgb(Color.DarkOrange), 2); if (!isAddressExist) { rects.Add(rec2); isAddressExist = true; } } else if (area > min * rate && area < max * rate) { Point[] pts = contour.ToArray(); PointF[] ptfs = new PointF[pts.Length]; for (int pi = 0; pi < pts.Length; pi++) { ptfs[pi] = new PointF(pts[pi].X, pts[pi].Y); } Rectangle rec = PointCollection.BoundingRectangle(ptfs); img.Draw(rec, new Rgb(Color.DarkOrange), 2); rects.Add(rec); } } } } #endregion #region draw rectangles foreach (RotatedRect box in boxList) { img.Draw(box, new Rgb(Color.DarkOrange), 2); } pre_img = show_img; show_img = img.Bitmap; rform.UpdateImage(show_img); //img.Save("rect_" + this.count + ".png"); #endregion }
void DetectPolygons(UMat cannyEdgesImg, bool detectTriangles, bool detectRectangles, bool detectHexagons, int area) { triangles = new List <Triangle2DF>(); rectangles = new List <RotatedRect>(); hexagons = new List <LineSegment2D[]>(); // find contours from binary image VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); CvInvoke.FindContours(cannyEdgesImg, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); for (int i = 0; i < contours.Size; i++) { // go trough all detected contours VectorOfPoint contour = contours[i]; // select i-th contour // approximate a polygon VectorOfPoint approxContour = new VectorOfPoint(); CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.025, true); if (CvInvoke.ContourArea(approxContour, false) > 250) //only consider contours bigger than defined area { int areaTresshold = 1000; if (area != 0) { if (CvInvoke.ContourArea(approxContour, false) < area - areaTresshold || CvInvoke.ContourArea(approxContour, false) > area + areaTresshold) { //only consider contours near defined area // if area is smaller or bigger than defined -> continue to next countour as this one doesn't fit continue; } // debug - min area //if (CvInvoke.ContourArea(approxContour, false) > area) // continue; } if (approxContour.Size == 3 && detectTriangles) { // triangle Point[] pts = approxContour.ToArray(); // take points that define a triangle triangles.Add(new Triangle2DF(pts[0], pts[1], pts[2])); // add triangle to the list } else if (approxContour.Size == 4 && detectRectangles) { // rectangle // Determine if all the angles in the contour are within [80, 100] degree bool isRectangle = true; // create a line segment from points Point[] pts = approxContour.ToArray(); LineSegment2D[] edges = PointCollection.PolyLine(pts, true); for (int j = 0; j < edges.Length; j++) { // go trough all edges of a potential rectangle // get angle between two adjcent edges double angle = Math.Abs(edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j])); if (angle < 80 || angle > 100) { isRectangle = false; break; } } if (isRectangle) { rectangles.Add(CvInvoke.MinAreaRect(approxContour)); // if it's a rectangle add it to the list } } else if (approxContour.Size == 6 && detectHexagons) { // hexagon // Determine if all the angles in the contour are within [50, 70] degree bool isHexagon = true; // create a line segment from points Point[] pts = approxContour.ToArray(); LineSegment2D[] edges = PointCollection.PolyLine(pts, true); for (int j = 0; j < edges.Length; j++) { // go trough all edges of a potential hexagon // get angle between two adjcent edges double angle = Math.Abs(edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j])); if (angle < 50 || angle > 70) { isHexagon = false; break; } } if (isHexagon) { // if it's a hexagon add it to the list hexagons.Add(edges); } } } } }
private void FindStopSign(Image <Bgr, byte> img, List <Image <Gray, Byte> > stopSignList, List <Rectangle> boxList, VectorOfVectorOfPoint contours, int[,] hierachy, int idx) { for (; idx >= 0; idx = hierachy[idx, 0]) { using (VectorOfPoint c = contours[idx]) using (VectorOfPoint approx = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(c, approx, CvInvoke.ArcLength(c, true) * 0.02, true); double area = CvInvoke.ContourArea(approx); if (area > 200) { double ratio = CvInvoke.MatchShapes(_octagon, approx, Emgu.CV.CvEnum.ContoursMatchType.I3); if (ratio > 0.1) //not a good match of contour shape { //check children if (hierachy[idx, 2] >= 0) { FindStopSign(img, stopSignList, boxList, contours, hierachy, hierachy[idx, 2]); } continue; } Rectangle box = CvInvoke.BoundingRectangle(c); Image <Gray, Byte> candidate; using (Image <Bgr, Byte> tmp = img.Copy(box)) candidate = tmp.Convert <Gray, byte>(); //Emgu.CV.UI.ImageViewer.Show(candidate); //set the value of pixels not in the contour region to zero using (Image <Gray, Byte> mask = new Image <Gray, byte>(box.Size)) { mask.Draw(contours, idx, new Gray(255), -1, LineType.EightConnected, null, int.MaxValue, new Point(-box.X, -box.Y)); double mean = CvInvoke.Mean(candidate, mask).V0; candidate._ThresholdBinary(new Gray(mean), new Gray(255.0)); candidate._Not(); mask._Not(); candidate.SetValue(0, mask); } int minMatchCount = 8; double uniquenessThreshold = 0.8; VectorOfKeyPoint _observeredKeypoint = new VectorOfKeyPoint(); Mat _observeredDescriptor = new Mat(); _detector.DetectAndCompute(candidate, null, _observeredKeypoint, _observeredDescriptor, false); if (_observeredKeypoint.Size >= minMatchCount) { int k = 2; //Matrix<int> indices = new Matrix<int>(_observeredDescriptor.Size.Height, k); Matrix <byte> mask; //using (Matrix<float> dist = new Matrix<float>(_observeredDescriptor.Size.Height, k)) using (VectorOfVectorOfDMatch matches = new VectorOfVectorOfDMatch()) { _modelDescriptorMatcher.KnnMatch(_observeredDescriptor, matches, k, null); mask = new Matrix <byte>(matches.Size, 1); mask.SetValue(255); Features2DToolbox.VoteForUniqueness(matches, uniquenessThreshold, mask); } int nonZeroCount = CvInvoke.CountNonZero(mask); if (nonZeroCount >= minMatchCount) { boxList.Add(box); stopSignList.Add(candidate); } } } } } }
public static (ShapeType, List <Point>) Check(List <Point> polygonPoints, int canvasWidth, int canvasHeigth) { if (!ClosedContour(polygonPoints)) { return(ShapeType.None, null); } CreateBitmap(canvasWidth, canvasHeigth, polygonPoints); Image <Bgr, byte> img = new Image <Bgr, byte>(@"IMAGE.bmp"); Image <Gray, byte> processed = img .Convert <Gray, byte>() .SmoothGaussian(5) .Canny(240, 200); VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); Mat m = new Mat(); CvInvoke.FindContours( processed, contours, m, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple); if (contours.Size == 0) { return(ShapeType.None, null); } double perimeter = CvInvoke.ArcLength(contours[0], true); var polygon = new VectorOfPoint(); CvInvoke.ApproxPolyDP(contours[0], polygon, 0.02 * perimeter, true); if (!CvInvoke.IsContourConvex(polygon)) { return(ShapeType.None, null); } var moments = CvInvoke.Moments(contours[0]); int x = (int)(moments.M10 / moments.M00); int y = (int)(moments.M01 / moments.M00); Point center = new Point(x, y); List <Point> points = new List <Point>(); for (int i = 0; i < polygon.Size; i++) { points.Add(new Point(polygon[i].X, polygon[i].Y)); } if (points.Count == 3) { return(ShapeType.Triangle, points); } else if (points.Count == 4) { return(RectangleOrSquare(center, perimeter, points)); } else if (points.Count > 4) { return(CircleOrEllipse(center, perimeter, points)); } return(ShapeType.None, null); }
public static IEnumerable <Rectangle> DetectSquares(Mat sourceImage) { Mat destinationImage = new Mat(); destinationImage.Create(sourceImage.Rows, sourceImage.Cols, sourceImage.Depth, 1); Mat greyscaleImage = new Mat(); CvInvoke.CvtColor(sourceImage, greyscaleImage, ColorConversion.Bgr2Gray); Mat detectedEdges = new Mat(); CvInvoke.GaussianBlur(greyscaleImage, detectedEdges, new Size(1, 1), 1); CvInvoke.Canny(detectedEdges, detectedEdges, Treshold, Treshold * 3); CvInvoke.Dilate(detectedEdges, detectedEdges, new Mat(), new Point(-1, -1), 3, BorderType.Default, new MCvScalar(255, 255, 255)); //ImageViewer.Show(detectedEdges); List <Rectangle> boxList = new List <Rectangle>(); //List<LineSegment2D> lines = new List<LineSegment2D>(); using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.FindContours(detectedEdges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); int count = contours.Size; for (int i = 0; i < count; i++) { using (VectorOfPoint approxContour = new VectorOfPoint()) using (VectorOfPoint approx = contours[i]) { CvInvoke.ApproxPolyDP(approx, approxContour, CvInvoke.ArcLength(approx, true) * 0.035, true); Point[] pts = approxContour.ToArray(); LineSegment2D[] edges = PointCollection.PolyLine(pts, true); //lines.AddRange(edges); double contourArea = CvInvoke.ContourArea(approxContour, true); if (contourArea >= 500 && contourArea <= detectedEdges.Width * detectedEdges.Height / 5) { if (approxContour.Size >= 2) { bool isRectangle = true; for (int j = 0; j < edges.Length; j++) { double angle = Math.Abs(edges[(j + 1) % edges.Length] .GetExteriorAngleDegree(edges[j])); if (angle < 85 || angle > 95) { isRectangle = false; break; } } if (isRectangle) { RotatedRect currentRectangle = CvInvoke.MinAreaRect(approxContour); Rectangle minRectangle = currentRectangle.MinAreaRect(); //int ninetyPercentWidth = minRectangle.Width - (int)(minRectangle.Width * 0.05); //int ninetyPercentHeight = minRectangle.Height - (int)(minRectangle.Height * 0.05); //minRectangle.Size = new Size(ninetyPercentWidth, ninetyPercentHeight); //minRectangle.Offset(5, 5); boxList.Add(minRectangle); } } } } } } return(boxList); }
void ProcessFrame(object sender, EventArgs e) { Mat frame = _cameraCapture.QueryFrame(); Mat smoothedFrame = new Mat(); CvInvoke.GaussianBlur(frame, smoothedFrame, new Size(3, 3), 1); //filter out noises #region use the BG/FG detector to find the foreground mask Mat foregroundMask = new Mat(); _fgDetector.Apply(smoothedFrame, foregroundMask); #endregion List <TrackedObject> toBeRemovedList = new List <TrackedObject>(); List <Rectangle> boundingBoxesTracked = new List <Rectangle>(); List <int> idsTracked = new List <int>(); foreach (TrackedObject t in _trackers) { Rectangle boundingBox; bool success = t.Update(frame, out boundingBox); if (success) { boundingBoxesTracked.Add(boundingBox); idsTracked.Add(t.Id); } else { toBeRemovedList.Add(t); } } foreach (TrackedObject t in toBeRemovedList) { _trackers.Remove(t); t.Dispose(); } List <Rectangle> newObjects = new List <Rectangle>(); int minAreaThreshold = 100; using (Mat canny = new Mat()) using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.Canny(foregroundMask, canny, 180, 100); CvInvoke.FindContours(canny, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple); int count = contours.Size; for (int i = 0; i < count; i++) { using (VectorOfPoint contour = contours[i]) using (VectorOfPoint approxContour = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true); if (CvInvoke.ContourArea(approxContour, false) > minAreaThreshold) //only consider contours with area greater than threshold { Rectangle r = CvInvoke.BoundingRectangle(approxContour); bool overlapped = false; foreach (var trackedObj in boundingBoxesTracked) { if (r.IntersectsWith(trackedObj)) { overlapped = true; break; } } if (!overlapped) { newObjects.Add(r); } } } } } foreach (Rectangle r in newObjects) { TrackedObject t = new TrackedObject(_idCounter); boundingBoxesTracked.Add(r); idsTracked.Add(_idCounter); t.Init(frame, r); _trackers.Add(t); _idCounter++; } for (int i = 0; i < boundingBoxesTracked.Count; i++) { Rectangle boundingBox = boundingBoxesTracked[i]; CvInvoke.Rectangle(frame, boundingBox, new MCvScalar(255.0, 255.0, 255.0), 2); CvInvoke.PutText(frame, idsTracked[i].ToString(), new Point(boundingBox.X, boundingBox.Y), FontFace.HersheyPlain, 1.0, new MCvScalar(255.0, 255.0, 255.0)); } imageBox1.Image = frame; imageBox2.Image = foregroundMask; }
public Image <Bgr, byte> ReturnContours(Image <Bgr, byte> image, int minArea, Label label) { if (prepImage == null) { prepImage = ReturnBinarized(image, 90); } var resultImage = prepImage.Convert <Gray, byte>(); int trisCount = 0; int rectCount = 0; int circleCount = 0; // shapes var contours = new VectorOfVectorOfPoint(); CvInvoke.FindContours( resultImage, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); var contoursImage = sourceImage.Copy(); for (int i = 0; i < contours.Size; i++) { //contoursImage.Draw(points, new Bgr(Color.GreenYellow), 2); // отрисовка точек var approxContour = new VectorOfPoint(); CvInvoke.ApproxPolyDP(contours[i], approxContour, CvInvoke.ArcLength(contours[i], true) * 0.05, true); var points = approxContour.ToArray(); if (approxContour.Size == 3) { var S = CvInvoke.ContourArea(approxContour, false); if (S > minArea) { trisCount++; var pointsTri = approxContour.ToArray(); contoursImage.Draw(new Triangle2DF(pointsTri[0], pointsTri[1], pointsTri[2]), new Bgr(Color.GreenYellow), 2); } } if (isRectangle(points)) { var S = CvInvoke.ContourArea(approxContour, false); if (S > minArea) { rectCount++; contoursImage.Draw(CvInvoke.MinAreaRect(approxContour), new Bgr(Color.Blue), 2); } } } //circles List <CircleF> circles = new List <CircleF>(CvInvoke.HoughCircles(resultImage, HoughModes.Gradient, 1.0, 250, 100, 50, 5, contoursImage.Width / 3)); foreach (CircleF circle in circles) { CvInvoke.Circle(contoursImage, Point.Round(circle.Center), (int)circle.Radius, new Bgr(Color.Red).MCvScalar, 2); circleCount++; //resultImage.Draw(circle, new Bgr(Color.GreenYellow), 2); } label.Text = "Количество треугольников = " + trisCount + "\nКоличество прямоугольников = " + rectCount + "\nКоличество кругов = " + circleCount; return(contoursImage); }
// Maximum Value, Minimum Value and their locations // Mean Color or Mean Intensity public void calcularRegionProps(Image <Gray, byte> inputRegionIMG, double AreaMin) { // Declaração do vetor de vetores de pontos Emgu.CV.Util.VectorOfVectorOfPoint vetordeVetdePontos = new Emgu.CV.Util.VectorOfVectorOfPoint(); // Declaração de uma matriz Mat hierarquia = new Mat(); // Aplicação da função FindContour CvInvoke.FindContours( inputRegionIMG // Recebe a imagem de entrada , vetordeVetdePontos // Recebe um vetor de pontos de contorno , hierarquia // Recebe a hierarquia dos pontos , Emgu.CV.CvEnum.RetrType.Tree // Recebe o tipo de arvore e contornos , Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxNone // Tip de aproximação aos contornos , new Point(0, 0) // Offset do ponto, posso omitir ou declarar um ponto a 0 0 ); Image <Bgr, Byte> input = inputRegionIMG.Convert <Bgr, byte>(); //Até aqui encontro o contorno. Deve ser só 1!!!, portanto deve ser o contorno 0, //mas mesmo assim vamos fazer um teste para ver qual o contorno a usar // Pontos buffer PointF buffer_Minx = new PointF(inputRegionIMG.Width, inputRegionIMG.Height); PointF buffer_MaxX = new PointF(0, 0); PointF buffer_MinY = new PointF(inputRegionIMG.Width, inputRegionIMG.Height); PointF buffer_MaxY = new PointF(0, 0); for (int i = 0; i < vetordeVetdePontos.Size; i++) { Area = Math.Abs(CvInvoke.ContourArea(vetordeVetdePontos[i], true)); // calcula a area do contorno if (Area >= AreaMin) { for (int iter = 0; iter < vetordeVetdePontos[i].Size; iter++) { //----------------- Calculo do extreme ----------------- // Calcula o valor do ponto mais à esquerda if (vetordeVetdePontos[i][iter].X < buffer_Minx.X) { buffer_Minx = vetordeVetdePontos[i][iter]; } // Calcula o valor do ponto mais à direita if (vetordeVetdePontos[i][iter].X > buffer_MaxX.X) { buffer_MaxX = vetordeVetdePontos[i][iter]; } // Calcula o valor do ponto Y mais em cima if (vetordeVetdePontos[i][iter].Y < buffer_MinY.Y) { buffer_MinY = vetordeVetdePontos[i][iter]; } // Calcula o valor do ponto Y mais em baixo if (vetordeVetdePontos[i][iter].Y > buffer_MaxY.Y) { buffer_MaxY = vetordeVetdePontos[i][iter]; } //----------------- Fim do calculo do extreme ----------------- } // ------------- Calculo do Centroid --------------------- Moments momento = CvInvoke.Moments(vetordeVetdePontos[i]); int X = (int)(momento.M10 / momento.M00); int Y = (int)(momento.M01 / momento.M00); Centroid = new PointF(X, Y); // ------------------------------------------------------ // ------------ Calculo do AspectRatio ------------------ AspectRatio = inputRegionIMG.Width / inputRegionIMG.Height; //------------------------------------------------------- //------------- Calculo da BoundingBox ------------------ BoundingBox = CvInvoke.BoundingRectangle(vetordeVetdePontos[i]); //------------------------------------------------------- // ------------ Calculo do Extent ------------------- float rect_area = BoundingBox.Width * BoundingBox.Height; Extent = (float)Area / rect_area; // ------------------------------------------------------ // --------------- ConvectHULL -------------------------- CvInvoke.ConvexHull(vetordeVetdePontos[i], ConvexHull, false); //------------------------------------------------------- // --------------- ConvectHULL_area --------------------- ConvexHull_area = CvInvoke.ContourArea(ConvexHull); //------------------------------------------------------- //----------------- Solidity --------------------------- Solidity = Area / ConvexHull_area; // ------------------------------------------------------ //-------------- Diametro Equivalente ------------------- EquivalentDiameter = Math.Sqrt(4 * Area / Math.PI); // ------------------------------------------------------ //--------------- Circulo Envolvente -------------------- CirculoEnvolvente = CvInvoke.MinEnclosingCircle(vetordeVetdePontos[i]); //------------------------------------------------------- //--------------- Circulo Perimetro -------------------- perimetro = CvInvoke.ArcLength(vetordeVetdePontos[i], true); // ----------------------------------------------------- // -------------- Circularity (Fator de forma)---------- Circularity = (4 * Math.PI * Area) / (perimetro * perimetro); //------------------------------------------------------ // --------------- Verifica se é convexo --------------- isConvex = CvInvoke.IsContourConvex(vetordeVetdePontos[i]); //------------------------------------------------------ // ------------- Apriximação do contorno --------------- CvInvoke.ApproxPolyDP( vetordeVetdePontos[i], // Cada vetor de um contorno iterado ContourApproximation, // Vetor que vai conter a aproximação 0.1 * perimetro, // Expande o perimetro true // Calcula um aproximação ao contorno externo ); // ----------------------------------------------------- // ------------- Devolve o contorno -------------------- Contorno = vetordeVetdePontos[i]; // ------------------------------------------------------ // ------------ Retangulo rodado --------------------- RotatedRect retanguloRodado = CvInvoke.MinAreaRect(vetordeVetdePontos[i]); PointF[] vetorPontos = CvInvoke.BoxPoints(retanguloRodado); BoundingBoxRectRodado = new Point[vetorPontos.Length]; for (int iterador = 0; iterador < vetorPontos.Length; iterador++) { BoundingBoxRectRodado[iterador].X = (int)vetorPontos[iterador].X; BoundingBoxRectRodado[iterador].Y = (int)vetorPontos[iterador].Y; } // ------------ AnguloRecExterior ---------------------- AnguloRectExterior = retanguloRodado.Angle; // ----------------------------------------------------- // ------------ EllipseImagem -------------------------- EllipseValores = CvInvoke.FitEllipseAMS(vetordeVetdePontos[i]); // ----------------------------------------------------- // Fitting a Line --------------- //--------------------------- // salta do ciclo for i = vetordeVetdePontos.Size; } } Extreme.Mais_a_esquerda = buffer_Minx; Extreme.Mais_a_Direita = buffer_MaxX; Extreme.Mais_em_baixo = buffer_MaxY; Extreme.Mais_em_cima = buffer_MinY; }
private Mat DoCalibration(Image <Bgr, byte> medianBlurImageIn) { DebugImages[(int)SelectedImage.InImageB] = medianBlurImageIn[0].Mat; DebugImages[(int)SelectedImage.InImageG] = medianBlurImageIn[1].Mat; DebugImages[(int)SelectedImage.InImageR] = medianBlurImageIn[2].Mat; var InImageSum = medianBlurImageIn[0] + medianBlurImageIn[1] + medianBlurImageIn[2]; DebugImages[(int)SelectedImage.InImageSum] = InImageSum.Mat; Mat threshold = new Mat(); CvInvoke.Threshold(InImageSum, threshold, Parameters.Threshold, 255, ThresholdType.Binary); DebugImages[(int)SelectedImage.threshold] = threshold; Mat CannyImage = new Mat(); CvInvoke.Canny(threshold, CannyImage, Parameters.CannyThreshold1, Parameters.CannyThreshold2, 3, true); DebugImages[(int)SelectedImage.Canny] = CannyImage; var contoursImage = medianBlurImageIn.Clone(); DebugImages[(int)SelectedImage.approxContour] = contoursImage.Mat; using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.FindContours(CannyImage, contours, null, RetrType.External, ChainApproxMethod.ChainApproxNone); VectorOfPoint maxContour = null; double arcSize = -1; for (int i = 0; i < contours.Size; i++) { var arc = CvInvoke.ArcLength(contours[i], true); if (arc > arcSize) { arcSize = arc; maxContour = contours[i]; } } if (maxContour != null) { using (VectorOfPoint approxContour = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(maxContour, approxContour, Parameters.ContourEpsilon, true); var convexContour = CvInvoke.ConvexHull(approxContour.ToArray().Select((x) => new PointF(x.X, x.Y)).ToArray()); var pointConvexContour = convexContour.Select((x) => new Point((int)x.X, (int)x.Y)).ToArray(); var circle = CvInvoke.MinEnclosingCircle(convexContour); if (convexContour.Length == 6 && validateAsked) { validateAsked = false; Parameters.Center = new Point((int)circle.Center.X, (int)circle.Center.Y); var maxY = convexContour.Max((x) => x.Y); var indexSommetHaut = convexContour.ToList().FindIndex((x) => x.Y >= maxY - 0.1); for (int i = indexSommetHaut; i < convexContour.Length; i++) { Parameters.Points[i] = pointConvexContour[i]; } for (int i = 0; i < indexSommetHaut; i++) { Parameters.Points[i] = pointConvexContour[i]; } grid.Refresh(); Save(); chkAutoCalibration.Checked = false; } contoursImage.DrawPolyline(pointConvexContour, true, new Bgr(Color.Green), 3); contoursImage.Draw(circle, new Bgr(Color.DarkGreen), 3); contoursImage.Draw(new Cross2DF(circle.Center, 10, 10), new Bgr(Color.DarkGreen), 3); } } return(DebugImages[(int)Parameters.SelectedImage]); } }
public void DisplayWebcam(popup popup) { while (true) { Mat frame = ReadCamera1(); int largestCircle = 0; List <Shape> foundShape = new List <Shape>(); List <char> shapeType = new List <char>(); // resize to PictureBox aspect ratio int newHeight = (frame.Size.Height * pictureBox0.Size.Width) / frame.Size.Width; Size newSize = new Size(pictureBox0.Size.Width, newHeight); CvInvoke.Resize(frame, frame, newSize); Image <Hsv, Byte> img = frame.ToImage <Hsv, Byte>(); Image <Gray, byte> coralNestImg = frame.ToImage <Gray, Byte>(); Image <Gray, byte> coralOutcropImg = frame.ToImage <Gray, Byte>(); Image <Gray, byte> starfishImg = frame.ToImage <Gray, Byte>(); Image <Bgr, byte> drawnImage = frame.ToImage <Bgr, byte>(); Image <Bgr, byte> coralNestDrawn = frame.ToImage <Bgr, byte>(); Image <Bgr, byte> coralOutcropDrawn = frame.ToImage <Bgr, byte>(); Image <Bgr, byte> starfishDrawn = frame.ToImage <Bgr, byte>(); Image <Gray, byte> gridImg = frame.ToImage <Gray, Byte>(); Image <Bgr, byte> gridDrawn = frame.ToImage <Bgr, byte>(); //Line Follow Hsv T_Lower = new Hsv(colorThresholds[4].h_Lower, colorThresholds[4].s_Lower, colorThresholds[4].v_Lower); Hsv T_Upper = new Hsv(colorThresholds[4].h_Upper, colorThresholds[4].s_Upper, colorThresholds[4].v_Upper); Image <Gray, byte> laneImg = frame.ToImage <Gray, Byte>(); laneImg = img.InRange(T_Lower, T_Upper).Erode(2).Dilate(2); //count for columbs int leftC = 0; int centerC = 0; int rightC = 0; for (int i = (laneImg.Height / 20) * 15; i < laneImg.Height; i++) { for (int j = (laneImg.Width / 20) * 14; j < (laneImg.Width / 20) * 16; j++) { //left if (laneImg.Data[i, j, 0] == 255) { leftC++; } } for (int j = (laneImg.Width / 20) * 16; j < (laneImg.Width / 20) * 18; j++) { //center if (laneImg.Data[i, j, 0] == 255) { centerC++; } } for (int j = (laneImg.Width / 20) * 18; j < (laneImg.Width / 20) * 20; j++) { //right if (laneImg.Data[i, j, 0] == 255) { rightC++; } } } if (leftC > centerC && leftC > rightC) { //twist left Twist twist = new Twist(); twist.Linear.Z = 1f; SetInput(twist); label7.Invoke(new Action(() => { label7.Text = "left"; })); } else { if (centerC > rightC && centerC > leftC) { // twist center Twist twist = new Twist(); twist.Linear.X = 1f; SetInput(twist); label7.Invoke(new Action(() => { label7.Text = "center"; })); } else { //twist right Twist twist = new Twist(); twist.Linear.Z = -1f; SetInput(twist); label7.Invoke(new Action(() => { label7.Text = "right"; })); } } if (leftC + rightC + centerC <= 100) { Twist twist = new Twist(); twist.Linear.X = 0; SetInput(twist); //Update keys popup.UpdateKeys(key); } // Find Centers and Draw Bounding Rectangle for (int i = 0; i < 3; i++) { VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); List <Shape> shapes = new List <Shape>(); Mat draw = new Mat(); Hsv t_Lower = new Hsv(colorThresholds[i].h_Lower, colorThresholds[i].s_Lower, colorThresholds[i].v_Lower); Hsv t_Upper = new Hsv(colorThresholds[i].h_Upper, colorThresholds[i].s_Upper, colorThresholds[i].v_Upper); int shapeIndex = 0; double largestArea = 0; switch (i) { case 0: coralNestImg = img.InRange(t_Lower, t_Upper).Erode(2).Dilate(2); CvInvoke.FindContours(coralNestImg, contours, draw, Emgu.CV.CvEnum.RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple); break; case 1: coralOutcropImg = img.InRange(t_Lower, t_Upper).Erode(2).Dilate(2); CvInvoke.FindContours(coralOutcropImg, contours, draw, Emgu.CV.CvEnum.RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple); break; case 2: starfishImg = img.InRange(t_Lower, t_Upper).Erode(2).Dilate(2); CvInvoke.FindContours(starfishImg, contours, draw, Emgu.CV.CvEnum.RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple); break; default: break; } for (int j = 0; j < contours.Size; j++) { double peramiter = CvInvoke.ArcLength(contours[j], true); VectorOfPoint positions = new VectorOfPoint(); CvInvoke.ApproxPolyDP(contours[j], positions, 0.03 * peramiter, true); var moments = CvInvoke.Moments((contours[j])); shapes.Add(new Shape()); //Find Centroid of shape and area and store in shape class shapes[j].x_Center = (moments.M10 / moments.M00); shapes[j].y_Center = (moments.M01 / moments.M00); shapes[j].area = CvInvoke.ContourArea(contours[j]); } //Only compute if there are shapes on screen if (shapes.Count > 0) { // find largest shape sstore it for (int j = 0; j < shapes.Count; j++) { if (shapes[j].area > largestArea) { largestArea = shapes[j].area; shapeIndex = j; } } Rectangle boundingRect = new Rectangle((int)(shapes[shapeIndex].x_Center - 50), (int)(shapes[shapeIndex].y_Center - 50), 100, 100); switch (i) { case 0: coralNestDrawn = coralNestImg.Convert <Bgr, byte>(); coralNestDrawn.Draw(boundingRect, new Bgr(0, 0, 255), 3, LineType.EightConnected, 0); //Add to list of shapes found foundShape.Add(shapes[shapeIndex]); shapeType.Add('n'); break; case 1: coralOutcropDrawn = coralOutcropImg.Convert <Bgr, byte>(); coralOutcropDrawn.Draw(boundingRect, new Bgr(0, 0, 255), 3, LineType.EightConnected, 0); //Add to list of shapes found foundShape.Add(shapes[shapeIndex]); shapeType.Add('o'); break; case 2: starfishDrawn = starfishImg.Convert <Bgr, byte>(); starfishDrawn.Draw(boundingRect, new Bgr(0, 0, 255), 3, LineType.EightConnected, 0); //Add to list of shapes found foundShape.Add(shapes[shapeIndex]); shapeType.Add('s'); break; } } } //Circle Detection /* // var findEdges = img.SmoothGaussian((int)(colorThresholds[3].h_Upper)).Convert<Gray, byte>().ThresholdBinaryInv(new Gray(colorThresholds[3].s_Lower), new Gray(colorThresholds[3].s_Upper)).Erode((int)(colorThresholds[3].h_Lower)).Dilate((int)(colorThresholds[3].h_Lower)); * * Hsv c_Lower = new Hsv(colorThresholds[3].h_Lower, colorThresholds[3].s_Lower, colorThresholds[3].v_Lower); * Hsv c_Upper = new Hsv(colorThresholds[3].h_Upper, colorThresholds[3].s_Upper, colorThresholds[3].v_Upper); * Image<Gray, byte> findEdges = frame.ToImage<Gray, Byte>(); * findEdges = img.InRange(c_Lower, c_Upper).Erode(2); * * Gray cannyThreshold = new Gray(180); * Gray cannyThresholdLinking = new Gray(120); * Gray circleAccumulatorThreshold = new Gray(60); * * CircleF[] foundCircles = findEdges.HoughCircles( * cannyThreshold, * circleAccumulatorThreshold, * 4.0, //Resolution of the accumulator used to detect centers of the circles * 4.0, //Resolution of the accumulator used to detect centers of the circles * 10.0, //min distance * 10, //min radius * 30 //max radius * )[0]; //Get the circles from the first channel * * drawnImage = findEdges.Convert<Bgr, Byte>(); * * * // Find Largest Circle and Draw it on Frame * for (int j = 0; j < foundCircles.Length; j++) * { * if (j == 0) * { * // Skip 0 because its the largest circle at this time * } * else * { * if (foundCircles[j].Area > foundCircles[largestCircle].Area) // Check to see if this is the Largest Circle * { * largestCircle = j; * } * } * } * if (foundCircles.Length != 0) * drawnImage.Draw(foundCircles[largestCircle], new Bgr(0, 255, 0), 3, LineType.EightConnected, 0); // Circle Draw * */ // Grid Detection VectorOfVectorOfPoint Contours = new VectorOfVectorOfPoint(); Mat Draw = new Mat(); Hsv g_Lower = new Hsv(colorThresholds[5].h_Lower, colorThresholds[5].s_Lower, colorThresholds[5].v_Lower); Hsv g_Upper = new Hsv(colorThresholds[5].h_Upper, colorThresholds[5].s_Upper, colorThresholds[5].v_Upper); gridImg = img.InRange(g_Lower, g_Upper).Erode(2).Dilate(2); CvInvoke.FindContours(coralNestImg, Contours, Draw, Emgu.CV.CvEnum.RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple); List <Shape> gShapes = new List <Shape>(); for (int j = 0; j < Contours.Size; j++) { double peramiter = CvInvoke.ArcLength(Contours[j], true); VectorOfPoint positions = new VectorOfPoint(); CvInvoke.ApproxPolyDP(Contours[j], positions, 0.03 * peramiter, true); var moments = CvInvoke.Moments((Contours[j])); gShapes.Add(new Shape()); //Find Centroid of shape and area and store in shape class gShapes[j].x_Center = (moments.M10 / moments.M00); gShapes[j].y_Center = (moments.M01 / moments.M00); gShapes[j].area = CvInvoke.ContourArea(Contours[j]); } if (gShapes.Count > 0) { for (int i = 0; i < gShapes.Count; i++) { if (gShapes[i].area > 400 || gShapes[i].area < 20000) { gShapes.RemoveAt(i); // remove unwanted shapes } } /* * // outline grid squares found * gridDrawn = gridImg.Convert<Bgr, byte>(); * for(int i =0;i<gShapes.Count; i++) * { * Rectangle boundingRect = new Rectangle((int)(gShapes[i].x_Center - 50), (int)(gShapes[i].y_Center - 50), 100, 100); * gridDrawn.Draw(boundingRect, new Bgr(0, 0, 255), 3, LineType.EightConnected, 0); * } * * for(int i = 0; i < gShapes.Count; i++) * { * if (LastPosition.Count == 0) * { * LastPosition.Add(gShapes[i]); // store shapes positions for next rotation * start = 0; * end = foundShape.Count; * //check if centroids are close to those of found shapes * for (int j = 0; j < foundShape.Count; j++) * { * // Check centerpoints with tolerance of +- 20 * if(((foundShape[j].x_Center < gShapes[i].x_Center + 20) && (foundShape[j].x_Center > gShapes[i].x_Center - 20)) && ((foundShape[j].y_Center < gShapes[i].y_Center + 20) && (foundShape[j].y_Center > gShapes[i].y_Center - 20))) * { * key[i] = shapeType[j]; * } * } * * } * else * { * int tEnd = 0; * for(int j = 0; j < gShapes.Count; j++) * { * * if (((LastPosition[j].x_Center < gShapes[i].x_Center + 10) && (LastPosition[j].x_Center > gShapes[i].x_Center - 10)) && ((LastPosition[j].y_Center < gShapes[i].y_Center + 10) && (LastPosition[j].y_Center > gShapes[i].y_Center - 10))) * { * tEnd = j; * } * end = tEnd; * start = (end - foundShape.Count); * * } * * for (int j = 0; j < gShapes.Count; j++) * { * * if (((foundShape[j].x_Center < gShapes[i].x_Center + 20) && (foundShape[j].x_Center > gShapes[i].x_Center - 20)) && ((foundShape[j].y_Center < gShapes[i].y_Center + 20) && (foundShape[j].y_Center > gShapes[i].y_Center - 20))) * { * key[i + start] = shapeType[j]; * } * * } * } * } */ } // Grid analysis // Display Images pictureBox0.Image = frame.Bitmap; pictureBox1.Image = coralNestDrawn.Bitmap; pictureBox2.Image = coralOutcropDrawn.Bitmap; pictureBox3.Image = starfishDrawn.Bitmap; pictureBox4.Image = drawnImage.Bitmap; pictureBox5.Image = laneImg.Bitmap; GridBox.Image = gridDrawn.Bitmap; if (!Sleep(20)) { this.Invoke(new Action(() => { Close(); })); break; } } }
private void contours_Click(object sender, EventArgs e) { if (source == null) { MessageBox.Show("Please open an image."); return; } #region reset UI squareNum.Text = "0"; triangleNum.Text = "0"; circleNum.Text = "0"; lineNum.Text = "0"; #endregion try { #region image manipulation int sg; int.TryParse(smoothGaussian.Text, out sg); int lowerBound; int.TryParse(lower.Text, out lowerBound); int upperBound; int.TryParse(upper.Text, out upperBound); var temp = source.SmoothGaussian(sg).Convert <Gray, byte>().ThresholdBinary(new Gray(lowerBound), new Gray(upperBound));; if (inverse.Checked) { temp = source.SmoothGaussian(sg).Convert <Gray, byte>().ThresholdBinaryInv(new Gray(lowerBound), new Gray(upperBound)); } if (pyr.Checked) { CvInvoke.PyrDown(temp, temp); CvInvoke.PyrUp(temp, temp); } processedImage.Image = temp.Bitmap; #endregion #region find contours VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); CvInvoke.FindContours(temp, contours, new Mat(), RetrType.External, ChainApproxMethod.ChainApproxSimple); #endregion #region guess shapes Image <Bgr, byte> final = source.Copy(); double approxAmount; double.TryParse(approxValue.Text, out approxAmount); double minRatio; double maxRatio; double minArea; double.TryParse(ratioValue.Text, out minRatio); double.TryParse(marea.Text, out minArea); maxRatio = 1 / minRatio; double bx; double.TryParse(bounding.Text, out bx); for (int i = 0; i < contours.Size; i++) { var contour = contours[i]; double perimeter = CvInvoke.ArcLength(contour, true); VectorOfPoint approx = new VectorOfPoint(); CvInvoke.ApproxPolyDP(contour, approx, approxAmount * perimeter, true); CvInvoke.DrawContours(final, contours, i, new MCvScalar(0, 0, 255), 1); Rectangle bounds = CvInvoke.BoundingRectangle(contour); final.Draw(bounds, new Bgr(255, 0, 0)); finalImage.Image = final.Bitmap; double area = CvInvoke.ContourArea(contour); if (!(bounds.X > bx && bounds.X < final.Width - bx)) { if (messages.Checked) { MessageBox.Show("Not in bounds"); } continue; } if (!(bounds.Y > bx && bounds.Y < final.Height - bx)) { if (messages.Checked) { MessageBox.Show("Not in bounds"); } continue; } if (area < minArea) { if (messages.Checked) { MessageBox.Show("Not large enough"); } continue; } if (approx.Size == 3) { int current; int.TryParse(triangleNum.Text, out current); current += 1; triangleNum.Text = current.ToString(); } else if (approx.Size == 4) { Point[] test = approx.ToArray(); Point a = test[0]; Point b = test[1]; Point c = test[2]; double width = Math.Sqrt((((double)(a.X - b.X)) * ((double)(a.X - b.X))) + (((double)(a.Y - b.Y)) * ((double)(a.Y - b.Y)))); double height = Math.Sqrt((((double)(c.X - b.X)) * ((double)(c.X - b.X))) + (((double)(c.Y - b.Y)) * ((double)(c.Y - b.Y)))); double ratio = width / height; int current; if (ratio > minRatio && ratio < maxRatio) { int.TryParse(squareNum.Text, out current); current += 1; squareNum.Text = current.ToString(); } else { int.TryParse(lineNum.Text, out current); current += 1; lineNum.Text = current.ToString(); } } else { int current; int.TryParse(circleNum.Text, out current); current += 1; circleNum.Text = current.ToString(); } if (messages.Checked) { MessageBox.Show("Current shape: " + approx.Size.ToString()); } } #endregion } catch (Exception exception) { MessageBox.Show(exception.Message); } }
/// <summary> /// Поиск знака. Метод Кенни (поиск по границам) /// </summary> /// <param name="img">Исходное изображение</param> /// <param name="brickSingList">Список знаков на изображении</param> /// <param name="boxList">Список областей со знаком</param> /// <param name="contours">Контур</param> /// <param name="hierachy"></param> /// <param name="idx"></param> private void FindBrickSing(Mat img, List <Mat> brickSingList, List <Rectangle> boxList, VectorOfVectorOfPoint contours, int[,] hierachy, int idx) { for (; idx >= 0; idx = hierachy[idx, 0]) { using (VectorOfPoint c = contours[idx]) using (VectorOfPoint approx = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(c, approx, CvInvoke.ArcLength(c, true) * 0.02, true); double area = CvInvoke.ContourArea(approx); if (area > 200) { double ratio = CvInvoke.MatchShapes(_octagon, approx, ContoursMatchType.I3); if (ratio > 0.1) //Подходящих совпадений не найдено { if (hierachy[idx, 2] >= 0) { FindBrickSing(img, brickSingList, boxList, contours, hierachy, hierachy[idx, 2]); } continue; } Rectangle box = CvInvoke.BoundingRectangle(c); Mat candidate = new Mat(); //Поиск кандидата на искомое вхождение using (Mat tmp = new Mat(img, box)) { CvInvoke.CvtColor(tmp, candidate, ColorConversion.Bgr2Gray); } //Устанавливаем значение пикселей вне контура равным нулю using (Mat mask = new Mat(candidate.Size.Height, candidate.Width, DepthType.Cv8U, 1)) { mask.SetTo(new MCvScalar(0)); CvInvoke.DrawContours(mask, contours, idx, new MCvScalar(255), -1, LineType.EightConnected, null, int.MaxValue, new Point(-box.X, -box.Y)); double mean = CvInvoke.Mean(candidate, mask).V0; CvInvoke.Threshold(candidate, candidate, mean, 255, ThresholdType.Binary); CvInvoke.BitwiseNot(candidate, candidate); CvInvoke.BitwiseNot(mask, mask); candidate.SetTo(new MCvScalar(0), mask); } int minMatchCount = 0; double uniquenessThreshold = 0.0; VectorOfKeyPoint observaredKeyPoint = new VectorOfKeyPoint(); Mat observeredDescriptor = new Mat(); _detector.DetectAndCompute(candidate, null, observaredKeyPoint, observeredDescriptor, false); //Обозначаем искомое вхождение if (observaredKeyPoint.Size >= minMatchCount) { int i = 2; Mat mask; using (VectorOfVectorOfDMatch matches = new VectorOfVectorOfDMatch()) { _modelDescriptorMatcher.KnnMatch(observeredDescriptor, matches, i, null); mask = new Mat(matches.Size, 1, DepthType.Cv8U, 1); Features2DToolbox.VoteForUniqueness(matches, uniquenessThreshold, mask); } int nonZeroCount = CvInvoke.CountNonZero(mask); if (nonZeroCount >= minMatchCount) { boxList.Add(box); brickSingList.Add(candidate); } } } } } }
public List <CircleF> HoughCircles(Image <Bgr, byte> EyeRoi, // Input image int minRadius, // Circle Radius int maxRadius, double dp = 0.1, // Resolution of the accumulator used to detect centers of the circles double minDist = 0.01, //min detected circles distance double CannyThres = 80, // Canny high threshold double HoughThres = 80 // Hough counting threshold ) { //轉灰階 img_Gray = EyeRoi.Convert <Gray, Byte>(); img_Gray._GammaCorrect(0.6); img_Bgr = EyeRoi.Clone(); // Laplace 邊緣強化 img_laplace = img_Gray.Convert <Gray, float>(); //Convert to 8-bit image Point[] minLoc, maxLoc; double[] mins, maxs; img_laplace.MinMax(out mins, out maxs, out minLoc, out maxLoc); img_laplaceByte = img_laplace.ConvertScale <byte>(255 / maxs[0], 0); img_Sobel = img_laplaceByte.Convert <Gray, float>(); img_SobelX = img_laplaceByte.Sobel(1, 0, 3); img_SobelY = img_laplaceByte.Sobel(0, 1, 3); img_SobelX = img_SobelX.AbsDiff(new Gray(0)); img_SobelY = img_SobelY.AbsDiff(new Gray(0)); img_Sobel = img_SobelX + img_SobelY; //Find sobel min or max value //Find sobel min or max value position img_Sobel.MinMax(out mins, out maxs, out minLoc, out maxLoc); //Conversion to 8-bit image sobelImage = img_Sobel.ConvertScale <byte>(255 / maxs[0], 0); //Adaptive Threshold img_Ada = img_Gray.Clone(); CvInvoke.AdaptiveThreshold(img_laplaceByte, img_Ada, 255, AdaptiveThresholdType.GaussianC, ThresholdType.Binary, 7, 0); img_Threshold = img_Ada.Clone(); //Median Filter CvInvoke.MedianBlur(img_Threshold, img_Threshold, 3); // Canny img_Edge = img_Gray.CopyBlank(); img_Edge = img_Threshold.Canny(30, 90); VectorOfVectorOfPoint Contours = new VectorOfVectorOfPoint(); List <VectorOfPoint> C = new List <VectorOfPoint>(); CvInvoke.FindContours(img_Edge, Contours, null, RetrType.External, ChainApproxMethod.ChainApproxNone); img_Edge = img_Gray.CopyBlank(); img_EdgeText = EyeRoi.CopyBlank(); double maxLen = 0; int Inx = 0; if (Contours.Size > 0) { for (int i = 0; i < Contours.Size; i++) { double len = CvInvoke.ArcLength(Contours[i], true); if (len > maxLen) { maxLen = len; Inx = i; } CvInvoke.DrawContours(img_Edge, Contours, i, new MCvScalar(255, 255, 255), 1, LineType.EightConnected, null); CvInvoke.DrawContours(img_EdgeText, Contours, i, new MCvScalar(255, 255, 255), 1, LineType.EightConnected, null); Rectangle rect = CvInvoke.BoundingRectangle(Contours[i]); CvInvoke.PutText(img_EdgeText, len.ToString("###.#"), new Point(rect.X, rect.Y + rect.Height), Emgu.CV.CvEnum.FontFace.HersheyDuplex, 0.2, new Bgr(Color.Red).MCvScalar); C.Add(Contours[i]); } try { do { Circles = CvInvoke.HoughCircles(img_Edge, // Input image HoughType.Gradient, // Method dp, //Resolution of the accumulator used to detect centers of the circles minDist, //min distance CannyThres, // Canny high threshold HoughThres, // Hough counting threshold minRadius, //min radius maxRadius //max radius ); list_Iris = new List <CircleF>(); HoughThres -= 5; if (HoughThres <= 0) { Console.WriteLine("cythred=0"); //Only save the first 30th Circles int limit = 0; foreach (CircleF cy in Circles) { list_Iris.Add(cy); limit++; if (limit == 60 || limit > Circles.Length) { break; } } } } while (list_Iris.Count <= 5); } catch (Emgu.CV.Util.CvException ex) { Console.WriteLine(ex); } // by gradient list_Iris = CircleVerify(list_Iris); } else { MessageBox.Show("無法偵測瞳孔,請重新拍攝 \r\n (Contours.size = 0)"); return(null); } if (list_Iris.Count != 0) { this.iris = list_Iris[0]; } return(list_Iris); }
private void HandleGrab(object sender, EventArgs e) { Mat image = new Mat(); if (capture.IsOpened) { capture.Retrieve(image); } if (image.IsEmpty) { return; } Mat grayImg = image.Clone(); CvInvoke.CvtColor(image, grayImg, ColorConversion.Bgr2Gray); CvInvoke.AdaptiveThreshold(grayImg, grayImg, 255, AdaptiveThresholdType.MeanC, ThresholdType.BinaryInv, 21, 11); VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); VectorOfPoint approx = new VectorOfPoint(); VectorOfVectorOfPoint candidates = new VectorOfVectorOfPoint(); Mat hierarchy = new Mat(); CvInvoke.FindContours(grayImg, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple); for (int i = 0; i < contours.Size; i++) { CvInvoke.ApproxPolyDP(contours[i], approx, CvInvoke.ArcLength(contours[i], true) * 0.05, true); if (approx.Size == 4) { if (CvInvoke.ContourArea(contours[i]) > 300) { var rect = CvInvoke.BoundingRectangle(approx); if (rect.Height > 0.95 * rect.Width || rect.Height < 0.95 * rect.Width) { candidates.Push(approx); CvInvoke.DrawContours(image, contours, i, new MCvScalar(0, 0, 255), 4); CvInvoke.Rectangle(image, rect, new MCvScalar(0, 255, 0), 3); } } } } for (int i = 0; i < candidates.Size; i++) { System.Drawing.PointF[] pts = new System.Drawing.PointF[4]; pts[0] = new System.Drawing.PointF(0, 0); pts[1] = new System.Drawing.PointF(64 - 1, 0); pts[2] = new System.Drawing.PointF(64 - 1, 64 - 1); pts[3] = new System.Drawing.PointF(0, 64 - 1); VectorOfPointF perfect = new VectorOfPointF(pts); System.Drawing.PointF[] sample_pts = new System.Drawing.PointF[4]; for (int j = 0; j < 4; j++) { sample_pts[j] = new System.Drawing.PointF(candidates[i][j].X, candidates[i][j].Y); } VectorOfPointF sample = new VectorOfPointF(sample_pts); var tf = CvInvoke.GetPerspectiveTransform(sample, perfect); Mat warped = new Mat(); CvInvoke.WarpPerspective(image, warped, tf, new System.Drawing.Size(64, 64)); CvInvoke.Imshow("Warped " + i, warped); } CvInvoke.Imshow("Original", image); CvInvoke.Imshow("Gray", grayImg); }
public List <List <string> > GetComments(string namePDF, Mat _frame) { List <List <string> > comments = new List <List <string> >(); List <String> aux_comments = new List <string>(); Image <Bgr, byte> imagen_aux = _frame.ToImage <Bgr, byte>(); imagen_aux = imagen_aux.Rotate(180, new Bgr(0, 0, 0)); Mat m = new Mat(); Mat n = new Mat(); Mat o = new Mat(); Mat aux = new Mat(); Mat binaryDiffFrame = new Mat(); Mat denoisedDiffFrame = new Mat(); Mat finalFrame = new Mat(); //Obtener directorio directorio = Directory.GetCurrentDirectory(); Console.WriteLine(directorio); //Cantidad de comentarios cantComentarios = 0; // //OBTENER COLOR // Image <Bgr, Byte> imge = _frame.ToImage <Bgr, Byte>(); Image <Bgr, byte> ret = imge.Copy(); Image <Bgr, byte> auxImge = imge.Copy(); Image <Bgr, byte> auxImge2 = imge.Copy(); Image <Bgr, byte> auxImge3 = imge.Copy(); Image <Bgr, byte> resultadoFinal = imge.Copy(); //Transformar a espacio de color HSV Image <Hsv, Byte> hsvimg = auxImge.Convert <Hsv, Byte>(); //extract the hue and value channels Image <Gray, Byte>[] channels = hsvimg.Split(); //separar en componentes Image <Gray, Byte> imghue = channels[0]; //hsv, channels[0] es hue. Image <Gray, Byte> imgval = channels[2]; //hsv, channels[2] es value. //Filtro amarillo //140 en adelante //30 Image <Gray, byte> huefilter = imghue.InRange(new Gray(0), new Gray(30)); //Filtro colores menos brillantes Image <Gray, byte> valfilter = imgval.InRange(new Gray(100), new Gray(255)); //Filtro de saturación - quitar blancos channels[1]._ThresholdBinary(new Gray(10), new Gray(255)); // Saturacion //Unir los filtros para obtener la imagen Image <Gray, byte> colordetimg = huefilter.And(valfilter).And(channels[1]);//aqui habia un Not() //Colorear imagen var mat = auxImge2.Mat; mat.SetTo(new MCvScalar(0, 0, 255), colordetimg); mat.CopyTo(ret); //Image<Bgr, byte> imgout = ret.CopyBlank();//imagen sin fondo negro ret._Or(auxImge2); //Muestra imagen con color destacado Mat SE2 = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle, new Size(3, 2), new Point(-1, -1)); CvInvoke.MorphologyEx(colordetimg, colordetimg, MorphOp.Erode, SE2, new Point(-1, -1), 3, BorderType.Default, new MCvScalar(255)); Mat SE3 = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle, new Size(3, 2), new Point(-1, -1)); CvInvoke.MorphologyEx(colordetimg, colordetimg, MorphOp.Dilate, SE3, new Point(-1, -1), 4, BorderType.Default, new MCvScalar(255)); Mat SE = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle, new Size(3, 3), new Point(-1, -1)); CvInvoke.MorphologyEx(colordetimg, aux, Emgu.CV.CvEnum.MorphOp.Close, SE, new Point(-1, -1), 5, Emgu.CV.CvEnum.BorderType.Reflect, new MCvScalar(255)); Image <Bgr, byte> temp = aux.ToImage <Bgr, byte>(); var temp2 = temp.SmoothGaussian(5).Convert <Gray, byte>().ThresholdBinary(new Gray(230), new Gray(255)); VectorOfVectorOfPoint contorno = new VectorOfVectorOfPoint(); Mat matAux = new Mat(); CvInvoke.FindContours(temp2, contorno, matAux, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple); for (int i = 0; i < contorno.Size; i++) { VectorOfPoint approxContour = new VectorOfPoint(); double perimetro = CvInvoke.ArcLength(contorno[i], true); VectorOfPoint approx = new VectorOfPoint(); double area = CvInvoke.ContourArea(contorno[i]); if (area > 15000) { var moments = CvInvoke.Moments(contorno[i]); int x = (int)(moments.M10 / moments.M00); int y = (int)(moments.M01 / moments.M00); CvInvoke.ApproxPolyDP(contorno[i], approx, 0.04 * perimetro, true); if (approx.Size == 4) //The contour has 4 vertices. { cantComentarios = cantComentarios + 1; CvInvoke.DrawContours(resultadoFinal, contorno, i, new MCvScalar(0, 255, 255), 2); RotatedRect rectangle = CvInvoke.MinAreaRect(approx); //CvInvoke.DrawContours(resultadoFinal, contorno, i, new MCvScalar(255, 255, 255), 2, LineType.AntiAlias); resultadoFinal.Draw(rectangle, new Bgr(Color.Cyan), 1); CvInvoke.PutText(resultadoFinal, "Comentario", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheySimplex, 0.5, new MCvScalar(0, 255, 255), 2); System.Drawing.Point[] pts = approx.ToArray(); System.Drawing.Rectangle box = new System.Drawing.Rectangle(); box = CvInvoke.BoundingRectangle(approx); coorComentario.Add(new Point(box.X, box.Y)); auxImge3.ROI = box; final = auxImge3.Copy(); //Bitmap src = bmp; final = final.Rotate(180, new Bgr(0, 0, 0)); final.Save("comment" + cantComentarios + ".jpg"); Image <Gray, Byte> finalGray = final.Convert <Gray, Byte>(); CvInvoke.cvResetImageROI(auxImge3); //El parámetro blockSize es el tamaño de la vecindad, y el valor de los píxeles procesados debe ser mayor que el valor de vecindad promedio menos param1 CvInvoke.AdaptiveThreshold(finalGray, finalGray, 255, AdaptiveThresholdType.MeanC, ThresholdType.Binary, 31, 20); } } } Console.WriteLine("cantidad de comentarios " + cantComentarios); if (cantComentarios > 0) { aux_comments.Add("SI"); comments.Add(aux_comments); SaveComments(namePDF); } else { aux_comments.Add("NO"); comments.Add(aux_comments); } return(comments); }
/// <summary> /// Determina si un contorno es un circulo, verificando que tenga al menos 7 puntos y todos estén al mismo radio del centro /// </summary> /// <param name="MaxVariation"> Máxima desviacion permitida (0 a 1) </param> /// <returns></returns> public static bool isCircle(this VectorOfPoint contour, float MaxVariation = 0.2f) { bool result = false; if (contour.Size >= 7) { Moments Moments = CvInvoke.Moments(contour); Vector2 Center = Vector2.zero; Center.x = (float)(Moments.M10 / Moments.M00); Center.y = (float)(Moments.M01 / Moments.M00); result = true; Vector2[] pts = contour.ToVector2(); float MaxRadius = (pts[0] - Center).magnitude; float MinRadius = MaxRadius; float MinLimit = 1 - MaxVariation; float MaxLimit = 1 + MaxVariation; //Verifica que el radio sea consistente for (int j = 1; j < pts.Length; j++) { float r = (pts[j] - Center).magnitude; if (r > MaxRadius) { MaxRadius = r; } if (r < MinRadius) { MinRadius = r; } } if (MinRadius / MaxRadius < MinLimit) { result = false; } //Verifica que el perímetro sea consistente if (result) { double perimetroReal = CvInvoke.ArcLength(contour, true); float Radio = (MaxRadius + MinRadius) * 0.5f; float perimetroIdeal = 6.28f * Radio; float factor = (float)(perimetroIdeal / perimetroReal); if ((factor < MinLimit) || (factor > MaxLimit)) { result = false; } } pts = null; } return(result); }
private MovesDetectionResult DetectMoves(CamService cam) { var maxDartContourArc = configService.MaxContourArcValue * 1.5; var maxDartContourArea = configService.MaxContourAreaValue * 1.5; var maxDartContourWidth = configService.MaxContourWidthValue * 1.5; var minDartContourArc = configService.MinContourArcValue; var minDartContourArea = configService.MinContourAreaValue; var minDartContourWidth = configService.MinContourWidthValue; var allContours = new VectorOfVectorOfPoint(); CvInvoke.FindContours(cam.ThrowExtractedRoiFrame, allContours, new Mat(), RetrType.External, ChainApproxMethod.ChainApproxNone); if (!detectionEnabled || allContours.Size == 0) { return(MovesDetectionResult.Nothing); } var contourWithMaxArc = new VectorOfPoint(); var contourWithMaxArea = new VectorOfPoint(); var contourWithMaxWidth = new VectorOfPoint(); var maxArс = 0.0; var maxArea = 0.0; var maxWidth = 0.0; for (var i = 0; i < allContours.Size; i++) { var tempContour = allContours[i]; var tempContourArс = CvInvoke.ArcLength(tempContour, true); if (tempContourArс > maxArс) { maxArс = tempContourArс; contourWithMaxArc = tempContour; } var tempContourArea = CvInvoke.ContourArea(tempContour); if (tempContourArea > maxArea) { maxArea = tempContourArea; contourWithMaxArea = tempContour; } var rect = CvInvoke.MinAreaRect(tempContour); var box = CvInvoke.BoxPoints(rect); var contourBoxPoint1 = new PointF(box[0].X, (float)cam.roiPosYSlider + box[0].Y); var contourBoxPoint2 = new PointF(box[1].X, (float)cam.roiPosYSlider + box[1].Y); var contourBoxPoint4 = new PointF(box[3].X, (float)cam.roiPosYSlider + box[3].Y); var side1 = MeasureService.FindDistance(contourBoxPoint1, contourBoxPoint2); var side2 = MeasureService.FindDistance(contourBoxPoint4, contourBoxPoint1); var tempContourWidth = side1 < side2 ? side1 : side2; if (tempContourWidth > maxWidth) { maxWidth = tempContourWidth; contourWithMaxWidth = tempContour; } } if (workingMode == DetectionServiceWorkingMode.Crossing || maxArс >= minDartContourArc && maxArс <= maxDartContourArc && maxArea >= minDartContourArea && maxArea <= maxDartContourArea && maxWidth >= minDartContourWidth && maxWidth <= maxDartContourWidth && contourWithMaxArc.Equals(contourWithMaxArea) && contourWithMaxArea.Equals(contourWithMaxWidth) && contourWithMaxWidth.Equals(contourWithMaxArc) ) { return(MovesDetectionResult.Throw); } if (maxArс > maxDartContourArc || maxArea > maxDartContourArea || maxWidth > maxDartContourWidth) { return(MovesDetectionResult.Extraction); } return(MovesDetectionResult.Nothing); }
private void DetectObject(Mat detectionFrame, Mat displayFrame, Rectangle box) { Image <Bgr, Byte> buffer_im = displayFrame.ToImage <Bgr, Byte>(); using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { VectorOfPoint biggestContour = null; IOutputArray hirarchy = null; CvInvoke.FindContours(detectionFrame, contours, hirarchy, RetrType.List, ChainApproxMethod.ChainApproxSimple); if (contours.Size > 0) { double maxArea = 0; int chosen = 0; VectorOfPoint contour = null; for (int i = 0; i < contours.Size; i++) { contour = contours[i]; double area = CvInvoke.ContourArea(contour); if (area > maxArea) { maxArea = area; chosen = i; } } //MarkDetectedObject(displayFrame, contours[chosen], maxArea);//dibuja una envoltura roja VectorOfPoint hullPoints = new VectorOfPoint(); VectorOfInt hullInt = new VectorOfInt(); CvInvoke.ConvexHull(contours[chosen], hullPoints, true); CvInvoke.ConvexHull(contours[chosen], hullInt, false); Mat defects = new Mat(); if (hullInt.Size > 3) { CvInvoke.ConvexityDefects(contours[chosen], hullInt, defects); } box = CvInvoke.BoundingRectangle(hullPoints); CvInvoke.Rectangle(displayFrame, box, drawingColor); //Box rectangulo que encierra el area mas grande // cropbox = crop_color_frame(displayFrame, box); buffer_im.ROI = box; Image <Bgr, Byte> cropped_im = buffer_im.Copy(); pictureBox8.Image = cropped_im.Bitmap; Point center = new Point(box.X + box.Width / 2, box.Y + box.Height / 2);//centro rectangulo MOUSE VectorOfPoint start_points = new VectorOfPoint(); VectorOfPoint far_points = new VectorOfPoint(); if (!defects.IsEmpty) { Matrix <int> m = new Matrix <int>(defects.Rows, defects.Cols, defects.NumberOfChannels); defects.CopyTo(m); int xe = 2000, ye = 2000; int xs = 2000, ys = 2000; int xer = 2000, yer = 2000; int xsr = 2000, ysr = 2000; int xem = 0, yem = 0; int xsm = 0, ysm = 0; int xez = 0, yez = 0; int xsz = 0, ysz = 0; int y = 0, x = 0; int ym = 0, xm = 0; int yr = 0, xr = 0; int yz = 0, xz = 0; for (int i = 0; i < m.Rows; i++) { int startIdx = m.Data[i, 0]; int endIdx = m.Data[i, 1]; int farIdx = m.Data[i, 2]; Point startPoint = contours[chosen][startIdx]; Point endPoint = contours[chosen][endIdx]; Point farPoint = contours[chosen][farIdx]; CvInvoke.Circle(displayFrame, endPoint, 3, new MCvScalar(0, 255, 255)); CvInvoke.Circle(displayFrame, startPoint, 3, new MCvScalar(255, 255, 0)); if (true) { if (endPoint.Y < ye) { xe = endPoint.X; ye = endPoint.Y; } if (startPoint.Y < ys) { xs = startPoint.X; ys = startPoint.Y; } if (ye < ys) { y = ye; x = xe; } else { y = ys; x = xs; } if (endPoint.Y > yem) { xem = endPoint.X; yem = endPoint.Y; } if (startPoint.Y > ysm) { xsm = startPoint.X; ysm = startPoint.Y; } if (yem > ysm) { ym = yem; xm = xem; } else { y = ys; x = xs; } if (endPoint.X < xer) { xer = endPoint.X; yer = endPoint.Y; } if (startPoint.X < xsr) { xsr = startPoint.X; ysr = startPoint.Y; } if (xer < xsr) { yr = yer; xr = xer; } else { yr = ysr; xr = xsr; } if (endPoint.X > xez) { xez = endPoint.X; yez = endPoint.Y; } if (startPoint.X > xsz) { xsz = startPoint.X; ysz = startPoint.Y; } if (xez > xsz) { yz = yez; xz = xez; } else { yz = ysz; xz = xsz; } } /*var info = new string[] { * * $"Posicion: {endPoint.X}, {endPoint.Y}" * }; * * WriteMultilineText(displayFrame, info, new Point(endPoint.X + 5, endPoint.Y));*/ double distance = Math.Round(Math.Sqrt(Math.Pow((center.X - farPoint.X), 2) + Math.Pow((center.Y - farPoint.Y), 2)), 1); if (distance < box.Height * 0.3) { CvInvoke.Circle(displayFrame, farPoint, 3, new MCvScalar(255, 0, 0)); } CvInvoke.Line(displayFrame, startPoint, endPoint, new MCvScalar(0, 255, 0)); // CvInvoke.Line(displayFrame, startPoint, farPoint, new MCvScalar(0, 255, 255)); } var infoe = new string[] { $"Punto", $"Posicion: {x}, {y}" }; var infos = new string[] { $"Punto", $"Posicion: {xm}, {ym}" }; var infor = new string[] { $"Punto", $"Posicion: {x}, {y}" }; var infoz = new string[] { $"Punto", $"Posicion: {xm}, {ym}" }; var infoCentro = new string[] { $"Centro", $"Posicion: {xm}, {ym}" }; var xCentro = (x + xm + xr + xz) / 4; var yCentro = (y + ym + yr + yz) / 4; WriteMultilineText(displayFrame, infoe, new Point(x + 30, y)); CvInvoke.Circle(displayFrame, new Point(x, y), 5, new MCvScalar(255, 0, 255), 2); Image <Bgr, byte> temp = detectionFrame.ToImage <Bgr, byte>(); var temp2 = temp.SmoothGaussian(5).Convert <Gray, byte>().ThresholdBinary(new Gray(230), new Gray(255)); VectorOfVectorOfPoint contorno = new VectorOfVectorOfPoint(); Mat mat = new Mat(); CvInvoke.FindContours(temp2, contorno, mat, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.LinkRuns); for (int i = 0; i < contorno.Size; i++) { double perimetro = CvInvoke.ArcLength(contorno[i], true); VectorOfPoint approx = new VectorOfPoint(); CvInvoke.ApproxPolyDP(contorno[i], approx, 0.04 * perimetro, true); CvInvoke.DrawContours(displayFrame, contorno, i, new MCvScalar(0, 255, 255), 2); } WriteMultilineText(displayFrame, infos, new Point(xm + 30, ym)); CvInvoke.Circle(displayFrame, new Point(xm, ym), 5, new MCvScalar(255, 0, 255), 2); WriteMultilineText(displayFrame, infor, new Point(xr + 30, yr)); CvInvoke.Circle(displayFrame, new Point(xr, yr), 5, new MCvScalar(255, 0, 255), 2); WriteMultilineText(displayFrame, infoz, new Point(xz + 30, yz)); CvInvoke.Circle(displayFrame, new Point(xz, yz), 5, new MCvScalar(255, 0, 255), 2); WriteMultilineText(displayFrame, infoz, new Point(xCentro + 30, yCentro)); CvInvoke.Circle(displayFrame, new Point(xCentro, yCentro), 2, new MCvScalar(0, 100, 0), 4); //CvInvoke.Circle(picture, new Point(x * 2, y * 4), 20, new MCvScalar(255, 0, 255), 2);*/ } } } }
public Mat ProcessImage(Mat img) { using (UMat gray = new UMat()) using (UMat cannyEdges = new UMat()) using (Mat triangleRectangleImage = new Mat(img.Size, DepthType.Cv8U, 3)) //image to draw triangles and rectangles on using (Mat circleImage = new Mat(img.Size, DepthType.Cv8U, 3)) //image to draw circles on using (Mat lineImage = new Mat(img.Size, DepthType.Cv8U, 3)) //image to drtaw lines on { //Convert the image to grayscale and filter out the noise CvInvoke.CvtColor(img, gray, ColorConversion.Bgr2Gray); //Remove noise CvInvoke.GaussianBlur(gray, gray, new Size(3, 3), 1); #region circle detection double cannyThreshold = 180.0; double circleAccumulatorThreshold = 120; CircleF[] circles = CvInvoke.HoughCircles(gray, HoughModes.Gradient, 2.0, 20.0, cannyThreshold, circleAccumulatorThreshold, 5); #endregion #region Canny and edge detection double cannyThresholdLinking = 120.0; CvInvoke.Canny(gray, cannyEdges, cannyThreshold, cannyThresholdLinking); LineSegment2D[] lines = CvInvoke.HoughLinesP( cannyEdges, 1, //Distance resolution in pixel-related units Math.PI / 45.0, //Angle resolution measured in radians. 20, //threshold 30, //min Line width 10); //gap between lines #endregion #region Find triangles and rectangles List <Triangle2DF> triangleList = new List <Triangle2DF>(); List <RotatedRect> boxList = new List <RotatedRect>(); //a box is a rotated rectangle using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.FindContours(cannyEdges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); int count = contours.Size; for (int i = 0; i < count; i++) { using (VectorOfPoint contour = contours[i]) using (VectorOfPoint approxContour = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true); if (CvInvoke.ContourArea(approxContour, false) > 250 ) //only consider contours with area greater than 250 { if (approxContour.Size == 3) //The contour has 3 vertices, it is a triangle { Point[] pts = approxContour.ToArray(); triangleList.Add(new Triangle2DF( pts[0], pts[1], pts[2] )); } else if (approxContour.Size == 4) //The contour has 4 vertices. { #region determine if all the angles in the contour are within [80, 100] degree bool isRectangle = true; Point[] pts = approxContour.ToArray(); LineSegment2D[] edges = PointCollection.PolyLine(pts, true); for (int j = 0; j < edges.Length; j++) { double angle = Math.Abs( edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j])); if (angle < 80 || angle > 100) { isRectangle = false; break; } } #endregion if (isRectangle) { boxList.Add(CvInvoke.MinAreaRect(approxContour)); } } } } } } #endregion #region draw triangles and rectangles triangleRectangleImage.SetTo(new MCvScalar(0)); foreach (Triangle2DF triangle in triangleList) { CvInvoke.Polylines(triangleRectangleImage, Array.ConvertAll(triangle.GetVertices(), Point.Round), true, new Bgr(Color.DarkBlue).MCvScalar, 2); } foreach (RotatedRect box in boxList) { CvInvoke.Polylines(triangleRectangleImage, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.DarkOrange).MCvScalar, 2); } //Drawing a light gray frame around the image CvInvoke.Rectangle(triangleRectangleImage, new Rectangle(Point.Empty, new Size(triangleRectangleImage.Width - 1, triangleRectangleImage.Height - 1)), new MCvScalar(120, 120, 120)); //Draw the labels CvInvoke.PutText(triangleRectangleImage, "Triangles and Rectangles", new Point(20, 20), FontFace.HersheyDuplex, 0.5, new MCvScalar(120, 120, 120)); #endregion #region draw circles circleImage.SetTo(new MCvScalar(0)); foreach (CircleF circle in circles) { CvInvoke.Circle(circleImage, Point.Round(circle.Center), (int)circle.Radius, new Bgr(Color.Brown).MCvScalar, 2); } //Drawing a light gray frame around the image CvInvoke.Rectangle(circleImage, new Rectangle(Point.Empty, new Size(circleImage.Width - 1, circleImage.Height - 1)), new MCvScalar(120, 120, 120)); //Draw the labels CvInvoke.PutText(circleImage, "Circles", new Point(20, 20), FontFace.HersheyDuplex, 0.5, new MCvScalar(120, 120, 120)); #endregion #region draw lines lineImage.SetTo(new MCvScalar(0)); foreach (LineSegment2D line in lines) { CvInvoke.Line(lineImage, line.P1, line.P2, new Bgr(Color.Green).MCvScalar, 2); } //Drawing a light gray frame around the image CvInvoke.Rectangle(lineImage, new Rectangle(Point.Empty, new Size(lineImage.Width - 1, lineImage.Height - 1)), new MCvScalar(120, 120, 120)); //Draw the labels CvInvoke.PutText(lineImage, "Lines", new Point(20, 20), FontFace.HersheyDuplex, 0.5, new MCvScalar(120, 120, 120)); #endregion Mat result = new Mat(); CvInvoke.VConcat(new Mat[] { img, triangleRectangleImage, circleImage, lineImage }, result); return(result); } }
private void wykryjZnaki() { //lista trójkątów List <Triangle2DF> triangleList = new List <Triangle2DF>(); //lista prostokątów i kwadratów List <RotatedRect> boxList = new List <RotatedRect>(); zwiekszProgressBar(1); //przetworzenie zdjecia do postaci wskazujacej tylko biale kontury na czarnym tle Image <Gray, byte> canny_zdj = new Image <Gray, byte>(imgInput.Width, imgInput.Height, new Gray(0)); canny_zdj = imgInput.Canny(300, 250); //przypisanie canny_zdj do pictureBox i rozciagniecie zdjecieCannyBox.Image = canny_zdj.Bitmap; zdjecieCannyBox.SizeMode = PictureBoxSizeMode.StretchImage; zwiekszProgressBar(2); LineSegment2D[] lines = CvInvoke.HoughLinesP( canny_zdj, 1, Math.PI / 45.0, 20, 30, 10); Image <Gray, byte> imgOut = canny_zdj.Convert <Gray, byte>().ThresholdBinary(new Gray(50), new Gray(200)); VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); Mat hier = new Mat(); zwiekszProgressBar(1); //wygladzenie obrazu imgSmooth = imgInput.PyrDown().PyrUp(); imgSmooth._SmoothGaussian(3); //ograniczenie wykrywanych figur do odpowiedniego zakresu ze skali RGB - zoltego imgOut = imgSmooth.InRange(new Bgr(0, 140, 150), new Bgr(80, 255, 255)); imgOut = imgOut.PyrDown().PyrUp(); imgOut._SmoothGaussian(3); zwiekszProgressBar(2); Dictionary <int, double> dict = new Dictionary <int, double>(); //wyszukanie konturow spelniajacych wymogi odnosnie mi.in. koloru CvInvoke.FindContours(imgOut, contours, null, Emgu.CV.CvEnum.RetrType.List, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple); label1.Text = contours.Size.ToString(); //jesli odnaleziono chocby jeden kontur if (contours.Size > 0) { //petla przechodzaca po wszystkich wykrytych konturach for (int i = 0; i < contours.Size; i++) { using (VectorOfPoint contour = contours[i]) using (VectorOfPoint approxContour = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true); //filtr wielkosci pola wykrytego konturu if (CvInvoke.ContourArea(approxContour, false) > 50) { //jesli to trójkąt if (approxContour.Size == 3) { //tablica punktow i dodanie ich do tablicy trojkatow Point[] pts = approxContour.ToArray(); triangleList.Add(new Triangle2DF( pts[0], pts[1], pts[2] )); //sprawdzenie czy wykryty trojkat jest figura obróconą jednym z wierzcholkow do dolu if (pts[1].X > pts[0].X && pts[1].Y > pts[0].Y) { //ustawienie znaku A-7 ustawWykrytyZnak(2); double area = CvInvoke.ContourArea(contours[i]); //dodanie do tablicy glownej dict.Add(i, area); } } //jesli to czworokat else if (approxContour.Size == 4) { bool isRectangle = true; ///rozbicie figury na pojedyncze krawedzie Point[] pts = approxContour.ToArray(); LineSegment2D[] edges = PointCollection.PolyLine(pts, true); //petla przechodzaca po wszystkich krawedziach for (int j = 0; j < edges.Length; j++) { //sprawdzenie wielkosci kąta miedzy sprawdzanymi krawedziami double angle = Math.Abs( edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j])); //przerwanie jesli kąty w figurze są mniejsze niż 80 i wieksze niż 100 if (angle < 80 || angle > 100) { isRectangle = false; break; } } if (isRectangle) { RotatedRect rrect = CvInvoke.MinAreaRect(contours[i]); //ostateczne sprawdzenie czy wykryta figura jest obrocona wzgledem srodka o wartosc od 40 do 50 //stopni - znak D-1 jest obroconym kwadratem o 45 st wzgledem srodka if ((rrect.Angle < -40 && rrect.Angle > -50) || (rrect.Angle > 40 && rrect.Angle < 50)) { boxList.Add(CvInvoke.MinAreaRect(approxContour)); double area = CvInvoke.ContourArea(contours[i]); dict.Add(i, area); ustawWykrytyZnak(1); } } } } } } } zwiekszProgressBar(2); var item = dict.OrderByDescending(v => v.Value); foreach (var it in item) { int key = int.Parse(it.Key.ToString()); //pobranie odpowiednich konturow Rectangle rect = CvInvoke.BoundingRectangle(contours[key]); //narysowanie czerwonego prostokata wokol wykrytego znaku CvInvoke.Rectangle(imgInput, rect, new MCvScalar(0, 0, 255), 1); } zwiekszProgressBar(2); pictureBox2.Image = imgInput.Bitmap; pictureBox2.SizeMode = PictureBoxSizeMode.StretchImage; //utworzenie zdjecia wskazujacego WSZYSTKIE kontury w poczatkowym zdjeciu - czerowne linie Image <Bgr, Byte> lineImage = imgInput.CopyBlank(); foreach (LineSegment2D line in lines) { lineImage.Draw(line, new Bgr(Color.Red), 1); } zdjecieWykrytyZnak.Image = lineImage.Bitmap; zdjecieWykrytyZnak.SizeMode = PictureBoxSizeMode.StretchImage; }
public static Bitmap ExtractDocumentFromBitmap(Bitmap bitmap) { if (bitmap.Width > bitmap.Height) { bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone); } using (var image = new Image <Bgr, byte>(bitmap)) using (var imageGray = image.Convert <Gray, byte>()) using (var filteredImage = new Image <Bgr, byte>(bitmap)) using (var cannyEdges = new UMat()) using (var contours = new VectorOfVectorOfPoint()) { CvInvoke.BilateralFilter(imageGray, filteredImage, 9, 75, 75); CvInvoke.AdaptiveThreshold(filteredImage, filteredImage, 255, AdaptiveThresholdType.GaussianC, ThresholdType.Binary, 115, 4); CvInvoke.MedianBlur(filteredImage, filteredImage, 11); CvInvoke.CopyMakeBorder(filteredImage, filteredImage, 5, 5, 5, 5, BorderType.Constant, new MCvScalar(0, 0, 0)); CvInvoke.Canny(filteredImage, cannyEdges, 200, 250); CvInvoke.FindContours(cannyEdges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); var cannyEdgesHeight = cannyEdges.Bitmap.Height; var cannyEdgesWidth = cannyEdges.Bitmap.Width; var areaContour = (cannyEdgesHeight - 10) * (cannyEdgesWidth - 10); var areaCount = areaContour * 0.5; double areaContour2; var sourcePointsVector = new VectorOfPoint(); for (int i = 0; i < contours.Size; i++) { using (var cont = contours[i]) { CvInvoke.ApproxPolyDP(cont, cont, CvInvoke.ArcLength(cont, true) * 0.05, true); if (cont.Size == 4 && CvInvoke.IsContourConvex(cont) && areaCount < CvInvoke.ContourArea(cont) && CvInvoke.ContourArea(cont) < areaContour) { sourcePointsVector = cont; areaContour2 = CvInvoke.ContourArea(cont); sortVector(sourcePointsVector); break; } } } var sortedVector = sortVector(sourcePointsVector); var vectorWithOffset = addOffsetToVector(sourcePointsVector, -5); var euclideanHeight = new int[] { getEuclideanDistance(vectorWithOffset[0], vectorWithOffset[1]), getEuclideanDistance(vectorWithOffset[2], vectorWithOffset[3]) }.Max(); var euclideanWidth = new int[] { getEuclideanDistance(vectorWithOffset[0], vectorWithOffset[2]), getEuclideanDistance(vectorWithOffset[1], vectorWithOffset[3]) }.Max(); VectorOfPoint targetPoints = new VectorOfPoint(new Point[] { new Point(0, 0), new Point(0, euclideanWidth), new Point(euclideanHeight, euclideanWidth), new Point(euclideanHeight, 0) }.ToArray()); var source = sortVector(vectorWithOffset).ToArray().Select(x => new PointF(x.X, x.Y)).ToArray(); var target = sortVector(targetPoints).ToArray().Select(x => new PointF(x.X, x.Y)).ToArray(); var tran = CvInvoke.GetPerspectiveTransform(source, target); CvInvoke.WarpPerspective(image, image, tran, new Size(euclideanHeight, euclideanWidth)); return(image.ToBitmap((int)standardDocumentWidth * 4, (int)standardDocumentHeight * 4)); } }
public static Bitmap PerformShapeDetection(Bitmap frame, ShapeDetectionVariables detectionVars) { StringBuilder msgBuilder = new StringBuilder("Performance: "); Image <Bgr, Byte> img = new Image <Bgr, byte>(frame); Mat MatImg = img.Mat; Mat outputImg = new Mat(); if (CudaInvoke.HasCuda) { using (GpuMat gMatSrc = new GpuMat()) using (GpuMat gMatDst = new GpuMat()) { gMatSrc.Upload(MatImg); CudaGaussianFilter noiseReducetion = new CudaGaussianFilter(MatImg.Depth, img.NumberOfChannels, MatImg.Depth, img.NumberOfChannels, new Size(1, 1), 0); noiseReducetion.Apply(gMatSrc, gMatDst); gMatDst.Download(outputImg); } } else { Mat pyrDown = new Mat(); CvInvoke.PyrDown(img, pyrDown); CvInvoke.PyrUp(pyrDown, img); outputImg = img.Mat; } UMat uimage = new UMat(); CvInvoke.CvtColor(outputImg, uimage, ColorConversion.Bgr2Gray); CircleF[] circles = new CircleF[0]; if (detectionVars.calcCircles) { circles = CvInvoke.HoughCircles( uimage, HoughType.Gradient, 1.0, 20.0, detectionVars.circleCannyThreshold, detectionVars.circleAccumulatorThreshold == 0 ? 1 : detectionVars.circleAccumulatorThreshold, detectionVars.minradius, detectionVars.maxRadius); } #region Canny and edge detection UMat cannyEdges = new UMat(); CvInvoke.Canny(uimage, cannyEdges, detectionVars.lineCannyThreshold, detectionVars.cannyThresholdLinking); LineSegment2D[] lines = new LineSegment2D[0]; if (detectionVars.calcLines) { lines = CvInvoke.HoughLinesP( cannyEdges, 1, //Distance resolution in pixel-related units Math.PI / 45.0, //Angle resolution measured in radians. detectionVars.lineThreshold, //threshold detectionVars.minLineWidth, //min Line width 10); //gap between lines } #endregion #region Find triangles and rectangles List <RotatedRect> boxList = new List <RotatedRect>(); //a box is a rotated rectangle if (detectionVars.calcRectTri) { using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.FindContours(cannyEdges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); int count = contours.Size; for (int i = 0; i < count; i++) { using (VectorOfPoint contour = contours[i]) using (VectorOfPoint approxContour = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true); if (CvInvoke.ContourArea(approxContour, false) > 250) //only consider contours with area greater than 250 { if (approxContour.Size == 4) //The contour has 4 vertices. { #region determine if all the angles in the contour are within [80, 100] degree bool isRectangle = true; Point[] pts = approxContour.ToArray(); LineSegment2D[] edges = PointCollection.PolyLine(pts, true); for (int j = 0; j < edges.Length; j++) { double angle = Math.Abs( edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j])); if (angle < 80 || angle > 100) { isRectangle = false; break; } } #endregion if (isRectangle) { boxList.Add(CvInvoke.MinAreaRect(approxContour)); } } } } } } } #endregion Image <Bgra, Byte> alphaImgShape = new Image <Bgra, byte>(img.Size.Width, img.Size.Height, new Bgra(0, 0, 0, .5)); Mat alphaimg = new Mat(); CvInvoke.CvtColor(img, alphaimg, ColorConversion.Bgr2Bgra); #region draw rectangles and triangles if (detectionVars.calcRectTri) { Image <Bgr, Byte> triangleRectangleImage = new Image <Bgr, Byte>(img.Size); foreach (RotatedRect box in boxList) { CvInvoke.Polylines(triangleRectangleImage, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(0, 255, 0).MCvScalar, 2); } CvInvoke.AddWeighted(alphaImgShape, .5, BlackTransparent(triangleRectangleImage), .5, 0, alphaImgShape); if (CudaInvoke.HasCuda) { using (GpuMat gMatSrc = new GpuMat()) using (GpuMat gMatSrc2 = new GpuMat()) using (GpuMat gMatDst = new GpuMat()) { gMatSrc.Upload(alphaimg); gMatSrc2.Upload(alphaImgShape); CudaInvoke.AlphaComp(gMatSrc, gMatSrc2, gMatDst, AlphaCompTypes.Plus); gMatDst.Download(alphaimg); } } else { img = Overlay(img, alphaImgShape); } } #endregion #region draw circles if (detectionVars.calcCircles) { Image <Bgr, Byte> circleImage = new Image <Bgr, Byte>(img.Size); foreach (CircleF circle in circles.Take(10)) { CvInvoke.Circle(circleImage, Point.Round(circle.Center), (int)circle.Radius, new Bgr(0, 255, 0).MCvScalar, 2); } alphaImgShape = new Image <Bgra, byte>(img.Size.Width, img.Size.Height, new Bgra(0, 0, 0, .5)); CvInvoke.AddWeighted(alphaImgShape, .7, BlackTransparent(circleImage), .5, 0, alphaImgShape); if (CudaInvoke.HasCuda) { using (GpuMat gMatSrc = new GpuMat()) using (GpuMat gMatSrc2 = new GpuMat()) using (GpuMat gMatDst = new GpuMat()) { gMatSrc.Upload(alphaimg); gMatSrc2.Upload(alphaImgShape); CudaInvoke.AlphaComp(gMatSrc, gMatSrc2, gMatDst, AlphaCompTypes.Plus); gMatDst.Download(alphaimg); } } else { img = Overlay(img, alphaImgShape); } } #endregion #region draw lines if (detectionVars.calcLines) { Image <Bgr, Byte> lineImage = new Image <Bgr, Byte>(img.Size); foreach (LineSegment2D line in lines) { CvInvoke.Line(lineImage, line.P1, line.P2, new Bgr(0, 255, 0).MCvScalar, 2); } alphaImgShape = new Image <Bgra, byte>(img.Size.Width, img.Size.Height, new Bgra(0, 0, 0, .5)); CvInvoke.AddWeighted(alphaImgShape, .5, BlackTransparent(lineImage), .5, 0, alphaImgShape); if (CudaInvoke.HasCuda) { using (GpuMat gMatSrc = new GpuMat()) using (GpuMat gMatSrc2 = new GpuMat()) using (GpuMat gMatDst = new GpuMat()) { gMatSrc.Upload(alphaimg); gMatSrc2.Upload(alphaImgShape); CudaInvoke.AlphaComp(gMatSrc, gMatSrc2, gMatDst, AlphaCompTypes.Plus); gMatDst.Download(alphaimg); } } else { img = Overlay(img, alphaImgShape); } } #endregion GC.Collect(); // first time I've had to use this but this program will use as much memory as possible, resulting in corrptions return(alphaimg.Bitmap ?? frame); }
public Tuple <double, double> contour_1(int min, int max, Image <Bgr, byte> imgInput, int iron_r, int szar_r, int rain_r) { double carea = 0; double len = 0; double pre_len = 0; double pre_carea = 0; // kontur, pole i obwód dla palety barw Iron if (iron_r == 1) { Image <Gray, byte> imgOut = imgInput.Convert <Gray, byte>().InRange(new Gray(min), new Gray(max)); Emgu.CV.Util.VectorOfVectorOfPoint contours = new Emgu.CV.Util.VectorOfVectorOfPoint(); Mat hier = new Mat(); CvInvoke.FindContours(imgOut, contours, hier, Emgu.CV.CvEnum.RetrType.Ccomp, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple); for (int i = 0; i < contours.Size; i++) { pre_carea = CvInvoke.ContourArea(contours[i]); carea = carea + pre_carea; pre_len = CvInvoke.ArcLength(contours[i], true); len = len + pre_len; } } // kontur, pole i obwód dla palety barw Rain else if (rain_r == 1) { Image <Gray, byte> imgOut = imgInput.Convert <Gray, byte>().ThresholdBinaryInv(new Gray(min), new Gray(max)); Emgu.CV.Util.VectorOfVectorOfPoint contours = new Emgu.CV.Util.VectorOfVectorOfPoint(); Mat hier = new Mat(); CvInvoke.FindContours(imgOut, contours, hier, Emgu.CV.CvEnum.RetrType.Ccomp, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple); for (int i = 0; i < contours.Size; i++) { pre_carea = CvInvoke.ContourArea(contours[i]); carea = carea + pre_carea; pre_len = CvInvoke.ArcLength(contours[i], true); len = len + pre_len; } } // kontur, pole i obwód dla skali szarości else if (szar_r == 1) { Image <Gray, byte>[] channels = imgInput.Split(); Image <Gray, byte> imgOut = channels[0]; Image <Gray, byte> imgOut_1 = imgOut.InRange(new Gray(min), new Gray(max)); Emgu.CV.Util.VectorOfVectorOfPoint contours = new Emgu.CV.Util.VectorOfVectorOfPoint(); Mat hier = new Mat(); CvInvoke.FindContours(imgOut_1, contours, hier, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple); for (int i = 0; i < contours.Size; i++) { pre_carea = CvInvoke.ContourArea(contours[i]); carea = carea + pre_carea; pre_len = CvInvoke.ArcLength(contours[i], true); len = len + pre_len; } } return(Tuple.Create(carea, len)); }
private void openFileDialog1_FileOk(object sender, CancelEventArgs e) { outputLabel.Text = ""; StringBuilder msgBuilder = new StringBuilder("Performance: "); Image <Bgr, Byte> img = new Image <Bgr, byte>(openFileDialog1.FileName) .Resize(400, 400, Emgu.CV.CvEnum.Inter.Linear, true); //Convert the image to grayscale and filter out the noise UMat uimage = new UMat(); CvInvoke.CvtColor(img, uimage, ColorConversion.Bgr2Gray); //use image pyr to remove noise UMat pyrDown = new UMat(); CvInvoke.PyrDown(uimage, pyrDown); CvInvoke.PyrUp(pyrDown, uimage); //Image<Gray, Byte> gray = img.Convert<Gray, Byte>().PyrDown().PyrUp(); #region circle detection Stopwatch watch = Stopwatch.StartNew(); double cannyThreshold = 80.0; double circleAccumulatorThreshold = 100; CircleF[] circles = CvInvoke.HoughCircles(uimage, HoughType.Gradient, 2.0, 5.0, cannyThreshold, circleAccumulatorThreshold, 5, 150); outputLabel.Text += "C: " + circles.Length; watch.Stop(); msgBuilder.Append(String.Format("Hough circles - {0} ms; ", watch.ElapsedMilliseconds)); #endregion #region Canny and edge detection watch.Reset(); watch.Start(); double cannyThresholdLinking = 270.0; UMat cannyEdges = new UMat(); CvInvoke.Canny(uimage, cannyEdges, cannyThreshold, cannyThresholdLinking); LineSegment2D[] lines = CvInvoke.HoughLinesP( cannyEdges, 1, //Distance resolution in pixel-related units Math.PI / 45.0, //Angle resolution measured in radians. 20, //threshold 30, //min Line width 10); //gap between lines watch.Stop(); outputLabel.Text += "\nL: " + lines.Length; msgBuilder.Append(String.Format("Canny & Hough lines - {0} ms; ", watch.ElapsedMilliseconds)); #endregion #region Find triangles and rectangles watch.Reset(); watch.Start(); List <Triangle2DF> triangleList = new List <Triangle2DF>(); List <RotatedRect> boxList = new List <RotatedRect>(); //a box is a rotated rectangle List <LineSegment2D> lineBoxes = new List <LineSegment2D>(); //for the species that looks like a line using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.FindContours(cannyEdges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); int count = contours.Size; for (int i = 0; i < count; i++) { using (VectorOfPoint contour = contours[i]) using (VectorOfPoint approxContour = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true); if (CvInvoke.ContourArea(approxContour, false) > 250) //only consider contours with area greater than 250 { if (approxContour.Size == 3) //The contour has 3 vertices, it is a triangle { Point[] pts = approxContour.ToArray(); triangleList.Add(new Triangle2DF( pts[0], pts[1], pts[2] )); } else if (approxContour.Size == 4) //The contour has 4 vertices. { #region determine if all the angles in the contour are within [80, 100] degree bool isRectangle = true; Point[] pts = approxContour.ToArray(); LineSegment2D[] edges = PointCollection.PolyLine(pts, true); for (int j = 0; j < edges.Length; j++) { double angle = Math.Abs( edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j])); if (angle < 80 || angle > 100) { isRectangle = false; break; } } #endregion if (isRectangle) { boxList.Add(CvInvoke.MinAreaRect(approxContour)); } } } } } } watch.Stop(); outputLabel.Text += "\nTriangles: " + triangleList.Count / 2; outputLabel.Text += "\nRectangles: " + boxList.Count / 2; msgBuilder.Append(String.Format("Triangles & Rectangles - {0} ms; ", watch.ElapsedMilliseconds)); #endregion this.Text = msgBuilder.ToString(); #region draw triangles and rectangles Image <Bgr, Byte> triangleRectangleImage = img.CopyBlank(); foreach (Triangle2DF triangle in triangleList) { img.Draw(triangle, new Bgr(Color.DarkBlue), 2); } foreach (RotatedRect box in boxList) { img.Draw(box, new Bgr(Color.DarkOrange), 2); } #endregion #region draw circles Image <Bgr, Byte> circleImage = img.CopyBlank(); foreach (CircleF circle in circles) { img.Draw(circle, new Bgr(Color.Brown), 2); } #endregion #region draw lines Image <Bgr, Byte> lineImage = img.CopyBlank(); foreach (LineSegment2D line in lines) { img.Draw(line, new Bgr(Color.Green), 2); } #endregion originalImageBox.Image = img.ToBitmap(); }
public void PerformShapeDetection() { if (fileNameTextBox.Text != String.Empty) { StringBuilder msgBuilder = new StringBuilder("Performance: "); //Load the image from file and resize it for display Image <Bgr, Byte> img = new Image <Bgr, byte>(fileNameTextBox.Text) .Resize(400, 400, Emgu.CV.CvEnum.Inter.Linear, true); //Convert the image to grayscale and filter out the noise UMat uimage = new UMat(); CvInvoke.CvtColor(img, uimage, ColorConversion.Bgr2Gray); //use image pyr to remove noise UMat pyrDown = new UMat(); CvInvoke.PyrDown(uimage, pyrDown); CvInvoke.PyrUp(pyrDown, uimage); //Image<Gray, Byte> gray = img.Convert<Gray, Byte>().PyrDown().PyrUp(); #region circle detection Stopwatch watch = Stopwatch.StartNew(); double cannyThreshold = 180.0; double circleAccumulatorThreshold = 120; CircleF[] circles = CvInvoke.HoughCircles(uimage, HoughType.Gradient, 2.0, 20.0, cannyThreshold, circleAccumulatorThreshold, 5); watch.Stop(); msgBuilder.Append(String.Format("Hough circles - {0} ms; ", watch.ElapsedMilliseconds)); #endregion #region Canny and edge detection watch.Reset(); watch.Start(); double cannyThresholdLinking = 120.0; UMat cannyEdges = new UMat(); CvInvoke.Canny(uimage, cannyEdges, cannyThreshold, cannyThresholdLinking); LineSegment2D[] lines = CvInvoke.HoughLinesP( cannyEdges, 1, //Distance resolution in pixel-related units Math.PI / 45.0, //Angle resolution measured in radians. 20, //threshold 30, //min Line width 10); //gap between lines watch.Stop(); msgBuilder.Append(String.Format("Canny & Hough lines - {0} ms; ", watch.ElapsedMilliseconds)); #endregion #region Find triangles and rectangles watch.Reset(); watch.Start(); List <Triangle2DF> triangleList = new List <Triangle2DF>(); List <RotatedRect> boxList = new List <RotatedRect>(); //a box is a rotated rectangle using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.FindContours(cannyEdges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); int count = contours.Size; for (int i = 0; i < count; i++) { using (VectorOfPoint contour = contours[i]) using (VectorOfPoint approxContour = new VectorOfPoint()) { CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true); if (CvInvoke.ContourArea(approxContour, false) > 250) //only consider contours with area greater than 250 { if (approxContour.Size == 3) //The contour has 3 vertices, it is a triangle { Point[] pts = approxContour.ToArray(); triangleList.Add(new Triangle2DF( pts[0], pts[1], pts[2] )); } else if (approxContour.Size == 4) //The contour has 4 vertices. { #region determine if all the angles in the contour are within [80, 100] degree bool isRectangle = true; Point[] pts = approxContour.ToArray(); LineSegment2D[] edges = PointCollection.PolyLine(pts, true); for (int j = 0; j < edges.Length; j++) { double angle = Math.Abs( edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j])); if (angle < 80 || angle > 100) { isRectangle = false; break; } } #endregion if (isRectangle) { boxList.Add(CvInvoke.MinAreaRect(approxContour)); } } } } } } watch.Stop(); msgBuilder.Append(String.Format("Triangles & Rectangles - {0} ms; ", watch.ElapsedMilliseconds)); #endregion originalImageBox.Image = img; this.Text = msgBuilder.ToString(); #region draw triangles and rectangles Mat triangleRectangleImage = new Mat(img.Size, DepthType.Cv8U, 3); triangleRectangleImage.SetTo(new MCvScalar(0)); foreach (Triangle2DF triangle in triangleList) { CvInvoke.Polylines(triangleRectangleImage, Array.ConvertAll(triangle.GetVertices(), Point.Round), true, new Bgr(Color.DarkBlue).MCvScalar, 2); } foreach (RotatedRect box in boxList) { CvInvoke.Polylines(triangleRectangleImage, Array.ConvertAll(box.GetVertices(), Point.Round), true, new Bgr(Color.DarkOrange).MCvScalar, 2); } triangleRectangleImageBox.Image = triangleRectangleImage; #endregion #region draw circles Mat circleImage = new Mat(img.Size, DepthType.Cv8U, 3); circleImage.SetTo(new MCvScalar(0)); foreach (CircleF circle in circles) { CvInvoke.Circle(circleImage, Point.Round(circle.Center), (int)circle.Radius, new Bgr(Color.Brown).MCvScalar, 2); } circleImageBox.Image = circleImage; #endregion #region draw lines Mat lineImage = new Mat(img.Size, DepthType.Cv8U, 3); lineImage.SetTo(new MCvScalar(0)); foreach (LineSegment2D line in lines) { CvInvoke.Line(lineImage, line.P1, line.P2, new Bgr(Color.Green).MCvScalar, 2); } lineImageBox.Image = lineImage; #endregion } }
public void GetBoundries(Image <Gray, Byte> binaryBackground, out List <Point[]> boundries, out List <Point[]> artefacts, out List <RotatedRect> boxes) { //Find outer boundries double minimumContourArea = 250; double minimumBoundryArea = 1000; //double approximationFactor = 0.001; List <Point[]> allBoundries = new List <Point[]>(); List <Point[]> allObjects = new List <Point[]>(); List <RotatedRect> boxList = new List <RotatedRect>(); using (Image <Gray, Byte> filteredBinary = binaryBackground.SmoothMedian(7)) using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) using (Mat hierarchy = new Mat()) { CvInvoke.FindContours(filteredBinary, contours, hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxNone); var temp = hierarchy.ToImage <Bgra, Byte>(); int count = contours.Size; List <int> boundryIds = new List <int>(); for (int i = 0; i < count; i++) { using (VectorOfPoint contour = contours[i]) { double contourArea = CvInvoke.ContourArea(contour); if (contourArea >= minimumBoundryArea) { Bgra currentContour = temp[0, i]; if (currentContour.Alpha == 0) { allBoundries.Add(contour.ToArray()); boundryIds.Add(i); } } } } for (int i = 0; i < count; i++) { using (VectorOfPoint contour = contours[i]) { double contourArea = CvInvoke.ContourArea(contour); if (contourArea >= minimumContourArea) { Bgra currentContour = temp[0, i]; if (!boundryIds.Contains(i) && boundryIds.Contains((int)currentContour.Alpha)) { bool isRectangle = true; bool isCircle = false; //Can the object be approximated as a circle or rectangle? using (VectorOfPoint apxContour = new VectorOfPoint()) { double epsilon = CvInvoke.ArcLength(contour, true) * 0.05; CvInvoke.ApproxPolyDP(contour, apxContour, epsilon, true); if (apxContour.Size == 4) //The contour has 4 vertices. { Point[] pts = apxContour.ToArray(); LineSegment2D[] edges = PointCollection.PolyLine(pts, true); for (int j = 0; j < edges.Length; j++) { double angle = Math.Abs(edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j])); if (angle < 70 || angle > 110) { isRectangle = false; break; } } if (isRectangle) { boxList.Add(CvInvoke.MinAreaRect(apxContour)); } } else { isRectangle = false; } } if (!isRectangle && !isCircle) { allObjects.Add(contour.ToArray()); } } } } } } //Find mouse //mousePoints = null; //using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) //{ // CvInvoke.FindContours(binaryMouse, contours, null, RetrType.External, ChainApproxMethod.ChainApproxNone); // int count = contours.Size; // double maxArea = 0; // for (int j = 0; j < count; j++) // { // using (VectorOfPoint contour = contours[j]) // { // double contourArea = CvInvoke.ContourArea(contour); // if (contourArea >= maxArea) // { // maxArea = contourArea; // mousePoints = contour.ToArray(); // } // } // } //} boundries = allBoundries; artefacts = allObjects; boxes = boxList; //Check if any contours can be approximated as shapes //We now have a list of boundries, if there's more than one it means something is sticking across the screen if (allBoundries.Count > 1) { //Need to find points from all boundries that are effectively parallel } //Image<Bgr, Byte> allContourImage = FirstFrame.Clone(); //allContourImage.DrawPolyline(mousePoints, true, new Bgr(Color.Yellow), 2); //allContourImage.DrawPolyline(allBoundries.ToArray(), true, new Bgr(Color.Red), 2); //allContourImage.DrawPolyline(allObjects.ToArray(), true, new Bgr(Color.LightGreen), 2); //foreach (var box in boxList) //{ // allContourImage.Draw(box.GetVertices().Select(x => new Point((int)x.X, (int)x.Y)).ToArray(), new Bgr(Color.Aqua), 2); //} }