public void BKTree_should_QueryBestMatchesBelowGivenThreshold() { BKTree <TestNode> tree = new BKTree <TestNode>(); TestNode search = new TestNode(new int[] { 399, 400, 400 }); TestNode best1 = new TestNode(41, new int[] { 400, 400, 400 }); TestNode best2 = new TestNode(42, new int[] { 403, 403, 403 }); TestNode best3 = new TestNode(43, new int[] { 406, 406, 406 }); tree.add(new TestNode(1, new int[] { 100, 100, 100 })); tree.add(new TestNode(2, new int[] { 200, 200, 200 })); tree.add(new TestNode(3, new int[] { 300, 300, 300 })); tree.add(best1); tree.add(best2); tree.add(new TestNode(5, new int[] { 500, 500, 500 })); Dictionary <TestNode, Int32> results; // Query for match within distance of 1 (best1 is only expected result) results = tree.query(search, 1); Assert.Equal(1, results.Count); Assert.Equal(1, DistanceMetric.calculateLeeDistance(search.Data, best1.Data)); Assert.Equal(1, results.Values.ElementAt(0)); Assert.Equal(41, results.Keys.ElementAt(0).Id); Assert.Equal(best1.Data, results.Keys.ElementAt(0).Data); // Query for match within distance of 10 (best1 & best2 are expected results) tree.add(best3); // exercise adding another node after already queried results = tree.query(search, 10); Assert.Equal(2, results.Count); Assert.Equal(1, DistanceMetric.calculateLeeDistance(search.Data, best1.Data)); Assert.Equal(10, DistanceMetric.calculateLeeDistance(search.Data, best2.Data)); Assert.True(results.Contains(new KeyValuePair <TestNode, int>(best1, 1))); Assert.True(results.Contains(new KeyValuePair <TestNode, int>(best2, 10))); // Query for matches within distance of 20 (best1, best2 & best3 are expected results) results = tree.query(search, 20); Assert.Equal(3, results.Count); Assert.Equal(1, DistanceMetric.calculateLeeDistance(search.Data, best1.Data)); Assert.Equal(10, DistanceMetric.calculateLeeDistance(search.Data, best2.Data)); Assert.Equal(19, DistanceMetric.calculateLeeDistance(search.Data, best3.Data)); Assert.True(results.Contains(new KeyValuePair <TestNode, int>(best1, 1))); Assert.True(results.Contains(new KeyValuePair <TestNode, int>(best2, 10))); Assert.True(results.Contains(new KeyValuePair <TestNode, int>(best3, 19))); }
/* * To use BKTree: * 1. Create a class dervied from BKTreeNode * 2. Add a member variable of your data to be sorted / retrieved * 3. Override the calculateDistance method to calculate the distance metric * between two nodes for the data to be sorted / retrieved. * 4. Instantiate a BKTree with the type name of the class created in (1). */ static void Main(string[] args) { /* * NOTE: More comprehensive examples of BK-Tree methods in unit tests */ // Exercise static distance metric methods -- just because Console.WriteLine( DistanceMetric.calculateHammingDistance( new byte[] { 0xEF, 0x35, 0x20 }, new byte[] { 0xAD, 0x13, 0x87 })); Console.WriteLine( DistanceMetric.calculateLeeDistance( new int[] { 196, 105, 48 }, new int[] { 201, 12, 51 })); Console.WriteLine( DistanceMetric.calculateLevenshteinDistance( "kitten", "sitting")); // Create BKTree with derived node class from top of file BKTree <ExampleNodeRecord> tree = new BKTree <ExampleNodeRecord>(); // Add some nodes tree.add(new ExampleNodeRecord(1, new int[] { 100, 200, 300 })); tree.add(new ExampleNodeRecord(2, new int[] { 110, 210, 310 })); tree.add(new ExampleNodeRecord(3, new int[] { 120, 220, 320 })); tree.add(new ExampleNodeRecord(4, new int[] { 130, 230, 330 })); tree.add(new ExampleNodeRecord(5, new int[] { 140, 240, 340 })); // Get best node from our tree with best distance Dictionary <ExampleNodeRecord, Int32> results = tree.findBestNodeWithDistance( new ExampleNodeRecord(new int[] { 103, 215, 303 })); // Get best nodes below threshold results = tree.query( new ExampleNodeRecord(new int[] { 103, 215, 303 }), 10); // arbitrary threshold // Dictionaries don't print well; so invent your own handy print routine }
public List <ImageRecord> QueryImage(string queryImagePath, object argument = null) { List <ImageRecord> rtnImageList = new List <ImageRecord>(); CEDD_Descriptor.CEDD cedd = new CEDD_Descriptor.CEDD(); int goodMatchDistance = 35; if (argument != null && argument is Int32) { goodMatchDistance = (int)argument; } double[] queryCeddDiscriptor; using (Bitmap bmp = new Bitmap(Image.FromFile(queryImagePath))) { queryCeddDiscriptor = cedd.Apply(bmp); } Stopwatch sw = Stopwatch.StartNew(); BKTree <CEDDTreeNode> ceddTree = null; if (!CacheHelper.Get <BKTree <CEDDTreeNode> >("CeddIndexTree", out ceddTree)) { CEDDRepository <BKTree <CEDDTreeNode> > repo = new CEDDRepository <BKTree <CEDDTreeNode> >(); ceddTree = repo.Load(); if (ceddTree == null) { throw new InvalidOperationException("Please index CEDD with BK-Tree before querying the Image"); } CacheHelper.Add <BKTree <CEDDTreeNode> >(ceddTree, "CeddIndexTree"); } sw.Stop(); Debug.WriteLine("Load tooked {0} ms", sw.ElapsedMilliseconds); CEDDTreeNode queryNode = new CEDDTreeNode { Id = 0, ImagePath = queryImagePath, CEDDDiscriptor = queryCeddDiscriptor }; sw.Reset(); sw.Start(); Dictionary <CEDDTreeNode, Int32> result = ceddTree.query(queryNode, goodMatchDistance); sw.Stop(); Debug.WriteLine("Query tooked {0} ms", sw.ElapsedMilliseconds); foreach (KeyValuePair <CEDDTreeNode, Int32> ceddNode in result) { ImageRecord rec = new ImageRecord { Id = ceddNode.Key.Id, ImageName = ceddNode.Key.ImageName, ImagePath = ceddNode.Key.ImagePath, Distance = ceddNode.Value }; rtnImageList.Add(rec); } rtnImageList = rtnImageList.OrderBy(x => x.Distance).ToList(); return(rtnImageList); }
/* * To use BKTree: * 1. Create a class dervied from BKTreeNode * 2. Add a member variable of your data to be sorted / retrieved * 3. Override the calculateDistance method to calculate the distance metric * between two nodes for the data to be sorted / retrieved. * 4. Instantiate a BKTree with the type name of the class created in (1). */ static void Main(string[] args) { /* * NOTE: More comprehensive examples of BK-Tree methods in unit tests */ // Exercise static distance metric methods -- just because Console.WriteLine( DistanceMetric.calculateHammingDistance( new byte[] { 0xEF, 0x35, 0x20 }, new byte[] { 0xAD, 0x13, 0x87 })); Console.WriteLine( DistanceMetric.calculateLeeDistance( new int[] { 196, 105, 48 }, new int[] { 201, 12, 51 })); Console.WriteLine( DistanceMetric.calculateLevenshteinDistance( "kitten", "sitting")); // Create BKTree with derived node class from top of file BKTree<ExampleNodeRecord> tree = new BKTree<ExampleNodeRecord>(); // Add some nodes tree.add( new ExampleNodeRecord( 1, new int[] {100,200,300}) ); tree.add( new ExampleNodeRecord( 2, new int[] {110,210,310}) ); tree.add( new ExampleNodeRecord( 3, new int[] {120,220,320}) ); tree.add( new ExampleNodeRecord( 4, new int[] {130,230,330}) ); tree.add( new ExampleNodeRecord( 5, new int[] {140,240,340}) ); // Get best node from our tree with best distance Dictionary<ExampleNodeRecord, Int32> results = tree.findBestNodeWithDistance( new ExampleNodeRecord( new int[] { 103, 215, 303 }) ); // Get best nodes below threshold results = tree.query( new ExampleNodeRecord(new int[] { 103, 215, 303 }), 10 ); // arbitrary threshold // Dictionaries don't print well; so invent your own handy print routine }
public void BKTree_should_QueryBestMatchesBelowGivenThreshold() { BKTree<TestNode> tree = new BKTree<TestNode>(); TestNode search = new TestNode(new int[] { 399, 400, 400 }); TestNode best1 = new TestNode(41, new int[] { 400, 400, 400 }); TestNode best2 = new TestNode(42, new int[] { 403, 403, 403 }); TestNode best3 = new TestNode(43, new int[] { 406, 406, 406 }); tree.add(new TestNode(1, new int[] { 100, 100, 100 })); tree.add(new TestNode(2, new int[] { 200, 200, 200 })); tree.add(new TestNode(3, new int[] { 300, 300, 300 })); tree.add(best1); tree.add(best2); tree.add(new TestNode(5, new int[] { 500, 500, 500 })); Dictionary<TestNode, Int32> results; // Query for match within distance of 1 (best1 is only expected result) results = tree.query(search, 1); Assert.Equal(1, results.Count); Assert.Equal(1, DistanceMetric.calculateLeeDistance(search.Data, best1.Data)); Assert.Equal(1, results.Values.ElementAt(0)); Assert.Equal(41, results.Keys.ElementAt(0).Id); Assert.Equal(best1.Data, results.Keys.ElementAt(0).Data); // Query for match within distance of 10 (best1 & best2 are expected results) tree.add(best3); // exercise adding another node after already queried results = tree.query(search, 10); Assert.Equal(2, results.Count); Assert.Equal(1, DistanceMetric.calculateLeeDistance(search.Data, best1.Data)); Assert.Equal(10, DistanceMetric.calculateLeeDistance(search.Data, best2.Data)); Assert.True(results.Contains(new KeyValuePair<TestNode, int>(best1, 1))); Assert.True(results.Contains(new KeyValuePair<TestNode, int>(best2, 10))); // Query for matches within distance of 20 (best1, best2 & best3 are expected results) results = tree.query(search, 20); Assert.Equal(3, results.Count); Assert.Equal(1, DistanceMetric.calculateLeeDistance(search.Data, best1.Data)); Assert.Equal(10, DistanceMetric.calculateLeeDistance(search.Data, best2.Data)); Assert.Equal(19, DistanceMetric.calculateLeeDistance(search.Data, best3.Data)); Assert.True(results.Contains(new KeyValuePair<TestNode, int>(best1, 1))); Assert.True(results.Contains(new KeyValuePair<TestNode, int>(best2, 10))); Assert.True(results.Contains(new KeyValuePair<TestNode, int>(best3, 19))); }