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); }