Преглед на файлове

-big performance+quality improvement for fingerDetection (using new pointSearch, hough-transformation and line-merging)
-implemented Vector2D (Vector<T> is way to unperfomant because of all the dynamic casts (we can't use generics here), for now we only need a 2D-float-vector, and maybe later a 3D-float-vector when handling planes)
-fingerTracking still not working properly (I will have a look at finger+touchTracker next)

Alexander Hendrich преди 10 години
родител
ревизия
285c980139

+ 105 - 120
bbiwarg/Detectors/Fingers/Finger.cs

@@ -13,162 +13,147 @@ namespace bbiwarg.Detectors.Fingers
 {
     class Finger
     {
-        private List<Vector<int>> fingerPoints;
-        private bool fingerEndPointsUpToDate = false;
-        private bool lineUpToDate = false;
+        private Vector2D tipPoint;
+        private Vector2D handPoint;
+        private Vector2D direction;
         private float length;
-        private Vector<int> tipPoint;
-        private Vector<int> handPoint;
-        private Vector<float> direction;
-        private Vector<float> pointOnLine;
-        private Vector<float> lineEndPoint1;
-        private Vector<float> lineEndPoint2;
-
-        public Finger(List<Vector<int>> fingerPoints) {
-            this.fingerPoints = fingerPoints;
+
+        public Finger(Vector2D p1, Vector2D p2) {
+            assignTipAndHandPoint(p1, p2);
         }
 
         public float getLength() {
-            if (!fingerEndPointsUpToDate) updateFingerEndPoints();
             return length;
         }
 
-        public int getNumFingerPoints() {
-            return fingerPoints.Count;
-        }
-
-        public List<Vector<int>> getFingerPoints() {
-            return fingerPoints;
-        }
-
-        public Vector<int> getTipPoint() {
-            if (!fingerEndPointsUpToDate) updateFingerEndPoints();
+        public Vector2D getTipPoint() {
             return tipPoint;
         }
 
-        public Vector<int> getHandPoint() {
-            if (!fingerEndPointsUpToDate) updateFingerEndPoints();
+        public Vector2D getHandPoint() {
             return handPoint;
         }
 
-        public Vector<float> getDirection()
-        {
-            if (!lineUpToDate) updateLine();
+        public Vector2D getDirection() {
             return direction;
         }
 
-        public Vector<float> getLineEndPoint1()
+        public float getSimilarity(Finger compareFinger)
         {
-            if (!lineUpToDate) updateLine();
-            return lineEndPoint1;
-        }
+            //thresholds
+            float thresholdMaxAngle = (float)(30 * Math.PI / 180); // 30°
+            float thresholdMaxParallelDistance = 40;
+            float thresholdMaxVerticalDistance = 40;
 
-        public Vector<float> getLineEndPoint2()
-        {
-            if (!lineUpToDate) updateLine();
-            return lineEndPoint2;
-        }
+            //check angle
+            float angle = direction.getMinAngleBetween(compareFinger.direction);
+            float angleSimilarity = Math.Max(1 - angle / thresholdMaxAngle, 0);
 
-        public void addFingerPoint(Vector<int> fingerPoint) {
-            fingerPoints.Add(fingerPoint);
-            fingerEndPointsUpToDate = false;
-            lineUpToDate = false;
-        }
+            //check parallel distance
+            float minParallelDistance = getMinParallelDistance(compareFinger);
+            float parallelDistanceSimilarity = Math.Max(1 - minParallelDistance / thresholdMaxParallelDistance, 0);
 
-        public bool isWithinDistance(Vector<int> point, float maxDistance) {
-            foreach (Vector<int> fp in fingerPoints) {
-                if (fp.subDistance(point, 2) <= maxDistance)
-                    return true;
-            }
-            return false;
+            //check vertical distance
+            float minVerticalDistance = getMinVerticalDistance(compareFinger);
+            float verticalDistanceSimilarity = Math.Max(1 - minVerticalDistance / thresholdMaxVerticalDistance, 0);
+
+            return (angleSimilarity + parallelDistanceSimilarity + verticalDistanceSimilarity) / 3;
         }
 
-        public float getSimilarity(Finger compareFinger)
+        public bool isMergeable(Finger mergeFinger)
         {
-            if (!fingerEndPointsUpToDate) updateFingerEndPoints();
-            if (!lineUpToDate) updateLine();
-
-            //startDistance
-            float maxStartDistance = 100;
-            float xDiffStart = lineEndPoint1.x - compareFinger.getLineEndPoint1().x;
-            float yDiffStart = lineEndPoint1.y - compareFinger.getLineEndPoint1().y;
-            float startDistance = (float)Math.Sqrt(xDiffStart * xDiffStart + yDiffStart * yDiffStart);
-            float startSimilarity = Math.Max(1 - (startDistance / maxStartDistance), 0);
-
-            //endDistance
-            float maxEndDistance = 100;
-            float xDiffEnd = lineEndPoint2.x - compareFinger.getLineEndPoint2().x;
-            float yDiffEnd = lineEndPoint2.y - compareFinger.getLineEndPoint2().y;
-            float endDistance = (float)Math.Sqrt(xDiffEnd * xDiffEnd + yDiffEnd * yDiffEnd);
-            float endSimilarity = Math.Max(1 - (endDistance / maxEndDistance), 0);
-
-            //direction
-            float scalaProduct = direction * compareFinger.getDirection();
-            float lengthDirection = direction.norm();
-            float lengthCompareDirection = compareFinger.getDirection().norm();
-            float directionSimilarity = Math.Abs(scalaProduct / (lengthDirection * lengthCompareDirection));
-
-            return (startSimilarity + endSimilarity + directionSimilarity) / 3;
+            //thresholds
+            float thresholdMaxAngle = (float) (15 * Math.PI / 180); // 15°
+            float thresholdMaxParallelDistance = 10;
+            float thresholdMaxVerticalDistance = 20;
+
+            //check angle
+            float angle = direction.getMinAngleBetween(mergeFinger.direction);
+            if (angle > thresholdMaxAngle) return false;
 
+            //check parallel distance
+            float minParallelDistance = getMinParallelDistance(mergeFinger);
+            if (minParallelDistance > thresholdMaxParallelDistance) return false;
+
+            //check vertical distance
+            float minVerticalDistance = getMinVerticalDistance(mergeFinger);
+            if (minVerticalDistance > thresholdMaxVerticalDistance) return false;
+
+            return true;
         }
 
-        private void updateFingerEndPoints() {
-            Vector<int> fp1 = fingerPoints[0];
-            Vector<int> fp2 = fingerPoints[0];
-            length = float.MinValue;
-
-            foreach (Vector<int> fp in fingerPoints) {
-                float distanceToFP1 = fp.subDistance(fp1, 2);
-                float distanceToFP2 = fp.subDistance(fp2, 2);
-
-                if (distanceToFP1 > length && distanceToFP1 >= distanceToFP2) {
-                    fp2 = fp;
-                    length = distanceToFP1;
-                }
-                else if (distanceToFP2 > length && distanceToFP2 > distanceToFP1) {
-                    fp1 = fp;
-                    length = distanceToFP2;
-                }
-            }
+        public void mergeFingers(Finger mergeFinger) {
+            Vector2D a1 = tipPoint;
+            Vector2D a2 = handPoint;
+            Vector2D b1 = mergeFinger.getTipPoint();
+            Vector2D b2 = mergeFinger.getHandPoint();
+
+            //find two points that are furthest apart
+            float distanceA1A2 = length;
+            float distanceA1B1 = a1.getDistanceTo(b1);
+            float distanceA1B2 = a1.getDistanceTo(b2);
+            float distanceA2B1 = a2.getDistanceTo(b1);
+            float distanceA2B2 = a2.getDistanceTo(b2);
+            float distanceB1B2 = mergeFinger.getLength();
+            float maxDistance = Math.Max(Math.Max(distanceA1A2, distanceA1B1), Math.Max(Math.Max(distanceA1B2, distanceA2B1), Math.Max(distanceA2B2, distanceB1B2)));
+
+            if(maxDistance == distanceA1A2) assignTipAndHandPoint(a1,a2);
+            else if(maxDistance == distanceA1B1) assignTipAndHandPoint(a1, b1);
+            else if(maxDistance == distanceA1B2) assignTipAndHandPoint(a1, b2);
+            else if(maxDistance == distanceA2B1) assignTipAndHandPoint(a2, b1);
+            else if(maxDistance == distanceA2B2) assignTipAndHandPoint(a2, b2);
+            else if(maxDistance == distanceB1B2) assignTipAndHandPoint(b1, b2);
+        }
 
-            if (fp1.y < fp2.y)
+        private void assignTipAndHandPoint(Vector2D p1, Vector2D p2)
+        {
+            if (p1.y < p2.y)
             {
-                tipPoint = fp1;
-                handPoint = fp2;
+                this.tipPoint = p1;
+                this.handPoint = p2;
             }
             else
             {
-                tipPoint = fp2;
-                handPoint = fp1;
+                this.tipPoint = p2;
+                this.handPoint = p1;
             }
 
-            fingerEndPointsUpToDate = true;
+            direction = handPoint - tipPoint;
+            length = direction.getLength();
         }
 
-        private void updateLine() {
-
-            if (!fingerEndPointsUpToDate) updateFingerEndPoints();
-
-            //update direction+pointOnLine
-            PointF[] pointArray = new PointF[fingerPoints.Count];
-            int i = 0;
-            foreach (Vector<int> fp in fingerPoints)
-            {
-                pointArray[i] = new PointF(fp.x, fp.y);
-                ++i;
-            }
-            PointF tempDirection;
-            PointF tempPointOnLine;
-            PointCollection.Line2DFitting(pointArray, Emgu.CV.CvEnum.DIST_TYPE.CV_DIST_L2, out tempDirection, out tempPointOnLine);
-            direction = new Vector<float>(tempDirection.X, tempDirection.Y);
-            pointOnLine = new Vector<float>(tempPointOnLine.X, tempPointOnLine.Y);
-
-            //update start+end
-            lineEndPoint1 = Vector<float>.projectToLine(tipPoint, direction, pointOnLine);
-            lineEndPoint2 = Vector<float>.projectToLine(handPoint, direction, pointOnLine);
-
-            lineUpToDate = true;
+        private float getMinParallelDistance(Finger finger)
+        {
+            Vector2D a1 = tipPoint;
+            Vector2D a2 = handPoint;
+            Vector2D b1 = finger.getTipPoint();
+            Vector2D b2 = finger.getHandPoint();
+
+            //project on finger line
+            Vector2D p1 = Vector2D.projectToLine(b1, direction, a1);
+            Vector2D p2 = Vector2D.projectToLine(b2, direction, a1);
+
+            float distanceP1B1 = p1.getDistanceTo(b1);
+            float distanceP2B2 = p2.getDistanceTo(b2);
+            return Math.Min(distanceP1B1, distanceP2B2);
         }
 
+        private float getMinVerticalDistance(Finger finger)
+        {
+            Vector2D a1 = tipPoint;
+            Vector2D a2 = handPoint;
+            Vector2D b1 = finger.getTipPoint();
+            Vector2D b2 = finger.getHandPoint();
+
+            //project on finger line
+            Vector2D p1 = Vector2D.projectToLine(b1, direction, a1);
+            Vector2D p2 = Vector2D.projectToLine(b2, direction, a1);
+
+            float distanceP1A1 = p1.getDistanceTo(a1);
+            float distanceP1A2 = p1.getDistanceTo(a2);
+            float distanceP2A1 = p2.getDistanceTo(a1);
+            float distanceP2A2 = p2.getDistanceTo(a2);
+            return Math.Min(Math.Min(distanceP1A1, distanceP1A2), Math.Min(distanceP2A1, distanceP2A2));
+        }
     }
 }

+ 99 - 108
bbiwarg/Detectors/Fingers/FingerDetector.cs

@@ -17,150 +17,141 @@ namespace bbiwarg.Detectors.Fingers
         private DepthImage depthImage;
         private EdgeImage edgeImage;
         private FingerImage fingerImage;
-        private List<Vector<int>> possibleFingerPoints;
-        private List<Finger> possibleFingers;
         private List<Finger> fingers;
+        Image<Gray, byte> fingerPoints;
 
         public FingerDetector(DepthImage depthImage, EdgeImage edgeImage, FingerImage fingerImage) {
             this.depthImage = depthImage;
             this.edgeImage = edgeImage;
             this.fingerImage = fingerImage;
 
-            findPossibleFingerPoints();
-            findPossibleFingers();
-            setFingers();
-            setFingerPoints();
+            Stopwatch sw = new Stopwatch();
+            sw.Start();
+
+            findFingerPoints();
+
+            sw.Stop();
+            Console.WriteLine("findFingerPoints:" + sw.ElapsedMilliseconds);
+            sw.Restart();
+
+            findFingers();
+
+            sw.Stop();
+            Console.WriteLine("findFingers:" + sw.ElapsedMilliseconds);
+
         }
 
         public List<Finger> getFingers() {
             return fingers;
         }
 
-        private void findPossibleFingerPoints()
-        {
+        private void findFingerPoints() {
             int width = depthImage.getWidth();
             int height = depthImage.getHeight();
-            int maxFingerSize = 30;
-            int minFingerSize = 10;
-            possibleFingerPoints = new List<Vector<int>>();
 
+            fingerPoints = new Image<Gray, byte>(width, height);
+            
             for (int y = 0; y < height; y++) {
                 for (int x = 0; x < width; x++) {
-                    if (edgeImage.isEdgeAt(x,y)) {
-                        //search horizontal
-                        bool edgeRightFound = false;
-                        int edgeRightX = x + minFingerSize;
-                        while (!edgeRightFound && edgeRightX < width) {
-                            if (edgeImage.isEdgeAt(edgeRightX,y))
-                                edgeRightFound = true;
-                            else
-                                edgeRightX++;
-                        }
-
-                        if (edgeRightFound){
-                            int midX = (edgeRightX + x) / 2;
-                            Int16 depthLeft = depthImage.getDepthAt(x, y);
-                            Int16 depthMid = depthImage.getDepthAt(midX, y);
-                            Int16 depthRight = depthImage.getDepthAt(edgeRightX, y);
-
-                            if ((edgeRightX - x) < maxFingerSize && depthLeft > depthMid && depthMid < depthRight) {
-                                possibleFingerPoints.Add(new Vector<int>(midX, y, depthMid)); 
-                                fingerImage.setFingerAt(midX, y, FingerImageState.possibleFinger);
-                            } 
-                        }
-
-                        //search vertical
-                        bool edgeBottomFound = false;
-                        int edgeBottomY = y + minFingerSize;
-                        while (!edgeBottomFound && edgeBottomY < height) {
-                            if (edgeImage.isEdgeAt(x, edgeBottomY))
-                                edgeBottomFound = true;
-                            else
-                                edgeBottomY++;
-                        }
-
-                        if (edgeBottomFound) {
-                            int midY = (edgeBottomY + y) / 2;
-                            Int16 depthTop = depthImage.getDepthAt(x, y);
-                            Int16 depthMid = depthImage.getDepthAt(x, midY);
-                            Int16 depthBottom = depthImage.getDepthAt(x, edgeBottomY);
-
-                            if ((edgeBottomY - y) < maxFingerSize && depthTop > depthMid && depthMid < depthBottom) {
-                                possibleFingerPoints.Add(new Vector<int>(x, midY, depthMid));
-                                fingerImage.setFingerAt(x, midY, FingerImageState.possibleFinger);
-                            }
-
-                        }
+                    if (edgeImage.isEdgeAt(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);
                     }
                 }
             }
         }
 
-        private void findPossibleFingers()
-        {
-            int width = depthImage.getWidth();
-            int height = depthImage.getHeight();
-            float fingerCylinderRadius = 5f;
-            possibleFingers = new List<Finger>();
-
-            foreach (Vector<int> pfp in possibleFingerPoints) {
-                //find nearest finger
-                List<Finger> nearFingerClusters = new List<Finger>();
-
-                for (int i = 0; i < possibleFingers.Count; i++)
-                {
-                    if (possibleFingers[i].isWithinDistance(pfp, fingerCylinderRadius)) {
-                        nearFingerClusters.Add(possibleFingers[i]);
-                    }
-                }
-
-                if (nearFingerClusters.Count == 0) {
-                    List<Vector<int>> fingerPoints = new List<Vector<int>>();
-                    fingerPoints.Add(pfp);
-                    possibleFingers.Add(new Finger(fingerPoints));
-                }
-                else if (nearFingerClusters.Count == 1)
-                    nearFingerClusters[0].addFingerPoint(pfp);
+        private void searchFingerPoint(Vector2D start, Vector2D direction, Image<Gray, byte> fingerPointsImage) {
+            int width = fingerPointsImage.Width;
+            int height = fingerPointsImage.Height;
+            float minFingerSize = 10;
+            float maxFingerSize = 30;
+            float stepSize = direction.getLength();
+
+
+            bool edgeFound = false;
+            Vector2D edge = start + minFingerSize * direction;
+            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 maxIndex = Math.Min(maxFingerSize, Math.Min(maxXIndex, maxYIndex));
+            
+            while (!edgeFound && index < maxIndex) {
+                if (edgeImage.isEdgeAt((int)edge.x, (int)edge.y))
+                    edgeFound = true;
                 else {
-                    //merge fingers
-                    List<Vector<int>> fingerPoints = new List<Vector<int>>();
-                    fingerPoints.Add(pfp);
-                    for (int j = 0; j < nearFingerClusters.Count; j++) {
-                        fingerPoints.Concat<Vector<int>>(nearFingerClusters[j].getFingerPoints());
-                        possibleFingers.Remove(nearFingerClusters[j]);
-                    }
-                    possibleFingers.Add(new Finger(fingerPoints));
+                    index += stepSize;
+                    edge += direction;
                 }
             }
+            
+            if (edgeFound && fingerDepthTest(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);
+            }
         }
 
-        private void setFingers()
-        {   
+        private bool fingerDepthTest(Vector2D p1, Vector2D 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);
+            return (depthP1 > depthMid && depthMid < depthP2);
+        }
+
+        private void findFingers()
+        {
             int width = depthImage.getWidth();
             int height = depthImage.getHeight();
-            float minFingerLength = 15.0f;
-            int minNumFingerPoints = 15;
+
+            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];
+
             fingers = new List<Finger>();
 
-            foreach (Finger finger in possibleFingers)
-            {
-                float length = finger.getLength();
-                int numFingerPoints = finger.getNumFingerPoints();
-                if (length > minFingerLength && numFingerPoints > minNumFingerPoints)
-                {
+            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);
+
+                List<Finger> mergeableFingers = new List<Finger>();
+
+                foreach (Finger f in fingers) {
+                    if (finger.isMergeable(f))
+                        mergeableFingers.Add(f);
+                }
+
+                if (mergeableFingers.Count == 0)
+                    fingers.Add(finger);
+                else if (mergeableFingers.Count == 1)
+                    mergeableFingers[0].mergeFingers(finger);
+                else {
+                    foreach (Finger mf in mergeableFingers) {
+                        finger.mergeFingers(mf);
+                        fingers.Remove(mf);
+                    }
                     fingers.Add(finger);
                 }
-            }      
-        }
+            }
 
-        private void setFingerPoints() {
-            //fingerImage.setFingers(fingers, FingerImageState.fingerDetected);
-            foreach (Finger finger in fingers) {
-                Vector<float> lineEndPoint1 = finger.getLineEndPoint1();
-                Vector<float> lineEndPoint2 = finger.getLineEndPoint2();
-                fingerImage.drawLine(lineEndPoint1, lineEndPoint2, FingerImageState.fingerDetected);
+            //draw fingers in fingerImage
+            foreach(Finger finger in fingers) {
+                fingerImage.drawLine(finger.getTipPoint(), finger.getHandPoint(), FingerImageState.fingerDetected);
             }
         }
-
     }
 }

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

@@ -54,7 +54,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) < minSimilarity)
                     {
                         tracked = false;
                         break;
@@ -63,7 +63,7 @@ namespace bbiwarg.Detectors.Fingers
                 }
                 if (tracked)
                 {
-                    fingerImage.drawLine(finger.getLineEndPoint1(), finger.getLineEndPoint2(), FingerImageState.fingerTracked);
+                    fingerImage.drawLine(finger.getTipPoint(), finger.getHandPoint(), FingerImageState.fingerTracked);
                     trackedFingers.Add(finger);
                 }
             }

+ 4 - 4
bbiwarg/Detectors/Touch/TouchDetector.cs

@@ -27,17 +27,17 @@ namespace bbiwarg.Detectors.Touch
             float floodValueThreshold = 0.5f;
 
             foreach (Finger finger in fingers) {
-                 Vector<int> tipPoint = finger.getTipPoint();
+                 Vector2D tipPoint = finger.getTipPoint();
 
-                float floodValue = getFloodValue(tipPoint.x, tipPoint.y);
+                float floodValue = getFloodValue((int)tipPoint.x, (int)tipPoint.y);
                 if (floodValue > floodValueThreshold)
                 {
                     //correct touchEvent position
-                    Vector<float> direction = finger.getDirection();
+                    Vector2D direction = finger.getDirection();
                     float directionFactor = -10;
                     float x = Math.Min(Math.Max(tipPoint.x + directionFactor * direction.x, 0), depthImage.getWidth()-1);
                     float y = Math.Min(Math.Max(tipPoint.y + directionFactor * direction.y, 0), depthImage.getHeight()-1);
-                    Vector<float> tep = new Vector<float>(new float[2]{x,y});
+                    Vector2D tep = new Vector2D(x,y);
 
                     touchImage.setTouchAt((int)tep.x, (int)tep.y, TouchImageState.touchDetected);
                     TouchEvent touchEvent = new TouchEvent((int)tep.x, (int)tep.y, floodValue, finger);

+ 1 - 1
bbiwarg/Graphics/OutputWindow.cs

@@ -132,7 +132,7 @@ namespace bbiwarg.Graphics
                     red = green = blue = 0;
                     if (videoHandle.isEdgeAt(x, y)) blue = Int16.MaxValue;
                     else if (fis == FingerImageState.fingerTracked) green = Int16.MaxValue;
-                    else if (fis == FingerImageState.fingerDetected) red = blue = Int16.MaxValue;
+                    else if (fis == FingerImageState.fingerDetected) red = blue = Int16.MaxValue / 2;
                     else if (fis == FingerImageState.possibleFinger) red = Int16.MaxValue;
 
                     edgeTextureData[index] = red;

+ 1 - 1
bbiwarg/Images/EdgeImage.cs

@@ -17,7 +17,7 @@ namespace bbiwarg.Images
             int maxDepth = depthImage.getMaxDepth();
             Image<Gray, Int16> depthImageInt16 = depthImage.getImage();
             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 = depthImageByte.Canny(150, 75, 3);
         }
 
         public bool isEdgeAt(int x, int y) {

+ 1 - 9
bbiwarg/Images/FingerImage.cs

@@ -34,15 +34,7 @@ namespace bbiwarg.Images
             return (FingerImageState)image.Data[y, x, 0];
         }
 
-        public void setFingers(List<Finger> fingers, FingerImageState state) {
-            foreach (Finger finger in fingers) {
-                foreach (Vector<int> fp in finger.getFingerPoints()) {
-                    setFingerAt(fp.x, fp.y, state);
-                }
-            }
-        }
-
-        public void drawLine(Vector<float> start, Vector<float> end, FingerImageState state)
+        public void drawLine(Vector2D start, Vector2D end, FingerImageState state)
         {
             int width = image.Width;
             int height = image.Height;

+ 22 - 2
bbiwarg/Utility/Vector.cs

@@ -33,10 +33,12 @@ namespace bbiwarg.Utility
         {
             this.elements = new T[numberOfElements];
         }
+
         public Vector(T[] elements)
         {
             this.elements = elements;
         }
+
         public Vector(Vector<T> vector)
         {
             this.elements = new T[vector.length()];
@@ -45,11 +47,13 @@ namespace bbiwarg.Utility
                 elements[i] = vector[i];
             }
         }
+
         public Vector<T> copy()
         {
             Vector<T> newVector = new Vector<T>(this);
             return newVector;
         }
+
         public T this[int index]
         {
             get
@@ -62,6 +66,7 @@ namespace bbiwarg.Utility
                 elements[index] = value;
             }
         }
+
         public int length()
         {
             return elements.Length;
@@ -124,6 +129,7 @@ namespace bbiwarg.Utility
             }
             return result;
         }
+
         public Vector<T> normalize() 
         {
             float norm = this.norm();
@@ -135,12 +141,12 @@ namespace bbiwarg.Utility
             return result;
         }
 
-
         private static void checkLength(Vector<T> vector1, Vector<T> vector2)
         {
             if (vector1.length() != vector2.length())
                 throw new ArgumentException("The vectors must have the same length");
         }
+
         public static Vector<T> operator +(Vector<T> summand1, Vector<T> summand2)
         {
             checkLength(summand1, summand2);
@@ -149,6 +155,7 @@ namespace bbiwarg.Utility
             result.add(summand2);
             return result;
         }
+
         public static Vector<T> operator -(Vector<T> minuend, Vector<T> subtrahend)
         {
             checkLength(minuend, subtrahend);
@@ -157,6 +164,7 @@ namespace bbiwarg.Utility
             result.subtract(subtrahend);
             return result;
         }
+
         public static T operator *(Vector<T> vector1, Vector<T> vector2)
         {
             checkLength(vector1, vector2);
@@ -168,6 +176,14 @@ namespace bbiwarg.Utility
             }
             return result;
         }
+
+        public static Vector<T> operator *(T factor, Vector<T> vector1)
+        {
+            Vector<T> result = new Vector<T>(vector1);
+            result.multiply(factor);
+            return result;
+        }
+
         public static bool operator ==(Vector<T> vector1, Vector<T> vector2)
         {
             checkLength(vector1, vector2);
@@ -182,10 +198,12 @@ namespace bbiwarg.Utility
             }
             return result;
         }
+
         public static bool operator !=(Vector<T> vector1, Vector<T> vector2)
         {
             return !(vector1 == vector2);
         }
+
         public static Vector<T> crossProduct(Vector<T> vector1, Vector<T> vector2)
         {
             if (vector1.length() != 3 || vector2.length() != 3)
@@ -198,6 +216,7 @@ namespace bbiwarg.Utility
 
             return result;
         }
+
         public static Vector<T> pointwiseMultiply(Vector<T> vector1, Vector<T> vector2)
         {
             checkLength(vector1, vector2);
@@ -208,6 +227,7 @@ namespace bbiwarg.Utility
             }
             return result;
         }
+
         public static float distancePointPlane(Vector<T> point, Vector<T> planeA, Vector<T> planeB, Vector<T> planeC)
         {
             //TODO - Diese funktion funktioniert nur mit T = float, 
@@ -240,7 +260,7 @@ namespace bbiwarg.Utility
 
         }
 
-        public static Vector<float> projectToLine(Vector<int> p, Vector<float> direction, Vector<float> pointOnLine)
+        public static Vector<float> projectToLine(Vector<float> p, Vector<float> direction, Vector<float> pointOnLine)
         {
             float px = p.x, py = p.y, dx = direction.x, dy = direction.y, ox = pointOnLine.x, oy = pointOnLine.y;
             float diffx = px - ox;

+ 75 - 0
bbiwarg/Utility/Vector2D.cs

@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace bbiwarg.Utility
+{
+    class Vector2D
+    {
+        public float x;
+        public float y;
+
+        public Vector2D(float x, float y) {
+            this.x = x;
+            this.y = y;
+        }
+
+        public float getLength() {
+            return (float) Math.Sqrt(x * x + y * y);
+        }
+
+        public float getDistanceTo(Vector2D vector) {
+            float xDiff = x - vector.x;
+            float yDiff = y - vector.y;
+            return (float)Math.Sqrt(xDiff * xDiff + yDiff * yDiff);
+        }
+
+        public float getMinAngleBetween(Vector2D vector) {
+            float angle = getAngleBetween(vector);
+            if (angle > Math.PI/2)
+                return (float) (Math.PI - angle);
+            else
+                return angle;
+        }
+
+        public float getAngleBetween(Vector2D vector) {
+            return (float)Math.Acos(dotProduct(vector) / (getLength() * vector.getLength()));
+        }
+
+        public float dotProduct(Vector2D vector) {
+            return x * vector.x + y * vector.y;
+        }
+
+        public static Vector2D projectToLine(Vector2D point, Vector2D direction, Vector2D pointOnLine) {
+            float px = point.x, py = point.y, dx = direction.x, dy = direction.y, ox = pointOnLine.x, oy = pointOnLine.y;
+            float diffx = px - ox;
+            float diffy = py - oy;
+
+            float diff_d = (diffx * dx + diffy * dy);
+            float d_d = (dx * dx + dy * dy);
+            float q = diff_d / d_d;
+
+            float newX = ox + q * dx;
+            float newY = oy + q * dy;
+
+            return new Vector2D(newX, newY);
+        }
+
+        public static Vector2D operator *(float scalar, Vector2D vector)
+        {
+            return new Vector2D(scalar * vector.x, scalar * vector.y);
+        }
+
+        public static Vector2D operator +(Vector2D vector1, Vector2D vector2)
+        {
+            return new Vector2D(vector1.x + vector2.x, vector1.y + vector2.y);
+        }
+
+        public static Vector2D operator -(Vector2D vector1, Vector2D vector2)
+        {
+            return new Vector2D(vector1.x - vector2.x, vector1.y - vector2.y);
+        }
+    }
+}

+ 1 - 0
bbiwarg/bbiwarg.csproj

@@ -84,6 +84,7 @@
     <Compile Include="MainBBWIWARG.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Utility\Vector.cs" />
+    <Compile Include="Utility\Vector2D.cs" />
     <Compile Include="VideoHandle.cs" />
   </ItemGroup>
   <ItemGroup>