Loading autocnet/graph/edge.py +6 −0 Original line number Diff line number Diff line Loading @@ -555,7 +555,13 @@ class Edge(dict, MutableMapping): Estimate a source and destination minimum bounding rectangle, in pixel space """ try: self.overlap_latlon_coords, self["source_mbr"], self["destin_mbr"] = self.source.geodata.compute_overlap(self.destination.geodata, **kwargs) except Exception as e: raise Exception("Overlap between {} and {} could not be " "computed: {}".format(self.source['image_name'], self.destination['image_name'], type(e))) def get_matches(self): # pragma: no cover if self.matches.empty: Loading autocnet/graph/network.py +4 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ MAXSIZE = {0: None, 8: 12500, 12: 15310} class CandidateGraph(nx.Graph): """ A NetworkX derived directed graph to store candidate overlap images. Loading Loading @@ -355,6 +356,7 @@ class CandidateGraph(nx.Graph): # If a json is supplied, load as dict if type(adjacency) is not dict: adjacency = os.path.join(basepath, adjacency) try: assert os.path.exists(adjacency) except AssertionError: Loading Loading @@ -643,6 +645,8 @@ class CandidateGraph(nx.Graph): of keys in graph_masks """ return_lis = [] if callable(function): function = function.__name__ for s, d, edge in self.edges_iter(data=True): try: Loading @@ -656,7 +660,6 @@ class CandidateGraph(nx.Graph): if any(return_lis): return return_lis def apply(self, function, on='edge',out=None, args=(), **kwargs): """ Applys a function to every node or edge, returns collected return Loading autocnet/graph/tests/test_network.py +111 −2 Original line number Diff line number Diff line Loading @@ -57,8 +57,117 @@ def test_size(graph): def test_add_image(graph): with pytest.raises(NotImplementedError): graph.add_image() # apply_funcs def extract_and_match(edge): for n in [edge.source, edge.destination]: n.extract_features(n.get_array(band=1), extractor_parameters={'nfeatures': 800}) edge.match() basepath = get_path('Apollo15') cube_adjacency = {"AS15-M-0297_crop.cub": ["AS15-M-0298_crop.cub"], "AS15-M-0298_crop.cub": ["AS15-M-0297_crop.cub"]} cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) # Test with all optional args cub_img = "AS15-M-0299_crop.cub" png_img = "AS15-M-0299_SML.png" cub_adj = {cub_img: ["AS15-M-0298_crop.cub", "AS15-M-0297_crop.cub"]} png_adj = {png_img: ["AS15-M-0298_crop.cub", "AS15-M-0297_crop.cub"]} cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=extract_and_match) # Assert everything worked properly assert cub_img in cang.graph['node_name_map'].keys() new_node_idx = cang.graph['node_name_map'][cub_img] assert new_node_idx in cang.node.keys() assert cang.node[new_node_idx]['image_name'] == cub_img assert sorted(cang.nodes()) == [0, 1, 2] assert sorted(cang.edges()) == [(0, 1), (0, 2), (1, 2)] assert cang[0][2].destination['image_name'] == cang.edge[0][2].destination['image_name'] == cub_img assert cang[1][2].destination['image_name'] == cang.edge[1][2].destination['image_name'] == cub_img # Test for file not found with pytest.raises(FileNotFoundError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, basepath=None) # Test with auto-detect adjacency cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, basepath=basepath) # Test auto-detect when there are nodes w/ invalid geospacial data cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(png_img, adjacency=png_adj, basepath=basepath) # Invalid cang.add_image(cub_img, basepath=basepath) # Autodetect # Test auto-detect when new node does not intersect # TODO: Need a non-intersecting cube file; network.py, lines 324-325 # Test when img is already in graph cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image("AS15-M-0297_crop.cub", basepath=basepath) # Test when adjacency is of wrong type with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(png_img, adjacency=1, basepath=basepath) # Invalid # Test when loading adjacency from json cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency='cube_adjacency.json', basepath=basepath) with pytest.raises(FileNotFoundError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency='null.json', basepath=basepath) # Test when adjacency doesn't contain image as key with pytest.raises(KeyError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency='two_image_adjacency.json', basepath=basepath) # Test when no adjacency supplied, but image doesn't have footprint; # This results in a disconnected node added to the graph cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) edges_bf = cang.edges() cang.add_image(png_img, basepath=basepath) assert cang.edges() == edges_bf # Assert no change in edges # Test when adjacency includes a node not already in the graph adj = cub_adj adj[cub_img].append("AS15-M-0300_crop.cub") cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=adj, basepath=basepath) # Test when adjacency includes a list of something other than image names adj[cub_img].append(1) with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=adj, basepath=basepath) # Test when apply_func is not a function / list of functions with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=1) with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=[extract_and_match, 1]) def test_island_nodes(disconnected_graph): Loading Loading
autocnet/graph/edge.py +6 −0 Original line number Diff line number Diff line Loading @@ -555,7 +555,13 @@ class Edge(dict, MutableMapping): Estimate a source and destination minimum bounding rectangle, in pixel space """ try: self.overlap_latlon_coords, self["source_mbr"], self["destin_mbr"] = self.source.geodata.compute_overlap(self.destination.geodata, **kwargs) except Exception as e: raise Exception("Overlap between {} and {} could not be " "computed: {}".format(self.source['image_name'], self.destination['image_name'], type(e))) def get_matches(self): # pragma: no cover if self.matches.empty: Loading
autocnet/graph/network.py +4 −1 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ MAXSIZE = {0: None, 8: 12500, 12: 15310} class CandidateGraph(nx.Graph): """ A NetworkX derived directed graph to store candidate overlap images. Loading Loading @@ -355,6 +356,7 @@ class CandidateGraph(nx.Graph): # If a json is supplied, load as dict if type(adjacency) is not dict: adjacency = os.path.join(basepath, adjacency) try: assert os.path.exists(adjacency) except AssertionError: Loading Loading @@ -643,6 +645,8 @@ class CandidateGraph(nx.Graph): of keys in graph_masks """ return_lis = [] if callable(function): function = function.__name__ for s, d, edge in self.edges_iter(data=True): try: Loading @@ -656,7 +660,6 @@ class CandidateGraph(nx.Graph): if any(return_lis): return return_lis def apply(self, function, on='edge',out=None, args=(), **kwargs): """ Applys a function to every node or edge, returns collected return Loading
autocnet/graph/tests/test_network.py +111 −2 Original line number Diff line number Diff line Loading @@ -57,8 +57,117 @@ def test_size(graph): def test_add_image(graph): with pytest.raises(NotImplementedError): graph.add_image() # apply_funcs def extract_and_match(edge): for n in [edge.source, edge.destination]: n.extract_features(n.get_array(band=1), extractor_parameters={'nfeatures': 800}) edge.match() basepath = get_path('Apollo15') cube_adjacency = {"AS15-M-0297_crop.cub": ["AS15-M-0298_crop.cub"], "AS15-M-0298_crop.cub": ["AS15-M-0297_crop.cub"]} cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) # Test with all optional args cub_img = "AS15-M-0299_crop.cub" png_img = "AS15-M-0299_SML.png" cub_adj = {cub_img: ["AS15-M-0298_crop.cub", "AS15-M-0297_crop.cub"]} png_adj = {png_img: ["AS15-M-0298_crop.cub", "AS15-M-0297_crop.cub"]} cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=extract_and_match) # Assert everything worked properly assert cub_img in cang.graph['node_name_map'].keys() new_node_idx = cang.graph['node_name_map'][cub_img] assert new_node_idx in cang.node.keys() assert cang.node[new_node_idx]['image_name'] == cub_img assert sorted(cang.nodes()) == [0, 1, 2] assert sorted(cang.edges()) == [(0, 1), (0, 2), (1, 2)] assert cang[0][2].destination['image_name'] == cang.edge[0][2].destination['image_name'] == cub_img assert cang[1][2].destination['image_name'] == cang.edge[1][2].destination['image_name'] == cub_img # Test for file not found with pytest.raises(FileNotFoundError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, basepath=None) # Test with auto-detect adjacency cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, basepath=basepath) # Test auto-detect when there are nodes w/ invalid geospacial data cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(png_img, adjacency=png_adj, basepath=basepath) # Invalid cang.add_image(cub_img, basepath=basepath) # Autodetect # Test auto-detect when new node does not intersect # TODO: Need a non-intersecting cube file; network.py, lines 324-325 # Test when img is already in graph cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image("AS15-M-0297_crop.cub", basepath=basepath) # Test when adjacency is of wrong type with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(png_img, adjacency=1, basepath=basepath) # Invalid # Test when loading adjacency from json cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency='cube_adjacency.json', basepath=basepath) with pytest.raises(FileNotFoundError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency='null.json', basepath=basepath) # Test when adjacency doesn't contain image as key with pytest.raises(KeyError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency='two_image_adjacency.json', basepath=basepath) # Test when no adjacency supplied, but image doesn't have footprint; # This results in a disconnected node added to the graph cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) edges_bf = cang.edges() cang.add_image(png_img, basepath=basepath) assert cang.edges() == edges_bf # Assert no change in edges # Test when adjacency includes a node not already in the graph adj = cub_adj adj[cub_img].append("AS15-M-0300_crop.cub") cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=adj, basepath=basepath) # Test when adjacency includes a list of something other than image names adj[cub_img].append(1) with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=adj, basepath=basepath) # Test when apply_func is not a function / list of functions with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=1) with pytest.raises(TypeError): cang = network.CandidateGraph.from_adjacency(cube_adjacency, basepath=basepath) cang.add_image(cub_img, adjacency=cub_adj, basepath=basepath, apply_func=[extract_and_match, 1]) def test_island_nodes(disconnected_graph): Loading