|
@@ -14,12 +14,30 @@ using Emgu.CV.Structure;
|
|
|
|
|
|
namespace bbiwarg.Recognition.PalmRecognition
|
|
|
{
|
|
|
+ /// <summary>
|
|
|
+ /// Detects palms by iterating over each hand, if the hand has exactly one finger (possible thumb) it calculates its convexity defects and checks if there is a convexity defect that matches the requirements for a thumb defect. If a thumb defect is found, the four palm points are generated and a new palm is created.
|
|
|
+ /// </summary>
|
|
|
class PalmDetector
|
|
|
{
|
|
|
+ /// <summary>
|
|
|
+ /// the depth image of the current frame
|
|
|
+ /// </summary>
|
|
|
private DepthImage depthImage;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// the hands in the current frame
|
|
|
+ /// </summary>
|
|
|
private List<Hand> hands;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// the palms in the current frames
|
|
|
+ /// </summary>
|
|
|
private List<Palm> palms;
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Detects palms in the current frame and stores them in frameData.detectedPalms
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="frameData">the current frame</param>
|
|
|
public void detectPalms(FrameData frameData)
|
|
|
{
|
|
|
depthImage = frameData.DepthImage;
|
|
@@ -30,6 +48,9 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
|
frameData.DetectedPalms = palms;
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Find Palms by checking each hand with only one finger, if that finger is a thumb.
|
|
|
+ /// </summary>
|
|
|
private void findPalms()
|
|
|
{
|
|
|
palms = new List<Palm>();
|
|
@@ -48,6 +69,11 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Gets the convexity Defects from a hand mask.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="hand">the hand</param>
|
|
|
+ /// <returns>the conveixty defects</returns>
|
|
|
private List<ConvexityDefect> findConvexityDefects(Hand hand)
|
|
|
{
|
|
|
List<ConvexityDefect> convexityDefects;
|
|
@@ -63,6 +89,12 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
|
return convexityDefects;
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Checks all convexity defects sorted by length if they match the thumb defect requirements and returns the first match or null if none match.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="thumb">the possible thumb</param>
|
|
|
+ /// <param name="convexityDefects">the convexity defects</param>
|
|
|
+ /// <returns></returns>
|
|
|
private ConvexityDefect findThumbDefect(Finger thumb, List<ConvexityDefect> convexityDefects)
|
|
|
{
|
|
|
convexityDefects.Sort((cd1, cd2) => (cd2.Depth.CompareTo(cd1.Depth)));
|
|
@@ -74,6 +106,12 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Finds the four palm points and creates a new palm
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="hand">the hand of the palm</param>
|
|
|
+ /// <param name="thumbDefect">the convexity defect of the thumb</param>
|
|
|
+ /// <returns>a new palm</returns>
|
|
|
private Palm createPalm(Hand hand, ConvexityDefect thumbDefect)
|
|
|
{
|
|
|
HandSide side = determineHandSide(thumbDefect);
|
|
@@ -83,12 +121,17 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
|
float palmLength = wristUpper.getDistanceTo(fingersUpper);
|
|
|
Vector2D directionWristFingers = thumbDefect.VectorLong.normalize();
|
|
|
Vector2D directionUpperLower = thumbDefect.VectorLong.getOrthogonal(side == HandSide.Right).normalize();
|
|
|
- Vector2D wristLower = wristUpper + palmWidth*directionUpperLower;
|
|
|
+ Vector2D wristLower = wristUpper + palmWidth * directionUpperLower;
|
|
|
Vector2D fingersLower = wristUpper + 0.75f * palmLength * directionWristFingers + 0.75f * palmWidth * directionUpperLower;
|
|
|
|
|
|
return new Palm(hand, thumbDefect, side, wristUpper, fingersUpper, fingersLower, wristLower);
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Determines the handedness of the palm's hand
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="thumbDefect">the convexity defect of the thumb</param>
|
|
|
+ /// <returns>the handedness of the palm's hand</returns>
|
|
|
private HandSide determineHandSide(ConvexityDefect thumbDefect)
|
|
|
{
|
|
|
if (thumbDefect.VectorShort.crossProduct(thumbDefect.VectorLong) < 0)
|
|
@@ -97,11 +140,17 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
|
return HandSide.Left;
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Finds the upper wrist end by walking from the defect.Inner towards the wrist direction, until it reaches the hand boundaries.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="hand">the hand</param>
|
|
|
+ /// <param name="thumbDefect">the convexity defect of the thumb</param>
|
|
|
+ /// <returns>the position of the upper wrist end</returns>
|
|
|
private Vector2D findWristUpper(Hand hand, ConvexityDefect thumbDefect)
|
|
|
{
|
|
|
Vector2D wristDirection = thumbDefect.VectorLong.getInverse().normalize();
|
|
|
Vector2D wristUpper = thumbDefect.Inner;
|
|
|
- Vector2D wristUpperNext = wristUpper + 5*wristDirection;
|
|
|
+ Vector2D wristUpperNext = wristUpper + 5 * wristDirection;
|
|
|
while (wristUpperNext.isInBound(depthImage.Size) && hand.isInside(wristUpperNext))
|
|
|
{
|
|
|
wristUpper = wristUpperNext;
|
|
@@ -110,6 +159,13 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
|
return wristUpper;
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Finds the upper finger end by walking from the defect.OuterLong in the finger direction, until it reaches the end of the middle finger below.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="hand">the hand</param>
|
|
|
+ /// <param name="thumbDefect">the convexity defect of the thumb</param>
|
|
|
+ /// <param name="side">the handedness</param>
|
|
|
+ /// <returns>the position of the upper fingers end</returns>
|
|
|
private Vector2D findFingersUpper(Hand hand, ConvexityDefect thumbDefect, HandSide side)
|
|
|
{
|
|
|
Vector2D fingersDirection = thumbDefect.VectorLong.normalize();
|
|
@@ -133,6 +189,13 @@ namespace bbiwarg.Recognition.PalmRecognition
|
|
|
return fingersUpper;
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Gets the palm width by checking for the maximum orthogonal length withing the hand along multiple positions on the index finger (defect.inner<->defect.outerLong)
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="hand">the hand</param>
|
|
|
+ /// <param name="thumbDefect">the convexity defect of the thumb</param>
|
|
|
+ /// <param name="side">the handedness</param>
|
|
|
+ /// <returns>the palm width</returns>
|
|
|
private float findPalmWidth(Hand hand, ConvexityDefect thumbDefect, HandSide side)
|
|
|
{
|
|
|
Vector2D lowerDirection = thumbDefect.VectorLong.getOrthogonal(side == HandSide.Right).normalize();
|