/// <summary> /// one sample stroke contains many template strokes /// </summary> /// <param name="sample"></param> /// <param name="template"></param> /// <returns>stroke index -> list of template indices it contains</returns> public static List <List <int> > StrokeToStrokeCorrespondenceConcatenating(List <SketchStroke> sample, List <SketchStroke> template) { List <List <int> > result = new List <List <int> >(); List <KeyValuePair <SketchStroke, int> > templateStrokeToIndex = new List <KeyValuePair <SketchStroke, int> >(); for (int i = 0; i < template.Count; i++) { templateStrokeToIndex.Add(new KeyValuePair <SketchStroke, int>(template[i], i)); } foreach (SketchStroke sampleStroke in sample) { templateStrokeToIndex.Sort((t1, t2) => SketchTools.DirectedHausdorffDistance(t1.Key.Points, sampleStroke.Points).CompareTo(SketchTools.DirectedHausdorffDistance(t2.Key.Points, sampleStroke.Points))); double currHausdorffFromSampleToTemplateList = double.MaxValue; SketchStroke currConcatenated = new SketchStroke(); List <int> currListIndices = new List <int>(); foreach (KeyValuePair <SketchStroke, int> pair in templateStrokeToIndex) { SketchStroke newConcatenated = SketchStroke.ConcatenateStrokes(pair.Key, currConcatenated); double newDistance = SketchTools.HausdorffDistance(sampleStroke, newConcatenated); if (newDistance < currHausdorffFromSampleToTemplateList) { currHausdorffFromSampleToTemplateList = newDistance; currConcatenated = newConcatenated; currListIndices.Add(pair.Value); } } result.Add(currListIndices); foreach (int currIndex in currListIndices) { templateStrokeToIndex.Remove(new KeyValuePair <SketchStroke, int>(template[currIndex], currIndex)); } } return(result); }
/// <summary> /// one to one, one to many, or many to one, result is from template to sample strokes /// </summary> /// <param name="sample"></param> /// <param name="template"></param> /// <returns></returns> public static List <List <int>[]> StrokeToStrokeCorrespondenceDifferentCountStartFromSample(List <SketchStroke> sample, List <SketchStroke> template) { List <List <int>[]> result = new List <List <int>[]>(); HashSet <int> usedSampleIndices = new HashSet <int>(); HashSet <int> usedTemplateIndices = new HashSet <int>(); List <SketchStroke> sampleNormalized = SketchPreprocessing.Normalize(sample, 128, 500, new SketchPoint(0.0, 0.0)); List <SketchStroke> templateNormalized = SketchPreprocessing.Normalize(template, 128, 500, new SketchPoint(0.0, 0.0)); int si = 0; while (si < sample.Count && usedTemplateIndices.Count < template.Count) { Debug.WriteLine("si = " + si); if (usedSampleIndices.Contains(si)) { si++; continue; } double oneToOneDis = double.MaxValue; int matchedIdx = -1; for (int ti = 0; ti < template.Count; ti++) { if (usedTemplateIndices.Contains(ti)) { continue; } double dis = SketchTools.HausdorffDistance(sampleNormalized[si], templateNormalized[ti]); if (dis < oneToOneDis) { oneToOneDis = dis; matchedIdx = ti; } } usedSampleIndices.Add(si); usedTemplateIndices.Add(matchedIdx); List <int> oneToManyIndices = new List <int>(); oneToManyIndices.Add(matchedIdx); List <int> manyToOneIndices = new List <int>(); manyToOneIndices.Add(si); SketchStroke currSampleStroke = sampleNormalized[si]; double oneToManyDis = oneToOneDis; int preSample = si - 1; int postSample = si + 1; while (preSample >= 0) { if (usedSampleIndices.Contains(preSample)) { break; } SketchStroke concatenatedStroke = SketchStroke.ConcatenateStrokes(sampleNormalized[preSample], currSampleStroke); double dis = SketchTools.HausdorffDistance(concatenatedStroke, templateNormalized[matchedIdx]); if (dis < oneToManyDis) { oneToManyDis = dis; oneToManyIndices.Insert(0, preSample); currSampleStroke = concatenatedStroke; } else { break; } preSample--; } while (postSample < sample.Count) { if (usedSampleIndices.Contains(postSample)) { break; } SketchStroke concatenatedStroke = SketchStroke.ConcatenateStrokes(currSampleStroke, sampleNormalized[postSample]); double dis = SketchTools.HausdorffDistance(concatenatedStroke, templateNormalized[matchedIdx]); if (dis < oneToManyDis) { oneToManyDis = dis; oneToManyIndices.Add(postSample); currSampleStroke = concatenatedStroke; } else { break; } postSample++; } SketchStroke currTemplateStroke = templateNormalized[matchedIdx]; double manyToOneDis = oneToOneDis; int preTemplate = matchedIdx - 1; int postTemplate = matchedIdx + 1; while (preTemplate >= 0) { if (usedTemplateIndices.Contains(preTemplate)) { break; } SketchStroke concatenatedStroke = SketchStroke.ConcatenateStrokes(templateNormalized[preTemplate], currTemplateStroke); double dis = SketchTools.HausdorffDistance(concatenatedStroke, sampleNormalized[si]); if (dis < manyToOneDis) { manyToOneDis = dis; manyToOneIndices.Insert(0, preTemplate); currTemplateStroke = concatenatedStroke; } else { break; } preTemplate--; } while (postTemplate < template.Count) { if (usedTemplateIndices.Contains(postTemplate)) { break; } SketchStroke concatenatedStroke = SketchStroke.ConcatenateStrokes(currTemplateStroke, templateNormalized[postTemplate]); double dis = SketchTools.HausdorffDistance(concatenatedStroke, sampleNormalized[si]); if (dis < manyToOneDis) { manyToOneDis = dis; manyToOneIndices.Add(postTemplate); currTemplateStroke = concatenatedStroke; } else { break; } postTemplate++; } Debug.WriteLine("matched index = " + matchedIdx); int flag = -2; // -1 for oneToMany, 0 for oneToOne, 1 for manyToOne if (oneToManyDis < oneToOneDis && manyToOneDis < oneToOneDis) { if (oneToManyDis < manyToOneDis) { flag = -1; } else { flag = 1; } } else if (oneToManyDis < oneToOneDis) { flag = -1; } else if (manyToOneDis < oneToOneDis) { flag = 1; } else { flag = 0; } if (flag == 0) { List <int> oneTemplate = new List <int>(); List <int> oneSample = new List <int>(); oneTemplate.Add(matchedIdx); oneSample.Add(si); result.Add(new List <int>[] { oneTemplate, oneSample }); usedTemplateIndices.Add(matchedIdx); usedSampleIndices.Add(matchedIdx); si++; } else if (flag == -1) // one to many { List <int> one = new List <int>(); List <int> many = new List <int>(); one.Add(matchedIdx); usedTemplateIndices.Add(matchedIdx); foreach (int index in oneToManyIndices) { usedSampleIndices.Add(index); many.Add(index); } result.Add(new List <int>[] { one, many }); si = many[many.Count - 1] + 1; } else if (flag == 1) // many to one { List <int> many = new List <int>(); List <int> one = new List <int>(); foreach (int index in manyToOneIndices) { usedTemplateIndices.Add(index); many.Add(index); } one.Add(si); result.Add(new List <int>[] { many, one }); usedSampleIndices.Add(matchedIdx); si++; } } return(result); }