/** * Turn sample into template. */ public void AddTemplate(Sample sample) { JackknifeTemplate t = new JackknifeTemplate(Blades, sample); templates.Add(t); int newlen = sample.Trajectory.Count; if (!templateLenghts.ContainsKey(sample.GestureId)) { templateLenghts.Add(sample.GestureId, newlen); } try { if (templateLenghts[sample.GestureId] < newlen) { templateLenghts[sample.GestureId] = newlen; } } catch (KeyNotFoundException) { } if (newlen > maxTemplateLen) { maxTemplateLen = newlen; } if (newlen < minTemplateLen) { minTemplateLen = newlen; } }
/** * Hardcode the rejection thresholds */ public void SetRejectionThresholds(double rt) { for (int t = 0; t < templates.Count; t++) { JackknifeTemplate temp = templates[t]; temp.RejectionThreshold = rt; templates[t] = temp; } }
/** * 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); }
/** * Find the lower bound score for a candidate * against a given template. */ private double LowerBound(List <Vector> vecs, JackknifeTemplate t) { double lb = 0.0; // lower bound int component_cnt = vecs[0].Size; for (int i = 0; i < vecs.Count; i++) { double cost = 0.0; for (int j = 0; j < component_cnt; j++) { if (Blades.InnerProduct) { if (vecs[i][j] < 0.0) { cost += vecs[i][j] * t.Lower[i][j]; } else { cost += vecs[i][j] * t.Upper[i][j]; } } else if (Blades.EuclideanDistance) { double diff = 0.0; if (vecs[i][j] < t.Lower[i][j]) { diff = vecs[i][j] - t.Lower[i][j]; } else if (vecs[i][j] > t.Upper[i][j]) { diff = vecs[i][j] - t.Upper[i][j]; } cost += (diff * diff); } else { throw new Exception("Should not get here!"); } } // inner products are bounded if (Blades.InnerProduct) { cost = 1.0 - Math.Min(1.0, Math.Max(-1.0, cost)); } lb += cost; } return(lb); }
/** * 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); }
/** * 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; } }
/** * Turn sample into template. */ public void AddTemplate(Sample sample) { JackknifeTemplate t = new JackknifeTemplate(Blades, sample); templates.Add(t); }
/** * 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); }