Loading autocnet/__init__.py +2 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ def cuda(enable=False, gpu=0): Node._extract_features = staticmethod(extract_features) from autocnet.matcher.cuda_matcher import match Edge.match = match Edge._match = staticmethod(match) from autocnet.matcher.cuda_decompose import decompose_and_match Edge.decompose_and_match = decompose_and_match Loading @@ -52,7 +52,7 @@ def cuda(enable=False, gpu=0): Node._extract_features = staticmethod(extract_features) from autocnet.matcher.cpu_matcher import match Edge.match = match Edge._match = staticmethod(match) from autocnet.matcher.cpu_decompose import decompose_and_match Edge.decompose_and_match = decompose_and_match Loading autocnet/graph/edge.py +15 −4 Original line number Diff line number Diff line Loading @@ -107,11 +107,22 @@ class Edge(dict, MutableMapping): ---------- k : int The number of neighbors to find """ Edge._match(self, k, **kwargs) @staticmethod def _match(edge, k=2, **kwargs): """ Patches the static cpu_matcher.match(edge) or cuda_match.match(edge) into the member method Edge.match() overlap : boolean Apply the matcher only to the overlapping area defined by the source_mbr and destin_mbr attributes (stored in the edge dict). Parameters ---------- edge : Edge The edge object to compute matches for; Edge.match() calls this with self k : int The number of neighbors to find """ pass Loading autocnet/matcher/cpu_matcher.py +14 −20 Original line number Diff line number Diff line Loading @@ -8,7 +8,7 @@ FLANN_INDEX_KDTREE = 1 # Algorithm to set centers, DEFAULT_FLANN_PARAMETERS = dict(algorithm=FLANN_INDEX_KDTREE, trees=3) def match(self, k=2, **kwargs): def match(edge, k=2, **kwargs): """ Given two sets of descriptors, utilize a FLANN (Approximate Nearest Neighbor KDTree) matcher to find the k nearest matches. Nearness is Loading @@ -32,11 +32,11 @@ def match(self, k=2, **kwargs): matches : dataframe A dataframe of matches """ if self.matches is None: self.matches = matches if edge.matches.empty: edge.matches = matches else: df = self.matches self.matches = df.append(matches, df = edge.matches edge.matches = df.append(matches, ignore_index=True, verify_integrity=True) Loading Loading @@ -78,25 +78,19 @@ def match(self, k=2, **kwargs): fl = FlannMatcher() # Get the correct descriptors # TODO: Extract into a helper function if 'aidx' in kwargs.keys(): aidx = kwargs['aidx'] kwargs.pop('aidx') else: aidx = None # Reset the edge.masks attrib; New matches would mean masks have to be # re-calculated edge.masks = pd.DataFrame() if 'bidx' in kwargs.keys(): bidx = kwargs['bidx'] kwargs.pop('bidx') else: bidx = None # Get the correct descriptors aidx = kwargs.pop('aidx', None) bidx = kwargs.pop('bidx', None) mono_matches(self.source, self.destination, aidx=aidx, bidx=bidx, **kwargs) mono_matches(edge.source, edge.destination, aidx=aidx, bidx=bidx) # Swap the indices since mono_matches is generic and source/destin are # swapped mono_matches(self.destination, self.source, aidx=bidx, bidx=aidx, **kwargs) self.matches.sort_values(by=['distance']) mono_matches(edge.destination, edge.source, aidx=bidx, bidx=aidx) edge.matches.sort_values(by=['distance']) class FlannMatcher(object): Loading autocnet/matcher/cuda_matcher.py +10 −9 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ import cudasift as cs import numpy as np import pandas as pd def match(self, ratio=0.8, **kwargs): def match(edge, ratio=0.8, **kwargs): """ Apply a composite CUDA matcher and ratio check. If this method is used, Loading @@ -14,11 +14,11 @@ def match(self, ratio=0.8, **kwargs): without significant gain in accuracy when using this implementation. """ source_kps = self.source.get_keypoints() source_des = self.source.descriptors source_kps = edge.source.get_keypoints() source_des = edge.source.descriptors destin_kps = self.destination.get_keypoints() destin_des = self.destination.descriptors destin_kps = edge.destination.get_keypoints() destin_des = edge.destination.descriptors s_siftdata = cs.PySiftData.from_data_frame(source_kps, source_des) d_siftdata = cs.PySiftData.from_data_frame(destin_kps, destin_des) Loading @@ -26,9 +26,9 @@ def match(self, ratio=0.8, **kwargs): cs.PyMatchSiftData(s_siftdata, d_siftdata) matches, _ = s_siftdata.to_data_frame() source = np.empty(len(matches)) source[:] = self.source['node_id'] source[:] = edge.source['node_id'] destination = np.empty(len(matches)) destination[:] = self.destination['node_id'] destination[:] = edge.destination['node_id'] df = pd.concat([pd.Series(source), pd.Series(matches.index), pd.Series(destination), matches.match, Loading @@ -37,5 +37,6 @@ def match(self, ratio=0.8, **kwargs): 'destination_idx', 'score', 'ambiguity'] # Set the matches and set the 'ratio' (ambiguity) mask self.matches = df self.masks['ratio'] = df['ambiguity'] <= ratio edge.matches = df edge.masks = pd.DataFrame() edge.masks['ratio'] = df['ambiguity'] <= ratio autocnet/matcher/tests/test_matcher.py +47 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ import cv2 from .. import cpu_matcher from autocnet.examples import get_path from autocnet.graph.network import CandidateGraph sys.path.append(os.path.abspath('..')) Loading Loading @@ -38,5 +39,51 @@ class TestMatcher(unittest.TestCase): self.assertEqual(len(w), 1) self.assertEqual(w[0].category, UserWarning) def test_cpu_match(self): # Build a graph adjacency = get_path('two_image_adjacency.json') basepath = get_path('Apollo15') cang = CandidateGraph.from_adjacency(adjacency, basepath=basepath) # Extract features cang.extract_features(extractor_parameters={'nfeatures': 700}) # Make sure cpu matcher is used for test edges = list() from autocnet.matcher.cpu_matcher import match as match for s, d in cang.edges(): cang[s][d]._match = match edges.append(cang[s][d]) # Assert none of the edges have masks yet for edge in edges: self.assertTrue(edge.masks.empty) # Match & outlier detect cang.match() cang.symmetry_checks() # Grab the length of a matches df match_len = len(edges[0].matches.index) # Assert symmetry check is now in all edge masks for edge in edges: self.assertTrue('symmetry' in edge.masks) # Assert matches have been populated for edge in edges: self.assertTrue(not edge.matches.empty) # Re-match cang.match() # Assert that new matches have been added on to old ones self.assertEqual(len(edges[0].matches.index), match_len * 2) # Assert that the match cleared the masks df for edge in edges: self.assertTrue(edge.masks.empty) def tearDown(self): pass Loading
autocnet/__init__.py +2 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ def cuda(enable=False, gpu=0): Node._extract_features = staticmethod(extract_features) from autocnet.matcher.cuda_matcher import match Edge.match = match Edge._match = staticmethod(match) from autocnet.matcher.cuda_decompose import decompose_and_match Edge.decompose_and_match = decompose_and_match Loading @@ -52,7 +52,7 @@ def cuda(enable=False, gpu=0): Node._extract_features = staticmethod(extract_features) from autocnet.matcher.cpu_matcher import match Edge.match = match Edge._match = staticmethod(match) from autocnet.matcher.cpu_decompose import decompose_and_match Edge.decompose_and_match = decompose_and_match Loading
autocnet/graph/edge.py +15 −4 Original line number Diff line number Diff line Loading @@ -107,11 +107,22 @@ class Edge(dict, MutableMapping): ---------- k : int The number of neighbors to find """ Edge._match(self, k, **kwargs) @staticmethod def _match(edge, k=2, **kwargs): """ Patches the static cpu_matcher.match(edge) or cuda_match.match(edge) into the member method Edge.match() overlap : boolean Apply the matcher only to the overlapping area defined by the source_mbr and destin_mbr attributes (stored in the edge dict). Parameters ---------- edge : Edge The edge object to compute matches for; Edge.match() calls this with self k : int The number of neighbors to find """ pass Loading
autocnet/matcher/cpu_matcher.py +14 −20 Original line number Diff line number Diff line Loading @@ -8,7 +8,7 @@ FLANN_INDEX_KDTREE = 1 # Algorithm to set centers, DEFAULT_FLANN_PARAMETERS = dict(algorithm=FLANN_INDEX_KDTREE, trees=3) def match(self, k=2, **kwargs): def match(edge, k=2, **kwargs): """ Given two sets of descriptors, utilize a FLANN (Approximate Nearest Neighbor KDTree) matcher to find the k nearest matches. Nearness is Loading @@ -32,11 +32,11 @@ def match(self, k=2, **kwargs): matches : dataframe A dataframe of matches """ if self.matches is None: self.matches = matches if edge.matches.empty: edge.matches = matches else: df = self.matches self.matches = df.append(matches, df = edge.matches edge.matches = df.append(matches, ignore_index=True, verify_integrity=True) Loading Loading @@ -78,25 +78,19 @@ def match(self, k=2, **kwargs): fl = FlannMatcher() # Get the correct descriptors # TODO: Extract into a helper function if 'aidx' in kwargs.keys(): aidx = kwargs['aidx'] kwargs.pop('aidx') else: aidx = None # Reset the edge.masks attrib; New matches would mean masks have to be # re-calculated edge.masks = pd.DataFrame() if 'bidx' in kwargs.keys(): bidx = kwargs['bidx'] kwargs.pop('bidx') else: bidx = None # Get the correct descriptors aidx = kwargs.pop('aidx', None) bidx = kwargs.pop('bidx', None) mono_matches(self.source, self.destination, aidx=aidx, bidx=bidx, **kwargs) mono_matches(edge.source, edge.destination, aidx=aidx, bidx=bidx) # Swap the indices since mono_matches is generic and source/destin are # swapped mono_matches(self.destination, self.source, aidx=bidx, bidx=aidx, **kwargs) self.matches.sort_values(by=['distance']) mono_matches(edge.destination, edge.source, aidx=bidx, bidx=aidx) edge.matches.sort_values(by=['distance']) class FlannMatcher(object): Loading
autocnet/matcher/cuda_matcher.py +10 −9 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ import cudasift as cs import numpy as np import pandas as pd def match(self, ratio=0.8, **kwargs): def match(edge, ratio=0.8, **kwargs): """ Apply a composite CUDA matcher and ratio check. If this method is used, Loading @@ -14,11 +14,11 @@ def match(self, ratio=0.8, **kwargs): without significant gain in accuracy when using this implementation. """ source_kps = self.source.get_keypoints() source_des = self.source.descriptors source_kps = edge.source.get_keypoints() source_des = edge.source.descriptors destin_kps = self.destination.get_keypoints() destin_des = self.destination.descriptors destin_kps = edge.destination.get_keypoints() destin_des = edge.destination.descriptors s_siftdata = cs.PySiftData.from_data_frame(source_kps, source_des) d_siftdata = cs.PySiftData.from_data_frame(destin_kps, destin_des) Loading @@ -26,9 +26,9 @@ def match(self, ratio=0.8, **kwargs): cs.PyMatchSiftData(s_siftdata, d_siftdata) matches, _ = s_siftdata.to_data_frame() source = np.empty(len(matches)) source[:] = self.source['node_id'] source[:] = edge.source['node_id'] destination = np.empty(len(matches)) destination[:] = self.destination['node_id'] destination[:] = edge.destination['node_id'] df = pd.concat([pd.Series(source), pd.Series(matches.index), pd.Series(destination), matches.match, Loading @@ -37,5 +37,6 @@ def match(self, ratio=0.8, **kwargs): 'destination_idx', 'score', 'ambiguity'] # Set the matches and set the 'ratio' (ambiguity) mask self.matches = df self.masks['ratio'] = df['ambiguity'] <= ratio edge.matches = df edge.masks = pd.DataFrame() edge.masks['ratio'] = df['ambiguity'] <= ratio
autocnet/matcher/tests/test_matcher.py +47 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ import cv2 from .. import cpu_matcher from autocnet.examples import get_path from autocnet.graph.network import CandidateGraph sys.path.append(os.path.abspath('..')) Loading Loading @@ -38,5 +39,51 @@ class TestMatcher(unittest.TestCase): self.assertEqual(len(w), 1) self.assertEqual(w[0].category, UserWarning) def test_cpu_match(self): # Build a graph adjacency = get_path('two_image_adjacency.json') basepath = get_path('Apollo15') cang = CandidateGraph.from_adjacency(adjacency, basepath=basepath) # Extract features cang.extract_features(extractor_parameters={'nfeatures': 700}) # Make sure cpu matcher is used for test edges = list() from autocnet.matcher.cpu_matcher import match as match for s, d in cang.edges(): cang[s][d]._match = match edges.append(cang[s][d]) # Assert none of the edges have masks yet for edge in edges: self.assertTrue(edge.masks.empty) # Match & outlier detect cang.match() cang.symmetry_checks() # Grab the length of a matches df match_len = len(edges[0].matches.index) # Assert symmetry check is now in all edge masks for edge in edges: self.assertTrue('symmetry' in edge.masks) # Assert matches have been populated for edge in edges: self.assertTrue(not edge.matches.empty) # Re-match cang.match() # Assert that new matches have been added on to old ones self.assertEqual(len(edges[0].matches.index), match_len * 2) # Assert that the match cleared the masks df for edge in edges: self.assertTrue(edge.masks.empty) def tearDown(self): pass