Jelajahi Sumber

Merge branch 'master' of https://git.tk.informatik.tu-darmstadt.de/etri-smartspaces

Conflicts:
	bbiwarg/Constants.cs
	bbiwarg/Detectors/Fingers/FingerDetector.cs
	bbiwarg/Detectors/Palm/PalmDetector.cs
Daniel Kauth 11 tahun lalu
induk
melakukan
80282cc942

+ 21 - 0
bbiwarg/Constants.cs

@@ -21,6 +21,7 @@ namespace bbiwarg
 
         public static readonly Color TouchEventDetectedColor = ColorDetected;
         public static readonly Color TouchEventTrackedColor = ColorTracked;
+        public static readonly Color TouchEventTipColor = Color.CornflowerBlue;
         public static readonly Color TouchEventAreaMatchedSubtractColor = Color.DarkOrange;
         public static readonly Color TouchEventAreaNonMatchedSubtractColor = Color.DarkSlateGray;
         public static readonly Color TouchEventStatusBarColor = Color.Green;
@@ -34,6 +35,18 @@ namespace bbiwarg
         public static readonly Color PalmConvexHullColor = Color.Green;
         public static readonly Color PalmThumbDefectColor = Color.Lime;
 
+        // finger detection
+        public static readonly int FingerStepSize = 2;
+        public static readonly int FingerMinNumSlices = 7;
+        public static readonly int FingerRemoveNumSlicesForCorrection = 3;
+        public static readonly int FingerMaxGapCounter = 10;
+        public static readonly int FingerMaxSliceDifferencePerStep = 5;
+        public static readonly int FingerMaxSize = 35;
+        public static readonly int FingerMinSize = 5;
+        public static readonly int FingerNumSlicesForRelativeDirection = 5;
+        public static readonly int FingerNumFramesUntilTracked = 2;
+        public static readonly float FingerMinSimilarityForTracking = 0.75f;
+
         // palm detection
         public static readonly float PalmMinDefectMidFingerLineDistance = 20; // defects with mid point ((start + end) / 2) closer than this to a finger line are removed 
         public static readonly float PalmMaxThumbDefectAngle = 110; // degree
@@ -42,6 +55,14 @@ namespace bbiwarg
         public static readonly int PalmGridRows = 4;
         public static readonly int PalmGridColumns = 3;
 
+        // touch detection
+        public static readonly float TouchEventMinFloodValue = 0.33f;
+        public static readonly int TouchEventTipCorrectionFactor = 5;
+        public static readonly int TouchEventAreaSize = 30;
+        public static readonly int TouchEventMaxDepthDifference = 20;
+        public static readonly int TouchEventFingerDiameter = 5;
+        public static readonly int TouchEventNumFramesUntilTracked = 2;
+
         // output window
         public static readonly int NumImagesPerRow = 4;
         public static readonly float WindwoSizeFactor = 1f; // output window size is scaled by this factor (from necessary size for images)

+ 17 - 31
bbiwarg/Detectors/Fingers/FingerDetector.cs

@@ -31,11 +31,8 @@ namespace bbiwarg.Detectors.Fingers
 
         private void findFingers()
         {
-            int minNumSlices = 7;
-            int width = depthImage.Width;
-            int height = depthImage.Height;
-            int maxX = width - 1;
-            int maxY = height - 1;
+            int maxX = depthImage.Width - 1;
+            int maxY = depthImage.Height - 1;
 
             Fingers = new List<Finger>();
 
@@ -57,7 +54,7 @@ namespace bbiwarg.Detectors.Fingers
                             if (slice != null)
                             {
                                 FingerSliceTrail trail = findFingerSliceTrail(slice, edgeDirection);
-                                if (trail != null && trail.NumSlices > minNumSlices)
+                                if (trail != null && trail.NumSlices > Constants.FingerMinNumSlices)
                                     createFingerFromTrail(trail);
                             }
                         }
