Browse Source

-rewritten fingerDetection (using adaptive slice direction instead of horizontal+vertical)
-performance improvements

Alexander Hendrich 10 years ago
parent
commit
94a4e85418

+ 16 - 0
bbiwarg/Detectors/Fingers/Finger.cs

@@ -21,6 +21,22 @@ namespace bbiwarg.Detectors.Fingers
             SliceTrail = sliceTrail;
         }
 
+        public Point[] getPolygon() {
+            List<Point> pointsA = new List<Point>();
+            List<Point> pointsB = new List<Point>();
+            //int numSlices = SliceTrail.NumSlices;
+            //for (int i = 0; i < numSlices; i++)
+            foreach(FingerSlice slice in SliceTrail.Slices)
+            {
+                pointsA.Add(slice.Start);
+                pointsB.Add(slice.End);
+            }
+
+            pointsB.Reverse();
+            pointsA.AddRange(pointsB);
+            return pointsA.ToArray();
+        }
+
         //TODO: redo (not use similarity but actual distances and angle instead)
         public float getSimilarity(Finger compareFinger)
         {

+ 188 - 139
bbiwarg/Detectors/Fingers/FingerDetector.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Drawing;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -16,211 +17,259 @@ namespace bbiwarg.Detectors.Fingers
         private DepthImage depthImage;
         private EdgeImage edgeImage;
         private FingerImage fingerImage;
-        private List<FingerSliceTrail> horizontalFingerSliceTrails;
-        private List<FingerSliceTrail> verticalFingerSliceTrails;
         public List<Finger> Fingers { get; private set; }
 
-
         public FingerDetector(DepthImage depthImage, EdgeImage edgeImage, FingerImage fingerImage)
         {
             this.depthImage = depthImage;
-            this.edgeImage = edgeImage;
+            this.edgeImage = edgeImage.copy();
             this.fingerImage = fingerImage;
 
-            findHorizontalFingerSliceTrails();
-            findVerticalFingerSliceTrails();
-            transformFingerSliceTrailsToFingers();
+            findFingers();
         }
 
-        private void findHorizontalFingerSliceTrails()
+        private void findFingers()
         {
-
-            horizontalFingerSliceTrails = new List<FingerSliceTrail>();
-
+            int minNumSlices = 20;
             int width = depthImage.Width;
             int height = depthImage.Height;
+            int maxX = width - 1;
+            int maxY = height - 1;
 
-            int minFingerSize = 10;
-            int maxFingerSize = 30;
+            Fingers = new List<Finger>();
 
-            //search horizontal finger-slices
-            for (int y = 0; y < height; y++)
+            for (int y = 1; y < maxY; y++)
             {
-                int x = 0;
-                while (x <= width - minFingerSize)
+                for (int x = 1; x < maxX; x++)
                 {
-                    if (edgeImage.isEdgeAt(x, y) && depthImage.getDepthAt(x, y) > depthImage.getDepthAt(x + 1, y))
+                    if (edgeImage.isEdgeAt(x, y))
                     {
-                        int sliceX1 = x;
-                        int maxSliceX2 = Math.Min(sliceX1 + maxFingerSize, width - 1);
-                        x++;
-                        while (x <= maxSliceX2)
+                        Vector2D edgePoint = new Vector2D(x, y);
+                        Vector2D edgeDirection = getEdgeDirection(edgePoint);
+                        if (edgeDirection != null)
                         {
-                            if (edgeImage.isEdgeAt(x, y))
+                            Vector2D dir = edgeDirection.getOrthogonal(true);
+                            if (depthImage.getDepthAt(edgePoint - dir) < depthImage.getDepthAt(edgePoint + dir))
+                                dir = dir.getInverse();
+
+                            FingerSlice slice = findFingerSliceFromStartEdge(edgePoint, dir);
+                            if (slice != null)
                             {
-                                int sliceX2 = x;
-                                Vector2D sliceStart = new Vector2D(Math.Max(sliceX1 - 1, 0), y);
-                                Vector2D sliceEnd = new Vector2D(Math.Min(sliceX2 + 1, width - 1), y);
-                                FingerSlice fingerSlice = new FingerSlice(sliceStart, sliceEnd);
-                                if (fingerSlice.Size > minFingerSize && fingerSliceDepthTest(fingerSlice))
-                                {
-                                    addHorizontalFingerSlice(fingerSlice);
-                                    fingerImage.drawLine(fingerSlice.LineSegment, FingerImageState.possibleFingerSlice);
-                                }
-                                break;
+                                FingerSliceTrail trail = findFingerSliceTrail(slice, edgeDirection);
+                                if (trail != null && trail.NumSlices > minNumSlices)
+                                    createFingerFromTrail(trail);
                             }
-                            else x++;
                         }
                     }
-                    else
-                        x++;
-
                 }
             }
         }
 
-        private void findVerticalFingerSliceTrails()
+        private Vector2D getEdgeDirection(Vector2D edgePoint)
         {
-            verticalFingerSliceTrails = new List<FingerSliceTrail>();
+            int x = edgePoint.IntX;
+            int y = edgePoint.IntY;
 
-            int width = depthImage.Width;
-            int height = depthImage.Height;
+            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();
+            else return null;
+        }
 
-            int minFingerSize = 10;
-            int maxFingerSize = 30;
+        private FingerSliceTrail findFingerSliceTrail(FingerSlice startSlice, Vector2D startDirection)
+        {
+            int minNumSlicesForCorrection = 15;
+            int numRemoveForCorrection = 3;
+
+            int maxX = depthImage.Width - 1;
+            int maxY = depthImage.Height - 1;
+
+            FingerSliceTrail trail = new FingerSliceTrail(startSlice);
+
+            Vector2D position = startSlice.Mid + startDirection;
+            Vector2D direction = startDirection;
 
-            //search vertical finger-slices
-            for (int x = 0; x < width; x++)
+            if (position.isWithin(0, 0, maxX, maxY))
             {
-                int y = 0;
-                while (y <= height - minFingerSize)
+                FingerSlice nextSlice = findFingerSliceFromMid(position, direction);
+                if (nextSlice != null)
                 {
-                    if (edgeImage.isEdgeAt(x, y) && depthImage.getDepthAt(x, y) > depthImage.getDepthAt(x, y + 1))
+                    trail.addSlice(nextSlice);
+                    trail = expandTrail(trail);
+
+                    if (trail.NumSlices > minNumSlicesForCorrection)
                     {
-                        int sliceY1 = y;
-                        int maxSliceY2 = Math.Min(sliceY1 + maxFingerSize, height - 1);
-                        y++;
-                        while (y <= maxSliceY2)
-                        {
-                            if (edgeImage.isEdgeAt(x, y))
-                            {
-                                int sliceY2 = y;
-                                Vector2D sliceStart = new Vector2D(x, Math.Max(sliceY1 - 1, 0));
-                                Vector2D sliceEnd = new Vector2D(x, Math.Min(sliceY2 + 1, height - 1));
-                                FingerSlice fingerSlice = new FingerSlice(sliceStart, sliceEnd);
-                                if (fingerSlice.Size > minFingerSize && fingerSliceDepthTest(fingerSlice))
-                                {
-                                    addVerticalFingerSlice(fingerSlice);
-                                    fingerImage.drawLine(fingerSlice.LineSegment, FingerImageState.possibleFingerSlice);
-                                }
-                                break;
-                            }
-                            else y++;
-                        }
+                        trail.Slices.Reverse();
+                        trail.Slices.RemoveRange(0, numRemoveForCorrection);
+                        trail = expandTrail(trail);
+                        trail.Slices.Reverse();
+                        return trail;
                     }
-                    else
-                        y++;
-
                 }
             }
+
+            return null;
+
         }
 
-        private void transformFingerSliceTrailsToFingers()
+        private FingerSliceTrail expandTrail(FingerSliceTrail trail)
         {
-            int minNumSlices = 15;
+            int maxX = depthImage.Width - 1;
+            int maxY = depthImage.Height - 1;
 
-            Fingers = new List<Finger>();
-            List<FingerSliceTrail> fingerSliceTrails = new List<FingerSliceTrail>();
-            fingerSliceTrails.AddRange(horizontalFingerSliceTrails);
-            fingerSliceTrails.AddRange(verticalFingerSliceTrails);
+            int numDirectionsForAverage = 10;
+
+            List<Vector2D> directions = new List<Vector2D>();
+            int numDirections = Math.Min(trail.NumSlices - 1, numDirectionsForAverage);
+            for (int i = 0; i < numDirections; i++) {
+                directions.Add(trail.Slices[i + 1].Mid - trail.Slices[i].Mid);
+            }
+
+            Vector2D currentDirection = Vector2D.mean(directions).normalize();
+            Vector2D currentPosition = trail.End.Mid + currentDirection;
+
+            int gapCounter = 0;
+            int numSlices = trail.NumSlices;
 
-            foreach (FingerSliceTrail trail in fingerSliceTrails)
+            FingerSlice lastSlice = trail.End;
+            FingerSlice nextSlice;
+
+            while (currentPosition.isWithin(0, 0, maxX, maxY) && gapCounter <= Math.Min(numSlices / 2, 10))
             {
-                if (trail.NumSlices >= minNumSlices)
+                nextSlice = findFingerSliceFromMid(currentPosition, currentDirection);
+                if (nextSlice != null && (nextSlice.Length < lastSlice.Length + 5 && nextSlice.Length > lastSlice.Length - 5))
                 {
-                    //reorder finger slice so that it goes tip->hand
-                    /*Int16 depthAtTip = depthImage.getDepthAt((int)trail.Start.Mid.X, (int)trail.Start.Mid.Y);
-                    Int16 depthAtHand = depthImage.getDepthAt((int)trail.End.Mid.X, (int)trail.End.Mid.Y);
-                    if (depthAtTip < depthAtHand)
-                        trail.reverse();*/
-                    
-                    Finger finger = new Finger(trail);
-
-                    //filter double hits (horizontal+vertical finger)
-                    bool addFinger = true;
-                    for (int i = Fingers.Count - 1; i >= 0; i--)
-                    {
-                        Finger f = Fingers[i];
-                        Utility.LineSegment2D lineA = finger.LineSegment;
-                        Utility.LineSegment2D lineB = f.LineSegment;
+                    gapCounter = 0;
+                    numSlices++;
+                    trail.addSlice(nextSlice);
+                    directions.Add((nextSlice.Mid - lastSlice.Mid));
 
-                        if(lineA.getVerticalDistanceTo(lineB) < 5 && lineA.getParallelDistanceTo(lineB) < 5)
-                        {
-                            if (finger.SliceTrail.NumSlices > f.SliceTrail.NumSlices)
-                                Fingers.RemoveAt(i);
-                            else
-                                addFinger = false;
-                        }
-                    }
+                    if (directions.Count == numDirectionsForAverage)
+                        directions.RemoveAt(0);
 
-                    if (addFinger)
-                    {
-                        Fingers.Add(finger);
-                        fingerImage.drawFinger(finger, FingerImageState.fingerDetected);
-                    }
+                    currentDirection = Vector2D.mean(directions).normalize();
+                    currentPosition = nextSlice.Mid + currentDirection;
 
+                    lastSlice = nextSlice;
+                }
+                else
+                {
+                    gapCounter++;
+                    currentPosition += currentDirection;
                 }
-
             }
 
+            return trail;
         }
 
-        private bool fingerSliceDepthTest(FingerSlice fingerSlice)
+        private FingerSlice findFingerSliceFromMid(Vector2D position, Vector2D direction)
         {
-            Int16 depthStart = depthImage.getDepthAt(fingerSlice.Start);
-            Int16 depthMid = depthImage.getDepthAt(fingerSlice.Mid);
-            Int16 depthEnd = depthImage.getDepthAt(fingerSlice.End);
-            return (depthStart > depthMid && depthMid < depthEnd);
+            if (edgeImage.isEdgeAt(position)) return null;
+
+            Vector2D dirStart = direction.getOrthogonal(true);
+            Vector2D dirEnd = direction.getOrthogonal(false);
+
+            Vector2D start = findNextEdge(position, dirStart);
+            if (start == null) return null;
+
+            Vector2D end = findNextEdge(position, dirEnd);
+            if (end == null) return null;
+
+            return getFingerSlice(start, end);
+        }
+        private FingerSlice findFingerSliceFromStartEdge(Vector2D start, Vector2D direction)
+        {
+
+            Vector2D end = findNextEdge(start, direction);
+            if (end == null) return null;
+
+            return getFingerSlice(start, end);
         }
 
-        private void addHorizontalFingerSlice(FingerSlice slice)
+        private Vector2D findNextEdge(Vector2D start, Vector2D direction)
         {
-            int maxYGap = 5;
-            int maxXDifference = 5;
+            int maxX = depthImage.Width - 1;
+            int maxY = depthImage.Height - 1;
+
+            int maxFingerSize = 30;
+
+            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;
 
-            bool assigned = false;
-            foreach (FingerSliceTrail trail in horizontalFingerSliceTrails)
+            int maxStepsLength = (int)(maxFingerSize / direction.Length);
+
+            int maxSteps = Math.Min(maxStepsLength, Math.Min(maxStepsX, maxStepsY));
+
+            Vector2D end = new Vector2D(start);
+            for (int i = 0; i < maxSteps; i++)
             {
-                FingerSlice trailEnd = trail.End;
-                if (slice.Mid.Y - trailEnd.Mid.Y <= maxYGap && Math.Abs(trailEnd.Mid.X - slice.Mid.X) <= maxXDifference)
+                end += direction;
+
+                if (edgeImage.isEdgeAt(end))
                 {
-                    trail.addSlice(slice);
-                    assigned = true;
+                    return end;
                 }
             }
 
-            if (!assigned)
-                horizontalFingerSliceTrails.Add(new FingerSliceTrail(slice));
+            return null;
         }
 
-        private void addVerticalFingerSlice(FingerSlice slice)
+        private FingerSlice getFingerSlice(Vector2D start, Vector2D end)
         {
-            int maxXGap = 5;
-            int maxYDifference = 5;
+            int maxX = depthImage.Width - 1;
+            int maxY = depthImage.Height - 1;
 
-            bool assigned = false;
-            foreach (FingerSliceTrail trail in verticalFingerSliceTrails)
-            {
-                FingerSlice trailEnd = trail.End;
-                if (slice.Mid.X - trailEnd.Mid.X <= maxXGap && Math.Abs(trailEnd.Mid.Y - slice.Mid.Y) <= maxYDifference)
-                {
-                    trail.addSlice(slice);
-                    assigned = true;
-                }
-            }
+            int minFingerSize = 5;
+            int maxFingerSize = 30;
+
+            Vector2D direction = (end - start).normalize();
+            Vector2D beforeStart = start - direction;
+            Vector2D behindEnd = end + direction;
+
+            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))
+                return slice;
+
+            return null;
+        }
+
+        private bool fingerSliceDepthTest(FingerSlice fingerSlice)
+        {
+            Int16 depthStart = depthImage.getDepthAt(fingerSlice.Start);
+            Int16 depthMid = depthImage.getDepthAt(fingerSlice.Mid);
+            Int16 depthEnd = depthImage.getDepthAt(fingerSlice.End);
+            return (depthStart > depthMid && depthMid < depthEnd);
+        }
+
+        private void createFingerFromTrail(FingerSliceTrail trail)
+        {
+            Finger finger = new Finger(trail);
+
+            //add finger
+            Fingers.Add(finger);
+
+            //draw finger
+            fingerImage.drawFinger(finger, FingerImageState.fingerDetected);
 
-            if (!assigned)
-                verticalFingerSliceTrails.Add(new FingerSliceTrail(slice));
+            //remove edges around detected finger to improve performance
+            edgeImage.removeFingerEdges(finger);
         }
     }
 }

