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/graph/network.py +11 −7 Original line number Diff line number Diff line Loading @@ -799,11 +799,11 @@ class CandidateGraph(nx.Graph): for s, d, edge in self.edges_iter(data=True): source_node = edge.source intersect_gdf = self.compute_intersection(source_node, clean_keys = clean_keys) overlap, _ = self.compute_intersection(source_node, clean_keys = clean_keys) matches, _ = edge.clean(clean_keys) kps = edge.get_keypoints(edge.source, index=matches['source_idx'])[['x', 'y']] reproj_geom = source_node.reproject_geom(intersect_gdf.query("overlaps_all == True").geometry.values[0].__geo_interface__['coordinates'][0]) reproj_geom = source_node.reproject_geom(overlap.geometry.values[0].__geo_interface__['coordinates'][0]) initial_mask = geom_mask(kps, reproj_geom) if (len(kps[initial_mask]) <= 0): Loading Loading @@ -858,17 +858,21 @@ class CandidateGraph(nx.Graph): proj_node_list.append(s) proj_gdf = gpd.GeoDataFrame({"geometry": proj_poly_list, "proj_node": proj_node_list}) # Overlay the all geometry and find the one geometry element that overlaps all of the images # Overlay all geometry and find the one geometry element that overlaps all of the images intersect_gdf = gpd.overlay(source_gdf, proj_gdf, how='intersection') intersect_gdf['overlaps_all'] = intersect_gdf.geometry.apply(lambda x:proj_gdf.geometry.contains(shapely.affinity.scale(x, .9, .9)).all()) if len(intersect_gdf) == 0: raise ValueError('Node ' + str(source['node_id']) + ' does not overlap with any other images in the candidate graph.') overlaps_mask = intersect_gdf.geometry.apply(lambda x:proj_gdf.geometry.contains(shapely.affinity.scale(x, .9, .9)).all()) overlaps_all = intersect_gdf[overlaps_mask] # If there is no intersection polygon that overlaps all of the images, union all of the intersection # polygons into one large polygon that does overlap all of the images if len(intersect_gdf.query("overlaps_all == True")) <= 0: if len(overlaps_all) <= 0: new_poly = shapely.ops.unary_union(intersect_gdf.geometry) intersect_gdf.loc[len(intersect_gdf)] = [source['node_id'], source['node_id'], new_poly, True] overlaps_all = gpd.GeoDataFrame({'source_node': source['node_id'], 'proj_node': source['node_id'], 'geometry': [new_poly]}) return intersect_gdf return overlaps_all, intersect_gdf def is_complete(self): """ Loading autocnet/graph/tests/test_network.py +5 −5 Original line number Diff line number Diff line Loading @@ -220,16 +220,16 @@ def test_intersection(): e.source = cang.node[s] e.destination = cang.node[d] intersect_gdf = cang.compute_intersection(3) overlap, intersect_gdf = cang.compute_intersection(3) # Test the correct areas were found # Test the correct areas were found for the overlap and # the intersect_gdf print(overlap.geometry.area) assert intersect_gdf.geometry[0].area == 7.5 assert intersect_gdf.geometry[1].area == 5 assert intersect_gdf.geometry[2].area == 5 assert intersect_gdf.geometry[3].area == 3.75 assert intersect_gdf.geometry[4].area == 21.25 # Check if the correct poly was determined to overlap all other images assert intersect_gdf.overlaps_all[4] == True assert overlap.geometry.area.values == 21.25 def test_set_maxsize(graph): 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 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/graph/network.py +11 −7 Original line number Diff line number Diff line Loading @@ -799,11 +799,11 @@ class CandidateGraph(nx.Graph): for s, d, edge in self.edges_iter(data=True): source_node = edge.source intersect_gdf = self.compute_intersection(source_node, clean_keys = clean_keys) overlap, _ = self.compute_intersection(source_node, clean_keys = clean_keys) matches, _ = edge.clean(clean_keys) kps = edge.get_keypoints(edge.source, index=matches['source_idx'])[['x', 'y']] reproj_geom = source_node.reproject_geom(intersect_gdf.query("overlaps_all == True").geometry.values[0].__geo_interface__['coordinates'][0]) reproj_geom = source_node.reproject_geom(overlap.geometry.values[0].__geo_interface__['coordinates'][0]) initial_mask = geom_mask(kps, reproj_geom) if (len(kps[initial_mask]) <= 0): Loading Loading @@ -858,17 +858,21 @@ class CandidateGraph(nx.Graph): proj_node_list.append(s) proj_gdf = gpd.GeoDataFrame({"geometry": proj_poly_list, "proj_node": proj_node_list}) # Overlay the all geometry and find the one geometry element that overlaps all of the images # Overlay all geometry and find the one geometry element that overlaps all of the images intersect_gdf = gpd.overlay(source_gdf, proj_gdf, how='intersection') intersect_gdf['overlaps_all'] = intersect_gdf.geometry.apply(lambda x:proj_gdf.geometry.contains(shapely.affinity.scale(x, .9, .9)).all()) if len(intersect_gdf) == 0: raise ValueError('Node ' + str(source['node_id']) + ' does not overlap with any other images in the candidate graph.') overlaps_mask = intersect_gdf.geometry.apply(lambda x:proj_gdf.geometry.contains(shapely.affinity.scale(x, .9, .9)).all()) overlaps_all = intersect_gdf[overlaps_mask] # If there is no intersection polygon that overlaps all of the images, union all of the intersection # polygons into one large polygon that does overlap all of the images if len(intersect_gdf.query("overlaps_all == True")) <= 0: if len(overlaps_all) <= 0: new_poly = shapely.ops.unary_union(intersect_gdf.geometry) intersect_gdf.loc[len(intersect_gdf)] = [source['node_id'], source['node_id'], new_poly, True] overlaps_all = gpd.GeoDataFrame({'source_node': source['node_id'], 'proj_node': source['node_id'], 'geometry': [new_poly]}) return intersect_gdf return overlaps_all, intersect_gdf def is_complete(self): """ Loading
autocnet/graph/tests/test_network.py +5 −5 Original line number Diff line number Diff line Loading @@ -220,16 +220,16 @@ def test_intersection(): e.source = cang.node[s] e.destination = cang.node[d] intersect_gdf = cang.compute_intersection(3) overlap, intersect_gdf = cang.compute_intersection(3) # Test the correct areas were found # Test the correct areas were found for the overlap and # the intersect_gdf print(overlap.geometry.area) assert intersect_gdf.geometry[0].area == 7.5 assert intersect_gdf.geometry[1].area == 5 assert intersect_gdf.geometry[2].area == 5 assert intersect_gdf.geometry[3].area == 3.75 assert intersect_gdf.geometry[4].area == 21.25 # Check if the correct poly was determined to overlap all other images assert intersect_gdf.overlaps_all[4] == True assert overlap.geometry.area.values == 21.25 def test_set_maxsize(graph): 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