|
@@ -28,13 +28,14 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
this.edgeImageAdapted = edgeImage.copy();
|
|
this.edgeImageAdapted = edgeImage.copy();
|
|
this.outputImage = outputImage;
|
|
this.outputImage = outputImage;
|
|
|
|
|
|
- findFingers();
|
|
|
|
|
|
+ detectFingers();
|
|
|
|
+ drawFingers();
|
|
}
|
|
}
|
|
|
|
|
|
- private void findFingers()
|
|
|
|
|
|
+ private void detectFingers()
|
|
{
|
|
{
|
|
- int maxX = depthImage.Width - 1;
|
|
|
|
- int maxY = depthImage.Height - 1;
|
|
|
|
|
|
+ int maxX = depthImage.BottomRight.IntX;
|
|
|
|
+ int maxY = depthImage.BottomRight.IntY;
|
|
|
|
|
|
Fingers = new List<Finger>();
|
|
Fingers = new List<Finger>();
|
|
|
|
|
|
@@ -48,7 +49,7 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
Vector2D edgeDirection = getEdgeDirection(edgePoint);
|
|
Vector2D edgeDirection = getEdgeDirection(edgePoint);
|
|
if (edgeDirection != null)
|
|
if (edgeDirection != null)
|
|
{
|
|
{
|
|
- Vector2D dir = edgeDirection.getOrthogonal(true);
|
|
|
|
|
|
+ Vector2D dir = edgeDirection.getOrthogonal();
|
|
if (depthImage.getDepthAt(edgePoint - dir) < depthImage.getDepthAt(edgePoint + dir))
|
|
if (depthImage.getDepthAt(edgePoint - dir) < depthImage.getDepthAt(edgePoint + dir))
|
|
dir = dir.getInverse();
|
|
dir = dir.getInverse();
|
|
|
|
|
|
@@ -81,15 +82,12 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
|
|
|
private FingerSliceTrail findFingerSliceTrail(FingerSlice startSlice, Vector2D startDirection)
|
|
private FingerSliceTrail findFingerSliceTrail(FingerSlice startSlice, Vector2D startDirection)
|
|
{
|
|
{
|
|
- int maxX = depthImage.Width - 1;
|
|
|
|
- int maxY = depthImage.Height - 1;
|
|
|
|
-
|
|
|
|
FingerSliceTrail trail = new FingerSliceTrail(startSlice);
|
|
FingerSliceTrail trail = new FingerSliceTrail(startSlice);
|
|
|
|
|
|
Vector2D direction = startDirection;
|
|
Vector2D direction = startDirection;
|
|
Vector2D position = startSlice.Mid + Constants.FingerStepSize * direction;
|
|
Vector2D position = startSlice.Mid + Constants.FingerStepSize * direction;
|
|
|
|
|
|
- if (position.isWithin(0, 0, maxX, maxY))
|
|
|
|
|
|
+ if (position.isInBound(Vector2D.Zero, depthImage.BottomRight))
|
|
{
|
|
{
|
|
FingerSlice nextSlice = findFingerSliceFromMid(position, direction);
|
|
FingerSlice nextSlice = findFingerSliceFromMid(position, direction);
|
|
if (nextSlice != null)
|
|
if (nextSlice != null)
|
|
@@ -99,10 +97,10 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
|
|
|
if (trail.NumSlices > Constants.FingerMinNumSlices / 2)
|
|
if (trail.NumSlices > Constants.FingerMinNumSlices / 2)
|
|
{
|
|
{
|
|
- trail.Slices.RemoveRange(0, Constants.FingerRemoveNumSlicesForCorrection);
|
|
|
|
- trail.Slices.Reverse();
|
|
|
|
- trail = expandTrail(trail, true);
|
|
|
|
- trail.Slices.Reverse();
|
|
|
|
|
|
+ trail.removeFirstSlices(Constants.FingerRemoveNumSlicesForCorrection);
|
|
|
|
+ trail.reverse();
|
|
|
|
+ trail = expandTrail(trail);
|
|
|
|
+ trail.reverse();
|
|
return trail;
|
|
return trail;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -112,26 +110,20 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- private FingerSliceTrail expandTrail(FingerSliceTrail trail, bool reversed = false)
|
|
|
|
|
|
+ private FingerSliceTrail expandTrail(FingerSliceTrail trail)
|
|
{
|
|
{
|
|
- int maxX = depthImage.Width - 1;
|
|
|
|
- int maxY = depthImage.Height - 1;
|
|
|
|
-
|
|
|
|
Vector2D currentDirection = trail.getEndDirection();
|
|
Vector2D currentDirection = trail.getEndDirection();
|
|
- Vector2D currentPosition = trail.End.Mid + Constants.FingerStepSize * currentDirection;
|
|
|
|
|
|
+ Vector2D currentPosition = trail.EndSlice.Mid + Constants.FingerStepSize * currentDirection;
|
|
|
|
|
|
int gapCounter = 0;
|
|
int gapCounter = 0;
|
|
int numSlices = trail.NumSlices;
|
|
int numSlices = trail.NumSlices;
|
|
|
|
|
|
- FingerSlice lastSlice = trail.End;
|
|
|
|
|
|
+ FingerSlice lastSlice = trail.EndSlice;
|
|
FingerSlice nextSlice;
|
|
FingerSlice nextSlice;
|
|
|
|
|
|
- while (currentPosition.isWithin(0, 0, maxX, maxY) && gapCounter <= Math.Min(numSlices, Constants.FingerMaxGapCounter))
|
|
|
|
|
|
+ while (currentPosition.isInBound(Vector2D.Zero, depthImage.BottomRight) && gapCounter <= Math.Min(numSlices, Constants.FingerMaxGapCounter))
|
|
{
|
|
{
|
|
- if (reversed)
|
|
|
|
- nextSlice = findFingerSliceFromMid(currentPosition, currentDirection.getInverse());
|
|
|
|
- else
|
|
|
|
- nextSlice = findFingerSliceFromMid(currentPosition, currentDirection);
|
|
|
|
|
|
+ nextSlice = findFingerSliceFromMid(currentPosition, currentDirection);
|
|
|
|
|
|
if (nextSlice != null && Math.Abs(nextSlice.Length - lastSlice.Length) <= Constants.FingerMaxSliceDifferencePerStep)
|
|
if (nextSlice != null && Math.Abs(nextSlice.Length - lastSlice.Length) <= Constants.FingerMaxSliceDifferencePerStep)
|
|
{
|
|
{
|
|
@@ -160,73 +152,29 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
Vector2D dirStart = direction.getOrthogonal(true);
|
|
Vector2D dirStart = direction.getOrthogonal(true);
|
|
Vector2D dirEnd = direction.getOrthogonal(false);
|
|
Vector2D dirEnd = direction.getOrthogonal(false);
|
|
|
|
|
|
- Vector2D start = findNextEdge(position, dirStart);
|
|
|
|
|
|
+ Vector2D start = edgeImageAdapted.findNextEdge(position, dirStart, Constants.FingerMaxSize);
|
|
if (start == null) return null;
|
|
if (start == null) return null;
|
|
|
|
|
|
- Vector2D end = findNextEdge(position, dirEnd);
|
|
|
|
|
|
+ Vector2D end = edgeImageAdapted.findNextEdge(position, dirEnd, Constants.FingerMaxSize);
|
|
if (end == null) return null;
|
|
if (end == null) return null;
|
|
|
|
|
|
return getFingerSlice(start, end);
|
|
return getFingerSlice(start, end);
|
|
}
|
|
}
|
|
private FingerSlice findFingerSliceFromStartEdge(Vector2D start, Vector2D direction)
|
|
private FingerSlice findFingerSliceFromStartEdge(Vector2D start, Vector2D direction)
|
|
{
|
|
{
|
|
- Vector2D end = findNextEdge(start + Constants.FingerSliceOverlapFactor * direction, direction);
|
|
|
|
|
|
+ Vector2D searchStart = start + Constants.FingerSliceOverlapFactor * direction;
|
|
|
|
+ Vector2D end = edgeImageAdapted.findNextEdge(searchStart, direction, Constants.FingerMaxSize);
|
|
if (end == null) return null;
|
|
if (end == null) return null;
|
|
|
|
|
|
return getFingerSlice(start, end);
|
|
return getFingerSlice(start, end);
|
|
}
|
|
}
|
|
|
|
|
|
- private Vector2D findNextEdge(Vector2D start, Vector2D direction, bool adaptedEdgeImage = true, bool stopAtMaxFingerSize = true, bool returnBoundIfNoEdge = false)
|
|
|
|
- {
|
|
|
|
- int maxX = depthImage.Width - 1;
|
|
|
|
- int maxY = depthImage.Height - 1;
|
|
|
|
-
|
|
|
|
- int maxStepsX;
|
|
|
|
- if (direction.X > 0)
|
|
|
|
- maxStepsX = (int)((maxX - start.X) / direction.X);
|
|
|
|
- else if (direction.X < 0)
|
|
|
|
- maxStepsX = (int)(start.X / Math.Abs(direction.X));
|
|
|
|
- else
|
|
|
|
- maxStepsX = int.MaxValue;
|
|
|
|
-
|
|
|
|
- int maxStepsY;
|
|
|
|
- if (direction.Y > 0)
|
|
|
|
- maxStepsY = (int)((maxY - start.Y) / direction.Y);
|
|
|
|
- else if (direction.Y < 0)
|
|
|
|
- maxStepsY = (int)(start.Y / Math.Abs(direction.Y));
|
|
|
|
- else
|
|
|
|
- maxStepsY = int.MaxValue;
|
|
|
|
-
|
|
|
|
- int maxSteps = Math.Min(maxStepsX, maxStepsY);
|
|
|
|
-
|
|
|
|
- if (stopAtMaxFingerSize)
|
|
|
|
- maxSteps = Math.Min(maxSteps, (int)(Constants.FingerMaxSize / direction.Length));
|
|
|
|
-
|
|
|
|
- Vector2D end = new Vector2D(start);
|
|
|
|
- for (int i = 0; i < maxSteps; i++)
|
|
|
|
- {
|
|
|
|
- end += direction;
|
|
|
|
-
|
|
|
|
- if ((adaptedEdgeImage && edgeImageAdapted.isRoughEdgeAt(end)) || (!adaptedEdgeImage && edgeImageOriginal.isRoughEdgeAt(end)))
|
|
|
|
- {
|
|
|
|
- return end;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (returnBoundIfNoEdge)
|
|
|
|
- return end;
|
|
|
|
- else
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
private FingerSlice getFingerSlice(Vector2D start, Vector2D end)
|
|
private FingerSlice getFingerSlice(Vector2D start, Vector2D end)
|
|
{
|
|
{
|
|
- int maxX = depthImage.Width - 1;
|
|
|
|
- int maxY = depthImage.Height - 1;
|
|
|
|
-
|
|
|
|
Vector2D direction = (end - start).normalize();
|
|
Vector2D direction = (end - start).normalize();
|
|
- Vector2D beforeStart = (start - Constants.FingerSliceOverlapFactor * direction).moveInBound(0, 0, maxX, maxY);
|
|
|
|
- Vector2D behindEnd = (end + Constants.FingerSliceOverlapFactor * direction).moveInBound(0, 0, maxY, maxY);
|
|
|
|
|
|
+ Vector2D directionInv = direction.getInverse();
|
|
|
|
+ Vector2D beforeStart = (start + Constants.FingerSliceOverlapFactor * directionInv).moveInBound(Vector2D.Zero, depthImage.BottomRight, direction);
|
|
|
|
+ Vector2D behindEnd = (end + Constants.FingerSliceOverlapFactor * direction).moveInBound(Vector2D.Zero, depthImage.BottomRight, directionInv);
|
|
|
|
|
|
FingerSlice slice = new FingerSlice(beforeStart, behindEnd);
|
|
FingerSlice slice = new FingerSlice(beforeStart, behindEnd);
|
|
if (slice.Length >= Constants.FingerMinSize && slice.Length <= Constants.FingerMaxSize && fingerSliceDepthTest(slice))
|
|
if (slice.Length >= Constants.FingerMinSize && slice.Length <= Constants.FingerMaxSize && fingerSliceDepthTest(slice))
|
|
@@ -252,26 +200,37 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
Finger finger = new Finger(trail);
|
|
Finger finger = new Finger(trail);
|
|
|
|
|
|
//add finger
|
|
//add finger
|
|
- Fingers.Add(finger);
|
|
|
|
-
|
|
|
|
- //draw finger
|
|
|
|
- drawDetectedFinger(finger);
|
|
|
|
|
|
+ if (!isCrippleFinger(finger))
|
|
|
|
+ Fingers.Add(finger);
|
|
|
|
|
|
//remove edges around detected finger to improve performance
|
|
//remove edges around detected finger to improve performance
|
|
- edgeImageAdapted.removeEdgesInsidePolygon(finger.getContour().ToArray());
|
|
|
|
|
|
+ edgeImageAdapted.removeEdgesInsidePolygon(finger.Contour.ToArray());
|
|
}
|
|
}
|
|
|
|
|
|
- private FingerSlice findOutSlice(Vector2D start, Vector2D direction)
|
|
|
|
|
|
+ private bool isCrippleFinger(Finger finger)
|
|
{
|
|
{
|
|
- int maxX = depthImage.Width - 1;
|
|
|
|
- int maxY = depthImage.Height - 1;
|
|
|
|
|
|
+ FingerSlice midSlice = finger.SliceTrail.MidSlice;
|
|
|
|
+ Vector2D direction = midSlice.Direction;
|
|
|
|
+ Vector2D directionInv = direction.getInverse();
|
|
|
|
+ Vector2D out1 = (midSlice.Start + Constants.FingerCrippleOutFactor * directionInv).moveInBound(Vector2D.Zero, depthImage.BottomRight, direction);
|
|
|
|
+ Vector2D out2 = (midSlice.End + Constants.FingerCrippleOutFactor * direction).moveInBound(Vector2D.Zero, depthImage.BottomRight, directionInv);
|
|
|
|
+
|
|
|
|
+ Int16 depthAtFinger = depthImage.getDepthAt(midSlice.Mid);
|
|
|
|
+ Int16 depthAtOut1 = depthImage.getDepthAt(out1);
|
|
|
|
+ Int16 depthAtOut2 = depthImage.getDepthAt(out2);
|
|
|
|
+ int minDepthDifference = Math.Min(Math.Abs(depthAtFinger - depthAtOut1), Math.Abs(depthAtFinger - depthAtOut2));
|
|
|
|
+
|
|
|
|
+ return (minDepthDifference < Constants.FingerCrippleOutMinDifference);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ private FingerSlice findOutSlice(Vector2D start, Vector2D direction)
|
|
|
|
+ {
|
|
Vector2D dirOrth1 = direction.getOrthogonal(true);
|
|
Vector2D dirOrth1 = direction.getOrthogonal(true);
|
|
Vector2D dirOrth2 = direction.getOrthogonal(false);
|
|
Vector2D dirOrth2 = direction.getOrthogonal(false);
|
|
|
|
|
|
- Vector2D outPoint = (start + Constants.FingerOutSliceFactor * direction).moveInBound(0, 0, maxX, maxY);
|
|
|
|
- Vector2D p1 = findNextEdge(outPoint, dirOrth1, false, false, true);
|
|
|
|
- Vector2D p2 = findNextEdge(outPoint, dirOrth2, false, false, true);
|
|
|
|
|
|
+ Vector2D outPoint = (start + Constants.FingerOutSliceFactor * direction).moveInBound(Vector2D.Zero, depthImage.BottomRight, direction.getInverse());
|
|
|
|
+ Vector2D p1 = edgeImageOriginal.findNextEdge(outPoint, dirOrth1, 0, true, false);
|
|
|
|
+ Vector2D p2 = edgeImageOriginal.findNextEdge(outPoint, dirOrth2, 0, true, false);
|
|
|
|
|
|
FingerSlice slice = new FingerSlice(p1, p2);
|
|
FingerSlice slice = new FingerSlice(p1, p2);
|
|
|
|
|
|
@@ -280,11 +239,8 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
|
|
|
private FingerSliceTrail orderTrailTipToHand(FingerSliceTrail trail)
|
|
private FingerSliceTrail orderTrailTipToHand(FingerSliceTrail trail)
|
|
{
|
|
{
|
|
- int maxX = depthImage.Width - 2;
|
|
|
|
- int maxY = depthImage.Height - 2;
|
|
|
|
-
|
|
|
|
- FingerSlice start = trail.Start;
|
|
|
|
- FingerSlice end = trail.End;
|
|
|
|
|
|
+ FingerSlice start = trail.StartSlice;
|
|
|
|
+ FingerSlice end = trail.EndSlice;
|
|
|
|
|
|
Vector2D direction = (end.Mid - start.Mid).normalize();
|
|
Vector2D direction = (end.Mid - start.Mid).normalize();
|
|
|
|
|
|
@@ -294,15 +250,15 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
float startOutLength = float.MaxValue;
|
|
float startOutLength = float.MaxValue;
|
|
float endOutLength = float.MaxValue;
|
|
float endOutLength = float.MaxValue;
|
|
|
|
|
|
- if (startOutSlice.Start.isWithin(1, 1, maxX, maxY) && startOutSlice.End.isWithin(1, 1, maxX, maxY))
|
|
|
|
|
|
+ if (startOutSlice.Start.isInBound(Vector2D.Zero, depthImage.BottomRight) && startOutSlice.End.isInBound(Vector2D.Zero, depthImage.BottomRight))
|
|
startOutLength = startOutSlice.Length;
|
|
startOutLength = startOutSlice.Length;
|
|
|
|
|
|
- if (endOutSlice.Start.isWithin(1, 1, maxX, maxY) && endOutSlice.End.isWithin(1, 1, maxX, maxY))
|
|
|
|
|
|
+ if (endOutSlice.Start.isInBound(Vector2D.Zero, depthImage.BottomRight) && endOutSlice.End.isInBound(Vector2D.Zero, depthImage.BottomRight))
|
|
endOutLength = endOutSlice.Length;
|
|
endOutLength = endOutSlice.Length;
|
|
|
|
|
|
if (startOutLength <= endOutLength)
|
|
if (startOutLength <= endOutLength)
|
|
{
|
|
{
|
|
- trail.Slices.Reverse();
|
|
|
|
|
|
+ trail.reverse();
|
|
outputImage.drawLineSegment(startOutSlice.LineSegment, Constants.FingerHandOutSliceColor);
|
|
outputImage.drawLineSegment(startOutSlice.LineSegment, Constants.FingerHandOutSliceColor);
|
|
outputImage.drawLineSegment(endOutSlice.LineSegment, Constants.FingerTipOutSliceColor);
|
|
outputImage.drawLineSegment(endOutSlice.LineSegment, Constants.FingerTipOutSliceColor);
|
|
}
|
|
}
|
|
@@ -315,15 +271,23 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
return trail;
|
|
return trail;
|
|
}
|
|
}
|
|
|
|
|
|
- private void drawDetectedFinger(Finger finger)
|
|
|
|
|
|
+ private void drawFingers()
|
|
|
|
+ {
|
|
|
|
+ foreach (Finger finger in Fingers)
|
|
|
|
+ {
|
|
|
|
+ drawFinger(finger);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void drawFinger(Finger finger)
|
|
{
|
|
{
|
|
FingerSliceTrail trail = finger.SliceTrail;
|
|
FingerSliceTrail trail = finger.SliceTrail;
|
|
for (int i = 0; i < trail.NumSlices; i++)
|
|
for (int i = 0; i < trail.NumSlices; i++)
|
|
{
|
|
{
|
|
- outputImage.drawLineSegment(trail.Slices[i].LineSegment, Constants.FingerSliceColor);
|
|
|
|
|
|
+ outputImage.drawLineSegment(trail[i].LineSegment, Constants.FingerSliceColor);
|
|
}
|
|
}
|
|
outputImage.drawLineSegment(finger.LineSegment, Constants.FingerDetectedColor);
|
|
outputImage.drawLineSegment(finger.LineSegment, Constants.FingerDetectedColor);
|
|
- outputImage.drawContour(finger.getContour(), Color.Red, 1);
|
|
|
|
|
|
+ outputImage.drawContour(finger.Contour, Constants.FingerContourColor, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|