+ 4 - 2
bbiwarg/Detectors/Fingers/FingerSlice.cs

@@ -12,13 +12,15 @@ namespace bbiwarg.Detectors.Fingers
         public Vector2D Start { get; private set; }
         public Vector2D Mid { get; private set; }
         public Vector2D End { get; private set; }
-        public LineSegment2D LineSegment { get { return new LineSegment2D(Start, End); } }
-        public float Size { get { return Start.getDistanceTo(End); } }
+        public LineSegment2D LineSegment { get; private set; }
+        public float Length { get; private set; }
 
         public FingerSlice(Vector2D start, Vector2D end) {
             Start = start;
             End = end;
             Mid = (start + end) / 2;
+            LineSegment = new LineSegment2D(Start, End);
+            Length = Start.getDistanceTo(End); ;
         }
 
     }

+ 0 - 4
bbiwarg/Detectors/Fingers/FingerSliceTrail.cs

@@ -25,9 +25,5 @@ namespace bbiwarg.Detectors.Fingers
         {
             Slices.Add(slice);
         }
-
-        public void reverse() {
-            Slices.Reverse();
-        }
     }
 }

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

@@ -49,7 +49,7 @@ namespace bbiwarg.Detectors.Palm
             this.edgeImage = edgeImage;
             this.palmImage = palmImage;
 
