Преглед изворни кода

Added min area rect of palm without thumb and wrist.

Daniel Kauth пре 10 година
родитељ
комит
e444b4f6f0
2 измењених фајлова са 133 додато и 32 уклоњено
  1. 128 32
      bbiwarg/Images/PalmImage.cs
  2. 5 0
      bbiwarg/Utility/Vector2D.cs

+ 128 - 32
bbiwarg/Images/PalmImage.cs

@@ -23,7 +23,13 @@ namespace bbiwarg.Images
         private Image<Gray, Byte> outputImage;
 
         private List<Finger> fingers;
-        
+
+        private Contour<Point> palmContour;
+        private List<MCvConvexityDefect> convexityDefects;
+        private Vector2D wristPoint, wristDirection;
+        private LineSegment2DF wristLine, thumbLine;
+        private MCvBox2D palmRect;
+
         private int width, height;
         
         public PalmImage(DepthImage depthImage, EdgeImage edgeImage, FingerDetector fingerDetector)
@@ -35,11 +41,28 @@ namespace bbiwarg.Images
             width = depthImage.getWidth();
             height = depthImage.getHeight();
 
+            outputImage = new Image<Gray, byte>(width, height, new Gray(0));
+
             fingers = getFingersWithoutThumb(fingerDetector);
             buildPointingHandMask();
             handImage = handImage.And(pointingHandMask);
 
-            findPalmContour();
+            findLongestPalmContour();
+            if (palmContour != null)
+            {
+                findConvexityDefactsSortedByDepth();
+                removeConvexityDefectsNearFingerTips();
+
+                findWristLine();
+                findThumbLine();
+
+                removePointsFromContour(wristLine, 1);
+                removePointsFromContour(thumbLine, 1);
+
+                findPalmRect();
+
+                draw();
+            }
         }
 
         private List<Finger> getFingersWithoutThumb(FingerDetector fingerDetector)
@@ -119,59 +142,132 @@ namespace bbiwarg.Images
             pointingHandMask = pointingHandMask.Erode(2);
         }
 
-        private void findPalmContour()
+        private void findLongestPalmContour()
         {
             Contour<Point> contour = handImage.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_EXTERNAL);
 
-            Contour<Point> maxContour = contour;
+            palmContour = contour;
             double maxPerimeter = 0;
             while (contour != null)
             {
                 if (contour.Perimeter > maxPerimeter)
                 {
                     maxPerimeter = contour.Perimeter;
-                    maxContour = contour;
+                    palmContour = contour;
                 }
                 contour = contour.HNext;
             }
+        }
 
-            if (maxContour != null)
+        private void findWristDirection()
+        {
+            PointF[] points = new PointF[palmContour.Count<Point>()];
+            int index = 0;
+            foreach (Point p in palmContour)
             {
-                Contour<Point> contourPoly = maxContour; //.ApproxPoly(0);
-                Seq<Point> hull = contourPoly.GetConvexHull(Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE);
-                Seq<MCvConvexityDefect> defects = contourPoly.GetConvexityDefacts(new MemStorage(), Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE);
+                points[index] = new PointF(p.X, p.Y);
+                ++index;
+            }
+            PointF direction, tmp;
+            PointCollection.Line2DFitting(points, Emgu.CV.CvEnum.DIST_TYPE.CV_DIST_L2, out direction, out tmp);
+            wristDirection = new Vector2D(-direction.Y, direction.X);
+        }
 
-                outputImage = new Image<Gray, byte>(width, height, new Gray(0));
-                outputImage.Draw(contourPoly, new Gray(1), 1);
-                outputImage.Draw(hull, new Gray(1), 1);
+        private void findConvexityDefactsSortedByDepth()
+        {
+            convexityDefects = new List<MCvConvexityDefect>(palmContour.GetConvexityDefacts(new MemStorage(), Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE));
+            convexityDefects.Sort(delegate(MCvConvexityDefect d1, MCvConvexityDefect d2) {
+                if (d1.Depth < d2.Depth)
+                    return 1;
+                else if (d1.Depth > d2.Depth)
+                    return -1;
+                return 0;
+            });
+        }
 