@@ -80,16 +77,13 @@ namespace bbiwarg.Detectors.Fingers
 
         private FingerSliceTrail findFingerSliceTrail(FingerSlice startSlice, Vector2D startDirection)
         {
-            int minNumSlicesForCorrection = 7;
-            int numRemoveForCorrection = 3;
-
             int maxX = depthImage.Width - 1;
             int maxY = depthImage.Height - 1;
 
             FingerSliceTrail trail = new FingerSliceTrail(startSlice);
 
             Vector2D direction = startDirection;
-            Vector2D position = startSlice.Mid + 2*direction;
+            Vector2D position = startSlice.Mid + Constants.FingerStepSize * direction;
 
             if (position.isWithin(0, 0, maxX, maxY))
             {
@@ -99,9 +93,9 @@ namespace bbiwarg.Detectors.Fingers
                     trail.addSlice(nextSlice);
                     trail = expandTrail(trail);
 
-                    if (trail.NumSlices > minNumSlicesForCorrection)
+                    if (trail.NumSlices > Constants.FingerMinNumSlices)
                     {
-                        trail.Slices.RemoveRange(0, numRemoveForCorrection);
+                        trail.Slices.RemoveRange(0, Constants.FingerRemoveNumSlicesForCorrection);
                         trail.Slices.Reverse();
                         trail = expandTrail(trail);
                         trail.Slices.Reverse();
@@ -120,7 +114,7 @@ namespace bbiwarg.Detectors.Fingers
             int maxY = depthImage.Height - 1;
 
             Vector2D currentDirection = trail.getEndDirection();
-            Vector2D currentPosition = trail.End.Mid + 2*currentDirection;
+            Vector2D currentPosition = trail.End.Mid + Constants.FingerStepSize * currentDirection;
 
             int gapCounter = 0;
             int numSlices = trail.NumSlices;
@@ -128,16 +122,17 @@ namespace bbiwarg.Detectors.Fingers
             FingerSlice lastSlice = trail.End;
             FingerSlice nextSlice;
 
-            while (currentPosition.isWithin(0, 0, maxX, maxY) && gapCounter <= Math.Min(numSlices, 10))
+            while (currentPosition.isWithin(0, 0, maxX, maxY) && gapCounter <= Math.Min(numSlices, Constants.FingerMaxGapCounter))
             {
                 nextSlice = findFingerSliceFromMid(currentPosition, currentDirection);
-                if (nextSlice != null && (nextSlice.Length < lastSlice.Length + 8 && nextSlice.Length > lastSlice.Length - 8))
+
+                if (nextSlice != null && Math.Abs(nextSlice.Length - lastSlice.Length) <= Constants.FingerMaxSliceDifferencePerStep)
                 {
                     gapCounter = 0;
                     numSlices++;
                     trail.addSlice(nextSlice);
                     currentDirection = trail.getEndDirection();
-                    currentPosition = nextSlice.Mid + 2*currentDirection;
+                    currentPosition = nextSlice.Mid + Constants.FingerStepSize * currentDirection;
 
                     lastSlice = nextSlice;
                 }
@@ -168,7 +163,6 @@ namespace bbiwarg.Detectors.Fingers
         }
         private FingerSlice findFingerSliceFromStartEdge(Vector2D start, Vector2D direction)
         {
-
             Vector2D end = findNextEdge(start, direction);
             if (end == null) return null;
 
@@ -180,8 +174,6 @@ namespace bbiwarg.Detectors.Fingers
             int maxX = depthImage.Width - 1;
             int maxY = depthImage.Height - 1;
 
-            int maxFingerSize = 35;
-
             int maxStepsX;
             if (direction.X > 0)
                 maxStepsX = (int)((maxX - start.X) / direction.X);
@@ -198,7 +190,7 @@ namespace bbiwarg.Detectors.Fingers
             else
                 maxStepsY = int.MaxValue;
 
-            int maxStepsLength = (int)(maxFingerSize / direction.Length);
+            int maxStepsLength = (int)(Constants.FingerMaxSize / direction.Length);
 
             int maxSteps = Math.Min(maxStepsLength, Math.Min(maxStepsX, maxStepsY));
 
@@ -220,18 +212,12 @@ namespace bbiwarg.Detectors.Fingers
             int maxX = depthImage.Width - 1;
             int maxY = depthImage.Height - 1;
 
-            int minFingerSize = 5;
-            int maxFingerSize = 35;
-
             Vector2D direction = (end - start).normalize();
-            Vector2D beforeStart = start - direction;
-            Vector2D behindEnd = end + direction;
+            Vector2D beforeStart = (start - direction).moveInBound(0, 0, maxX, maxY);
+            Vector2D behindEnd = (end + direction).moveInBound(0, 0, maxY, maxY);
 
-            start = beforeStart.isWithin(0, 0, maxX, maxY) ? beforeStart : start;
-            end = behindEnd.isWithin(0, 0, maxX, maxY) ? behindEnd : end;
-
-            FingerSlice slice = new FingerSlice(start, end);
-            if (slice.Length >= minFingerSize && slice.Length <= maxFingerSize && fingerSliceDepthTest(slice))
+            FingerSlice slice = new FingerSlice(beforeStart, behindEnd);
+            if (slice.Length >= Constants.FingerMinSize && slice.Length <= Constants.FingerMaxSize && fingerSliceDepthTest(slice))
                 return slice;
 
             return null;
@@ -254,7 +240,7 @@ namespace bbiwarg.Detectors.Fingers
 
             //draw finger
             drawDetectedFinger(finger);
-        
+
             //remove edges around detected finger to improve performance
             edgeImage.removeFingerEdges(finger);
         }

+ 2 - 2
bbiwarg/Detectors/Fingers/FingerSliceTrail.cs

@@ -13,7 +13,7 @@ namespace bbiwarg.Detectors.Fingers
         public FingerSlice Start { get { return Slices[0]; } }
         public FingerSlice End { get { return Slices[Slices.Count - 1]; } }
         public int NumSlices { get { return Slices.Count; } }
-        public LineSegment2D LineSegment { get { return new LineSegment2D(Start.Mid, End.Mid); } }
+        public LineSegment2D LineSegment { get { return new LineSegment2D(End.Mid, Start.Mid); } }
 
         public FingerSliceTrail(FingerSlice slice)
         {
@@ -27,7 +27,7 @@ namespace bbiwarg.Detectors.Fingers
         }
 
         public Vector2D getEndDirection() {
-            int numSlicesToInnerEnd = 5;
+            int numSlicesToInnerEnd = Constants.FingerNumSlicesForRelativeDirection;
             int innerEndIndex = Math.Max(0, NumSlices - numSlicesToInnerEnd);
 
             return (End.Mid - Slices[innerEndIndex].Mid).normalize();

+ 3 - 5
bbiwarg/Detectors/Fingers/FingerTracker.cs

@@ -18,11 +18,10 @@ namespace bbiwarg.Detectors.Fingers
 
         public FingerTracker()
         {
-            framesUntilTracked = 3;
-            detectedFingers = new List<Finger>[framesUntilTracked];
+            detectedFingers = new List<Finger>[Constants.FingerNumFramesUntilTracked];
             TrackedFingers = new List<Finger>();
 
-            for (int i = 0; i < framesUntilTracked; i++)
+            for (int i = 0; i < Constants.FingerNumFramesUntilTracked; i++)
             {
                 detectedFingers[i] = new List<Finger>();
             }
@@ -44,7 +43,6 @@ namespace bbiwarg.Detectors.Fingers
 
         private void findTrackedFingers()
         {
-            float minSimilarity = 0.75f;
             TrackedFingers = new List<Finger>();
 
             foreach (Finger finger in detectedFingers[0])
@@ -54,7 +52,7 @@ namespace bbiwarg.Detectors.Fingers
                 for (int i = 1; i < framesUntilTracked; i++)
                 {
                     Finger mostSimilarThisFrame = getMostSimilarFingerInFrame(mostSimilarLastFrame, i);
-                    if (mostSimilarThisFrame == null || mostSimilarLastFrame.getSimilarity(mostSimilarThisFrame) < minSimilarity)
+                    if (mostSimilarThisFrame == null || mostSimilarLastFrame.getSimilarity(mostSimilarThisFrame) < Constants.FingerMinSimilarityForTracking)
                     {
                         tracked = false;
                         break;

+ 1 - 1
bbiwarg/Detectors/Palm/PalmDetector.cs

@@ -159,7 +159,7 @@ namespace bbiwarg.Detectors.Palm
 
             i3.fillCircle(pos.IntX, pos.IntY, 3, Color.Red);
 
-            return new Point(HelperFunctions.thresholdRange<int>(0, width - 1, pos.IntX), HelperFunctions.thresholdRange<int>(0, height - 1, pos.IntY));
+            return pos;
         }
 
         public OutputImage i1, i2, i3, i4, i5, i6, i7, i8, i9;

+ 15 - 23
bbiwarg/Detectors/Touch/TouchDetector.cs

@@ -27,21 +27,19 @@ namespace bbiwarg.Detectors.Touch
             this.outputImage = outputImage;
             this.fingers = fingers;
             this.TouchEvents = new List<TouchEvent>();
-            float floodValueThreshold = 0.33f;
 
             foreach (Finger finger in fingers)
             {
                 Vector2D tipPoint = finger.Tip;
 
+                outputImage.fillCircle(tipPoint.IntX, tipPoint.IntY, 3, Constants.TouchEventTipColor);
+
                 float floodValue = getFloodValue(tipPoint);
-                if (floodValue > floodValueThreshold)
+                if (floodValue > Constants.TouchEventMinFloodValue)
                 {
                     //correct touchEvent position
                     Vector2D direction = finger.LineSegment.Line.Direction;
-                    float directionFactor = 10;
-                    float x = HelperFunctions.thresholdRange<float>(0, depthImage.Width - 1, tipPoint.X + directionFactor * direction.X);
-                    float y = HelperFunctions.thresholdRange<float>(0, depthImage.Height - 1, tipPoint.Y + directionFactor * direction.Y);
-                    Vector2D tep = new Vector2D(x, y);
+                    Vector2D tep = (tipPoint + Constants.TouchEventTipCorrectionFactor * direction).moveInBound(0, 0, depthImage.Width - 1, depthImage.Height - 1);
 
                     outputImage.fillCircle(tep.IntX, tep.IntY, 5, Constants.TouchEventDetectedColor);
                     TouchEvent touchEvent = new TouchEvent(tep, floodValue, finger);
@@ -52,26 +50,23 @@ namespace bbiwarg.Detectors.Touch
 
         private float getFloodValue(Point touchPoint)
         {
-            int searchSize = 15;
-            int maxDepthDifference = 20;
-            Int16 fingerDiameter = 5;
-            Int16 depthAtTouch = (Int16)(depthImage.getDepthAt(touchPoint) + fingerDiameter);
+            Int16 depthAtTouch = (Int16)(depthImage.getDepthAt(touchPoint) + Constants.TouchEventFingerDiameter);
 
-            int minX = Math.Max(touchPoint.X - searchSize, 0);
-            int maxX = Math.Min(touchPoint.X + searchSize, depthImage.Width);
-            int minY = Math.Max(touchPoint.Y - searchSize, 0);
-            int maxY = Math.Min(touchPoint.Y + searchSize, depthImage.Height);
+            int minX = Math.Max(touchPoint.X - Constants.TouchEventAreaSize / 2, 0);
+            int maxX = Math.Min(touchPoint.X + Constants.TouchEventAreaSize / 2, depthImage.Width-1);
+            int minY = Math.Max(touchPoint.Y - Constants.TouchEventAreaSize / 2, 0);
+            int maxY = Math.Min(touchPoint.Y + Constants.TouchEventAreaSize / 2, depthImage.Height-1);
 
             int matchedPixels = 0;
             int countedPixels = 0;
-            for (int x = minX; x < maxX; x++)
+            for (int x = minX; x <= maxX; x++)
             {
-                for (int y = minY; y < maxY; y++)
+                for (int y = minY; y <= maxY; y++)
                 {
                     Int16 depth = depthImage.getDepthAt(x, y);
                     Color color = outputImage.getColotAt(x, y);
                     Color subtractColor;
-                    if (depthAtTouch < depth && Math.Abs(depthAtTouch - depth) < maxDepthDifference)
+                    if (depthAtTouch < depth && Math.Abs(depthAtTouch - depth) < Constants.TouchEventMaxDepthDifference)
                     {
                         matchedPixels++;
                         subtractColor = Constants.TouchEventAreaMatchedSubtractColor;
@@ -88,12 +83,9 @@ namespace bbiwarg.Detectors.Touch
 
             float rel = (float)matchedPixels / (float)countedPixels;
 
-            //status bar (% of matched pixels) -> green
-            for (int x = minX; x < minX + (maxX - minX) * rel; x++)
-            {
-                outputImage.drawPixel(x, maxY - 1, Constants.TouchEventStatusBarColor);
-            }
-
+            outputImage.drawLineSegment(new Utility.LineSegment2D(new Vector2D(minX, maxY), new Vector2D(minX + rel * Constants.TouchEventAreaSize, maxY)), Constants.TouchEventStatusBarColor);
+            outputImage.drawLineSegment(new Utility.LineSegment2D(new Vector2D(minX, maxY-1), new Vector2D(minX + rel * Constants.TouchEventAreaSize, maxY-1)), Constants.TouchEventStatusBarColor);
+            
             return rel;
         }
     }

+ 2 - 3
bbiwarg/Detectors/Touch/TouchTracker.cs

@@ -18,10 +18,9 @@ namespace bbiwarg.Detectors.Touch
 
         public TouchTracker()
         {
-            framesUntilTracked = 2;
-            detectedTouchEvents = new List<TouchEvent>[framesUntilTracked];
+            detectedTouchEvents = new List<TouchEvent>[Constants.TouchEventNumFramesUntilTracked];
 
-            for (int i = 0; i < framesUntilTracked; i++)
+            for (int i = 0; i < Constants.TouchEventNumFramesUntilTracked; i++)
             {
                 detectedTouchEvents[i] = new List<TouchEvent>();
             }

+ 1 - 1
bbiwarg/Graphics/OutputWindow.cs

@@ -25,7 +25,7 @@ namespace bbiwarg.Graphics
         private Stopwatch watch;
 
         public OutputWindow(VideoHandle videoHandle)
-            : base((int) (Constants.WindwoSizeFactor * HelperFunctions.thresholdRange<int>(1, Constants.NumImagesPerRow, videoHandle.OutputImages.Length) * videoHandle.Width), 
+            : base((int) (Constants.WindwoSizeFactor * Math.Max(1, Math.Min(Constants.NumImagesPerRow, videoHandle.OutputImages.Length)) * videoHandle.Width), 
                    (int) (Constants.WindwoSizeFactor * (1 + (videoHandle.OutputImages.Length - 1) / Constants.NumImagesPerRow) * videoHandle.Height))
         {
             this.videoHandle = videoHandle;

+ 34 - 8
bbiwarg/Graphics/TouchEventVisualizer.cs

@@ -54,6 +54,9 @@ namespace bbiwarg.Graphics
         public void updateImage()
         {
             OutputImage = new OutputImage(width, height);
+            bool touched = currentTouchPositions != null ? true : false;
+            int touchX = touched ? currentTouchPositions.Last<Vector2D>().IntX : -1;
+            int touchY = touched ? currentTouchPositions.Last<Vector2D>().IntY : -1;
 
             //-- Border --
             int size = Math.Min(width, height);
@@ -63,26 +66,49 @@ namespace bbiwarg.Graphics
             //-- Grid --
             int numRows = Constants.PalmGridRows;
             int numColumns = Constants.PalmGridColumns;
-
-            for (int i = 1; i < numRows; i++)
+            int cellX1 = -1;
+            int cellY1 = -1;
+            int cellX2 = -1;
+            int cellY2 = -1;
+            int tmp = -1;
+            int tmp2 = -1;
+ 
+            for (int i = 0; i < numRows; i++)
             {
-                int tmp = size / numRows * i;
+                tmp = size / numRows * i;
+                tmp2 = size / numRows * (i + 1);
                 OutputImage.drawLineSegment(new LineSegment2D(new Vector2D(0, tmp), new Vector2D(size - 2, tmp)), Constants.PalmGridColor);
+                if (touched)
+                    if (touchY >= tmp && touchY < tmp2)
+                    {
+                        cellY1 = tmp;
+                        cellY2 = tmp2;
+                    }
             }
-            for (int i = 1; i < numColumns; i++)
+            for (int i = 0; i < numColumns; i++)
             {
-                int tmp = size / numColumns * i;
+                tmp = size / numColumns * i;
+                tmp2 = size / numColumns * (i + 1);
                 OutputImage.drawLineSegment(new LineSegment2D(new Vector2D(tmp, 0), new Vector2D(tmp, size - 2)), Constants.PalmGridColor);
+                if (touched)
+                    if (touchX >= tmp && touchX < tmp2)
+                    {
+                        cellX1 = tmp;
+                        cellX2 = tmp2;
+                    }
             }
 
+            if (touched)
+                OutputImage.drawRectangle(cellX1, cellY1, size/numColumns, size/numRows, Constants.PalmGridColor, -1);
+
             //-- Current Touch Event --
-            if (currentTouchPositions != null)
+            if (touched)
             {
                 for (int i = 1; i < currentTouchPositions.Count; ++i)
                 {
                     OutputImage.drawLineSegment(new LineSegment2D(currentTouchPositions[i - 1], currentTouchPositions[i]), Constants.TouchEventVisualizerLineColor);
                 }
-                OutputImage.fillCircle(currentTouchPositions.Last<Vector2D>().IntX, currentTouchPositions.Last<Vector2D>().IntY, 3, Constants.TouchEventVisualizerPointColor);
+                OutputImage.fillCircle(touchX, touchY, 3, Constants.TouchEventVisualizerPointColor);
             }
             //-- Last Touch Event --
             if (lastTouchPositions != null)
@@ -93,7 +119,7 @@ namespace bbiwarg.Graphics
                 }
                 OutputImage.fillCircle(lastTouchPositions.Last<Vector2D>().IntX, lastTouchPositions.Last<Vector2D>().IntY, 3, Constants.TouchEventVisualizerPointColor);
             }
-            
+
         }
 
         public void Reset()

+ 0 - 20
bbiwarg/Utility/HelperFunctions.cs

@@ -1,20 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace bbiwarg.Utility
-{
-    public static class HelperFunctions
-    {
-        public static T thresholdRange<T>(T min, T max, T value)
-        {
-            if (Comparer<T>.Default.Compare(min, value) > 0)
-                return min;
-            if (Comparer<T>.Default.Compare(value, max) > 0)
-                return max;
-            return value;
-        }
-    }
-}

+ 1 - 1
bbiwarg/Utility/LineSegment2D.cs

@@ -26,7 +26,7 @@ namespace bbiwarg.Utility
             P2 = p2;
 
             //line
-            Line = new Line2D(P1, P1 - P2);
+            Line = new Line2D(P1, P2-P1);
         }
 
         public float getParallelDistanceTo(LineSegment2D line)

+ 7 - 0
bbiwarg/Utility/Vector2D.cs

@@ -86,6 +86,13 @@ namespace bbiwarg.Utility
             return (X >= minX && Y >= minY && X <= maxX && Y <= maxY);
         }
 
+        public Vector2D moveInBound(float minX, float minY, float maxX, float maxY)
+        {
+            float x = Math.Min(maxX, Math.Max(minX, X));
+            float y = Math.Min(maxY, Math.Max(minY, Y));
+            return new Vector2D(x, y);
+        }
+
         public Vector2D getOrthogonal(bool side)
         {
             if (side)

+ 1 - 1
bbiwarg/VideoHandle.cs

@@ -180,7 +180,7 @@ namespace bbiwarg
 
             //detect touchEvents
             Timer.start("touchDetection");
-            touchDetector = new TouchDetector(fingerTracker.TrackedFingers, depthImage, OutputImages[2]);
+            touchDetector = new TouchDetector(fingerTracker.TrackedFingers, depthImage, OutputImages[0]);
             if (palmDetector.PalmQuad != null)
                 palmTouchDetector = new PalmTouchDetector(touchDetector.TouchEvents, palmDetector.PalmQuad);
             Timer.stop("touchDetection");

+ 0 - 1
bbiwarg/bbiwarg.csproj

@@ -88,7 +88,6 @@
     <Compile Include="InputProvider\IisuInputProvider.cs" />
     <Compile Include="MainBBWIWARG.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Utility\HelperFunctions.cs" />
     <Compile Include="Utility\Kalman2DPositionFilter.cs" />
     <Compile Include="Utility\Line2D.cs" />
     <Compile Include="Utility\LineSegment2D.cs" />