Loading autocnet/graph/edge.py +1 −1 Original line number Diff line number Diff line Loading @@ -292,7 +292,7 @@ class Edge(dict, MutableMapping): raise AttributeError('This edge does not yet have any matches computed.') matches, mask = self._clean(clean_keys) domain = self.source.handle.raster_size domain = self.source.geodata.raster_size # Massage the dataframe into the correct structure coords = self.source.get_keypoint_coordinates() Loading autocnet/graph/network.py +11 −23 Original line number Diff line number Diff line import itertools import math import os import warnings import dill as pickle import networkx as nx import numpy as np import pandas as pd import warnings from autocnet.fileio.io_gdal import GeoDataset from autocnet.fileio import io_utils from autocnet.fileio import io_hdf from autocnet.control.control import C from autocnet.fileio import io_hdf from autocnet.fileio import io_json from autocnet.matcher.matcher import FlannMatcher import autocnet.matcher.suppression_funcs as spf from autocnet.fileio import io_utils from autocnet.fileio.io_gdal import GeoDataset from autocnet.graph import markov_cluster from autocnet.graph.edge import Edge from autocnet.graph.node import Node from autocnet.graph import markov_cluster from autocnet.matcher.matcher import FlannMatcher from autocnet.vis.graph_view import plot_graph Loading Loading @@ -46,7 +46,6 @@ class CandidateGraph(nx.Graph): self.node_counter = 0 node_labels = {} self.node_name_map = {} self.graph_masks = pd.DataFrame() for node_name in self.nodes(): image_name = os.path.basename(node_name) Loading Loading @@ -374,7 +373,7 @@ class CandidateGraph(nx.Graph): """ _, self.clusters = func(self, *args, **kwargs) def apply_func_to_edges(self, function, *args, graph_mask_keys=[], **kwargs): def apply_func_to_edges(self, function, *args, **kwargs): """ Iterates over edges using an optional mask and and applies the given function. If func is not an attribute of Edge, raises AttributeError Loading @@ -385,20 +384,12 @@ class CandidateGraph(nx.Graph): graph_mask_keys : list of keys in graph_masks """ if graph_mask_keys: merged_graph_mask = self.graph_masks[graph_mask_keys].all(axis=1) edges_to_iter = merged_graph_mask[merged_graph_mask].index else: edges_to_iter = self.edges() if not isinstance(function, str): function = function.__name__ for s, d in edges_to_iter: curr_edge = self.get_edge_data(s, d) for s, d, edge in self.edges_iter(data=True): try: func = getattr(curr_edge, function) func = getattr(edge, function) except: raise AttributeError(function, ' is not an attribute of Edge') else: Loading Loading @@ -472,11 +463,8 @@ class CandidateGraph(nx.Graph): boolean mask for edges in the minimum spanning tree """ graph_mask = pd.Series(False, index=self.edges()) self.graph_masks['mst'] = graph_mask mst = nx.minimum_spanning_tree(self) self.graph_masks['mst'][mst.edges()] = True return self.create_edge_subgraph(mst.edges()) def to_filelist(self): """ Loading autocnet/graph/node.py +1 −1 Original line number Diff line number Diff line Loading @@ -272,7 +272,7 @@ class Node(dict, MutableMapping): if not hasattr(self, '_keypoints'): raise AttributeError('No keypoints extracted for this node.') domain = self.handle.raster_size domain = self.geodata.raster_size self._keypoints['strength'] = self._keypoints.apply(func, axis=1) if not hasattr(self, 'suppression'): Loading autocnet/graph/tests/test_network.py +28 −32 Original line number Diff line number Diff line Loading @@ -6,14 +6,11 @@ import unittest from unittest.mock import patch from unittest.mock import PropertyMock from unittest.mock import MagicMock from osgeo import ogr import gdal import numpy as np from autocnet.examples import get_path from autocnet.fileio import io_gdal from .. import network Loading Loading @@ -49,20 +46,24 @@ class TestCandidateGraph(unittest.TestCase): def test_apply_func_to_edges(self): graph = self.graph.copy() graph.minimum_spanning_tree() mst_graph = graph.minimum_spanning_tree() try: graph.apply_func_to_edges('incorrect_func') except AttributeError: pass graph.extract_features(extractor_parameters={'nfeatures': 500}) graph.match_features() graph.apply_func_to_edges("symmetry_check", graph_mask_keys=['mst']) mst_graph.extract_features(extractor_parameters={'nfeatures': 500}) mst_graph.match_features() mst_graph.apply_func_to_edges("symmetry_check") self.assertFalse(graph[0][2].masks['symmetry'].all()) self.assertFalse(graph[0][1].masks['symmetry'].all()) try: self.assertTrue(graph[1][2].masks['symmetry'].all()) except: pass def test_connected_subgraphs(self): subgraph_list = self.disconnected_graph.connected_subgraphs() Loading Loading @@ -159,14 +160,8 @@ class TestCandidateGraph(unittest.TestCase): self.assertEqual(test_sub_graph.edges(), sub_graph_from_matches.edges()) def tearDown(self): pass class TestGraphMasks(unittest.TestCase): @classmethod def setUpClass(cls): cls.test_dict = {"0": ["4", "2", "1", "3"], def test_minimum_spanning_tree(self): test_dict = {"0": ["4", "2", "1", "3"], "1": ["0", "3", "2", "6", "5"], "2": ["1", "0", "3", "4", "7"], "3": ["2", "0", "1", "5"], Loading @@ -175,13 +170,14 @@ class TestGraphMasks(unittest.TestCase): "6": ["1"], "7": ["2"]} cls.graph = network.CandidateGraph.from_adjacency(cls.test_dict) cls.graph.minimum_spanning_tree() removed_edges = cls.graph.graph_masks['mst'][cls.graph.graph_masks['mst'] == False].index graph = network.CandidateGraph.from_adjacency(test_dict) mst_graph = graph.minimum_spanning_tree() print(len(mst_graph.edges())) cls.mst_graph = cls.graph.copy() cls.mst_graph.remove_edges_from(removed_edges) self.assertEqual(sorted(mst_graph.nodes()), sorted(graph.nodes())) self.assertEqual(len(mst_graph.edges()), len(graph.edges())-5) def test_mst_output(self): self.assertEqual(sorted(self.mst_graph.nodes()), sorted(self.graph.nodes())) self.assertEqual(self.mst_graph.number_of_edges(), self.graph.number_of_edges()-5) No newline at end of file def tearDown(self): pass image_match_config.yml +1 −3 Original line number Diff line number Diff line Loading @@ -37,8 +37,6 @@ fundamental_matrices: subpixel_register: clean_keys: - ratio - symmetry - fundamental template_size: 5 threshold: 0.8 search_size: 15 Loading @@ -52,7 +50,7 @@ subpixel_register: suppress: clean_keys: - fundamental - ratio # Keyword arguments min_radius: 2 Loading Loading
autocnet/graph/edge.py +1 −1 Original line number Diff line number Diff line Loading @@ -292,7 +292,7 @@ class Edge(dict, MutableMapping): raise AttributeError('This edge does not yet have any matches computed.') matches, mask = self._clean(clean_keys) domain = self.source.handle.raster_size domain = self.source.geodata.raster_size # Massage the dataframe into the correct structure coords = self.source.get_keypoint_coordinates() Loading
autocnet/graph/network.py +11 −23 Original line number Diff line number Diff line import itertools import math import os import warnings import dill as pickle import networkx as nx import numpy as np import pandas as pd import warnings from autocnet.fileio.io_gdal import GeoDataset from autocnet.fileio import io_utils from autocnet.fileio import io_hdf from autocnet.control.control import C from autocnet.fileio import io_hdf from autocnet.fileio import io_json from autocnet.matcher.matcher import FlannMatcher import autocnet.matcher.suppression_funcs as spf from autocnet.fileio import io_utils from autocnet.fileio.io_gdal import GeoDataset from autocnet.graph import markov_cluster from autocnet.graph.edge import Edge from autocnet.graph.node import Node from autocnet.graph import markov_cluster from autocnet.matcher.matcher import FlannMatcher from autocnet.vis.graph_view import plot_graph Loading Loading @@ -46,7 +46,6 @@ class CandidateGraph(nx.Graph): self.node_counter = 0 node_labels = {} self.node_name_map = {} self.graph_masks = pd.DataFrame() for node_name in self.nodes(): image_name = os.path.basename(node_name) Loading Loading @@ -374,7 +373,7 @@ class CandidateGraph(nx.Graph): """ _, self.clusters = func(self, *args, **kwargs) def apply_func_to_edges(self, function, *args, graph_mask_keys=[], **kwargs): def apply_func_to_edges(self, function, *args, **kwargs): """ Iterates over edges using an optional mask and and applies the given function. If func is not an attribute of Edge, raises AttributeError Loading @@ -385,20 +384,12 @@ class CandidateGraph(nx.Graph): graph_mask_keys : list of keys in graph_masks """ if graph_mask_keys: merged_graph_mask = self.graph_masks[graph_mask_keys].all(axis=1) edges_to_iter = merged_graph_mask[merged_graph_mask].index else: edges_to_iter = self.edges() if not isinstance(function, str): function = function.__name__ for s, d in edges_to_iter: curr_edge = self.get_edge_data(s, d) for s, d, edge in self.edges_iter(data=True): try: func = getattr(curr_edge, function) func = getattr(edge, function) except: raise AttributeError(function, ' is not an attribute of Edge') else: Loading Loading @@ -472,11 +463,8 @@ class CandidateGraph(nx.Graph): boolean mask for edges in the minimum spanning tree """ graph_mask = pd.Series(False, index=self.edges()) self.graph_masks['mst'] = graph_mask mst = nx.minimum_spanning_tree(self) self.graph_masks['mst'][mst.edges()] = True return self.create_edge_subgraph(mst.edges()) def to_filelist(self): """ Loading
autocnet/graph/node.py +1 −1 Original line number Diff line number Diff line Loading @@ -272,7 +272,7 @@ class Node(dict, MutableMapping): if not hasattr(self, '_keypoints'): raise AttributeError('No keypoints extracted for this node.') domain = self.handle.raster_size domain = self.geodata.raster_size self._keypoints['strength'] = self._keypoints.apply(func, axis=1) if not hasattr(self, 'suppression'): Loading
autocnet/graph/tests/test_network.py +28 −32 Original line number Diff line number Diff line Loading @@ -6,14 +6,11 @@ import unittest from unittest.mock import patch from unittest.mock import PropertyMock from unittest.mock import MagicMock from osgeo import ogr import gdal import numpy as np from autocnet.examples import get_path from autocnet.fileio import io_gdal from .. import network Loading Loading @@ -49,20 +46,24 @@ class TestCandidateGraph(unittest.TestCase): def test_apply_func_to_edges(self): graph = self.graph.copy() graph.minimum_spanning_tree() mst_graph = graph.minimum_spanning_tree() try: graph.apply_func_to_edges('incorrect_func') except AttributeError: pass graph.extract_features(extractor_parameters={'nfeatures': 500}) graph.match_features() graph.apply_func_to_edges("symmetry_check", graph_mask_keys=['mst']) mst_graph.extract_features(extractor_parameters={'nfeatures': 500}) mst_graph.match_features() mst_graph.apply_func_to_edges("symmetry_check") self.assertFalse(graph[0][2].masks['symmetry'].all()) self.assertFalse(graph[0][1].masks['symmetry'].all()) try: self.assertTrue(graph[1][2].masks['symmetry'].all()) except: pass def test_connected_subgraphs(self): subgraph_list = self.disconnected_graph.connected_subgraphs() Loading Loading @@ -159,14 +160,8 @@ class TestCandidateGraph(unittest.TestCase): self.assertEqual(test_sub_graph.edges(), sub_graph_from_matches.edges()) def tearDown(self): pass class TestGraphMasks(unittest.TestCase): @classmethod def setUpClass(cls): cls.test_dict = {"0": ["4", "2", "1", "3"], def test_minimum_spanning_tree(self): test_dict = {"0": ["4", "2", "1", "3"], "1": ["0", "3", "2", "6", "5"], "2": ["1", "0", "3", "4", "7"], "3": ["2", "0", "1", "5"], Loading @@ -175,13 +170,14 @@ class TestGraphMasks(unittest.TestCase): "6": ["1"], "7": ["2"]} cls.graph = network.CandidateGraph.from_adjacency(cls.test_dict) cls.graph.minimum_spanning_tree() removed_edges = cls.graph.graph_masks['mst'][cls.graph.graph_masks['mst'] == False].index graph = network.CandidateGraph.from_adjacency(test_dict) mst_graph = graph.minimum_spanning_tree() print(len(mst_graph.edges())) cls.mst_graph = cls.graph.copy() cls.mst_graph.remove_edges_from(removed_edges) self.assertEqual(sorted(mst_graph.nodes()), sorted(graph.nodes())) self.assertEqual(len(mst_graph.edges()), len(graph.edges())-5) def test_mst_output(self): self.assertEqual(sorted(self.mst_graph.nodes()), sorted(self.graph.nodes())) self.assertEqual(self.mst_graph.number_of_edges(), self.graph.number_of_edges()-5) No newline at end of file def tearDown(self): pass
image_match_config.yml +1 −3 Original line number Diff line number Diff line Loading @@ -37,8 +37,6 @@ fundamental_matrices: subpixel_register: clean_keys: - ratio - symmetry - fundamental template_size: 5 threshold: 0.8 search_size: 15 Loading @@ -52,7 +50,7 @@ subpixel_register: suppress: clean_keys: - fundamental - ratio # Keyword arguments min_radius: 2 Loading