Пример #1
0
        /**
         * Match tempalte across entire image
         **/
        private static double[,] MapGradient(HandFrame handFrame, double[,] xTemplate, double[,] yTemplate)
        {
            int imageWidth     = handFrame.width;
            int imageHeight    = handFrame.height;
            int templateWidth  = xTemplate.GetLength(1);
            int templateHeight = xTemplate.GetLength(0);

            double[,] outMatrix = new double[imageHeight - templateHeight, imageWidth - templateWidth];

            // Iterate through each of the image points
            for (int Y = 0; Y < imageHeight - templateHeight; Y++)
            {
                for (int X = 0; X < imageWidth - templateWidth; X++)
                {
                    double sum = 0;
                    // Iterate through each point in the template
                    for (int y = 0; y < templateHeight; y++)
                    {
                        for (int x = 0; x < templateWidth; x++)
                        {
                            sum += Math.Sqrt(Math.Pow(handFrame.dy[Y + y, X + x] - yTemplate[y, x], 2) + Math.Pow(handFrame.dx[Y + y, X + x] - xTemplate[y, x], 2));
                        }
                    }
                    outMatrix[Y, X] = sum;
                }
            }
            return(outMatrix);
        }
Пример #2
0
        private static bool ParticleGradient(HandFrame handFrame, HandPoint handObj)
        {
            int radius         = DetectionParameters.radiusFromHandPixel;
            int imageWidth     = handFrame.width;
            int imageHeight    = handFrame.height;
            int templateWidth  = DetectionParameters.dxTemplate.GetLength(1);
            int templateHeight = DetectionParameters.dxTemplate.GetLength(0);

            short x  = 0;
            short y  = 0;
            short dx = 6;
            short dy = (short)(Math.Sqrt(3) * dx / 2);

            int distanceBetweenParticles = (int)(templateWidth * (0.4)); // Half the width of a "finger"

            // TO DO: center the particles
            int numParticles = (imageWidth / dx) * (imageHeight / dy);

            particle[] particles = new particle[numParticles];

            // Initialize particles
            for (int i = 0; i < particles.Length; i++)
            {
                // Set initial x and y
                //short x = (short)((i * distanceBetweenParticles) % imageWidth);
                //short y = (short)(distanceBetweenParticles * ((i * distanceBetweenParticles) / imageWidth));

                // If the particle is within the depth range, initialize it.
                if (((handFrame.abs[y, x] > (handObj.Depth - 100)) && (handFrame.abs[y, x] < (handObj.Depth + 100))) && (Math.Sqrt((x - radius) * (x - radius) + (y - radius) * (y - radius)) < (radius - 1)))
                {
                    particles[i] = new particle((short)(x), (short)(y));
                }

                x += dx;
                if (x >= imageWidth)
                {
                    x  = 0;
                    y += dy;
                    if (y % 2 == 1)
                    {
                        x += (short)(dx / 2);
                    }
                }
            }

            // run for cycles up to the template width.
            int iterations = (int)(templateWidth / 2);

            for (int t = 0; t < iterations; t++)
            {
                particle.runTrace(particles, DetectionParameters.dxTemplate, DetectionParameters.dyTemplate, handFrame);
            }

            DetectFingers.Detect(particles, handObj, handFrame);

            return(true);
        }
Пример #3
0
        // Runs a convolution of a separable function, using a 1D Kernal that's been separated
        public static void seperableConv(double[] kernal, HandFrame handFrame)
        {
            int imageWidth  = handFrame.width;
            int imageHeight = handFrame.height;
            int kernLength  = kernal.Length;

            float[,] tempx = new float[imageHeight, imageWidth];
            float[,] tempy = new float[imageHeight, imageWidth];
            double sumx;
            double sumy;

            // Run through convolution in the x direction
            for (int y = 0; y < imageHeight; y++)
            {
                for (int x = 0; x < imageWidth - kernLength; x++)
                {
                    sumx = 0;
                    sumy = 0;
                    for (int n = 0; n < kernLength; n++)
                    {
                        sumx += handFrame.dx[y, x + n] * kernal[n];
                        sumy += handFrame.dy[y, x + n] * kernal[n];
                    }

                    tempx[y, x + Convert.ToInt32(kernLength / 2)] = (float)sumx;
                    tempy[y, x + Convert.ToInt32(kernLength / 2)] = (float)sumy;
                }
            }

            // Run through the convolution in the y direction
            for (int x = 0; x < imageWidth; x++)
            {
                for (int y = 0; y < imageHeight - kernLength; y++)
                {
                    sumx = 0;
                    sumy = 0;
                    for (int n = 0; n < kernLength; n++)
                    {
                        sumx += tempx[y + n, x] * kernal[n];
                        sumy += tempy[y + n, x] * kernal[n];
                    }

                    // Scales value back down
                    handFrame.dx[y + Convert.ToInt32(kernLength / 2), x] = (float)sumx;
                    handFrame.dy[y + Convert.ToInt32(kernLength / 2), x] = (float)sumy;
                }
            }
        }
