//returns vector one minus vector two public static myCoord subtract(myCoord one, myCoord two) { myCoord toReturn = new myCoord(); toReturn.X = one.X - two.X; toReturn.Y = one.Y - two.Y; toReturn.Z = one.Z - two.Z; return(toReturn); }
private float fastDistanceFromPlane(myCoord point) { //source: http://mathworld.wolfram.com/Point-PlaneDistance.html //get a vector that represents moving from the point to the top left of the screen myCoord vectorFromPointToTopLeft = myCoord.subtract(point, KinectMainController.topLeft); return(myCoord.dotProduct(normalisedPlanePerpendicular, vectorFromPointToTopLeft)); }
private float fastDistanceFromPlane(myCoord point) { //source: http://mathworld.wolfram.com/Point-PlaneDistance.html //get a vector that represents moving from the point to the top left of the screen myCoord vectorFromPointToTopLeft = myCoord.subtract(point, KinectMainController.topLeft); return myCoord.dotProduct(normalisedPlanePerpendicular, vectorFromPointToTopLeft); }
//returns the scalar multiple of a given vector, without altering the original public static myCoord multByScalar(myCoord vector, float scalar) { myCoord toReturn = new myCoord(); toReturn.X = vector.X * scalar; toReturn.Y = vector.Y * scalar; toReturn.Z = vector.Z * scalar; return(toReturn); }
//returns the y coordinate of the point on the plane closest to this point private float yCoordPerpFromPlane(myCoord point) { //source: http://mathworld.wolfram.com/Point-PlaneDistance.html myCoord verticalEdgeDirection = myCoord.subtract(KinectMainController.topLeft, KinectMainController.bottomLeft); myCoord vectorFromPointToTopLeft = myCoord.subtract(KinectMainController.topLeft, point); return(myCoord.dotProduct(verticalEdgeDirection, vectorFromPointToTopLeft) / (float)Math.Pow(myCoord.norm(verticalEdgeDirection), 2)); }
private myCoord getCorner() { const float eps = 0.00006f; //epsilon value, dictates precision for the variance myCoord sample = new myCoord(); //sample data we get after each time span Queue <float> xQueue = new Queue <float>(10); //queues for the x, y, z values Queue <float> yQueue = new Queue <float>(10); //we get data every 0.2 seconds, and stop when we detect that the Queue <float> zQueue = new Queue <float>(10); //hand has stayed still for 2 seconds, hence analyse the last 10 values System.DateTime t1 = System.DateTime.Now; //current time System.TimeSpan span = new System.TimeSpan(0, 0, 0, 0, 200); //time span of 0.2 seconds between each sampling of the position System.DateTime t3 = new System.DateTime(); //time at which we have to get the new sample //fill the queues with the initial 10 samples while (xQueue.Count < 10) { t3 = t1.Add(span); //when we get the next round of data xQueue.Enqueue(xCoord); yQueue.Enqueue(yCoord); zQueue.Enqueue(zCoord); //get current round of data //wait until next round while (t1 < t3) { t1 = System.DateTime.Now; } } //compute the initial variances of position data float xVar = Variance(xQueue); float yVar = Variance(yQueue); float zVar = Variance(zQueue); //while the variances are to high, meaning the hand isn't still, keep tracking the hand while ((xVar > eps | yVar > eps | zVar > eps) || (xQueue.Average() == 0 && yQueue.Average() == 0 && zQueue.Average() == 0)) { t3 = t1.Add(span); //when we get next round of data xQueue.Dequeue(); yQueue.Dequeue(); zQueue.Dequeue(); //discard old data xQueue.Enqueue(xCoord); yQueue.Enqueue(yCoord); zQueue.Enqueue(zCoord); //get current round xVar = Variance(xQueue); yVar = Variance(yQueue); zVar = Variance(zQueue); //compute new variance //wait until next round while (t1 < t3) { t1 = System.DateTime.Now; } } //when the hand hasn't moved return it's position, averaging over the last 10 positions sample.X = xQueue.Average(); sample.Y = yQueue.Average(); sample.Z = zQueue.Average(); Console.Beep(); //give an audio confirmation to the user return(sample); }
//returns the cross product of vector one and vector two public static myCoord crossProduct(myCoord one, myCoord two) { //computed by definition of cross product myCoord answer = new myCoord(); answer.X = one.Y * two.Z - one.Z * two.Y; answer.Y = one.Z * two.X - one.X * two.Z; answer.Z = one.X * two.Y - one.Y - two.X; return(answer); }
//returns the distance of 'point' from the plane defined by the points planeOne, planeTwo, and planeThree. May be negative. public static float distanceFromPlane(myCoord planeOne, myCoord planeTwo, myCoord planeThree, myCoord point) { myCoord vectorFromPointToPlaneOne = subtract(point, planeOne); //compute plane perpendicular myCoord normalisedPlanePerpendicular = crossProduct(subtract(planeTwo, planeOne), subtract(planeThree, planeOne)); //normalise it normalisedPlanePerpendicular = multByScalar(normalisedPlanePerpendicular, 1 / norm(normalisedPlanePerpendicular)); //dot it with the vector from planeOne to point return(myCoord.dotProduct(normalisedPlanePerpendicular, vectorFromPointToPlaneOne)); }
public void justCalibrated() { //to get the normalised plane perpendicular (for caching): //source: http://mathworld.wolfram.com/Point-PlaneDistance.html //get a vector parallel to the top and side edges of the screen myCoord horizontalEdgeDirection = myCoord.subtract(KinectMainController.topRight, KinectMainController.topLeft); myCoord verticalEdgeDirection = myCoord.subtract(KinectMainController.bottomLeft, KinectMainController.topLeft); //get a vector perpendicular to the plane (not yet normalised) normalisedPlanePerpendicular = myCoord.crossProduct(horizontalEdgeDirection, verticalEdgeDirection); //normalise it - will fail if two points on the screen are in the same place (makes the planePerpendicular 0) - TODO I have NOT guarded against this normalisedPlanePerpendicular = myCoord.multByScalar(normalisedPlanePerpendicular, 1 / myCoord.norm(normalisedPlanePerpendicular)); }
//returns one 'dotproduct' two. public static float dotProduct(myCoord one, myCoord two) { return one.X * two.X + one.Y * two.Y + one.Z * two.Z; }
//returns one 'dotproduct' two. public static float dotProduct(myCoord one, myCoord two) { return(one.X * two.X + one.Y * two.Y + one.Z * two.Z); }
//returns the euclidean norm of a 3d vector public static float norm(myCoord vector) { return((float)Math.Sqrt(vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z)); }
void _sensor_AllFramesReady(object sender, AllFramesReadyEventArgs e) { if (!KinectMainController.isCalibrated || !KinectMainController.doMouseInput) { return; } Skeleton first = Kinetique.Calibrator.GetFirstSkeleton(e); if (first == null) { return; } var rightHand = first.Joints[JointType.HandRight]; if (rightHand.TrackingState != JointTrackingState.Tracked) { //Don't have a good read on the joints so we cannot process gestures return; } myCoord handLeft = new myCoord(); handLeft.X = first.Joints[JointType.HandLeft].Position.X; handLeft.Y = first.Joints[JointType.HandLeft].Position.Y; handLeft.Z = first.Joints[JointType.HandLeft].Position.Z; myCoord handRight = new myCoord(); handRight.X = first.Joints[JointType.HandRight].Position.X; handRight.Y = first.Joints[JointType.HandRight].Position.Y; handRight.Z = first.Joints[JointType.HandRight].Position.Z; //distance in metres from screen float handRightDistance = Math.Abs(fastDistanceFromPlane(handRight)); //scalars between 0 and 1 - 0 is the left, and the top float handRightX = xCoordPerpFromPlane(handRight); float handRightY = yCoordPerpFromPlane(handRight); outputToListener(handRightX, handRightY, handRightDistance, 0); ////distance in metres from screen float handLeftDistance = Math.Abs(fastDistanceFromPlane(handLeft)); //scalars between 0 and 1 - 0 is the left, and the top float handLeftX = xCoordPerpFromPlane(handLeft); float handLeftY = yCoordPerpFromPlane(handLeft); if (handLeftDistance < metresFromPlaneToDraw && !handDown[1]) { handDown[1] = true; if (!handDown[0]) { listener.MouseDown(mouseX, mouseY, 1); listener.MouseUp(mouseX, mouseY, 1); } } else if (handLeftDistance > metresFromPlaneToDraw && handDown[1]) { handDown[1] = false; } if (handRightDistance > 1 && handLeftDistance > 1) { KinectMainController.doGestureRecognition = false; } else { KinectMainController.doGestureRecognition = true; } }
//returns the y coordinate of the point on the plane closest to this point private float yCoordPerpFromPlane(myCoord point) { //source: http://mathworld.wolfram.com/Point-PlaneDistance.html myCoord verticalEdgeDirection = myCoord.subtract(KinectMainController.topLeft, KinectMainController.bottomLeft); myCoord vectorFromPointToTopLeft = myCoord.subtract(KinectMainController.topLeft, point); return myCoord.dotProduct(verticalEdgeDirection, vectorFromPointToTopLeft) / (float) Math.Pow(myCoord.norm(verticalEdgeDirection), 2); }
void _sensor_AllFramesReady(object sender, AllFramesReadyEventArgs e) { if (!KinectMainController.isCalibrated || !KinectMainController.doMouseInput) return; Skeleton first = Kinetique.Calibrator.GetFirstSkeleton(e); if (first == null) { return; } var rightHand = first.Joints[JointType.HandRight]; if (rightHand.TrackingState != JointTrackingState.Tracked) { //Don't have a good read on the joints so we cannot process gestures return; } myCoord handLeft = new myCoord(); handLeft.X = first.Joints[JointType.HandLeft].Position.X; handLeft.Y = first.Joints[JointType.HandLeft].Position.Y; handLeft.Z = first.Joints[JointType.HandLeft].Position.Z; myCoord handRight = new myCoord(); handRight.X = first.Joints[JointType.HandRight].Position.X; handRight.Y = first.Joints[JointType.HandRight].Position.Y; handRight.Z = first.Joints[JointType.HandRight].Position.Z; //distance in metres from screen float handRightDistance = Math.Abs(fastDistanceFromPlane(handRight)); //scalars between 0 and 1 - 0 is the left, and the top float handRightX = xCoordPerpFromPlane(handRight); float handRightY = yCoordPerpFromPlane(handRight); outputToListener(handRightX, handRightY, handRightDistance, 0); ////distance in metres from screen float handLeftDistance = Math.Abs(fastDistanceFromPlane(handLeft)); //scalars between 0 and 1 - 0 is the left, and the top float handLeftX = xCoordPerpFromPlane(handLeft); float handLeftY = yCoordPerpFromPlane(handLeft); if (handLeftDistance < metresFromPlaneToDraw && !handDown[1]) { handDown[1] = true; if (!handDown[0]) { listener.MouseDown(mouseX, mouseY, 1); listener.MouseUp(mouseX, mouseY, 1); } } else if (handLeftDistance > metresFromPlaneToDraw && handDown[1]) handDown[1] = false; if (handRightDistance > 1 && handLeftDistance > 1) KinectMainController.doGestureRecognition = false; else KinectMainController.doGestureRecognition = true; }
//returns vector one minus vector two public static myCoord subtract(myCoord one, myCoord two) { myCoord toReturn = new myCoord(); toReturn.X = one.X - two.X; toReturn.Y = one.Y - two.Y; toReturn.Z = one.Z - two.Z; return toReturn; }
//returns the euclidean norm of a 3d vector public static float norm(myCoord vector) { return (float)Math.Sqrt(vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z); }
//returns the scalar multiple of a given vector, without altering the original public static myCoord multByScalar(myCoord vector, float scalar) { myCoord toReturn = new myCoord(); toReturn.X = vector.X * scalar; toReturn.Y = vector.Y * scalar; toReturn.Z = vector.Z * scalar; return toReturn; }
//returns the distance of 'point' from the plane defined by the points planeOne, planeTwo, and planeThree. May be negative. public static float distanceFromPlane(myCoord planeOne, myCoord planeTwo, myCoord planeThree, myCoord point) { myCoord vectorFromPointToPlaneOne = subtract(point, planeOne); //compute plane perpendicular myCoord normalisedPlanePerpendicular = crossProduct(subtract(planeTwo, planeOne), subtract(planeThree, planeOne)); //normalise it normalisedPlanePerpendicular = multByScalar(normalisedPlanePerpendicular, 1 / norm(normalisedPlanePerpendicular)); //dot it with the vector from planeOne to point return myCoord.dotProduct(normalisedPlanePerpendicular, vectorFromPointToPlaneOne); }
//returns the cross product of vector one and vector two public static myCoord crossProduct(myCoord one, myCoord two) { //computed by definition of cross product myCoord answer = new myCoord(); answer.X = one.Y * two.Z - one.Z * two.Y; answer.Y = one.Z * two.X - one.X * two.Z; answer.Z = one.X * two.Y - one.Y - two.X; return answer; }
private myCoord getCorner() { const float eps = 0.00006f; //epsilon value, dictates precision for the variance myCoord sample = new myCoord(); //sample data we get after each time span Queue<float> xQueue = new Queue<float>(10); //queues for the x, y, z values Queue<float> yQueue = new Queue<float>(10); //we get data every 0.2 seconds, and stop when we detect that the Queue<float> zQueue = new Queue<float>(10); //hand has stayed still for 2 seconds, hence analyse the last 10 values System.DateTime t1 = System.DateTime.Now; //current time System.TimeSpan span = new System.TimeSpan(0, 0, 0, 0, 200); //time span of 0.2 seconds between each sampling of the position System.DateTime t3 = new System.DateTime(); //time at which we have to get the new sample //fill the queues with the initial 10 samples while (xQueue.Count < 10) { t3 = t1.Add(span); //when we get the next round of data xQueue.Enqueue(xCoord); yQueue.Enqueue(yCoord); zQueue.Enqueue(zCoord); //get current round of data //wait until next round while (t1 < t3) { t1 = System.DateTime.Now; } } //compute the initial variances of position data float xVar = Variance(xQueue); float yVar = Variance(yQueue); float zVar = Variance(zQueue); //while the variances are to high, meaning the hand isn't still, keep tracking the hand while ((xVar > eps | yVar > eps | zVar > eps) || (xQueue.Average() == 0 && yQueue.Average() == 0 && zQueue.Average() == 0)) { t3 = t1.Add(span); //when we get next round of data xQueue.Dequeue(); yQueue.Dequeue(); zQueue.Dequeue(); //discard old data xQueue.Enqueue(xCoord); yQueue.Enqueue(yCoord); zQueue.Enqueue(zCoord); //get current round xVar = Variance(xQueue); yVar = Variance(yQueue); zVar = Variance(zQueue); //compute new variance //wait until next round while (t1 < t3) { t1 = System.DateTime.Now; } } //when the hand hasn't moved return it's position, averaging over the last 10 positions sample.X = xQueue.Average(); sample.Y = yQueue.Average(); sample.Z = zQueue.Average(); Console.Beep(); //give an audio confirmation to the user return sample; }