|
@@ -16,14 +16,40 @@ using Emgu.CV.Structure;
|
|
|
|
|
|
namespace bbiwarg.Recognition.HandRecognition
|
|
namespace bbiwarg.Recognition.HandRecognition
|
|
{
|
|
{
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Finds Hands by iterating over all fingers and flooding them. Each filled region is considered to be one hand and each finger belongs to one hand. To improve the hand contours, the hand mask are filled with the defects caused by overlapping fingers.
|
|
|
|
+ /// </summary>
|
|
class HandDetector
|
|
class HandDetector
|
|
{
|
|
{
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// the depth image of the current frame
|
|
|
|
+ /// </summary>
|
|
private DepthImage depthImage;
|
|
private DepthImage depthImage;
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// the modified depth image of the current frame (hand flooding changes depth image)
|
|
|
|
+ /// </summary>
|
|
private Image<Gray, byte> modifiedHandDepthImage;
|
|
private Image<Gray, byte> modifiedHandDepthImage;
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// the fingers in the current frame
|
|
|
|
+ /// </summary>
|
|
private List<Finger> fingers;
|
|
private List<Finger> fingers;
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// a mapping of hands and list of fingers, that don't belong to that specific hand
|
|
|
|
+ /// </summary>
|
|
private Dictionary<Hand, List<Finger>> otherHandsFingers;
|
|
private Dictionary<Hand, List<Finger>> otherHandsFingers;
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// the hands in the current frame
|
|
|
|
+ /// </summary>
|
|
private List<Hand> hands;
|
|
private List<Hand> hands;
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Detects Hands in the current frame and stores found hands in frameData.detectedHands
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="frameData">the current frame</param>
|
|
public void detectHands(FrameData frameData)
|
|
public void detectHands(FrameData frameData)
|
|
{
|
|
{
|
|
depthImage = frameData.DepthImage;
|
|
depthImage = frameData.DepthImage;
|
|
@@ -37,6 +63,9 @@ namespace bbiwarg.Recognition.HandRecognition
|
|
frameData.DetectedHands = hands;
|
|
frameData.DetectedHands = hands;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Creates the modified hand image. The image is a copy of the original depth image with a contour around each finger (to prevent floodfill from filling through fingers).
|
|
|
|
+ /// </summary>
|
|
private void createModifiedHandEdgeImage()
|
|
private void createModifiedHandEdgeImage()
|
|
{
|
|
{
|
|
modifiedHandDepthImage = depthImage.Image.Copy();
|
|
modifiedHandDepthImage = depthImage.Image.Copy();
|
|
@@ -49,6 +78,9 @@ namespace bbiwarg.Recognition.HandRecognition
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Finds hands by flood filling from each finger (mask). All unassigned fingers that lie within the hand are assigned to the hand, all other fingers are mapped as fingers that don't belong to that specific hand.
|
|
|
|
+ /// </summary>
|
|
private void findHands()
|
|
private void findHands()
|
|
{
|
|
{
|
|
hands = new List<Hand>();
|
|
hands = new List<Hand>();
|
|
@@ -80,6 +112,11 @@ namespace bbiwarg.Recognition.HandRecognition
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Flood fills from a given point and returns the filled area as mask.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="p">flood fill starting point</param>
|
|
|
|
+ /// <returns>the filled area as mask</returns>
|
|
private Image<Gray, byte> getHandMask(Vector2D p)
|
|
private Image<Gray, byte> getHandMask(Vector2D p)
|
|
{
|
|
{
|
|
Image<Gray, byte> mask = new Image<Gray, byte>(depthImage.Size.Width + 2, depthImage.Size.Height + 2);
|
|
Image<Gray, byte> mask = new Image<Gray, byte>(depthImage.Size.Width + 2, depthImage.Size.Height + 2);
|
|
@@ -88,12 +125,18 @@ namespace bbiwarg.Recognition.HandRecognition
|
|
return mask.Copy(new Rectangle(1, 1, depthImage.Size.Width, depthImage.Size.Height));
|
|
return mask.Copy(new Rectangle(1, 1, depthImage.Size.Width, depthImage.Size.Height));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Fixes overlapping fingers by merging two hands if they are seperated by a finger and/or fills holes caused by overlapping fingers.
|
|
|
|
+ /// </summary>
|
|
private void fixOverlappingFingers()
|
|
private void fixOverlappingFingers()
|
|
{
|
|
{
|
|
extendOrMergeThroughOverlappingFingers();
|
|
extendOrMergeThroughOverlappingFingers();
|
|
fillOverlappingFingers();
|
|
fillOverlappingFingers();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Merges two hands if they are seperatd by an overlapping finger or extends the hand mask through an overlapping finger.
|
|
|
|
+ /// </summary>
|
|
private void extendOrMergeThroughOverlappingFingers()
|
|
private void extendOrMergeThroughOverlappingFingers()
|
|
{
|
|
{
|
|
List<Hand> mergedHands = new List<Hand>();
|
|
List<Hand> mergedHands = new List<Hand>();
|
|
@@ -156,14 +199,26 @@ namespace bbiwarg.Recognition.HandRecognition
|
|
hands.Remove(mergedHand);
|
|
hands.Remove(mergedHand);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Merges two hands together and updates the list of other hands fingers.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="hand">the first hand (other hand will be merged to this one)</param>
|
|
|
|
+ /// <param name="mergeHand">the second hand (this hand will be dropped afterwards)</param>
|
|
private void mergeToHand(Hand hand, Hand mergeHand)
|
|
private void mergeToHand(Hand hand, Hand mergeHand)
|
|
{
|
|
{
|
|
hand.mergeWith(mergeHand);
|
|
hand.mergeWith(mergeHand);
|
|
|
|
|
|
foreach (Finger finger in mergeHand.Fingers)
|
|
foreach (Finger finger in mergeHand.Fingers)
|
|
otherHandsFingers[hand].Remove(finger);
|
|
otherHandsFingers[hand].Remove(finger);
|
|
|
|
+
|
|
|
|
+ otherHandsFingers.Remove(mergeHand);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Extends the hand mask of a given hand by flood filling starting from the given point.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="hand">the hand that should be extended</param>
|
|
|
|
+ /// <param name="p">the flood fill starting point</param>
|
|
private void extendToHand(Hand hand, Vector2D p)
|
|
private void extendToHand(Hand hand, Vector2D p)
|
|
{
|
|
{
|
|
Image<Gray, byte> extendMask = getHandMask(p);
|
|
Image<Gray, byte> extendMask = getHandMask(p);
|
|
@@ -173,14 +228,20 @@ namespace bbiwarg.Recognition.HandRecognition
|
|
hand.extendMask(extendMask);
|
|
hand.extendMask(extendMask);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Fills holes caused by overlapping fingers.
|
|
|
|
+ /// </summary>
|
|
private void fillOverlappingFingers()
|
|
private void fillOverlappingFingers()
|
|
{
|
|
{
|
|
foreach (Hand hand in hands)
|
|
foreach (Hand hand in hands)
|
|
{
|
|
{
|
|
- hand.fillOverlappingFingers(otherHandsFingers[hand], depthImage.Size);
|
|
|
|
|
|
+ hand.fillOverlappingFingers(otherHandsFingers[hand]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Finds the hands centroids.
|
|
|
|
+ /// </summary>
|
|
private void findCentroids() {
|
|
private void findCentroids() {
|
|
foreach (Hand hand in hands)
|
|
foreach (Hand hand in hands)
|
|
hand.findCentroid();
|
|
hand.findCentroid();
|