Пример #4
0
        public static HandFrame zoomOnHand(short[] depthFrame, DepthFrameParams DFSettings, ObjectPoint handPos)
        {
            HandFrame HF = new HandFrame(DFSettings.Width, DFSettings.Height, handPos.X, handPos.Y, getRadiusFromHand(handPos.Depth));

            // converts the 2d X and Y from output matrix to the 1d array Depth Image: DeptImgWidth*Y + X
            // should have xShift and yShift incorporated??????
            int startPoint = DFSettings.Width * Math.Max(1, (handPos.Y - HF.radius)) + Math.Max(1, handPos.X - HF.radius);
            int endPoint   = Math.Min(depthFrame.Length - 1, DFSettings.Width * (handPos.Y + HF.radius) + handPos.X + HF.radius);

            int x = 0;
            int y = 0;

            for (int i = startPoint; i <= endPoint; i++)
            {
                // wraps the linear array to create the 2D Matrix
                if (x >= HF.width)
                {
                    i += DFSettings.Width - HF.width - 1;
                    x  = 0;
                    y++;
                    continue;
                }

                depthFrame[i] = (short)(depthFrame[i] >> DFSettings.Bitmask);

                // Kinect reports unknown values as -1 or 0
                if (depthFrame[i] <= 0 || depthFrame[i] >= handPos.Depth + HF.radius)
                {
                    depthFrame[i] = (short)(handPos.Depth + HF.radius);
                }

                HF.abs[y, x] = (short)(depthFrame[i]);
                HF.dx[y, x]  = threshold(depthFrame[i] - depthFrame[i - 1], FingerDetection.DetectionParameters.dxThreshold);
                HF.dy[y, x]  = threshold(depthFrame[i] - depthFrame[i - DFSettings.Width], FingerDetection.DetectionParameters.dyThreshold);

                x++;
            }

            return(HF);
        }
Пример #5
0
        public static int updateFingersFromDepth(short[] depthFrame, DepthFrameParams DFP, HandPoint[] hands)
        {
            // Check left hand
            if (hands[(int)HandPoint.HANDS.LEFT].tracked)
            {
                // Zoom on hand and get dx, dy
                HandFrame HF = ProcessDepthImage.zoomOnHand(depthFrame, DFP, hands[(int)HandPoint.HANDS.LEFT]);
                // Smooth dx, dy;
                Convolution.seperableConv(DetectionParameters.seperableKernal, HF);
                hands[(int)HandPoint.HANDS.LEFT].tracked = ParticleGradient(HF, hands[(int)HandPoint.HANDS.LEFT]);
            }

            // Check right hand
            if (hands[(int)HandPoint.HANDS.RIGHT].tracked)
            {
                // Zoom on hand and get dx, dy
                HandFrame HF = ProcessDepthImage.zoomOnHand(depthFrame, DFP, hands[(int)HandPoint.HANDS.RIGHT]);
                // Smooth dx, dy;
                Convolution.seperableConv(DetectionParameters.seperableKernal, HF);
                hands[(int)HandPoint.HANDS.RIGHT].tracked = ParticleGradient(HF, hands[(int)HandPoint.HANDS.RIGHT]);
            }

            return(1);
        }
Пример #6
0
        public static void Detect(particle[] particles, HandPoint h, HandFrame hf)
        {
            int radius = hf.radius;

            // Initialize an array of particles matching fingers
            particle[] f = new particle[5];
            for (int i = 0; i < f.Length; i++)
            {
                f[i] = new particle((short)(radius - 1), (short)(radius - 1));
            }

            if (particles != null)
            {
                // for each finger
                for (int i = 0; i < f.Length; i++)
                {
                    //h.fingers[i].position_Pixels += 0.1 * h.fingers[i].elapsedMillis * h.fingers[i].velocity_Pixels;

                    //double a = .25;
                    // get the best value
                    for (int j = 0; j < particles.Length; j++)
                    {
                        if (particles[j] != null && particles[j].match_coefficient > f[i].match_coefficient)
                        {
                            f[i].x = particles[j].x;
                            f[i].y = particles[j].y;
                            f[i].z = hf.abs[particles[j].y, particles[j].x];
                            f[i].match_coefficient = particles[j].match_coefficient;

                            //f[i].matchCoefficient /= (hf.abs[f[i].y, f[i].x] - h.Depth + 100);
                            //f[i].matchCoefficient /= ((1 - a) + a * DetectionParameters.gaussian(Math.Sqrt(
                            //     (particles[j].x - (h.fingers[i].X - h.X + radius))
                            //    * (particles[j].x - (h.fingers[i].X - h.X + radius))
                            //    + (particles[j].y - (h.fingers[i].Y - h.Y + radius))
                            //    * (particles[j].y - (h.fingers[i].Y - h.Y + radius))), 10));
                        }
                    }

                    // remove all particles within the finger area
                    for (int j = 0; j < particles.Length; j++)
                    {
                        // Remove particles within the radius of a finger
                        if (particles[j] != null &&
                            Math.Sqrt(
                                (particles[j].x - f[i].x) * (particles[j].x - f[i].x) +
                                (particles[j].y - f[i].y) * (particles[j].y - f[i].y)) <= SIZE_OF_FINGER_PIXELS)
                        //if (particles[j] != null && particles[j].x == f[i].x && particles[j].y == f[i].y)
                        {
                            particles[j] = null;
                        }
                    }

                    // Calculate rotations for the finger
                    SetFingerRotations(f[i], hf.abs[f[i].y, f[i].x], h.angle_from_elbow_degrees, radius);
                }
            }

            Array.Sort(f, Compare); // Sort the 5 fingers clockwise around the hand

            for (int i = 0; i < h.fingers.Length; i++)
            {
                h.fingers[i].updateKalman(new Point3D {
                    X = f[i].x - radius, Y = f[i].y - radius, Z = hf.abs[f[i].y, f[i].x] - h.position_pixels_absolute.Z
                });
                h.fingers[i].angle_from_hand_degrees.X = f[i].angle_from_hand_degrees.X;
            }
        }
