Beispiel #1
0
        public Program()
        {
            List <Point_2D> gesture = new List <Point_2D>();

            string line;

            while ((line = Console.ReadLine()) != null && line != "")
            {
                string[] value_str  = line.Split(' ');
                var      data_point = new Point_2D();
                data_point.time = float.Parse(value_str[0]);
                data_point.x    = float.Parse(value_str[1]);
                data_point.y    = float.Parse(value_str[2]);
                data_point.z    = float.Parse(value_str[3]);
                gesture.Add(data_point);
            }

            // above is for demo code only
            Console.WriteLine("start");
            var watch = System.Diagnostics.Stopwatch.StartNew();

            Bounds       bounds = calculate_bounds(ref gesture, 0, gesture.Count);
            List <float> angles = new List <float>();

            if (LP_ENABLE)
            {
                gesture = gaussian_average_lowpass(gesture, LP_KERNEL_SIZE, LP_SIGMA);
            }

            float    angle_sum    = calculate_angles(ref gesture, ref angles, bounds);
            Point_2D avg_vel_vec2 = mean_velocity_2D(ref gesture);
            //Point_3D avg_vel_vec3 = mean_velocity_3D(ref gesture3D);

            float    gesture_width  = bounds.max_x - bounds.min_x;
            float    gesture_height = bounds.max_y - bounds.min_y;
            float    gesture_depth  = bounds.max_z - bounds.min_z;
            Point_2D start          = gesture[0];
            Point_2D end            = gesture[gesture.Count - 1];

            Gesture_Meta ret = new Gesture_Meta();

            ret.type = Gesture.unknown;
            //ret.avg_vel_vector = avg_vel_vec3;
            ret.angle_sum = angle_sum;
            ret.bounds    = bounds;

            // get velocity & acceleration vectors for gestures
            List <Point_2D> sparse_gesture = sparsify(ref gesture);
            List <Point_2D> vel_vectors    = derive_vector_list(ref sparse_gesture);
            List <Point_2D> acc_vectors    = derive_vector_list(ref vel_vectors);

            float[] vel_norms     = vector_list_norms(ref vel_vectors, true);
            float[] acc_norms     = vector_list_norms(ref acc_vectors, true);
            float[] global_angles = vector_list_angles(ref sparse_gesture);

            // ******************** gesture classification *********************
            float vel_vec_norm = vec2_norm(avg_vel_vec2, false);
            float x_pos_dev    = angle(avg_vel_vec2, new Point_2D(0, 1, 0, 0), false);
            float y_pos_dev    = angle(avg_vel_vec2, new Point_2D(0, 0, 1, 0), false);
            float z_pos_dev    = angle(avg_vel_vec2, new Point_2D(0, 0, 0, 1), false);
            float x_neg_dev    = angle(avg_vel_vec2, new Point_2D(0, -1, 0, 0), false);
            float y_neg_dev    = angle(avg_vel_vec2, new Point_2D(0, 0, -1, 0), false);
            float z_neg_dev    = angle(avg_vel_vec2, new Point_2D(0, 0, 0, -1), false);
            bool  x_pos        = x_pos_dev < x_neg_dev;
            bool  y_pos        = y_pos_dev < y_neg_dev;
            bool  z_pos        = z_pos_dev < z_neg_dev;
            bool  z_gesture    = gesture_depth > gesture_height &&
                                 gesture_depth > gesture_width;

            if (vel_vec_norm < VEL_VEC_NORM_THRESH && Math.Abs(angle_sum) > 6 * ANGLE_SUM_THRESH)
            {
                // likely a circle
                float min_angle = (float)((2 - ANGLE_SUM_THRESH) * Math.PI);
                float max_angle = (float)((2 + ANGLE_SUM_THRESH) * Math.PI);
                if (angle_sum > min_angle && angle_sum < max_angle)
                {
                    ret.type = Gesture.circle_ccw;
                }
                if (angle_sum < -min_angle && angle_sum > -max_angle)
                {
                    ret.type = Gesture.circle_cw;
                }
            }
            else if (vel_vec_norm > VEL_VEC_NORM_THRESH && z_gesture || gesture_depth > Z_DEPTH_THRESH)
            {
                // likely a gesture with depth
                if (z_pos_dev < ANGLE_DEVIATION_THRESH && Math.Abs(avg_vel_vec2.z) > 0.2)
                {
                    ret.type = Gesture.push;
                }
                else if (z_neg_dev < ANGLE_DEVIATION_THRESH && Math.Abs(avg_vel_vec2.z) > 0.2)
                {
                    ret.type = Gesture.pull;
                }
            }
            else if (ret.type == Gesture.unknown)
            {
                // likely a gesture of one or more line segments
                List <LinearSegment> segments = find_linear_segments(global_angles, sparse_gesture, bounds);
                Console.WriteLine(segments.Count);

                foreach (var s in segments)
                {
                    Console.WriteLine(s.val + " " + s.weight);
                }

                //Gesture[] candidate_gestures = gesture_len_map[segments.Count];
                Gesture[] candidate_gestures;
                gesture_len_map.TryGetValue(segments.Count, out candidate_gestures);
                if (candidate_gestures != null)
                {
                    foreach (Gesture g in candidate_gestures)
                    {
                        if (matches_linear_segments(segments, g, sparse_gesture,
                                                    alt_start_allowed_map[g]))
                        {
                            ret.type = g;
                            break;
                        }
                    }
                }
            }

            // Debug print
            watch.Stop();
            float time = watch.ElapsedMilliseconds;

            Console.WriteLine(time + "ms");
            Console.WriteLine(ret.type);

            //HoughPoint[] hh = hough_transform(sparse_gesture);
            //foreach(var h in hh) {
            //    Console.WriteLine(h.i + ": " /*+ h.r + " "*/ + h.phi + " @ " + h.weight);
            //}
        }
    public Gesture_Meta recognize_gesture(List <Point_2D> gesture, List <Point_3D> gesture3D)
    {
        if (gesture.Count <= 2 * LP_KERNEL_SIZE)
        {
            var gm = new Gesture_Meta();
            gm.type = Gesture.unknown;
            return(gm);
        }
        Bounds       bounds = calculate_bounds(ref gesture, 0, gesture.Count);
        List <float> angles = new List <float>();

        if (LP_ENABLE)
        {
            gesture = gaussian_average_lowpass(gesture, LP_KERNEL_SIZE, LP_SIGMA);
        }

        float    angle_sum    = calculate_angles(ref gesture, ref angles, bounds);
        Point_2D avg_vel_vec2 = mean_velocity_2D(ref gesture);
        Point_3D avg_vel_vec3 = mean_velocity_3D(ref gesture3D);

        float    gesture_width  = bounds.max_x - bounds.min_x;
        float    gesture_height = bounds.max_y - bounds.min_y;
        float    gesture_depth  = bounds.max_z - bounds.min_z;
        Point_2D start          = gesture[0];
        Point_2D end            = gesture[gesture.Count - 1];

        Gesture_Meta ret = new Gesture_Meta();

        ret.type           = Gesture.unknown;
        ret.avg_vel_vector = avg_vel_vec3;
        ret.angle_sum      = angle_sum;
        ret.bounds         = bounds;

        List <Point_2D> sparse_gesture = sparsify(ref gesture);

        float[] global_angles = vector_list_angles(ref sparse_gesture);

        // ************************ Classify gesture **************************
        float vel_vec_norm = vec2_norm(avg_vel_vec2, false);
        float x_pos_dev    = angle(avg_vel_vec2, new Point_2D(0, 1, 0, 0), false);
        float y_pos_dev    = angle(avg_vel_vec2, new Point_2D(0, 0, 1, 0), false);
        float z_pos_dev    = angle(avg_vel_vec2, new Point_2D(0, 0, 0, 1), false);
        float x_neg_dev    = angle(avg_vel_vec2, new Point_2D(0, -1, 0, 0), false);
        float y_neg_dev    = angle(avg_vel_vec2, new Point_2D(0, 0, -1, 0), false);
        float z_neg_dev    = angle(avg_vel_vec2, new Point_2D(0, 0, 0, -1), false);
        bool  x_pos        = x_pos_dev < x_neg_dev;
        bool  y_pos        = y_pos_dev < y_neg_dev;
        bool  z_pos        = z_pos_dev < z_neg_dev;
        bool  z_gesture    = gesture_depth > gesture_height &&
                             gesture_depth > gesture_width;

        // likely a gesture with depth
        if (vel_vec_norm > VEL_VEC_NORM_THRESH && z_gesture || gesture_depth > Z_DEPTH_THRESH)
        {
            if (z_pos_dev < ANGLE_DEVIATION_THRESH && Math.Abs(avg_vel_vec2.z) > 0.2)
            {
                ret.type = Gesture.push;
            }
            else if (z_neg_dev < ANGLE_DEVIATION_THRESH && Math.Abs(avg_vel_vec2.z) > 0.2)
            {
                ret.type = Gesture.pull;
            }
        }

        // likely a gesture of one or more line segments
        if (ret.type == Gesture.unknown)
        {
            List <LinearSegment> segments = find_linear_segments(global_angles, sparse_gesture, bounds);
            Console.WriteLine(segments.Count);

            Gesture[] candidate_gestures;
            gesture_len_map.TryGetValue(segments.Count, out candidate_gestures);
            if (candidate_gestures != null)
            {
                foreach (Gesture g in candidate_gestures)
                {
                    if (matches_linear_segments(segments, g, sparse_gesture,
                                                alt_start_allowed_map[g]))
                    {
                        ret.type = g;
                        break;
                    }
                }
            }
        }

        // likely a circle
        if (ret.type == Gesture.unknown)
        {
            // likely a circle
            float min_angle = (float)((2 - ANGLE_SUM_THRESH) * Math.PI);
            float max_angle = (float)((2 + ANGLE_SUM_THRESH) * Math.PI);
            if (angle_sum > min_angle && angle_sum < max_angle)
            {
                ret.type = Gesture.circle_ccw;
            }
            else if (angle_sum < -min_angle && angle_sum > -max_angle)
            {
                ret.type = Gesture.circle_cw;
            }
            else if (angle_sum > 6 * Math.PI)
            {
                ret.type = Gesture.spiral_ccw;
            }
        }

        return(ret);
    }