-                foreach (MCvConvexityDefect defect in defects)
+        private void removeConvexityDefectsNearFingerTips()
+        {
+            List<MCvConvexityDefect> newDefects = new List<MCvConvexityDefect>();
+            foreach (MCvConvexityDefect d in convexityDefects)
+            {
+                float minFingerTipDist = float.MaxValue;
+                foreach (Finger f in fingers)
                 {
-                    Vector2D center = (new Vector2D(defect.StartPoint) + new Vector2D(defect.EndPoint)) / 2;
-
-                    float minFingerDist = float.MaxValue;
-                    foreach (Finger f in fingers)
-                    {
-                        float dist = f.Tip.getDistanceTo(new Vector2D(defect.DepthPoint));
-                        if (dist < minFingerDist)
-                            minFingerDist = dist;
-                    }
-
-                    if (minFingerDist > 20)
-                    {
-                        //Console.WriteLine(minFingerDist);
-                        outputImage.Draw(new LineSegment2DF(defect.DepthPoint, center), new Gray(1), 1);
-                    }
+                    float dist = f.Tip.getDistanceTo(new Vector2D(d.DepthPoint));
+                    if (dist < minFingerTipDist)
+                        minFingerTipDist = dist;
                 }
-                //Console.WriteLine();
+                if (minFingerTipDist > 20)
+                    newDefects.Add(d);
             }
+            convexityDefects = newDefects;
+        }
+
+        private void findWristPoint()
+        {
+            if (convexityDefects.Count > 1)
+                wristPoint = new Vector2D(convexityDefects[1].DepthPoint);
+            else
+                wristPoint = new Vector2D(-1, -1);
+        }
+
+        private void findWristLine()
+        {
+            findWristPoint();
+            findWristDirection();
+            wristLine = new LineSegment2DF(wristPoint - 1000 * wristDirection, wristPoint + 1000 * wristDirection);
+        }
+
+        private void findThumbLine()
+        {
+            if (convexityDefects.Count > 0)
+            {
+                MCvConvexityDefect thumbDefect = convexityDefects[0];
+                Vector2D p1 = new Vector2D(thumbDefect.DepthPoint);
+                Vector2D p2 = new Vector2D(thumbDefect.StartPoint);
+                Vector2D direction = (p1 - p2).normalize();
+                thumbLine = new LineSegment2DF(p1 - 1000 * direction, p1 + 1000 * direction);
+            }
+            else
+            {
+                thumbLine = new LineSegment2DF(new PointF(-1, -1), new PointF(-1, -1));
+            }
+        }
+
+        private void removePointsFromContour(LineSegment2DF line, int sideToRemove)
+        {
+            Contour<Point> newContour = new Contour<Point>(new MemStorage());
+            int index = 0;
+            foreach (Point p in palmContour)
+            {
+                if (line.Side(p) != sideToRemove)
+                {
+                    newContour.Insert(index, p);
+                    ++index;
+                }
+            }
+            palmContour = newContour;
+        }
+
+        private void findPalmRect()
+        {
+            palmRect = palmContour.GetMinAreaRect();
+        }
+
+        private void draw()
+        {
+            //outputImage.Draw(palmContour, new Gray(1), 1);
+            PointF[] vertices = palmRect.GetVertices();
+            for (int i = 0; i < 4; ++i)
+                outputImage.Draw(new LineSegment2DF(vertices[i], vertices[(i + 1) % 4]), new Gray(1), 1);
+
+            outputImage.Draw(wristLine, new Gray(1), 1);
+            outputImage.Draw(thumbLine, new Gray(1), 1);
         }
 
         public bool belongsToPalm(int x, int y)
         {
-            if (outputImage != null)
-                return outputImage.Data[y, x, 0] == 1;
-            return false;
+            return outputImage.Data[y, x, 0] == 1;
         }
     }
 }

+ 5 - 0
bbiwarg/Utility/Vector2D.cs

@@ -24,6 +24,11 @@ namespace bbiwarg.Utility
             setXY(point.X, point.Y);
         }
 
+        public Vector2D(PointF point)
+        {
+            setXY(point.X, point.Y);
+        }
+
         public static implicit operator PointF(Vector2D vec)
         {
             return new PointF(vec.X, vec.Y);