/** * Check if buffer matches a certain template */ public bool IsMatch( List <Vector> trajectory, int gid, out double score) { JackknifeFeatures features = new JackknifeFeatures(Blades, trajectory); double best_score = double.PositiveInfinity; bool ret = false; for (int tid = 0; tid < templates.Count; tid++) { if (templates[tid].Sample.GestureId != gid) { continue; } double cf = 1; if (Blades.CFAbsDistance) { cf *= 1.0 / Math.Max(0.01, features.Abs.Dot(templates[tid].Features.Abs)); } if (Blades.CFBbWidths) { cf *= 1.0 / Math.Max(0.01, features.Bb.Dot(templates[tid].Features.Bb)); } JackknifeTemplate temp = templates[tid]; temp.CF = cf; templates[tid] = temp; if (Blades.LowerBound) { JackknifeTemplate tempLB = templates[tid]; tempLB.LB = cf * LowerBound(features.Vecs, templates[tid]); templates[tid] = tempLB; } double d = templates[tid].CF; d *= DTW(features.Vecs, templates[tid].Features.Vecs); if (d < templates[tid].RejectionThreshold) { ret = true; } if (d < best_score) { best_score = d; } } score = best_score; return(ret); }
/** * Check if buffer matches a certain template */ public List <Machete.ContinuousResult> IsMatch( List <Vector> trajectory, int start, int end) { List <Machete.ContinuousResult> res = new List <Machete.ContinuousResult>(); JackknifeFeatures features = new JackknifeFeatures(Blades, trajectory); for (int tid = 0; tid < templates.Count; tid++) { double cf = 1; if (Blades.CFAbsDistance) { cf *= 1.0 / Math.Max(0.01, features.Abs.Dot(templates[tid].Features.Abs)); } if (Blades.CFBbWidths) { cf *= 1.0 / Math.Max(0.01, features.Bb.Dot(templates[tid].Features.Bb)); } //JackknifeTemplate temp = templates[tid]; //temp.CF = cf; //templates[tid] = temp; templates[tid].CF = cf; if (Blades.LowerBound) { JackknifeTemplate tempLB = templates[tid]; tempLB.LB = cf * LowerBound(features.Vecs, templates[tid]); templates[tid] = tempLB; } double d = templates[tid].CF; d *= DTW(features.Vecs, templates[tid].Features.Vecs); if (d < templates[tid].RejectionThreshold) { // Add to the Continuous Results Machete.ContinuousResult cr = new Machete.ContinuousResult(); cr.startFrameNo = start; cr.endFrameNo = end; cr.score = d; cr.gid = templates[tid].GestureId; res.Add(cr); } } return(res); }
/** * Constructor. */ public JackknifeTemplate(JackknifeBlades blades, Sample sample) { this.Sample = sample; GestureId = sample.GestureId; // Any default value less than zero will ensure if // lower bounding is disabled, we don't cull any // instance. LB = -1; // A default value of one will ensure that the DTW // score is not modified when all correction factors // are disabled. CF = 1; // A default value that will never cause rejection. // So if the recognizer is not trained, things will // still work as expected. RejectionThreshold = double.PositiveInfinity; Lower = new List <Vector>(); Upper = new List <Vector>(); // Extract import information about the sample. Features = new JackknifeFeatures(blades, sample.Trajectory); List <Vector> vecs = Features.Vecs; int componentCnt = vecs[0].Size; // For each component find the min and max value // within the radius (Sakoe-Chiba band). for (int i = 0; i < vecs.Count; i++) { Vector maximum = new Vector(double.NegativeInfinity, componentCnt); Vector minimum = new Vector(double.PositiveInfinity, componentCnt); for (int j = Math.Max(0, i - blades.Radius); j < Math.Min(i + blades.Radius + 1, vecs.Count); j++) { for (int k = 0; k < componentCnt; k++) { maximum[k] = Math.Max(maximum[k], vecs[j][k]); minimum[k] = Math.Min(minimum[k], vecs[j][k]); } } Upper.Add(maximum); Lower.Add(minimum); } }
/** * 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; } }
/** * Determine gesture class of the given sample. * The gesture id is returned. * * This function can be modified to return an n-best list, but * because of early rejection, such a list may not make sense. * */ public int Classify(List <Vector> trajectory) { JackknifeFeatures features = new JackknifeFeatures(Blades, trajectory); int templateCnt = templates.Count; for (int t = 0; t < templateCnt; t++) { double cf = 1; if (Blades.CFAbsDistance) { cf *= 1 / Math.Max(0.01, features.Abs.Dot(templates[t].Features.Abs)); } if (Blades.CFBbWidths) { cf *= 1 / Math.Max(0.01, features.Bb.Dot(templates[t].Features.Bb)); } JackknifeTemplate temp = templates[t]; temp.CF = cf; templates[t] = temp; if (Blades.LowerBound) { JackknifeTemplate tempLB = templates[t]; tempLB.LB = cf * LowerBound(features.Vecs, templates[t]); templates[t] = tempLB; } } templates.Sort(new SortTemplate()); double best = double.PositiveInfinity; int ret = -1; for (int t = 0; t < templateCnt; t++) { if (templates[t].LB > templates[t].RejectionThreshold) { continue; } if (templates[t].LB > best) { continue; } double score = templates[t].CF; score *= DTW(features.Vecs, templates[t].Features.Vecs); if (score > templates[t].RejectionThreshold) { continue; } if (score < best) { best = score; ret = templates[t].GestureId; } } return(ret); }