/// <summary> /// Get the item in the specific index /// </summary> /// <param name="index">The index</param> /// <returns>The item in the specific index</returns> public Triangle2DF this[int index] { get { Triangle2DF result = new Triangle2DF(); VectorOfTriangle2DFGetItem(_ptr, index, ref result); return(result); } }
private Mat DisplayTriangleOnInfrared(Mat infraredMat, Triangle2DF tri) { using (Mat convertMat = new Mat(infraredMat.Size, DepthType.Cv8U, 1)) { infraredMat.ConvertTo(convertMat, DepthType.Cv8U, 1 / 256d); Mat displayMat = new Mat(infraredMat.Size, DepthType.Cv8U, 3); CvInvoke.CvtColor(convertMat, displayMat, ColorConversion.Gray2Bgr); CvInvoke.Polylines(displayMat, Array.ConvertAll(tri.GetVertices(), System.Drawing.Point.Round), true, new Bgr(0, 0, 255).MCvScalar, 2); return(displayMat); } }
/// <summary> /// Convert the standard vector to an array of Triangle2DF /// </summary> /// <returns>An array of Triangle2DF</returns> public Triangle2DF[] ToArray() { Triangle2DF[] res = new Triangle2DF[Size]; if (res.Length > 0) { GCHandle handle = GCHandle.Alloc(res, GCHandleType.Pinned); VectorOfTriangle2DFCopyData(_ptr, handle.AddrOfPinnedObject()); handle.Free(); } return(res); }
/// <summary> /// Retruns the triangles subdivision of the current planar subdivision. /// </summary> /// <param name="includeVirtualPoints">Indicates if virtual points should be included or not</param> /// <remarks>The triangles might contains virtual points that do not belongs to the inserted points, if you do not want those points, set <paramref name="includeVirtualPoints"> to false</paramref></remarks> /// <returns>The triangles subdivision in the current plannar subdivision</returns> public Triangle2DF[] GetDelaunayTriangles(bool includeVirtualPoints) { int size = ((MCvSet)Marshal.PtrToStructure(MCvSubdiv2D.edges, typeof(MCvSet))).total * 2; Triangle2DF[] triangles = new Triangle2DF[size]; GCHandle handle = GCHandle.Alloc(triangles, GCHandleType.Pinned); CvInvoke.PlanarSubdivisionGetTriangles(_ptr, handle.AddrOfPinnedObject(), ref size, includeVirtualPoints ? 1 : 0); handle.Free(); Array.Resize(ref triangles, size); return(triangles); }
public static int GetDiameter(Triangle2DF triangle2DF) { var listX = new List <float>(); listX.Add(triangle2DF.V0.X); listX.Add(triangle2DF.V1.X); listX.Add(triangle2DF.V2.X); var min = listX.Min(); var max = listX.Max(); return((int)(max - min + 15)); }
public void ThreadedFunction() { while (true) { while (!FApply) { Thread.Sleep(5); } int SliceCount; Spread <PointF[]> points; Spread <Triangle2DF[]> triangles; lock (FLockPoints) { SliceCount = FPoints.SliceCount; points = new Spread <PointF[]>(SliceCount); for (int i = 0; i < SliceCount; i++) { points[i] = new PointF[FPoints[i].Length]; Array.Copy(FPoints[i], points[i], FPoints[i].Length); } } triangles = new Spread <Triangle2DF[]>(SliceCount); for (int i = 0; i < SliceCount; i++) { PlanarSubdivision subdivision = new PlanarSubdivision(points[i] as PointF[]); triangles[i] = subdivision.GetDelaunayTriangles(false); } lock (FTriangles) { FTriangles.SliceCount = SliceCount; Triangle2DF t; for (int i = 0; i < SliceCount; i++) { FTriangles[i] = new Triangle2DF[triangles[i].Length]; for (int j = 0; j < triangles[i].Length; j++) { t = triangles[i][j]; FTriangles[i][j] = new Triangle2DF(t.V0, t.V1, t.V2); } } } FResults = true; } }
/// <summary> /// Create planar subdivision for random points /// </summary> /// <param name="maxValue">The points contains values between [0, maxValue)</param> /// <param name="pointCount">The total number of points to create</param> public static void CreateSubdivision(float maxValue, int pointCount, out Triangle2DF[] delaunayTriangles, out VoronoiFacet[] voronoiFacets) { #region create random points in the range of [0, maxValue] PointF[] pts = new PointF[pointCount]; Random r = new Random((int)(DateTime.Now.Ticks & 0x0000ffff)); for (int i = 0; i < pts.Length; i++) pts[i] = new PointF((float)r.NextDouble() * maxValue, (float)r.NextDouble() * maxValue); #endregion using (Subdiv2D subdivision = new Subdiv2D(pts)) { //Obtain the delaunay's triangulation from the set of points; delaunayTriangles = subdivision.GetDelaunayTriangles(); //Obtain the voronoi facets from the set of points voronoiFacets = subdivision.GetVoronoiFacets(); } }
private void CalculateNormal(Mat depthMat, Triangle2DF tri) { if (depthMat == null || (tri.Centeroid.X == 0 && tri.Centeroid.Y == 0)) { return; } var vertices = Array.ConvertAll(tri.GetVertices(), System.Drawing.Point.Round); var point2dList = vertices;// Kolos.haromszog.belsopontok(vertices); #region Kolos normalvektor //var point3dList = new List<Kolos.pont3d>(); //foreach (var point2d in point2dList) { // var zcoord = GetMatElementU16(depthMat, point2d.X, point2d.Y); // if(zcoord != 0) // point3dList.Add(CalculateWorldPosition(point2d.X, point2d.Y, depthMat.Cols, zcoord)); //} //var normal = Kolos.normalvektor.kiszamitas(point3dList); //Console.WriteLine($"Normálvektor X:{normal[0].ToString("F4")} Y:{normal[1].ToString("F4")}, Z: {normal[2].ToString("F4")}"); #endregion MCvPoint3D32f[] vertices3d = new MCvPoint3D32f[3]; for (int i = 0; i < 3; i++) { var point2d = point2dList[i]; var zcoord = GetMatElementU16(depthMat, point2d.X, point2d.Y); if (zcoord == 0) { return; } var point3d = CalculateWorldPosition(point2d.X, point2d.Y, depthMat.Cols, zcoord); vertices3d[i] = new MCvPoint3D32f((float)point3d.x, (float)point3d.y, (float)point3d.z); } var tri3d = new Triangle3DF(vertices3d[0], vertices3d[1], vertices3d[2]); var normal = tri3d.Normal; Console.WriteLine($"Normal: X:{normal.X} Y:{normal.Y} Z:{normal.Z}"); }
/* * public void TestArrayChangeDimension() * { * float[] vec = new float[10]; * for (int i = 0; i < vec.Length; i++) * vec[i] = (float)i; * * float[,] vec2 = new float[vec.Length, 1]; * * GCHandle hdl1 = GCHandle.Alloc(vec, GCHandleType.Pinned); * GCHandle hdl2 = GCHandle.Alloc(vec2, GCHandleType.Pinned); * Emgu.Util.Toolbox.memcpy(hdl1.AddrOfPinnedObject(), hdl2.AddrOfPinnedObject(), vec.Length * Marshal.SizeOf(typeof(float))); * hdl1.Free(); * hdl2.Free(); * //Array.Copy(vec, vec2, vec.Length); * * for (int i = 0; i < vec.Length; i++) * { * Assert.AreEqual(vec[i], vec2[i, 0]); * } * }*/ private void TestMap() { PointF center = new PointF(-110032, -110032); float width = 10000, height = 12000; Map <Gray, Byte> map = new Map <Gray, byte>(new RectangleF(center.X - width / 2, center.Y - height / 2, width, height), new PointF(100, 100)); PointF[] pts = new PointF[] { new PointF((float)center.X + 3120, (float)center.Y + 2310), new PointF((float)center.X - 220, (float)center.Y - 4120) }; map.DrawPolyline(pts, false, new Gray(255.0), 1); Triangle2DF tri = new Triangle2DF( new PointF((float)center.X - 1000.0f, (float)center.Y + 200.0f), new PointF((float)center.X - 3000.0f, (float)center.Y + 200.0f), new PointF((float)center.X - 700f, (float)center.Y + 800.0f)); map.Draw(tri, new Gray(80), 0); map.Draw(tri, new Gray(255), 1); ImageViewer.Show(map); }
/// <summary> /// Default constructor /// </summary> /* public PolyFromTris(Triangle2DF[] t) { //tris = new Triangle2DF(); innerPoints = new List<PointF>(); this.tris = t; }*/ /// <summary> /// Sets triangles structure /// </summary> public void setTris(Triangle2DF[] t) { this.tris = t; }
public void TestTriangle() { PointF p1 = new PointF(0, 0); PointF p2 = new PointF(1, 0); PointF p3 = new PointF(0, 1); Triangle2DF tri = new Triangle2DF(p1, p2, p3); double epsilon = 1e-12; //Trace.WriteLine(tri.Area); //Trace.WriteLine(((p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X))*0.5); Assert.IsTrue(Math.Abs(tri.Area - 0.5) < epsilon); }
private void btnProcess_Click(object sender, EventArgs e) { if (original == null) { lblError.Text = "Please browse the image"; lblError.Visible = true; btnProcess.Enabled = btnSaveImage.Enabled = false; return; } if (cbCircle.Checked == false && cbLine.Checked == false & cbRectangle.Checked == false && cbTriangle.Checked == false) { lblError.Text = "Please choose the shape detection type"; lblError.Visible = true; original = temp = new Image <Bgr, byte>(openFileDialog.FileName); pbChosenImage.Image = original.ToBitmap(); return; } lblError.Visible = false; temp = new Image <Bgr, byte>(openFileDialog.FileName); if (cbLine.Checked == true) { LineSegment2D[] lines = edge.HoughLinesBinary(2, Math.PI / 180, 50, 50, 10)[0]; foreach (LineSegment2D line in lines) { temp.Draw(line, new Bgr(Color.Yellow), 10); } pbChosenImage.Image = temp.Bitmap; } if (cbCircle.Checked == true) { CircleF[] circles = edge.HoughCircles(new Gray(150), new Gray(150), 2, 50, 10, 100)[0]; foreach (CircleF circle in circles) { temp.Draw(circle, new Bgr(Color.Red), 10); } pbChosenImage.Image = temp.Bitmap; } if (cbTriangle.Checked == true) { for (Contour <Point> contour = edge.FindContours(); contour != null; contour = contour.HNext ) { if (contour.Area > 200) { MemStorage mem = new MemStorage(); Contour <Point> contourDalem = contour.ApproxPoly(contour.Perimeter * 0.16, mem); if (contourDalem.Total == 3) { Point[] points = contourDalem.ToArray(); Triangle2DF triangle = new Triangle2DF(points[0], points[1], points[2]); temp.Draw(triangle, new Bgr(Color.Green), 10); } } } pbChosenImage.Image = temp.Bitmap; } if (cbRectangle.Checked == true) { for (Contour <Point> contour = edge.FindContours(); contour != null; contour = contour.HNext ) { if (contour.Area > 200) { MemStorage mem = new MemStorage(); Contour <Point> contourDalem = contour.ApproxPoly(contour.Perimeter * 0.16, mem); if (contourDalem.Total == 4) { Point[] points = contourDalem.ToArray(); bool rectangle = true; LineSegment2D[] lines = PointCollection.PolyLine(points, true); for (int i = 0; i < lines.Length; i++) { double angle = Math.Abs(lines[(i + 1) % lines.Length].GetExteriorAngleDegree(lines[i])); if (angle < 80 || angle > 100) { rectangle = false; break; } } if (rectangle == true) { temp.Draw(contourDalem.GetMinAreaRect(), new Bgr(Color.Gold), 10); } } } } pbChosenImage.Image = temp.Bitmap; } }
/// <summary> /// Draws trangulated poly to colored Bgr image in green /// </summary> /// <param name="img">Image we're drawing to</param> /// <param name="trisList">Triangles list</param> /// <param name="imgBox">Box we're inserting image to</param> public void drawTris(Image<Bgr, Byte> img, Triangle2DF[] trisList, ref Emgu.CV.UI.ImageBox imgBox) { //Draw the Delaunay triangulation foreach (Triangle2DF tri in trisList) { img.Draw(tri, new Bgr(Color.DarkOliveGreen), 1); } imgBox.Image = img; }
/* public static void TestCodeBook() { int learningFrames = 40; using (BlobDetector detector = new BlobDetector(CvEnum.BlobDetectorType.Simple)) using (BlobSeq blobs = new BlobSeq()) using (Capture capture = new Capture("tree.avi")) using (BGCodeBookModel<Ycc> bgmodel = new BGCodeBookModel<Ycc>()) { #region Set color thresholds values //bgmodel.MCvBGCodeBookModel.ModMin0 = bgmodel.MCvBGCodeBookModel.ModMin1 = bgmodel.MCvBGCodeBookModel.ModMin2 = 3; //bgmodel.MCvBGCodeBookModel.ModMax0 = bgmodel.MCvBGCodeBookModel.ModMax1 = bgmodel.MCvBGCodeBookModel.ModMax2 = 10; //bgmodel.MCvBGCodeBookModel.CbBounds0 = bgmodel.MCvBGCodeBookModel.CbBounds1 = bgmodel.MCvBGCodeBookModel.CbBounds2 = 10; #endregion ImageViewer viewer = new ImageViewer(); int count = 0; EventHandler processFrame = delegate(Object sender, EventArgs e) { Image<Bgr, Byte> img = capture.RetrieveBgrFrame(); if (img == null) { return; } viewer.Text = String.Format("Processing {0}th image. {1}", count++, learningFrames > 0 ? "(Learning)" : String.Empty); using (Image<Ycc, Byte> ycc = img.Convert<Ycc, Byte>()) //using YCC color space for BGCodeBook { if (learningFrames == 0) //training is completed bgmodel.ClearStale(bgmodel.MCvBGCodeBookModel.T / 2, Rectangle.Empty, null); if (learningFrames > 0) bgmodel.Apply(ycc); else if (learningFrames <= 0) { bgmodel.Diff(ycc, Rectangle.Empty); Image<Gray, Byte> m = bgmodel.ForegroundMask.Clone(); blobs.Clear(); if (detector.DetectNewBlob(m, blobs, null)) { foreach (MCvBlob b in blobs) m.Draw((Rectangle) b, new Gray(100), 2); } viewer.Image = m; } learningFrames--; System.Threading.Thread.Sleep(100); } img.Dispose(); }; capture.ImageGrabbed += processFrame; capture.Start(); viewer.ShowDialog(); } } public void TestArrayChangeDimension() { float[] vec = new float[10]; for (int i = 0; i < vec.Length; i++) vec[i] = (float)i; float[,] vec2 = new float[vec.Length, 1]; GCHandle hdl1 = GCHandle.Alloc(vec, GCHandleType.Pinned); GCHandle hdl2 = GCHandle.Alloc(vec2, GCHandleType.Pinned); Emgu.Util.Toolbox.memcpy(hdl1.AddrOfPinnedObject(), hdl2.AddrOfPinnedObject(), vec.Length * Marshal.SizeOf(typeof(float))); hdl1.Free(); hdl2.Free(); //Array.Copy(vec, vec2, vec.Length); for (int i = 0; i < vec.Length; i++) { Assert.AreEqual(vec[i], vec2[i, 0]); } }*/ private void TestMap() { PointF center = new PointF(-110032, -110032); float width = 10000, height = 12000; Map<Gray, Byte> map = new Map<Gray, byte>(new RectangleF(center.X - width/2, center.Y - height/2, width, height), new PointF(100, 100)); PointF[] pts = new PointF[] { new PointF( (float)center.X + 3120,(float) center.Y + 2310), new PointF((float)center.X -220, (float) center.Y-4120) }; map.DrawPolyline(pts, false, new Gray(255.0), 1); Triangle2DF tri = new Triangle2DF( new PointF((float)center.X - 1000.0f, (float)center.Y + 200.0f), new PointF((float)center.X - 3000.0f, (float)center.Y + 200.0f), new PointF((float)center.X - 700f, (float)center.Y + 800.0f)); map.Draw(tri, new Gray(80), 0); map.Draw(tri, new Gray(255), 1); ImageViewer.Show(map); }
private void altProcess(Bitmap bm, int level) { var img = new Image <Bgr, byte>(bm); if (level == 1) { var resImage = new Image <Bgr, byte>(img.Bitmap); CvInvoke.BilateralFilter(resImage, img, 30, 80, 80); CvInvoke.MedianBlur(img, img, 5); resImage = img; } else if (level == 2) { CvInvoke.MedianBlur(img, img, 5); var resImage = new Image <Bgr, byte>(img.Bitmap); CvInvoke.BilateralFilter(resImage, img, 25, 75, 75); CvInvoke.Blur(img, img, new Size(5, 5), new Point(0, 0)); } var grayimage = new Image <Gray, byte>(bm); CvInvoke.CvtColor(img, grayimage, ColorConversion.Bgr2Gray); BlackBG(grayimage); Console.WriteLine("Filtering done"); var cannyThreshold = GetKMeansThreshold(grayimage); label2.Text = cannyThreshold.ToString(); Thresholding(grayimage, cannyThreshold); Console.WriteLine("Canny threshold using KMEANS found " + cannyThreshold); //Convert the image to grayscale and filter out the noise var cannyEdges = new UMat(); Console.WriteLine("Canny threshold using KMEANS found " + cannyThreshold); var uimage = new UMat(); CvInvoke.CvtColor(img, uimage, ColorConversion.Bgr2Gray); CvInvoke.Canny(uimage, cannyEdges, cannyThreshold, cannyThreshold); BlobCounter blobCounter = new BlobCounter( ); if (level == 1) { blobCounter.FilterBlobs = true; blobCounter.MinHeight = 25; blobCounter.MinWidth = 25; blobCounter.ProcessImage(cannyEdges.Bitmap); } else { blobCounter.ProcessImage(grayimage.ToBitmap()); } //blobCounter.ProcessImage(grayimage.ToBitmap()); Blob[] blobs = blobCounter.GetObjectsInformation( ); SimpleShapeChecker shapeChecker = new SimpleShapeChecker(); var triangleList = new List <Triangle2DF>(); var boxList = new List <RotatedRect>(); var circleList = new List <CircleF>(); Bitmap newBM = new Bitmap(img.Bitmap); Graphics g = Graphics.FromImage(newBM); Pen redPen = new Pen(Color.Red, 2); Pen yellowPen = new Pen(Color.Yellow, 2); Pen greenPen = new Pen(Color.Green, 2); Pen bluePen = new Pen(Color.Blue, 2); for (int i = 0, n = blobs.Length; i < n; i++) { List <IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]); AForge.Point center; float radius; if (shapeChecker.IsCircle(edgePoints, out center, out radius)) { //g.DrawEllipse(bluePen, // (float)(center.X - radius), (float)(center.Y - radius), // (float)(radius * 2), (float)(radius * 2)); circleList.Add(new CircleF(new PointF(center.X, center.Y), radius)); } else { List <IntPoint> corners; if (edgePoints.Count > 1) { if (shapeChecker.IsQuadrilateral(edgePoints, out corners)) { System.Console.WriteLine(corners.Count); if (shapeChecker.CheckPolygonSubType(corners) == PolygonSubType.Square || shapeChecker.CheckPolygonSubType(corners) == PolygonSubType.Rectangle) { IntPoint minXY, maxXY; PointsCloud.GetBoundingRectangle(corners, out minXY, out maxXY); AForge.Point c = PointsCloud.GetCenterOfGravity(corners); //g.DrawPolygon(greenPen, ToPointsArray(corners)); boxList.Add(new RotatedRect(new PointF(c.X, c.Y), new SizeF(maxXY.X - minXY.X, maxXY.Y - minXY.Y), 0)); } } else { corners = PointsCloud.FindQuadrilateralCorners(edgePoints); if (corners.Count == 3) { Triangle2DF tri = new Triangle2DF(new PointF(corners[0].X, corners[0].Y), new PointF(corners[1].X, corners[1].Y), new PointF(corners[2].X, corners[2].Y)); triangleList.Add(tri); //g.DrawPolygon(yellowPen, ToPointsArray(corners)); } //g.DrawPolygon(redPen, ToPointsArray(corners)); } } } } Console.WriteLine("boxes " + boxList.Count); Console.WriteLine("triangles " + triangleList.Count); Console.WriteLine("circles " + circleList.Count); redPen.Dispose(); greenPen.Dispose(); bluePen.Dispose(); yellowPen.Dispose(); //g.Dispose(); resPicBox.Image = newBM; CircleF[] circles = circleList.ToArray(); var cList = circles.ToList(); FilterSame(boxList, triangleList, cList, img.Width * img.Height); circles = cList.ToArray(); var points = new List <PointF>(); var Image = img.CopyBlank(); foreach (var triangle in triangleList) { Image.Draw(triangle, new Bgr(Color.Red), 3); points.Add(triangle.Centeroid); } foreach (var box in boxList) { Image.Draw(box, new Bgr(Color.Blue), 3); points.Add(box.Center); } foreach (var circle in circles) { Image.Draw(circle, new Bgr(Color.DarkCyan), 3); points.Add(circle.Center); } var listPoints = SortPoints(points, img); for (var i = 0; i < listPoints.Length; i++) { Console.WriteLine(listPoints[i].X.ToString() + " " + listPoints[i].Y.ToString()); } System.Console.WriteLine("Points sorted, num of objects " + listPoints.Length.ToString()); resPicBox.Image = (Image + img).ToBitmap(); if (listPoints.Length > 3) { var bezSegList = InterpolatePointWithBeizerCurves(listPoints.ToList <PointF>()); var gr = Graphics.FromImage(resPicBox.Image); var p = new Pen(Color.Red); foreach (BeizerCurveSegment seg in bezSegList) { var bezierList = GetBez(new PointF[] { seg.StartPoint, seg.FirstControlPoint, seg.SecondControlPoint, seg.EndPoint }); for (var i = 0; i < bezierList.Length - 1; i++) { gr.DrawLine(p, bezierList[i], bezierList[i + 1]); } } } else { var gr = Graphics.FromImage(resPicBox.Image); var p = new Pen(Color.Red); for (var i = 0; i < listPoints.Length - 1; i++) { gr.DrawLine(p, listPoints[i], listPoints[i + 1]); } } //var bezierList = GetBezierCurve1(listPoints); }
public void DetectFingers(Image<Gray, Byte> image) { /* Point3D ptHandProjective = this.depth.ConvertRealWorldToProjective(ptHand); Size offset = new Size((int)ptHandProjective.X, (int)ptHandProjective.Y); //get the hand Image<Gray, Byte> image = detector.DetectHand(this.depth, ptHand); */ //image = image.PyrDown().PyrUp(); //image._SmoothGaussian(5); //image._ThresholdBinary(new Gray(149), new Gray(255)); Graphics g = Graphics.FromImage(this.bitmap); MemStorage storage1 = new MemStorage(); Contour<Point> contours = new Contour<Point>(storage1); // Find the biggest contour for (Contour<Point> tempContours = image.FindContours(); tempContours != null; tempContours = tempContours.HNext) { if (tempContours.Area > contours.Area) contours = tempContours; } //Console.WriteLine(contours.Area); if (contours.Area != 0) { List<KeyValuePair<Point, bool>> significantPts = new List<KeyValuePair<Point, bool>>(); Rectangle contourRectangle = contours.BoundingRectangle; g.DrawRectangle(new Pen(Brushes.Green), contourRectangle); //Seq<Point> contoursHull = contours.GetConvexHull(Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE); // Convert the set of contour points to a polygon for graphical representation Seq<Point> poly = contours.ApproxPoly(20); Point[] polygon = poly.ToArray(); PointF[] contourF = Array.ConvertAll(contours.ToArray(), new Converter<Point, PointF>(PointToPointF)); //CircleF palmCircle = PointCollection.MinEnclosingCircle(contourF); //CircleF palmCircle = PointCollection.EllipseLeastSquareFitting(contourF); //MCvBox2D box = PointCollection.MinAreaRect(contourF); //g.DrawRectangle(new Pen(Brushes.Aquamarine),(Rectangle) box.MinAreaRect()); //drawCircle(g, new Pen(Brushes.Green), PointFToPoint(palmCircle.Center), (int) Math.Round(palmCircle.Radius)); // Get the convex hull based on the contour polygon Seq<Point> convexHull = poly.GetConvexHull(Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE); /* * Handle opening and closing of the fist each frame. * Fisting gesture controls the left mouse button. * Based on the ratio of area between the convex and the hull. * (See calculation above) Threshold currently set to 0.8 * * NEED TO HAND COORDINATES */ double hullArea = convexHull.Area; double contourArea = contours.Area; double currentHullRatio = contourArea / hullArea; // newest ratio is in front of array hullRatios[2] = hullRatios[1]; hullRatios[1] = hullRatios[0]; hullRatios[0] = currentHullRatio; this.fixedHullRatio = hullRatios[2]; if (smoothHullRatios && this.frame > 3) { this.hullRatios = smoothHullRatioArray(this.hullRatios); } bool fistClosed = true; stopTracking = true; if (shouldHandClose()) { stopTracking = true; fistClosed = false; } if (shouldControlMouse) { //clickMouse(fistClosed); } // Get the convexity defects from the contour stopwatch.Restart(); Seq<Emgu.CV.Structure.MCvConvexityDefect> contourDefects = contours.GetConvexityDefacts(storage1, Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE); stopwatch.Stop(); //Console.WriteLine(Math.Round(1000.0 * (double)stopwatch.ElapsedTicks / Stopwatch.Frequency, 4) + ", GetConvexityDefacts()"); // Draw the polygon that was converted from the contour /* for (int i = 0; i < polygon.Length; i++) { if (i == polygon.Length - 1) g.DrawLine((new Pen(Brushes.Blue))), polygon[i], polygon[0]); else g.DrawLine((new Pen(Brushes.Blue))), polygon[i], polygon[i + 1]); } */ // Draw more polygon stuff ?? foreach (Point p in poly) { significantPts.Add(new KeyValuePair<Point, bool>(p, false)); //g.DrawLine((new Pen(Brushes.Blue))), p.X, p.Y, p.X + 10, p.Y + 10); } int fingertips = 0; Point[] defectPoints = new Point[contourDefects.Count()]; Point[] fingerPoints = new Point[contourDefects.Count()]; Point[] endPoints = new Point[contourDefects.Count()]; int count = 0; int fingerCount = 0; ///--- DEFECTS foreach (MCvConvexityDefect defect in contourDefects) { // Construct a triangle from the defect Triangle2DF defectTriangle = new Triangle2DF(defect.DepthPoint, defect.StartPoint, defect.EndPoint); // Check that the area of the defect triangle is between 1% and 33% of the contour area if (defectTriangle.Area > contours.Area / 100 && defectTriangle.Area < contours.Area / 3) { ///--- endPoints[count] = defect.EndPoint; defectPoints[count] = defect.DepthPoint; count++; // Get the angle of the defect double defectAngle = getVertexAngle(defect.DepthPoint, defect.StartPoint, defect.EndPoint); if (defectAngle < 100 && !defect.EndPoint.Equals(Point.Empty)) fingerPoints[fingerCount++] = defect.EndPoint; ///--- //g.DrawPolygon(new Pen(Brushes.Pink), defectTriangle.GetVertices()); significantPts.Add(new KeyValuePair<Point, bool>(defect.DepthPoint, true)); g.DrawLine((new Pen(Brushes.Green)), defect.StartPoint, defect.EndPoint); g.DrawLine((new Pen(Brushes.Red)), defect.DepthPoint, defect.StartPoint); g.DrawLine((new Pen(Brushes.Blue)), defect.DepthPoint, defect.EndPoint); // Draw the depth point of the defects (hull point) g.DrawRectangle(new Pen(Brushes.Green), new Rectangle(Point.Subtract(defect.DepthPoint, new Size(5, 5)), new Size(10, 10))); // Check if angle is obtuse or acute g.DrawString(defectAngle.ToString(), new Font(FontFamily.GenericSerif,5), Brushes.Blue, defect.DepthPoint.X + 5, defect.DepthPoint.Y + 5); /* if (defectAngle < 70) drawCircle(g,new Pen(Brushes.White, 2), defect.StartPoint, 5); else if (defectAngle < 100) { drawCircle(g, new Pen(Brushes.White, 2), defect.StartPoint, 5); drawCircle(g, new Pen(Brushes.White, 2), defect.EndPoint, 5); } else drawCircle(g, new Pen(Brushes.Gray, 2), defect.StartPoint, 5); */ } } ///--- ///--- K-CURVATURE stopwatch.Restart(); //Point[] curvePoints = endPoints.ToArray(); Point[] curvePoints = convexHull.ToArray(); //int[] indexArray = getContourCurvatureIndices(contours, curvePoints); int[] indexArray = KCurvature.getContourCurvatureIndices(contours, curvePoints); //KCurve1(contours, indexArray, g); //KCurve2(contours, indexArray, g); Accord.Math.Geometry.KCurvature kcurve = new Accord.Math.Geometry.KCurvature(16, new AForge.DoubleRange(30, 90)); List<AForge.IntPoint> intPointContour = convertToIntPoint(contours.ToArray()); List<AForge.IntPoint> contourPeaks = kcurve.FindPeaks(intPointContour); this.minFingerDistance = getMinDistance(contourPeaks.ToArray()); ///--- /// Trying to find the forearm stopwatch.Restart(); /// /// method 1 /// Point[] forearmPoints = new Point[convexHull.Count()]; int k = 0; foreach (Point p in convexHull.ToArray()) { double error = 15; if (Math.Abs(p.Y - contours.BoundingRectangle.Bottom) < error) { //g.DrawRectangle(new Pen(Brushes.Aquamarine), p.X, p.Y, 5, 5); forearmPoints[k] = p; //Console.WriteLine("point {1}: {0}",p.ToString(), k); k++; } } Point p0; //Console.WriteLine("forearm points: {0}", forearmPoints.Count()); if (forearmPoints.Count() == 1) p0 = forearmPoints[0]; else p0 = getMidPoint(forearmPoints[0], forearmPoints[1]); //Console.WriteLine("midpoint : {0}", p0.ToString()); g.DrawRectangle(new Pen(Brushes.Aquamarine), p0.X, p0.Y, 5, 5); g.DrawLine(new Pen(Brushes.Aquamarine),p0 ,convertPoint3D(lastPoint)); /// /// /// /* //Point[] possibleWristPoints = convexHull.Intersect(contours).ToArray(); Point[] possibleWristPoints = convexHull.ToArray(); for (int i = 0; i < possibleWristPoints.Count(); i++) { Point p = possibleWristPoints[i]; double error = 10; if (Math.Abs(p.Y - contours.BoundingRectangle.Bottom) < error) g.DrawRectangle(new Pen(Brushes.Aquamarine), p.X, p.Y, 10, 10); double minDistance = 1000000; for (int j = 0; j < contourPeaks.Count(); j++) { AForge.IntPoint p2 = contourPeaks[j]; double pointDistance = getPointDistance(p, new Point(p2.X, p2.Y)); if (pointDistance < minDistance) minDistance = pointDistance; } //if (minDistance > 50) //g.DrawRectangle(new Pen(Brushes.Aquamarine), p.X, p.Y, 10, 10); //LineSegment2D line = new LineSegment2D(possibleWristPoints[i], possibleWristPoints[i + 1]); //Point midPoint = getMidPoint(possibleWristPoints[i], possibleWristPoints[i + 1]); //if (contourRectangle.Bottom == midPoint.X) //if (contours.Contains(line.P1) && contours.Contains(line.P2)) //g.DrawLine(new Pen(Brushes.Aquamarine), possibleWristPoints[i], possibleWristPoints[i + 1]); //g.DrawString(i.ToString(), DefaultFont, Brushes.Red, p.X, p.Y); //Console.WriteLine("Possible wrist point: {0}, {1}", p.X, p.Y); //i++; } */ stopwatch.Stop(); //Console.WriteLine("polygon/contour intersect time: {0}", Math.Round(1000.0 * (double)stopwatch.ElapsedTicks / Stopwatch.Frequency, 4)); ///--- /// // Count the finger tips found if we've processed 3 frames already if (frame > fingersDetectedHistorySize) { for (int i = 0; i < fingersDetectedHistorySize - 1; i++) { //Console.WriteLine("finger history {0}: {1}", i, fingersDetectedHistory[i]); fingersDetectedHistory[i] = fingersDetectedHistory[i + 1]; } fingersDetectedHistory[fingersDetectedHistorySize - 1] = contourPeaks.Count() - 1; if (fingersDetectedHistory[fingersDetectedHistorySize-1] == fingersDetectedHistory[fingersDetectedHistorySize-3] && fingersDetectedHistory[fingersDetectedHistorySize-3] != fingersDetectedHistory[fingersDetectedHistorySize-2]) fingersDetectedHistory[fingersDetectedHistorySize-2] = fingersDetectedHistory[fingersDetectedHistorySize-3]; //Console.WriteLine("Fingers: {0}", fingersDetectedHistory[0]); } if (this.startClickLag) this.clickLag++; double perimeterMultiplier = (this.lastPoint.Z / 800); double contourPerimeter = contours.Perimeter * perimeterMultiplier; int fingers = contourPeaks.Count - 1; // contourPerimeter > 700 is an experiemental value obtained my analyzing my own // hand contour. this must be changed for other users. //if ((contourPerimeter > 600 || fingers > 3) && !this.leftButtonDown) if ((fingers > 3) && !this.leftButtonDown) { if (this.clickLag < 7) this.clickLag++; else { stopTracking = false; this.clickLag = 0; } /* if (this.startClickLag && !mouseActionReset) { if (this.clickLag < 20) { stopTracking = true; this.clickLag++; } else { this.clickLag = 0; this.startClickLag = false; } } else stopTracking = true; * */ } // this doesnt account for releasing the left mouse button if (this.frame > 5 && shouldControlMouse && fingersDetectedHistory[0] == fingersDetectedHistory[1] && fingersDetectedHistory[1] == fingersDetectedHistory[2]) { if (!leftButtonDown) stopTracking = true; if (fingersDetectedHistory[0] == 1) { this.frameCount++; if (this.frameCount > 25) sendMouseEvent(11); } else { if (this.frameCount > 3 && this.frameCount < 25) sendMouseEvent(1); else if (this.frameCount > 25) sendMouseEvent(11); else sendMouseEvent(fingersDetectedHistory[0]); this.frameCount = 0; } } // Highlight the finger tip positions int peakIndex = 1; foreach (AForge.IntPoint p in contourPeaks) { g.DrawRectangle(new Pen(Brushes.White), p.X - 2, p.Y - 2, 4, 4); g.DrawString(peakIndex.ToString(), DefaultFont, Brushes.White, p.X + 4, p.Y - 4); peakIndex++; } stopwatch.Stop(); //Console.WriteLine("KCurve time {0} ms", Math.Round(1000.0 * (double)stopwatch.ElapsedTicks / Stopwatch.Frequency, 4)); ///--- /// // to build a circle just start with a square and filter by radius distance //Point polygonCenter = getCentroid(polygon); //Point contourCenter = getCentroid(contours.ToArray()); //updatePalm(g, contours); updatePalmNite(); /* drawCircle(g, new Pen(Brushes.BlueViolet), contourRectangleCenter, 10); drawCircle(g, new Pen(Brushes.BlueViolet), contourRectangleCenter, 25); drawCircle(g, new Pen(Brushes.BlueViolet), contourRectangleCenter, 50); */ //Console.WriteLine(this.lastPoint.X + ", " + this.lastPoint.Y + ": " + depth.GetMetaData()[(int)this.lastPoint.X, (int)this.lastPoint.Y]); g.DrawString("now " + (contourPeaks.Count() - 1).ToString(), DefaultFont, Brushes.White, 50, 130); g.DrawString("filtered " + fingersDetectedHistory[0].ToString(), DefaultFont, Brushes.White, 50, 150); g.DrawString(Math.Round(this.hullRatios[2], 4).ToString(), DefaultFont, Brushes.White, 50, 170); g.DrawString("handOpen:"+fistClosed.ToString(), DefaultFont, Brushes.White, 50, 190); g.DrawString("Frames: "+this.frame, DefaultFont, Brushes.White, 50, 210); if (shouldControlMouse && !stopTracking) g.DrawString("Cursor: " + lastScaledMousePoint.X+", "+lastScaledMousePoint.Y, DefaultFont, Brushes.White, 50, 230); g.DrawString(depth.GetMetaData().FPS.ToString(), DefaultFont, Brushes.White, 50, 250); g.DrawString(this.minFingerDistance.ToString(), DefaultFont, Brushes.White, 50, 270); //g.DrawClosedCurve(new Pen(Brushes.Purple), fingerPoints); //Save the frame to disk (if specified) if (this.captureFrames) this.bitmap.Save(System.IO.Path.Combine(this.frameDir,this.frame + ".png"), ImageFormat.Png); this.frame++; } }
private void CreateDelaunay(ref Mat img, ref Subdiv2D subdiv, ref VectorOfPointF points, bool drawAnimated, ref VectorOfVectorOfInt triangleIndexes) { PointF[] pointsArr = points.ToArray(); foreach (PointF p in pointsArr) { subdiv.Insert(p); if (drawAnimated) { Mat imgCopy = img.Clone(); DrawDelaunay(ref imgCopy, ref subdiv, new MCvScalar(255, 255, 255)); CvInvoke.Imshow("Delaunay Triangulation", imgCopy); } } // Unfortunately we don't get the triangles by there original point indexes. // We only get them with their vertex coordinates. // So we have to map them again to get the triangles with their point indexes. Size size = img.Size; Rectangle rect = new Rectangle(0, 0, size.Width, size.Height); VectorOfInt ind = new VectorOfInt(); int[] indArr = new int[3]; Triangle2DF[] triangleList = subdiv.GetDelaunayTriangles(); for (int i = 0; i < triangleList.Length; i++) { Triangle2DF t = triangleList[i]; PointF ptzero = new PointF { X = t.V0.X, Y = t.V0.Y }; PointF[] PZero = new PointF[] { ptzero }; PointF ptone = new PointF { X = t.V1.X, Y = t.V1.Y }; PointF[] POne = new PointF[] { ptone }; PointF pttwo = new PointF { X = t.V2.X, Y = t.V2.Y }; PointF[] PTwo = new PointF[] { pttwo }; VectorOfPointF pt = new VectorOfPointF(); pt.Push(PZero); pt.Push(POne); pt.Push(PTwo); if (rect.Contains(new Point((int)pt[0].X, (int)pt[0].Y)) && rect.Contains(new Point((int)pt[1].X, (int)pt[1].Y)) && rect.Contains(new Point((int)pt[2].X, (int)pt[2].Y))) { for (int j = 0; j < 3; j++) { for (int k = 0; k < points.Size; k++) { if (Math.Abs(pt[j].X - points[k].X) < 1.0 && Math.Abs(pt[j].Y - points[k].Y) < 1) { indArr[j] = k; } } } } ind = new VectorOfInt(indArr); triangleIndexes.Push(ind); } }
public void TriangleRectangleImage(ref VectorOfVectorOfPoint contours, double epsilonFact = 0.05, double minArea = 10) { Stopwatch watch = Stopwatch.StartNew(); triangleList = new List <Triangle2DF>(); boxList = new List <RotatedRect>(); //a box is a rotated rectangle int count = contours.Size; for (int i = 0; i < count; i++) { VectorOfPoint contour = contours[i]; VectorOfPoint approxContour = new VectorOfPoint(); double epsilon = CvInvoke.ArcLength(contour, true) * epsilonFact; CvInvoke.ApproxPolyDP(contour, approxContour, epsilon, true); //sign of area gives orientation double area = CvInvoke.ContourArea(approxContour, true); area = Math.Abs(area); if (area > minArea) //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(); Triangle2DF triangle = new Triangle2DF(pts[0], pts[1], pts[2]); triangleList.Add(triangle); } else if (approxContour.Size == 4) //The contour has 4 vertices. { //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++) { int index = (j + 1) % edges.Length; double angle = edges[index].GetExteriorAngleDegree(edges[j]); angle = Math.Abs(angle); if (angle < 80 || angle > 100) { isRectangle = false; break; } } // RotatedRect rotatedRect = CvInvoke.MinAreaRect(approxContour); if (isRectangle) { boxList.Add(rotatedRect); } } } } // } watch.Stop(); msgBuilder.Append(String.Format("Triangles & Rectangles - {0} ms; ", watch.ElapsedMilliseconds)); }
public void ThreadedFunction() { while (true) { while (!FApply) Thread.Sleep(5); int SliceCount; Spread<PointF[]> points; Spread<Triangle2DF[]> triangles; lock (FLockPoints) { SliceCount = FPoints.SliceCount; points = new Spread<PointF[]>(SliceCount); for (int i = 0; i < SliceCount; i++) { points[i] = new PointF[FPoints[i].Length]; Array.Copy(FPoints[i], points[i], FPoints[i].Length); } } triangles = new Spread<Triangle2DF[]>(SliceCount); for (int i = 0; i < SliceCount; i++) { PlanarSubdivision subdivision = new PlanarSubdivision(points[i] as PointF[]); triangles[i] = subdivision.GetDelaunayTriangles(false); } lock (FTriangles) { FTriangles.SliceCount = SliceCount; Triangle2DF t; for (int i = 0; i < SliceCount; i++) { FTriangles[i] = new Triangle2DF[triangles[i].Length]; for (int j = 0; j < triangles[i].Length; j++ ) { t = triangles[i][j]; FTriangles[i][j] = new Triangle2DF(t.V0, t.V1, t.V2); } } } FResults = true; } }
internal static extern void VectorOfTriangle2DFGetItem(IntPtr vec, int index, ref Triangle2DF element);
/// <summary> /// Draws trangulated poly /// </summary> /// <param name="img">Image we're drawing to</param> /// <param name="trisList">Triangles list</param> /// <param name="imgBox">Box we're inserting image to</param> public void drawTris(Image<Gray, Byte> img, Triangle2DF[] trisList, ref Emgu.CV.UI.ImageBox imgBox) { //Draw the Delaunay triangulation foreach (Triangle2DF tri in trisList) { img.Draw(tri, new Gray(128.0f), 2); } imgBox.Image = img; }