Пример #7
0
        // Run one iteration of life-cycle for each particle and update
        internal static void runTrace(particle[] p, double[,] xT, double[,] yT, HandFrame image)
        {
            int templateHeight     = xT.GetLength(0);
            int templateWidth      = xT.GetLength(1);
            int halfTemplateHeight = Convert.ToInt32(templateHeight / 2);
            int halfTemplateWidth  = Convert.ToInt32(templateWidth / 2);

            // for each particle
            for (int i = 0; i < p.Length; i++)
            {
                // check if initialized
                if ((p[i] != null) && (p[i].alive))
                {
                    if (image.evaluated[p[i].y, p[i].x])
                    {
                        p[i] = null;
                        continue;
                    }
                    image.evaluated[p[i].y, p[i].x] = true;

                    // run match for each direction
                    int    testDirection   = p[i].previous_direction; // set the initial direction to test to the previous direction
                    double testCoefficient = p[i].previous_match_coefficient;
                    double tempCoefficient;

                    // test each direction around the point until you reach the starting point
                    // adds one more iteration if the 'first' bit is set.
                    int d = (p[i].previous_direction + 1) % 4;
                    if (p[i].previous_direction < 0)
                    {
                        p[i].previous_direction = 0;
                    }

                    do
                    {
                        // Run match
                        tempCoefficient = matchFilter(xT, yT, p[i].x + moveX[d] - halfTemplateWidth, p[i].y + moveY[d] - halfTemplateHeight, templateWidth, templateHeight, image);

                        // Test if value is better than previous direction
                        if (tempCoefficient > testCoefficient)
                        {
                            testCoefficient = tempCoefficient;
                            testDirection   = d;
                        }
                        d = ++d % 4;
                    } while (d != p[i].previous_direction);


                    // Test if final value is higher than the current center value
                    if (testCoefficient > p[i].match_coefficient)
                    {
                        //if (image.evaluate[p[i].y, p[i].x])
                        //{
                        //    p[i] = null;
                        //    continue;
                        //}
                        // Update particle values

                        // adjust the previous direction so that it is 180degrees when it is saved.
                        p[i].previous_direction         = (sbyte)((testDirection + 2) % 4);
                        p[i].previous_match_coefficient = p[i].match_coefficient;
                        p[i].match_coefficient          = testCoefficient;
                        p[i].x = (short)(p[i].x + moveX[testDirection]);
                        p[i].y = (short)(p[i].y + moveY[testDirection]);
                        //image.evaluate[p[i].y, p[i].x] = true;
                    }
                    // Otherwise, stop evaluating.
                    else
                    {
                        p[i].alive = false;
                    }
                }
            }
        }
Пример #8
0
        // Run one match filter
        static double matchFilter(double[,] xT, double[,] yT, int startX, int startY, int templateWidth, int templateHeight, HandFrame image)
        {
            // make sure we're in bounds
            if ((startX - 1 < 0) || (startX + templateWidth + 1 > image.width) || (startY - 1 < 0) || (startY + templateHeight + 1 > image.height))
            {
                return(0);
            }

            // Reset the sum
            double sum = 0;

            // iterate through x and y values running a absolute value of the difference
            for (int y = 0; y < templateHeight; y += 2)
            {
                for (int x = 0; x < templateWidth; x += 2)
                {
                    sum += image.dy[startY + y, startX + x] * yT[y, x] + image.dx[startY + y, startX + x] * xT[y, x];
                }
            }
            return(sum);
        }