|
@@ -23,7 +23,13 @@ namespace bbiwarg.Images
|
|
private Image<Gray, Byte> outputImage;
|
|
private Image<Gray, Byte> outputImage;
|
|
|
|
|
|
private List<Finger> fingers;
|
|
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;
|
|
private int width, height;
|
|
|
|
|
|
public PalmImage(DepthImage depthImage, EdgeImage edgeImage, FingerDetector fingerDetector)
|
|
public PalmImage(DepthImage depthImage, EdgeImage edgeImage, FingerDetector fingerDetector)
|
|
@@ -35,11 +41,28 @@ namespace bbiwarg.Images
|
|
width = depthImage.getWidth();
|
|
width = depthImage.getWidth();
|
|
height = depthImage.getHeight();
|
|
height = depthImage.getHeight();
|
|
|
|
|
|
|
|
+ outputImage = new Image<Gray, byte>(width, height, new Gray(0));
|
|
|
|
+
|
|
fingers = getFingersWithoutThumb(fingerDetector);
|
|
fingers = getFingersWithoutThumb(fingerDetector);
|
|
buildPointingHandMask();
|
|
buildPointingHandMask();
|
|
handImage = handImage.And(pointingHandMask);
|
|
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)
|
|
private List<Finger> getFingersWithoutThumb(FingerDetector fingerDetector)
|
|
@@ -119,59 +142,132 @@ namespace bbiwarg.Images
|
|
pointingHandMask = pointingHandMask.Erode(2);
|
|
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> 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;
|
|
double maxPerimeter = 0;
|
|
while (contour != null)
|
|
while (contour != null)
|
|
{
|
|
{
|
|
if (contour.Perimeter > maxPerimeter)
|
|
if (contour.Perimeter > maxPerimeter)
|
|
{
|
|
{
|
|
maxPerimeter = contour.Perimeter;
|
|
maxPerimeter = contour.Perimeter;
|
|
- maxContour = contour;
|
|
|
|
|
|
+ palmContour = contour;
|
|
}
|
|
}
|
|
contour = contour.HNext;
|
|
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)
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|