|
@@ -17,8 +17,10 @@ namespace bbiwarg.Detectors.Fingers
|
|
private DepthImage depthImage;
|
|
private DepthImage depthImage;
|
|
private EdgeImage edgeImage;
|
|
private EdgeImage edgeImage;
|
|
private FingerImage fingerImage;
|
|
private FingerImage fingerImage;
|
|
|
|
+ private Image<Gray, byte> fingerPointsImage;
|
|
|
|
+ private List<Line2D> fingerLines;
|
|
private List<Finger> fingers;
|
|
private List<Finger> fingers;
|
|
- Image<Gray, byte> fingerPoints;
|
|
|
|
|
|
+
|
|
|
|
|
|
public FingerDetector(DepthImage depthImage, EdgeImage edgeImage, FingerImage fingerImage) {
|
|
public FingerDetector(DepthImage depthImage, EdgeImage edgeImage, FingerImage fingerImage) {
|
|
this.depthImage = depthImage;
|
|
this.depthImage = depthImage;
|
|
@@ -34,10 +36,18 @@ namespace bbiwarg.Detectors.Fingers
|
|
Console.WriteLine("findFingerPoints:" + sw.ElapsedMilliseconds);
|
|
Console.WriteLine("findFingerPoints:" + sw.ElapsedMilliseconds);
|
|
sw.Restart();
|
|
sw.Restart();
|
|
|
|
|
|
|
|
+ findFingerLines();
|
|
|
|
+
|
|
|
|
+ sw.Stop();
|
|
|
|
+ Console.WriteLine("findFingerLines:" + sw.ElapsedMilliseconds);
|
|
|
|
+ sw.Restart();
|
|
|
|
+
|
|
|
|
+
|
|
findFingers();
|
|
findFingers();
|
|
|
|
|
|
- Console.WriteLine("findFingers:" + sw.ElapsedMilliseconds);
|
|
|
|
sw.Stop();
|
|
sw.Stop();
|
|
|
|
+ Console.WriteLine("findFingers:" + sw.ElapsedMilliseconds);
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
public List<Finger> getFingers() {
|
|
public List<Finger> getFingers() {
|
|
@@ -48,17 +58,17 @@ namespace bbiwarg.Detectors.Fingers
|
|
int width = depthImage.getWidth();
|
|
int width = depthImage.getWidth();
|
|
int height = depthImage.getHeight();
|
|
int height = depthImage.getHeight();
|
|
|
|
|
|
- fingerPoints = new Image<Gray, byte>(width, height);
|
|
|
|
|
|
+ fingerPointsImage = new Image<Gray, byte>(width, height);
|
|
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
for (int y = 0; y < height; y++) {
|
|
for (int x = 0; x < width; x++) {
|
|
for (int x = 0; x < width; x++) {
|
|
if (edgeImage.isEdgeAt(x, y))
|
|
if (edgeImage.isEdgeAt(x, y))
|
|
{
|
|
{
|
|
Vector2D startPoint = new Vector2D(x, y);
|
|
Vector2D startPoint = new Vector2D(x, y);
|
|
- searchFingerPoint(startPoint, new Vector2D(1, 0), fingerPoints);
|
|
|
|
- searchFingerPoint(startPoint, new Vector2D(0, 1), fingerPoints);
|
|
|
|
- //searchFingerPoint(startPoint, new Vector2D(1, -1), fingerPoints);
|
|
|
|
- //searchFingerPoint(startPoint, new Vector2D(1, 1), fingerPoints);
|
|
|
|
|
|
+ searchFingerPoint(startPoint, new Vector2D(1, 0), fingerPointsImage);
|
|
|
|
+ searchFingerPoint(startPoint, new Vector2D(0, 1), fingerPointsImage);
|
|
|
|
+ //searchFingerPoint(startPoint, new Vector2D(1, -1).normalize(), fingerPointsImage);
|
|
|
|
+ //searchFingerPoint(startPoint, new Vector2D(1, 1).normalize(), fingerPointsImage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -69,31 +79,31 @@ namespace bbiwarg.Detectors.Fingers
|
|
int height = fingerPointsImage.Height;
|
|
int height = fingerPointsImage.Height;
|
|
float minFingerSize = 10;
|
|
float minFingerSize = 10;
|
|
float maxFingerSize = 30;
|
|
float maxFingerSize = 30;
|
|
- float stepSize = direction.getLength();
|
|
|
|
|
|
+ direction = direction.normalize();
|
|
|
|
|
|
|
|
|
|
bool edgeFound = false;
|
|
bool edgeFound = false;
|
|
Vector2D edge = start + minFingerSize * direction;
|
|
Vector2D edge = start + minFingerSize * direction;
|
|
float index = minFingerSize;
|
|
float index = minFingerSize;
|
|
- float maxXIndex = (direction.x == 0) ? float.MaxValue : ((direction.x > 0) ? ((width - start.x) / direction.x) : (-start.x / direction.x));
|
|
|
|
- float maxYIndex = (direction.y == 0) ? float.MaxValue : ((direction.y > 0) ? ((height - start.y) / direction.y) : (-start.y / direction.y));
|
|
|
|
|
|
+ float maxXIndex = (direction.X == 0) ? float.MaxValue : ((direction.X > 0) ? ((width - start.X) / direction.X) : (-start.X / direction.X));
|
|
|
|
+ float maxYIndex = (direction.Y == 0) ? float.MaxValue : ((direction.Y > 0) ? ((height - start.Y) / direction.Y) : (-start.Y / direction.Y));
|
|
|
|
|
|
float maxIndex = Math.Min(maxFingerSize, Math.Min(maxXIndex, maxYIndex));
|
|
float maxIndex = Math.Min(maxFingerSize, Math.Min(maxXIndex, maxYIndex));
|
|
|
|
|
|
if (index < maxIndex)
|
|
if (index < maxIndex)
|
|
{
|
|
{
|
|
- Int16 depthStart = depthImage.getDepthAt((int)start.x, (int)start.y);
|
|
|
|
- Int16 depthEdge = depthImage.getDepthAt((int)edge.x, (int)edge.y);
|
|
|
|
|
|
+ Int16 depthStart = depthImage.getDepthAt((int)start.X, (int)start.Y);
|
|
|
|
+ Int16 depthEdge = depthImage.getDepthAt((int)edge.X, (int)edge.Y);
|
|
|
|
|
|
if (depthStart > depthEdge)
|
|
if (depthStart > depthEdge)
|
|
{
|
|
{
|
|
while (!edgeFound && index < maxIndex)
|
|
while (!edgeFound && index < maxIndex)
|
|
{
|
|
{
|
|
- if (edgeImage.isEdgeAt((int)edge.x, (int)edge.y))
|
|
|
|
|
|
+ if (edgeImage.isEdgeAt((int)edge.X, (int)edge.Y))
|
|
edgeFound = true;
|
|
edgeFound = true;
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- index += stepSize;
|
|
|
|
|
|
+ index++;
|
|
edge += direction;
|
|
edge += direction;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -103,65 +113,73 @@ namespace bbiwarg.Detectors.Fingers
|
|
if (edgeFound && fingerDepthTest(start, edge))
|
|
if (edgeFound && fingerDepthTest(start, edge))
|
|
{
|
|
{
|
|
Vector2D mid = 0.5f * (start + edge);
|
|
Vector2D mid = 0.5f * (start + edge);
|
|
- fingerPointsImage.Data[(int)mid.y, (int)mid.x, 0] = byte.MaxValue;
|
|
|
|
- fingerImage.setFingerAt((int)mid.x, (int)mid.y, FingerImageState.possibleFinger);
|
|
|
|
|
|
+ fingerPointsImage.Data[(int)mid.Y, (int)mid.X, 0] = byte.MaxValue;
|
|
|
|
+ fingerImage.setFingerAt((int)mid.X, (int)mid.Y, FingerImageState.possibleFinger);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private bool fingerDepthTest(Vector2D p1, Vector2D p2) {
|
|
private bool fingerDepthTest(Vector2D p1, Vector2D p2) {
|
|
Vector2D mid = 0.5f * (p1 + p2);
|
|
Vector2D mid = 0.5f * (p1 + p2);
|
|
- Int16 depthP1 = depthImage.getDepthAt((int)p1.x, (int)p1.y);
|
|
|
|
- Int16 depthMid = depthImage.getDepthAt((int)mid.x, (int)mid.y);
|
|
|
|
- Int16 depthP2 = depthImage.getDepthAt((int)p2.x, (int)p2.y);
|
|
|
|
|
|
+ Int16 depthP1 = depthImage.getDepthAt((int)p1.X, (int)p1.Y);
|
|
|
|
+ Int16 depthMid = depthImage.getDepthAt((int)mid.X, (int)mid.Y);
|
|
|
|
+ Int16 depthP2 = depthImage.getDepthAt((int)p2.X, (int)p2.Y);
|
|
return (depthP1 > depthMid && depthMid < depthP2);
|
|
return (depthP1 > depthMid && depthMid < depthP2);
|
|
}
|
|
}
|
|
|
|
|
|
- private void findFingers()
|
|
|
|
- {
|
|
|
|
- int width = depthImage.getWidth();
|
|
|
|
- int height = depthImage.getHeight();
|
|
|
|
-
|
|
|
|
- fingerPoints = fingerPoints.Dilate(1);
|
|
|
|
-
|
|
|
|
- double rhoResolution = 1;
|
|
|
|
- double thetaResolution = Math.PI / 90.0;
|
|
|
|
- int threshold = 10;
|
|
|
|
- double minLineWidth = 20;
|
|
|
|
- double gapBetweenLines = 2;
|
|
|
|
-
|
|
|
|
- LineSegment2D[] lines = fingerPoints.HoughLinesBinary(rhoResolution, thetaResolution, threshold, minLineWidth, gapBetweenLines)[0];
|
|
|
|
|
|
+ private void findFingerLines() {
|
|
|
|
+ float maxCombinableAngle = (float) (Math.PI * 20 / 180);
|
|
|
|
+ float maxCombinableParallelDistance = 10;
|
|
|
|
+ float maxCombinableVerticalDistance = 10;
|
|
|
|
|
|
- fingers = new List<Finger>();
|
|
|
|
-
|
|
|
|
- foreach (LineSegment2D line in lines) {
|
|
|
|
- Vector2D p1 = new Vector2D(line.P1.X, line.P1.Y);
|
|
|
|
- Vector2D p2 = new Vector2D(line.P2.X, line.P2.Y);
|
|
|
|
- Finger finger = new Finger(p1, p2);
|
|
|
|
|
|
+ fingerPointsImage = fingerPointsImage.Dilate(1);
|
|
|
|
+ LineSegment2D[] lineSegments = fingerPointsImage.HoughLinesBinary(1, Math.PI / 90, 10, 20, 2)[0];
|
|
|
|
|
|
- List<Finger> mergeableFingers = new List<Finger>();
|
|
|
|
-
|
|
|
|
- foreach (Finger f in fingers) {
|
|
|
|
- if (finger.isMergeable(f))
|
|
|
|
- mergeableFingers.Add(f);
|
|
|
|
|
|
+ fingerLines = new List<Line2D>();
|
|
|
|
+ foreach (LineSegment2D lineSegment in lineSegments)
|
|
|
|
+ {
|
|
|
|
+ Line2D line = new Line2D(new Vector2D(lineSegment.P1), new Vector2D(lineSegment.P2));
|
|
|
|
+
|
|
|
|
+ List<Line2D> combineableLines = new List<Line2D>();
|
|
|
|
+ foreach(Line2D fingerLine in fingerLines) {
|
|
|
|
+ float angle = line.getAngleBetween(fingerLine);
|
|
|
|
+ if (angle <= maxCombinableAngle) {
|
|
|
|
+ float parallelDistance = line.getParallelDistanceTo(fingerLine);
|
|
|
|
+ if (parallelDistance <= maxCombinableParallelDistance) {
|
|
|
|
+ float verticalDistance = line.getVerticalDistanceTo(fingerLine);
|
|
|
|
+ if (verticalDistance <= maxCombinableVerticalDistance) {
|
|
|
|
+ combineableLines.Add(fingerLine);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (combineableLines.Count == 0) {
|
|
|
|
+ fingerLines.Add(line);
|
|
}
|
|
}
|
|
-
|
|
|
|
- if (mergeableFingers.Count == 0)
|
|
|
|
- fingers.Add(finger);
|
|
|
|
- else if (mergeableFingers.Count == 1)
|
|
|
|
- mergeableFingers[0].mergeFingers(finger);
|
|
|
|
else {
|
|
else {
|
|
- foreach (Finger mf in mergeableFingers) {
|
|
|
|
- finger.mergeFingers(mf);
|
|
|
|
- fingers.Remove(mf);
|
|
|
|
|
|
+ foreach (Line2D mergableLine in combineableLines) {
|
|
|
|
+ fingerLines.Remove(mergableLine);
|
|
}
|
|
}
|
|
- fingers.Add(finger);
|
|
|
|
|
|
+ combineableLines.Add(line);
|
|
|
|
+ fingerLines.Add(new Line2D(combineableLines));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void findFingers()
|
|
|
|
+ {
|
|
|
|
+ float minLength = 20;
|
|
|
|
+ float minNumCombinedLines = 2;
|
|
|
|
|
|
- //draw fingers in fingerImage
|
|
|
|
- foreach(Finger finger in fingers) {
|
|
|
|
- fingerImage.drawLine(finger.getTipPoint(), finger.getHandPoint(), FingerImageState.fingerDetected);
|
|
|
|
|
|
+ fingers = new List<Finger>();
|
|
|
|
+ foreach (Line2D line in fingerLines) {
|
|
|
|
+ if (line.Length >= minLength && line.NumCombinedLines >= minNumCombinedLines)
|
|
|
|
+ {
|
|
|
|
+ fingers.Add(new Finger(line));
|
|
|
|
+ fingerImage.drawLine(line, FingerImageState.fingerDetected);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|