|
@@ -16,14 +16,16 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
class FingerDetector
|
|
|
{
|
|
|
private DepthImage depthImage;
|
|
|
- private EdgeImage edgeImage;
|
|
|
+ private EdgeImage edgeImageOriginal;
|
|
|
+ private EdgeImage edgeImageAdapted;
|
|
|
private OutputImage outputImage;
|
|
|
public List<Finger> Fingers { get; private set; }
|
|
|
|
|
|
public FingerDetector(DepthImage depthImage, EdgeImage edgeImage, OutputImage outputImage)
|
|
|
{
|
|
|
this.depthImage = depthImage;
|
|
|
- this.edgeImage = edgeImage.copy();
|
|
|
+ this.edgeImageOriginal = edgeImage;
|
|
|
+ this.edgeImageAdapted = edgeImage.copy();
|
|
|
this.outputImage = outputImage;
|
|
|
|
|
|
findFingers();
|
|
@@ -36,11 +38,11 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
|
|
|
Fingers = new List<Finger>();
|
|
|
|
|
|
- for (int y = 1; y < maxY; y += 5) //y++ for 100% coverage, but y+=5 for 99% coverage and 3 times better perfomance
|
|
|
+ for (int y = 1; y < maxY; y += 5)
|
|
|
{
|
|
|
for (int x = 1; x < maxX; x++)
|
|
|
{
|
|
|
- if (edgeImage.isEdgeAt(x, y))
|
|
|
+ if (edgeImageAdapted.isEdgeAt(x, y))
|
|
|
{
|
|
|
Vector2D edgePoint = new Vector2D(x, y);
|
|
|
Vector2D edgeDirection = getEdgeDirection(edgePoint);
|
|
@@ -55,7 +57,9 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
{
|
|
|
FingerSliceTrail trail = findFingerSliceTrail(slice, edgeDirection);
|
|
|
if (trail != null && trail.NumSlices > Constants.FingerMinNumSlices)
|
|
|
+ {
|
|
|
createFingerFromTrail(trail);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -68,10 +72,10 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
int x = edgePoint.IntX;
|
|
|
int y = edgePoint.IntY;
|
|
|
|
|
|
- if (edgeImage.isEdgeAt(x, y - 1) && edgeImage.isEdgeAt(x, y + 1)) return new Vector2D(0, 1);
|
|
|
- else if (edgeImage.isEdgeAt(x - 1, y) && edgeImage.isEdgeAt(x + 1, y)) return new Vector2D(1, 0);
|
|
|
- else if (edgeImage.isEdgeAt(x - 1, y - 1) && edgeImage.isEdgeAt(x + 1, y + 1)) return new Vector2D(1, 1).normalize();
|
|
|
- else if (edgeImage.isEdgeAt(x + 1, y - 1) && edgeImage.isEdgeAt(x - 1, y + 1)) return new Vector2D(1, -1).normalize();
|
|
|
+ if (edgeImageAdapted.isEdgeAt(x, y - 1) && edgeImageAdapted.isEdgeAt(x, y + 1)) return new Vector2D(0, 1);
|
|
|
+ else if (edgeImageAdapted.isEdgeAt(x - 1, y) && edgeImageAdapted.isEdgeAt(x + 1, y)) return new Vector2D(1, 0);
|
|
|
+ else if (edgeImageAdapted.isEdgeAt(x - 1, y - 1) && edgeImageAdapted.isEdgeAt(x + 1, y + 1)) return new Vector2D(1, 1).normalize();
|
|
|
+ else if (edgeImageAdapted.isEdgeAt(x + 1, y - 1) && edgeImageAdapted.isEdgeAt(x - 1, y + 1)) return new Vector2D(1, -1).normalize();
|
|
|
else return null;
|
|
|
}
|
|
|
|
|
@@ -93,11 +97,11 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
trail.addSlice(nextSlice);
|
|
|
trail = expandTrail(trail);
|
|
|
|
|
|
- if (trail.NumSlices > Constants.FingerMinNumSlices)
|
|
|
+ if (trail.NumSlices > Constants.FingerMinNumSlices / 2)
|
|
|
{
|
|
|
trail.Slices.RemoveRange(0, Constants.FingerRemoveNumSlicesForCorrection);
|
|
|
trail.Slices.Reverse();
|
|
|
- trail = expandTrail(trail);
|
|
|
+ trail = expandTrail(trail, true);
|
|
|
trail.Slices.Reverse();
|
|
|
return trail;
|
|
|
}
|
|
@@ -108,7 +112,7 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
|
|
|
}
|
|
|
|
|
|
- private FingerSliceTrail expandTrail(FingerSliceTrail trail)
|
|
|
+ private FingerSliceTrail expandTrail(FingerSliceTrail trail, bool reversed = false)
|
|
|
{
|
|
|
int maxX = depthImage.Width - 1;
|
|
|
int maxY = depthImage.Height - 1;
|
|
@@ -124,7 +128,10 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
|
|
|
while (currentPosition.isWithin(0, 0, maxX, maxY) && gapCounter <= Math.Min(numSlices, Constants.FingerMaxGapCounter))
|
|
|
{
|
|
|
- nextSlice = findFingerSliceFromMid(currentPosition, currentDirection);
|
|
|
+ if (reversed)
|
|
|
+ nextSlice = findFingerSliceFromMid(currentPosition, currentDirection.getInverse());
|
|
|
+ else
|
|
|
+ nextSlice = findFingerSliceFromMid(currentPosition, currentDirection);
|
|
|
|
|
|
if (nextSlice != null && Math.Abs(nextSlice.Length - lastSlice.Length) <= Constants.FingerMaxSliceDifferencePerStep)
|
|
|
{
|
|
@@ -148,7 +155,7 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
|
|
|
private FingerSlice findFingerSliceFromMid(Vector2D position, Vector2D direction)
|
|
|
{
|
|
|
- if (edgeImage.isEdgeAt(position)) return null;
|
|
|
+ if (edgeImageAdapted.isRoughEdgeAt(position)) return null;
|
|
|
|
|
|
Vector2D dirStart = direction.getOrthogonal(true);
|
|
|
Vector2D dirEnd = direction.getOrthogonal(false);
|
|
@@ -163,13 +170,13 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
}
|
|
|
private FingerSlice findFingerSliceFromStartEdge(Vector2D start, Vector2D direction)
|
|
|
{
|
|
|
- Vector2D end = findNextEdge(start, direction);
|
|
|
+ Vector2D end = findNextEdge(start + Constants.FingerSliceOverlapFactor * direction, direction);
|
|
|
if (end == null) return null;
|
|
|
|
|
|
return getFingerSlice(start, end);
|
|
|
}
|
|
|
|
|
|
- private Vector2D findNextEdge(Vector2D start, Vector2D direction, bool stopAtMaxFingerSize = true, bool returnBoundIfNoEdge = false)
|
|
|
+ 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;
|
|
@@ -200,7 +207,7 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
{
|
|
|
end += direction;
|
|
|
|
|
|
- if (edgeImage.isEdgeAt(end))
|
|
|
+ if ((adaptedEdgeImage && edgeImageAdapted.isRoughEdgeAt(end)) || (!adaptedEdgeImage && edgeImageOriginal.isRoughEdgeAt(end)))
|
|
|
{
|
|
|
return end;
|
|
|
}
|
|
@@ -218,8 +225,8 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
int maxY = depthImage.Height - 1;
|
|
|
|
|
|
Vector2D direction = (end - start).normalize();
|
|
|
- Vector2D beforeStart = (start - direction).moveInBound(0, 0, maxX, maxY);
|
|
|
- Vector2D behindEnd = (end + direction).moveInBound(0, 0, maxY, maxY);
|
|
|
+ Vector2D beforeStart = (start - Constants.FingerSliceOverlapFactor * direction).moveInBound(0, 0, maxX, maxY);
|
|
|
+ Vector2D behindEnd = (end + Constants.FingerSliceOverlapFactor * direction).moveInBound(0, 0, maxY, maxY);
|
|
|
|
|
|
FingerSlice slice = new FingerSlice(beforeStart, behindEnd);
|
|
|
if (slice.Length >= Constants.FingerMinSize && slice.Length <= Constants.FingerMaxSize && fingerSliceDepthTest(slice))
|
|
@@ -251,7 +258,7 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
drawDetectedFinger(finger);
|
|
|
|
|
|
//remove edges around detected finger to improve performance
|
|
|
- edgeImage.removeFingerEdges(finger);
|
|
|
+ edgeImageAdapted.removeEdgesInsidePolygon(finger.getContour().ToArray());
|
|
|
}
|
|
|
|
|
|
private FingerSlice findOutSlice(Vector2D start, Vector2D direction)
|
|
@@ -262,9 +269,9 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
Vector2D dirOrth1 = direction.getOrthogonal(true);
|
|
|
Vector2D dirOrth2 = direction.getOrthogonal(false);
|
|
|
|
|
|
- Vector2D outPoint = (start + Constants.FingerOutSliceFactor * Constants.FingerStepSize * direction).moveInBound(0, 0, maxX, maxY);
|
|
|
- Vector2D p1 = findNextEdge(outPoint, dirOrth1, false, true);
|
|
|
- Vector2D p2 = findNextEdge(outPoint, dirOrth2, false, true);
|
|
|
+ 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);
|
|
|
|
|
|
FingerSlice slice = new FingerSlice(p1, p2);
|
|
|
|
|
@@ -283,7 +290,7 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
|
|
|
Vector2D direction = (end.Mid - start.Mid).normalize();
|
|
|
|
|
|
- FingerSlice startOutSlice = findOutSlice(start.Mid, -1 * direction);
|
|
|
+ FingerSlice startOutSlice = findOutSlice(start.Mid, direction.getInverse());
|
|
|
FingerSlice endOutSlice = findOutSlice(end.Mid, direction);
|
|
|
|
|
|
float startOutLength = float.MaxValue;
|
|
@@ -309,6 +316,7 @@ namespace bbiwarg.Detectors.FingerDetection
|
|
|
outputImage.drawLineSegment(trail.Slices[i].LineSegment, Constants.FingerSliceColor);
|
|
|
}
|
|
|
outputImage.drawLineSegment(finger.LineSegment, Constants.FingerDetectedColor);
|
|
|
+ outputImage.drawContour(finger.getContour(), Color.Red, 1);
|
|
|
}
|
|
|
}
|
|
|
}
|