-            handImage = depthImage.Image.Convert<Byte>(delegate(short s) { return (s == depthImage.getMaxDepth()) ? (byte)0 : (byte)1; });
+            handImage = depthImage.Image.Convert<Byte>(delegate(byte s) { return (s == depthImage.MaxDepth-depthImage.MinDepth) ? (byte)0 : (byte)1; });
 
             fingers = getFingersWithoutThumb(detectedFingers);
             buildPointingHandMask();
@@ -135,7 +135,7 @@ namespace bbiwarg.Detectors.Palm
             pointingHandMask = new Image<Gray, byte>(width, height, new Gray(0));
             fillFingerSlices(pointingHandMask, 1);
             pointingHandMask = pointingHandMask.Dilate(1);
-            pointingHandMask = pointingHandMask.Or(edgeImage.getImage().Convert<Byte>(delegate(byte b) { return (b == 0) ? (byte)0 : (byte)1; }));
+            pointingHandMask = pointingHandMask.Or(edgeImage.Image.Convert<Byte>(delegate(byte b) { return (b == 0) ? (byte)0 : (byte)1; }));
             pointingHandMask = pointingHandMask.Dilate(1);
 
             MCvConnectedComp tmp = new MCvConnectedComp();

+ 14 - 51
bbiwarg/Images/DepthImage.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Drawing;
 using System.Linq;
 using System.Text;
