|
@@ -18,14 +18,12 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
{
|
|
{
|
|
class PalmDetector
|
|
class PalmDetector
|
|
{
|
|
{
|
|
- private OutputImage outputImage;
|
|
|
|
-
|
|
|
|
|
|
+ public Contour<Point> PalmContour { get; private set; }
|
|
|
|
+ public Vector2D ThumbDefectStart { get; private set; }
|
|
|
|
+ public Vector2D ThumbDefectEnd { get; private set; }
|
|
|
|
+ public Vector2D ThumbDefectDepth { get; private set; }
|
|
private Hand palmHand, pointingHand;
|
|
private Hand palmHand, pointingHand;
|
|
- private Contour<Point> palmContour;
|
|
|
|
private List<MCvConvexityDefect> convexityDefects;
|
|
private List<MCvConvexityDefect> convexityDefects;
|
|
- private Vector2D thumbDefectStart;
|
|
|
|
- private Vector2D thumbDefectEnd;
|
|
|
|
- private Vector2D thumbDefectDepth;
|
|
|
|
private Kalman2DPositionFilter thumbDefectDepthFilter, thumbDefectStartFilter, thumbDefectEndFilter;
|
|
private Kalman2DPositionFilter thumbDefectDepthFilter, thumbDefectStartFilter, thumbDefectEndFilter;
|
|
private int numFramesNoHandFound;
|
|
private int numFramesNoHandFound;
|
|
private Quadrangle lastPalmQuad;
|
|
private Quadrangle lastPalmQuad;
|
|
@@ -44,9 +42,8 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
Constants.PalmThumbDefectmYY, Constants.PalmThumbDefectProcessNoise);
|
|
Constants.PalmThumbDefectmYY, Constants.PalmThumbDefectProcessNoise);
|
|
}
|
|
}
|
|
|
|
|
|
- public void findPalmQuad(OutputImage outputImage, List<Hand> hands, Image<Gray, Byte> foregroundMask)
|
|
|
|
|
|
+ public void findPalmQuad(List<Hand> hands, Image<Gray, Byte> foregroundMask)
|
|
{
|
|
{
|
|
- this.outputImage = outputImage;
|
|
|
|
this.hands = hands;
|
|
this.hands = hands;
|
|
|
|
|
|
if (hands.Count == 1 && hands[0].Fingers.Count == 1)
|
|
if (hands.Count == 1 && hands[0].Fingers.Count == 1)
|
|
@@ -97,8 +94,6 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
{
|
|
{
|
|
numFramesNoHandFound = 0;
|
|
numFramesNoHandFound = 0;
|
|
}
|
|
}
|
|
-
|
|
|
|
- draw();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
public void reset()
|
|
public void reset()
|
|
@@ -106,7 +101,7 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
thumbDefectDepthFilter.reset();
|
|
thumbDefectDepthFilter.reset();
|
|
thumbDefectStartFilter.reset();
|
|
thumbDefectStartFilter.reset();
|
|
thumbDefectEndFilter.reset();
|
|
thumbDefectEndFilter.reset();
|
|
- palmContour = null;
|
|
|
|
|
|
+ PalmContour = null;
|
|
PalmQuad = null;
|
|
PalmQuad = null;
|
|
PalmHandSide = Hand.HandSide.Left;
|
|
PalmHandSide = Hand.HandSide.Left;
|
|
numFramesNoHandFound = 0;
|
|
numFramesNoHandFound = 0;
|
|
@@ -118,14 +113,14 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
Contour<Point> contour = palmHand.Mask.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
|
|
Contour<Point> contour = palmHand.Mask.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
|
|
Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_EXTERNAL);
|
|
Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_EXTERNAL);
|
|
|
|
|
|
- palmContour = 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;
|
|
- palmContour = contour;
|
|
|
|
|
|
+ PalmContour = contour;
|
|
}
|
|
}
|
|
contour = contour.HNext;
|
|
contour = contour.HNext;
|
|
}
|
|
}
|
|
@@ -133,7 +128,7 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
|
|
|
|
private void findConvexityDefectsSortedByDepth()
|
|
private void findConvexityDefectsSortedByDepth()
|
|
{
|
|
{
|
|
- convexityDefects = new List<MCvConvexityDefect>(palmContour.GetConvexityDefacts(new MemStorage(), Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE));
|
|
|
|
|
|
+ convexityDefects = new List<MCvConvexityDefect>(PalmContour.GetConvexityDefacts(new MemStorage(), Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE));
|
|
convexityDefects.Sort(delegate(MCvConvexityDefect d1, MCvConvexityDefect d2)
|
|
convexityDefects.Sort(delegate(MCvConvexityDefect d1, MCvConvexityDefect d2)
|
|
{
|
|
{
|
|
if (d1.Depth < d2.Depth)
|
|
if (d1.Depth < d2.Depth)
|
|
@@ -217,35 +212,35 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
|
|
|
|
if (thumbDefect != null)
|
|
if (thumbDefect != null)
|
|
{
|
|
{
|
|
- thumbDefectDepth = new Vector2D(thumbDefect.Value.DepthPoint);
|
|
|
|
- thumbDefectStart = new Vector2D(thumbDefect.Value.StartPoint);
|
|
|
|
- thumbDefectEnd = new Vector2D(thumbDefect.Value.EndPoint);
|
|
|
|
|
|
+ ThumbDefectDepth = new Vector2D(thumbDefect.Value.DepthPoint);
|
|
|
|
+ ThumbDefectStart = new Vector2D(thumbDefect.Value.StartPoint);
|
|
|
|
+ ThumbDefectEnd = new Vector2D(thumbDefect.Value.EndPoint);
|
|
|
|
|
|
if (!thumbDefectDepthFilter.Initialized)
|
|
if (!thumbDefectDepthFilter.Initialized)
|
|
{
|
|
{
|
|
- thumbDefectDepthFilter.setInitialPosition(thumbDefectDepth);
|
|
|
|
- thumbDefectStartFilter.setInitialPosition(thumbDefectStart);
|
|
|
|
- thumbDefectEndFilter.setInitialPosition(thumbDefectEnd);
|
|
|
|
|
|
+ thumbDefectDepthFilter.setInitialPosition(ThumbDefectDepth);
|
|
|
|
+ thumbDefectStartFilter.setInitialPosition(ThumbDefectStart);
|
|
|
|
+ thumbDefectEndFilter.setInitialPosition(ThumbDefectEnd);
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- thumbDefectDepth = thumbDefectDepthFilter.getCorrectedPosition(thumbDefectDepth);
|
|
|
|
- thumbDefectStart = thumbDefectStartFilter.getCorrectedPosition(thumbDefectStart);
|
|
|
|
- thumbDefectEnd = thumbDefectEndFilter.getCorrectedPosition(thumbDefectEnd);
|
|
|
|
|
|
+ ThumbDefectDepth = thumbDefectDepthFilter.getCorrectedPosition(ThumbDefectDepth);
|
|
|
|
+ ThumbDefectStart = thumbDefectStartFilter.getCorrectedPosition(ThumbDefectStart);
|
|
|
|
+ ThumbDefectEnd = thumbDefectEndFilter.getCorrectedPosition(ThumbDefectEnd);
|
|
}
|
|
}
|
|
|
|
|
|
Vector2D handLength, handWidth, longestLineEndpoint, topLeft, bottomLeft, bottomRight, topRight;
|
|
Vector2D handLength, handWidth, longestLineEndpoint, topLeft, bottomLeft, bottomRight, topRight;
|
|
|
|
|
|
- Vector2D startDepth = thumbDefectStart - thumbDefectDepth;
|
|
|
|
- Vector2D endDepth = thumbDefectEnd - thumbDefectDepth;
|
|
|
|
|
|
+ Vector2D startDepth = ThumbDefectStart - ThumbDefectDepth;
|
|
|
|
+ Vector2D endDepth = ThumbDefectEnd - ThumbDefectDepth;
|
|
|
|
|
|
if (startDepth.Length > endDepth.Length)
|
|
if (startDepth.Length > endDepth.Length)
|
|
{
|
|
{
|
|
handLength = startDepth;
|
|
handLength = startDepth;
|
|
- longestLineEndpoint = thumbDefectStart;
|
|
|
|
|
|
+ longestLineEndpoint = ThumbDefectStart;
|
|
if (hands.Count == 1)
|
|
if (hands.Count == 1)
|
|
{
|
|
{
|
|
- if (thumbDefectStart.X > thumbDefectDepth.X)
|
|
|
|
|
|
+ if (ThumbDefectStart.X > ThumbDefectDepth.X)
|
|
hands[0].Side = Hand.HandSide.Left;
|
|
hands[0].Side = Hand.HandSide.Left;
|
|
else
|
|
else
|
|
hands[0].Side = Hand.HandSide.Right;
|
|
hands[0].Side = Hand.HandSide.Right;
|
|
@@ -254,10 +249,10 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
else
|
|
else
|
|
{
|
|
{
|
|
handLength = endDepth;
|
|
handLength = endDepth;
|
|
- longestLineEndpoint = thumbDefectEnd;
|
|
|
|
|
|
+ longestLineEndpoint = ThumbDefectEnd;
|
|
if (hands.Count == 1)
|
|
if (hands.Count == 1)
|
|
{
|
|
{
|
|
- if (thumbDefectEnd.X > thumbDefectDepth.X)
|
|
|
|
|
|
+ if (ThumbDefectEnd.X > ThumbDefectDepth.X)
|
|
hands[0].Side = Hand.HandSide.Left;
|
|
hands[0].Side = Hand.HandSide.Left;
|
|
else
|
|
else
|
|
hands[0].Side = Hand.HandSide.Right;
|
|
hands[0].Side = Hand.HandSide.Right;
|
|
@@ -268,7 +263,7 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
{
|
|
{
|
|
handWidth = 0.85f * new Vector2D(-handLength.Y, handLength.X);
|
|
handWidth = 0.85f * new Vector2D(-handLength.Y, handLength.X);
|
|
topLeft = longestLineEndpoint + 0.15f * handLength;
|
|
topLeft = longestLineEndpoint + 0.15f * handLength;
|
|
- bottomLeft = thumbDefectDepth - 0.4f * handLength;
|
|
|
|
|
|
+ bottomLeft = ThumbDefectDepth - 0.4f * handLength;
|
|
bottomRight = bottomLeft + handWidth;
|
|
bottomRight = bottomLeft + handWidth;
|
|
topRight = bottomRight + 1.2f * handLength - 0.3f * handWidth;
|
|
topRight = bottomRight + 1.2f * handLength - 0.3f * handWidth;
|
|
}
|
|
}
|
|
@@ -276,7 +271,7 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
{
|
|
{
|
|
handWidth = 0.85f * new Vector2D(handLength.Y, -handLength.X);
|
|
handWidth = 0.85f * new Vector2D(handLength.Y, -handLength.X);
|
|
topRight = longestLineEndpoint + 0.15f * handLength;
|
|
topRight = longestLineEndpoint + 0.15f * handLength;
|
|
- bottomRight = thumbDefectDepth - 0.4f * handLength;
|
|
|
|
|
|
+ bottomRight = ThumbDefectDepth - 0.4f * handLength;
|
|
bottomLeft = bottomRight + handWidth;
|
|
bottomLeft = bottomRight + handWidth;
|
|
topLeft = bottomLeft + 1.2f * handLength - 0.3f * handWidth;
|
|
topLeft = bottomLeft + 1.2f * handLength - 0.3f * handWidth;
|
|
}
|
|
}
|
|
@@ -297,47 +292,5 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
if (lastPalmQuad != null && getForegroundPixelPercentage(lastPalmQuad, foregroundMask) <= Constants.PalmMaxPrecentageQuadForegroundReset)
|
|
if (lastPalmQuad != null && getForegroundPixelPercentage(lastPalmQuad, foregroundMask) <= Constants.PalmMaxPrecentageQuadForegroundReset)
|
|
reset();
|
|
reset();
|
|
}
|
|
}
|
|
-
|
|
|
|
- private void draw()
|
|
|
|
- {
|
|
|
|
- if (palmContour != null && palmContour.Count<Point>() > 0)
|
|
|
|
- {
|
|
|
|
- outputImage.drawContour(palmContour, Constants.PalmConturColor);
|
|
|
|
- outputImage.drawPoints(palmContour.GetConvexHull(Emgu.CV.CvEnum.ORIENTATION.CV_CLOCKWISE), Constants.PalmConvexHullColor);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (PalmQuad != null)
|
|
|
|
- {
|
|
|
|
- outputImage.fillCircle(thumbDefectStart.IntX, thumbDefectStart.IntY, 3, Color.Red);
|
|
|
|
- outputImage.fillCircle(thumbDefectEnd.IntX, thumbDefectEnd.IntY, 3, Color.Red);
|
|
|
|
- outputImage.fillCircle(thumbDefectDepth.IntX, thumbDefectDepth.IntY, 3, Color.Red);
|
|
|
|
-
|
|
|
|
- outputImage.drawLineSegment(new Utility.LineSegment2D(thumbDefectDepth, (thumbDefectStart + thumbDefectEnd) / 2.0f), Constants.PalmThumbDefectColor, 1);
|
|
|
|
-
|
|
|
|
- Vector2D[] vertices = PalmQuad.Vertices;
|
|
|
|
- for (int i = 0; i < 4; ++i)
|
|
|
|
- outputImage.drawLineSegment(new bbiwarg.Utility.LineSegment2D(vertices[i], vertices[(i + 1) % 4]), Constants.PalmQuadColor);
|
|
|
|
-
|
|
|
|
- drawGrid(new Vector2D(vertices[0]), new Vector2D(vertices[1]), new Vector2D(vertices[2]), new Vector2D(vertices[3]));
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void drawGrid(Vector2D a, Vector2D b, Vector2D c, Vector2D d)
|
|
|
|
- {
|
|
|
|
- Vector2D relAB = (b - a) / Constants.PalmGridRows;
|
|
|
|
- Vector2D relDC = (c - d) / Constants.PalmGridRows;
|
|
|
|
- Vector2D relBC = (c - b) / Constants.PalmGridColumns;
|
|
|
|
- Vector2D relAD = (d - a) / Constants.PalmGridColumns;
|
|
|
|
-
|
|
|
|
- for (int i = 1; i < Constants.PalmGridRows; i++)
|
|
|
|
- {
|
|
|
|
- outputImage.drawLineSegment(new bbiwarg.Utility.LineSegment2D(a + i * relAB, d + i * relDC), Constants.PalmGridColor);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (int i = 1; i < Constants.PalmGridColumns; i++)
|
|
|
|
- {
|
|
|
|
- outputImage.drawLineSegment(new bbiwarg.Utility.LineSegment2D(a + i * relAD, b + i * relBC), Constants.PalmGridColor);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|