/** * The main data extraction work is done in the constructor. * * This is where we: * * 1) Resample the trajectory to a fixed number * of points (resample_cnt). * * 2) Calculate the normalized direction vector * between each resampled point or the z-score * normalized points. * * 3) Extract correction factor related data. * * It is highly recommended that the sample trajectory points * have been smoothed with a low pass filter before calling * this function. A simple exponential smoothing filter will * probably be adequate for most case. */ public JackknifeFeatures(JackknifeBlades blades, List <Vector> points) { this.Vecs = new List <Vector>(); // Number of components per point. int m = points[0].Size; // resample the trajectory to a fixed number of points this.Pts = Mathematics.Resample(points, blades.ResampleCnt); // To track the bounding box widths, // start with one point and expand. Vector minimum = new Vector(Pts[0].Data); Vector maximum = new Vector(Pts[0].Data); // The abs distance traversed starts with zeros. this.Abs = new Vector(0, m); // Incrementally extract information. for (int i = 1; i < blades.ResampleCnt; i++) { // In-between point direction vector. Vector vec = Pts[i] - Pts[i - 1]; // Update correction factor features. for (int j = 0; j < m; j++) { this.Abs[j] += Math.Abs(vec[j]); minimum[j] = Math.Min(minimum[j], Pts[i][j]); maximum[j] = Math.Max(maximum[j], Pts[i][j]); } // Save the points or direction vectors, // depending on the selected measure. if (blades.InnerProduct) { this.Vecs.Add(vec.Normalize()); } else if (blades.EuclideanDistance) { // In ED scenario, make sure not to forget first point as // loop starts at 1. if (i == 1) { this.Vecs.Add(Pts[0]); } this.Vecs.Add(Pts[i]); } else { throw new Exception("This should not happen!"); } } // Z-score normalize the vecs if required, // typically only if using euclidean distance if (blades.ZNormalize) { Mathematics.ZNormalize(this.Vecs); } // normalize the correction factor vectors this.Abs.Normalize(); this.Bb = (maximum - minimum).Normalize(); }
/** * Learn a rejection threshold for each template. * Call after all templates have been added. * * See explanation in jackknife_train to understand * the input parameters. */ public void Train(int gpsrN, int gpsrR, double beta) { int template_cnt = templates.Count; List <Distributions> distributions = new List <Distributions>(); List <Vector> synthetic = new List <Vector>(); double worst_score = 0.0; Random rand = new Random(); // // Create negative samples. // for (int i = 0; i < 1000; i++) { synthetic.Clear(); // Splice two samples together // to create one negative sample. for (int j = 0; j < 2; j++) { int t = rand.Next(template_cnt); Sample s = templates[t].Sample; int len = s.Trajectory.Count; int start = rand.Next(len / 2); for (int kk = 0; kk < len / 2; kk++) { synthetic.Add(s.Trajectory[start + kk]); } } JackknifeFeatures features = new JackknifeFeatures(Blades, synthetic); // and score it for (int t = 0; t < template_cnt; t++) { double score = DTW( features.Vecs, templates[t].Features.Vecs); if (worst_score < score) { worst_score = score; } if (i > 50) { distributions[t].AddNegativeScore(score); } } // Generate a few samples to get an estimate // of worst possible score. if (i != 50) { continue; } // allocate distributions for (int t = 0; t < template_cnt; t++) { distributions.Add(new Distributions(worst_score, 1000)); } } // // Create positive examples. // for (int t = 0; t < template_cnt; t++) { for (int i = 0; i < 1000; i++) { synthetic.Clear(); // Create a synthetic variation of the sample. synthetic = Mathematics.GPSR(templates[t].Sample.Trajectory, gpsrN, 0.25, gpsrR); JackknifeFeatures features = new JackknifeFeatures(Blades, synthetic); // and score it double score = DTW(features.Vecs, templates[t].Features.Vecs); distributions[t].AddPositiveScore(score); } } // // Now extract the rejection thresholds. // for (int t = 0; t < template_cnt; t++) { double threshold = distributions[t].RejectionThreshold(beta); JackknifeTemplate temp = templates[t]; temp.RejectionThreshold = threshold; templates[t] = temp; } }