@@ -11,23 +12,23 @@ namespace bbiwarg.Images
 {
     class DepthImage
     {
-        public Image<Gray, Int16> Image { get; private set; }
-        public int Width { get { return Image.Width; } }
-        public int Height { get { return Image.Height; } }
+        public Image<Gray, byte> Image { get; private set; }
+        public int Width { get; private set; }
+        public int Height { get; private set; }
         public Int16 MinDepth { get; private set; }
         public Int16 MaxDepth { get; private set; }
 
-        public DepthImage(Image<Gray, Int16> image)
+        public DepthImage(Image<Gray, Int16> image, Int16 minDepth)
         {
-            this.Image = image;
-
-            //smooth
-            this.Image = image.SmoothMedian(3);
+            Width = image.Width;
+            Height = image.Height;
 
             //threshold min&maxDepth
-            MinDepth = findMinDepth();
-            MaxDepth = (Int16)(MinDepth + 200);
-            thresholdDepth(MinDepth, MaxDepth);
+            MinDepth = minDepth;
+            MaxDepth = (Int16)(MinDepth + 200); // max = minDepth+255 (else it can't fit whole range in byte image)
+
+            //smooth+threshold
+            Image = image.SmoothMedian(3).Convert<byte>(delegate(Int16 depth) { if (depth > MaxDepth || depth < MinDepth) return (byte)(MaxDepth - MinDepth); else return (byte)(depth - MinDepth); });
 
         }
 
@@ -38,7 +39,7 @@ namespace bbiwarg.Images
 
         public Int16 getDepthAt(int x, int y)
         {
-            return Image.Data[y, x, 0];
+            return (Int16) (MinDepth + Image.Data[y, x, 0]);
         }
 
         public void setDepthAt(Point point, Int16 depth)
@@ -48,7 +49,7 @@ namespace bbiwarg.Images
 
         public void setDepthAt(int x, int y, Int16 depth)
         {
-            Image.Data[y, x, 0] = depth;
+            Image.Data[y, x, 0] = (byte) (depth - MinDepth);
         }
 
         public float getRelativeDepthAt(Point point)
@@ -61,43 +62,5 @@ namespace bbiwarg.Images
             float minMaxInterval = Math.Max(MaxDepth - MinDepth, 1);
             return (getDepthAt(x, y) - MinDepth) / minMaxInterval;
         }
-
-        public Int16 getMinDepth()
-        {
-            return MinDepth;
-        }
-
-        public Int16 getMaxDepth()
-        {
-            return MaxDepth;
-        }
-
-        private Int16 findMinDepth()
-        {
-            MinDepth = Int16.MaxValue;
-            for (int x = 0; x < Width; ++x)
-            {
-                for (int y = 0; y < Height; ++y)
-                {
-                    Int16 depth = getDepthAt(x, y);
-                    if (depth < MinDepth)
-                        MinDepth = depth;
-                }
-            }
-            return MinDepth;
-        }
-
-        private void thresholdDepth(Int16 min, Int16 max)
-        {
-            for (int x = 0; x < Width; ++x)
-            {
-                for (int y = 0; y < Height; ++y)
-                {
-                    Int16 depth = getDepthAt(x, y);
-                    if (depth > max || depth < min)
-                        setDepthAt(x, y, max);
-                }
-            }
-        }
     }
 }

+ 21 - 10
bbiwarg/Images/EdgeImage.cs

@@ -1,32 +1,43 @@
 using System;
 using System.Collections.Generic;
+using System.Drawing;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using Emgu.CV;
 using Emgu.CV.Structure;
+using bbiwarg.Detectors.Fingers;
 
 namespace bbiwarg.Images
 {
     class EdgeImage
     {
-        private Image<Gray, Byte> image;
+        public Image<Gray, Byte> Image {get; private set;}
 
         public EdgeImage(DepthImage depthImage) {
-            int minDepth = depthImage.getMinDepth();
-            int maxDepth = depthImage.getMaxDepth();
-            Image<Gray, Int16> depthImageInt16 = depthImage.Image;
-            Image<Gray, Byte> depthImageByte = depthImageInt16.Convert<Byte>(delegate(Int16 depth) { return (byte)(((depth - minDepth) * Byte.MaxValue) / (maxDepth - minDepth)); });
-            image = depthImageByte.Canny(100, 75, 3);
+            Image = depthImage.Image.Canny(100, 75, 3);
+        }
+
+        public EdgeImage(Image<Gray, Byte> edgeImage) {
+            Image = edgeImage;
+        }
+
+        public bool isEdgeAt(Point point) {
+            return isEdgeAt(point.X, point.Y);
         }
 
         public bool isEdgeAt(int x, int y) {
-            return (image.Data[y,x,0] > 0);
+            return (Image.Data[y,x,0] > 0);
+        }
+
+        public void removeFingerEdges(Finger finger) {
+            Point[] polygon = finger.getPolygon();
+
+            Image.FillConvexPoly(polygon, new Gray(0));
         }
 
-        public Image<Gray, Byte> getImage()
-        {
-            return image;
+        public EdgeImage copy() {
+            return new EdgeImage(Image.Copy());
         }
     }
 }

+ 24 - 2
bbiwarg/Utility/Vector2D.cs

@@ -21,6 +21,12 @@ namespace bbiwarg.Utility
             Y = y;
         }
 
+        public Vector2D(Vector2D vec)
+        {
+            X = vec.X;
+            Y = vec.Y;
+        }
+
         public Vector2D(Point point)
         {
             X = point.X;
@@ -64,12 +70,28 @@ namespace bbiwarg.Utility
 
         public Vector2D normalize()
         {
-            return new Vector2D(X / Length, Y / Length);
+            float length = Length;
+            return new Vector2D(X / length, Y / length);
+        }
+
+        public bool isWithin(float minX, float minY, float maxX, float maxY) {
+            return (X >= minX && Y >= minY && X <= maxX && Y <= maxY);
+        }
+
+        public Vector2D getOrthogonal(bool side) {
+            if (side)
+                return new Vector2D(Y, -X);
+            else
+                return new Vector2D(-Y, X);
+        }
+
+        public Vector2D getInverse() {
+            return new Vector2D(-X, -Y);
         }
 
         public override string ToString()
         {
-            return "(" + X + ", " + Y + ")";
+            return "(" + X + "|" + Y + ")";
         }
 
         public static Vector2D operator *(float scalar, Vector2D vector)

+ 6 - 2
bbiwarg/VideoHandle.cs

@@ -126,13 +126,17 @@ namespace bbiwarg
             Height = inputFrame.Height;
 
             //create depthImage
+            Int16 minDepth = Int16.MaxValue;
             Image<Gray, Int16> image = new Image<Gray, Int16>(Width, Height);
             for (int x = 0; x < Width; x++) {
                 for (int y = 0; y < Height; y++) {
-                    image.Data[y, x, 0] = inputFrame.getDepthAt(x, y);
+                    Int16 depth = inputFrame.getDepthAt(x, y);
+                    image.Data[y, x, 0] = depth;
+                    if(depth < minDepth)
+                        minDepth = depth;
                 }
             }
-            depthImage = new DepthImage(image);
+            depthImage = new DepthImage(image, minDepth);
 
             //create images
             edgeImage = new EdgeImage(depthImage);