Loading .travis.yml +3 −9 Original line number Original line Diff line number Diff line Loading @@ -4,7 +4,6 @@ sudo: false branches: branches: only: only: - master - master - dev python: python: - "3.5" - "3.5" Loading @@ -28,9 +27,9 @@ install: - conda info -a - conda info -a # Create a virtual env and install dependencies # Create a virtual env and install dependencies # conda is explicitly included here to try to get it into a non-root env. It is NOT needed outside of CI testing and binstar upload. - conda create -y -q -n test-env python=$TRAVIS_PYTHON_VERSION nose numpy pillow scipy pandas networkx scikit-image sqlalchemy numexpr dill cython pyyaml - conda install python=3.5 nose numpy pillow scipy pandas networkx scikit-image sqlalchemy numexpr dill cython pyyaml # Activate the env - source activate test-env # Install the non-conda packages if required, requirements.txt duplicates are ignored # Install the non-conda packages if required, requirements.txt duplicates are ignored - conda install -c https://conda.anaconda.org/jlaura opencv3=3.0.0 - conda install -c https://conda.anaconda.org/jlaura opencv3=3.0.0 Loading @@ -40,15 +39,11 @@ install: - pip install coverage - pip install coverage - pip install coveralls - pip install coveralls # Install libs to support upload to binstar - conda install anaconda-client binstar conda-build script: script: - nosetests --with-coverage --cover-package=autocnet - nosetests --with-coverage --cover-package=autocnet after_success: after_success: - coveralls - coveralls - python ci_support/upload_or_check_non_existence.py ci_support jlaura --channel=main notifications: notifications: webhooks: webhooks: Loading @@ -65,4 +60,3 @@ notifications: - krodriguez@usgs.gov - krodriguez@usgs.gov on_success: always on_success: always on_failure: always on_failure: always autocnet/graph/edge.py +1 −1 Original line number Original line 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.') raise AttributeError('This edge does not yet have any matches computed.') matches, mask = self._clean(clean_keys) matches, mask = self._clean(clean_keys) domain = self.source.geodata.raster_size domain = self.source.handle.raster_size # Massage the dataframe into the correct structure # Massage the dataframe into the correct structure coords = self.source.get_keypoint_coordinates() coords = self.source.get_keypoint_coordinates() Loading autocnet/graph/network.py +23 −11 Original line number Original line Diff line number Diff line import itertools import itertools import math import math import os import os import warnings import dill as pickle import dill as pickle import networkx as nx import networkx as nx import numpy as np import numpy as np import pandas as pd import pandas as pd import warnings from autocnet.control.control import C from autocnet.fileio.io_gdal import GeoDataset from autocnet.fileio import io_utils from autocnet.fileio import io_hdf from autocnet.fileio import io_hdf from autocnet.control.control import C from autocnet.fileio import io_json from autocnet.fileio import io_json from autocnet.fileio import io_utils from autocnet.matcher.matcher import FlannMatcher from autocnet.fileio.io_gdal import GeoDataset import autocnet.matcher.suppression_funcs as spf from autocnet.graph import markov_cluster from autocnet.graph.edge import Edge from autocnet.graph.edge import Edge from autocnet.graph.node import Node from autocnet.graph.node import Node from autocnet.matcher.matcher import FlannMatcher from autocnet.graph import markov_cluster from autocnet.vis.graph_view import plot_graph from autocnet.vis.graph_view import plot_graph Loading Loading @@ -46,6 +46,7 @@ class CandidateGraph(nx.Graph): self.node_counter = 0 self.node_counter = 0 node_labels = {} node_labels = {} self.node_name_map = {} self.node_name_map = {} self.graph_masks = pd.DataFrame() for node_name in self.nodes(): for node_name in self.nodes(): image_name = os.path.basename(node_name) image_name = os.path.basename(node_name) Loading Loading @@ -373,7 +374,7 @@ class CandidateGraph(nx.Graph): """ """ _, self.clusters = func(self, *args, **kwargs) _, self.clusters = func(self, *args, **kwargs) def apply_func_to_edges(self, function, *args, **kwargs): def apply_func_to_edges(self, function, *args, graph_mask_keys=[], **kwargs): """ """ Iterates over edges using an optional mask and and applies the given function. Iterates over edges using an optional mask and and applies the given function. If func is not an attribute of Edge, raises AttributeError If func is not an attribute of Edge, raises AttributeError Loading @@ -384,12 +385,20 @@ class CandidateGraph(nx.Graph): graph_mask_keys : list graph_mask_keys : list of keys in graph_masks 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): if not isinstance(function, str): function = function.__name__ function = function.__name__ for s, d, edge in self.edges_iter(data=True): for s, d in edges_to_iter: curr_edge = self.get_edge_data(s, d) try: try: func = getattr(edge, function) func = getattr(curr_edge, function) except: except: raise AttributeError(function, ' is not an attribute of Edge') raise AttributeError(function, ' is not an attribute of Edge') else: else: Loading @@ -406,8 +415,11 @@ class CandidateGraph(nx.Graph): boolean mask for edges in the minimum spanning tree 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) mst = nx.minimum_spanning_tree(self) return self.create_edge_subgraph(mst.edges()) self.graph_masks['mst'][mst.edges()] = True def to_filelist(self): def to_filelist(self): """ """ Loading autocnet/graph/node.py +1 −1 Original line number Original line Diff line number Diff line Loading @@ -272,7 +272,7 @@ class Node(dict, MutableMapping): if not hasattr(self, '_keypoints'): if not hasattr(self, '_keypoints'): raise AttributeError('No keypoints extracted for this node.') raise AttributeError('No keypoints extracted for this node.') domain = self.geodata.raster_size domain = self.handle.raster_size self._keypoints['strength'] = self._keypoints.apply(func, axis=1) self._keypoints['strength'] = self._keypoints.apply(func, axis=1) if not hasattr(self, 'suppression'): if not hasattr(self, 'suppression'): Loading autocnet/graph/tests/test_network.py +32 −28 Original line number Original line Diff line number Diff line Loading @@ -6,11 +6,14 @@ import unittest from unittest.mock import patch from unittest.mock import patch from unittest.mock import PropertyMock from unittest.mock import PropertyMock from unittest.mock import MagicMock from osgeo import ogr from osgeo import ogr import gdal import numpy as np import numpy as np from autocnet.examples import get_path from autocnet.examples import get_path from autocnet.fileio import io_gdal from .. import network from .. import network Loading Loading @@ -46,24 +49,20 @@ class TestCandidateGraph(unittest.TestCase): def test_apply_func_to_edges(self): def test_apply_func_to_edges(self): graph = self.graph.copy() graph = self.graph.copy() mst_graph = graph.minimum_spanning_tree() graph.minimum_spanning_tree() try: try: graph.apply_func_to_edges('incorrect_func') graph.apply_func_to_edges('incorrect_func') except AttributeError: except AttributeError: pass pass mst_graph.extract_features(extractor_parameters={'nfeatures': 500}) graph.extract_features(extractor_parameters={'nfeatures': 500}) mst_graph.match_features() graph.match_features() mst_graph.apply_func_to_edges("symmetry_check") graph.apply_func_to_edges("symmetry_check", graph_mask_keys=['mst']) self.assertFalse(graph[0][2].masks['symmetry'].all()) self.assertFalse(graph[0][2].masks['symmetry'].all()) self.assertFalse(graph[0][1].masks['symmetry'].all()) self.assertFalse(graph[0][1].masks['symmetry'].all()) try: self.assertTrue(graph[1][2].masks['symmetry'].all()) self.assertTrue(graph[1][2].masks['symmetry'].all()) except: pass def test_connected_subgraphs(self): def test_connected_subgraphs(self): subgraph_list = self.disconnected_graph.connected_subgraphs() subgraph_list = self.disconnected_graph.connected_subgraphs() Loading Loading @@ -160,8 +159,14 @@ class TestCandidateGraph(unittest.TestCase): self.assertEqual(test_sub_graph.edges(), sub_graph_from_matches.edges()) self.assertEqual(test_sub_graph.edges(), sub_graph_from_matches.edges()) def test_minimum_spanning_tree(self): def tearDown(self): test_dict = {"0": ["4", "2", "1", "3"], pass class TestGraphMasks(unittest.TestCase): @classmethod def setUpClass(cls): cls.test_dict = {"0": ["4", "2", "1", "3"], "1": ["0", "3", "2", "6", "5"], "1": ["0", "3", "2", "6", "5"], "2": ["1", "0", "3", "4", "7"], "2": ["1", "0", "3", "4", "7"], "3": ["2", "0", "1", "5"], "3": ["2", "0", "1", "5"], Loading @@ -170,14 +175,13 @@ class TestCandidateGraph(unittest.TestCase): "6": ["1"], "6": ["1"], "7": ["2"]} "7": ["2"]} graph = network.CandidateGraph.from_adjacency(test_dict) cls.graph = network.CandidateGraph.from_adjacency(cls.test_dict) mst_graph = graph.minimum_spanning_tree() cls.graph.minimum_spanning_tree() removed_edges = cls.graph.graph_masks['mst'][cls.graph.graph_masks['mst'] == False].index print(len(mst_graph.edges())) self.assertEqual(sorted(mst_graph.nodes()), sorted(graph.nodes())) cls.mst_graph = cls.graph.copy() self.assertEqual(len(mst_graph.edges()), len(graph.edges())-5) cls.mst_graph.remove_edges_from(removed_edges) def test_mst_output(self): def tearDown(self): self.assertEqual(sorted(self.mst_graph.nodes()), sorted(self.graph.nodes())) pass self.assertEqual(self.mst_graph.number_of_edges(), self.graph.number_of_edges()-5) No newline at end of file Loading
.travis.yml +3 −9 Original line number Original line Diff line number Diff line Loading @@ -4,7 +4,6 @@ sudo: false branches: branches: only: only: - master - master - dev python: python: - "3.5" - "3.5" Loading @@ -28,9 +27,9 @@ install: - conda info -a - conda info -a # Create a virtual env and install dependencies # Create a virtual env and install dependencies # conda is explicitly included here to try to get it into a non-root env. It is NOT needed outside of CI testing and binstar upload. - conda create -y -q -n test-env python=$TRAVIS_PYTHON_VERSION nose numpy pillow scipy pandas networkx scikit-image sqlalchemy numexpr dill cython pyyaml - conda install python=3.5 nose numpy pillow scipy pandas networkx scikit-image sqlalchemy numexpr dill cython pyyaml # Activate the env - source activate test-env # Install the non-conda packages if required, requirements.txt duplicates are ignored # Install the non-conda packages if required, requirements.txt duplicates are ignored - conda install -c https://conda.anaconda.org/jlaura opencv3=3.0.0 - conda install -c https://conda.anaconda.org/jlaura opencv3=3.0.0 Loading @@ -40,15 +39,11 @@ install: - pip install coverage - pip install coverage - pip install coveralls - pip install coveralls # Install libs to support upload to binstar - conda install anaconda-client binstar conda-build script: script: - nosetests --with-coverage --cover-package=autocnet - nosetests --with-coverage --cover-package=autocnet after_success: after_success: - coveralls - coveralls - python ci_support/upload_or_check_non_existence.py ci_support jlaura --channel=main notifications: notifications: webhooks: webhooks: Loading @@ -65,4 +60,3 @@ notifications: - krodriguez@usgs.gov - krodriguez@usgs.gov on_success: always on_success: always on_failure: always on_failure: always
autocnet/graph/edge.py +1 −1 Original line number Original line 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.') raise AttributeError('This edge does not yet have any matches computed.') matches, mask = self._clean(clean_keys) matches, mask = self._clean(clean_keys) domain = self.source.geodata.raster_size domain = self.source.handle.raster_size # Massage the dataframe into the correct structure # Massage the dataframe into the correct structure coords = self.source.get_keypoint_coordinates() coords = self.source.get_keypoint_coordinates() Loading
autocnet/graph/network.py +23 −11 Original line number Original line Diff line number Diff line import itertools import itertools import math import math import os import os import warnings import dill as pickle import dill as pickle import networkx as nx import networkx as nx import numpy as np import numpy as np import pandas as pd import pandas as pd import warnings from autocnet.control.control import C from autocnet.fileio.io_gdal import GeoDataset from autocnet.fileio import io_utils from autocnet.fileio import io_hdf from autocnet.fileio import io_hdf from autocnet.control.control import C from autocnet.fileio import io_json from autocnet.fileio import io_json from autocnet.fileio import io_utils from autocnet.matcher.matcher import FlannMatcher from autocnet.fileio.io_gdal import GeoDataset import autocnet.matcher.suppression_funcs as spf from autocnet.graph import markov_cluster from autocnet.graph.edge import Edge from autocnet.graph.edge import Edge from autocnet.graph.node import Node from autocnet.graph.node import Node from autocnet.matcher.matcher import FlannMatcher from autocnet.graph import markov_cluster from autocnet.vis.graph_view import plot_graph from autocnet.vis.graph_view import plot_graph Loading Loading @@ -46,6 +46,7 @@ class CandidateGraph(nx.Graph): self.node_counter = 0 self.node_counter = 0 node_labels = {} node_labels = {} self.node_name_map = {} self.node_name_map = {} self.graph_masks = pd.DataFrame() for node_name in self.nodes(): for node_name in self.nodes(): image_name = os.path.basename(node_name) image_name = os.path.basename(node_name) Loading Loading @@ -373,7 +374,7 @@ class CandidateGraph(nx.Graph): """ """ _, self.clusters = func(self, *args, **kwargs) _, self.clusters = func(self, *args, **kwargs) def apply_func_to_edges(self, function, *args, **kwargs): def apply_func_to_edges(self, function, *args, graph_mask_keys=[], **kwargs): """ """ Iterates over edges using an optional mask and and applies the given function. Iterates over edges using an optional mask and and applies the given function. If func is not an attribute of Edge, raises AttributeError If func is not an attribute of Edge, raises AttributeError Loading @@ -384,12 +385,20 @@ class CandidateGraph(nx.Graph): graph_mask_keys : list graph_mask_keys : list of keys in graph_masks 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): if not isinstance(function, str): function = function.__name__ function = function.__name__ for s, d, edge in self.edges_iter(data=True): for s, d in edges_to_iter: curr_edge = self.get_edge_data(s, d) try: try: func = getattr(edge, function) func = getattr(curr_edge, function) except: except: raise AttributeError(function, ' is not an attribute of Edge') raise AttributeError(function, ' is not an attribute of Edge') else: else: Loading @@ -406,8 +415,11 @@ class CandidateGraph(nx.Graph): boolean mask for edges in the minimum spanning tree 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) mst = nx.minimum_spanning_tree(self) return self.create_edge_subgraph(mst.edges()) self.graph_masks['mst'][mst.edges()] = True def to_filelist(self): def to_filelist(self): """ """ Loading
autocnet/graph/node.py +1 −1 Original line number Original line Diff line number Diff line Loading @@ -272,7 +272,7 @@ class Node(dict, MutableMapping): if not hasattr(self, '_keypoints'): if not hasattr(self, '_keypoints'): raise AttributeError('No keypoints extracted for this node.') raise AttributeError('No keypoints extracted for this node.') domain = self.geodata.raster_size domain = self.handle.raster_size self._keypoints['strength'] = self._keypoints.apply(func, axis=1) self._keypoints['strength'] = self._keypoints.apply(func, axis=1) if not hasattr(self, 'suppression'): if not hasattr(self, 'suppression'): Loading
autocnet/graph/tests/test_network.py +32 −28 Original line number Original line Diff line number Diff line Loading @@ -6,11 +6,14 @@ import unittest from unittest.mock import patch from unittest.mock import patch from unittest.mock import PropertyMock from unittest.mock import PropertyMock from unittest.mock import MagicMock from osgeo import ogr from osgeo import ogr import gdal import numpy as np import numpy as np from autocnet.examples import get_path from autocnet.examples import get_path from autocnet.fileio import io_gdal from .. import network from .. import network Loading Loading @@ -46,24 +49,20 @@ class TestCandidateGraph(unittest.TestCase): def test_apply_func_to_edges(self): def test_apply_func_to_edges(self): graph = self.graph.copy() graph = self.graph.copy() mst_graph = graph.minimum_spanning_tree() graph.minimum_spanning_tree() try: try: graph.apply_func_to_edges('incorrect_func') graph.apply_func_to_edges('incorrect_func') except AttributeError: except AttributeError: pass pass mst_graph.extract_features(extractor_parameters={'nfeatures': 500}) graph.extract_features(extractor_parameters={'nfeatures': 500}) mst_graph.match_features() graph.match_features() mst_graph.apply_func_to_edges("symmetry_check") graph.apply_func_to_edges("symmetry_check", graph_mask_keys=['mst']) self.assertFalse(graph[0][2].masks['symmetry'].all()) self.assertFalse(graph[0][2].masks['symmetry'].all()) self.assertFalse(graph[0][1].masks['symmetry'].all()) self.assertFalse(graph[0][1].masks['symmetry'].all()) try: self.assertTrue(graph[1][2].masks['symmetry'].all()) self.assertTrue(graph[1][2].masks['symmetry'].all()) except: pass def test_connected_subgraphs(self): def test_connected_subgraphs(self): subgraph_list = self.disconnected_graph.connected_subgraphs() subgraph_list = self.disconnected_graph.connected_subgraphs() Loading Loading @@ -160,8 +159,14 @@ class TestCandidateGraph(unittest.TestCase): self.assertEqual(test_sub_graph.edges(), sub_graph_from_matches.edges()) self.assertEqual(test_sub_graph.edges(), sub_graph_from_matches.edges()) def test_minimum_spanning_tree(self): def tearDown(self): test_dict = {"0": ["4", "2", "1", "3"], pass class TestGraphMasks(unittest.TestCase): @classmethod def setUpClass(cls): cls.test_dict = {"0": ["4", "2", "1", "3"], "1": ["0", "3", "2", "6", "5"], "1": ["0", "3", "2", "6", "5"], "2": ["1", "0", "3", "4", "7"], "2": ["1", "0", "3", "4", "7"], "3": ["2", "0", "1", "5"], "3": ["2", "0", "1", "5"], Loading @@ -170,14 +175,13 @@ class TestCandidateGraph(unittest.TestCase): "6": ["1"], "6": ["1"], "7": ["2"]} "7": ["2"]} graph = network.CandidateGraph.from_adjacency(test_dict) cls.graph = network.CandidateGraph.from_adjacency(cls.test_dict) mst_graph = graph.minimum_spanning_tree() cls.graph.minimum_spanning_tree() removed_edges = cls.graph.graph_masks['mst'][cls.graph.graph_masks['mst'] == False].index print(len(mst_graph.edges())) self.assertEqual(sorted(mst_graph.nodes()), sorted(graph.nodes())) cls.mst_graph = cls.graph.copy() self.assertEqual(len(mst_graph.edges()), len(graph.edges())-5) cls.mst_graph.remove_edges_from(removed_edges) def test_mst_output(self): def tearDown(self): self.assertEqual(sorted(self.mst_graph.nodes()), sorted(self.graph.nodes())) pass self.assertEqual(self.mst_graph.number_of_edges(), self.graph.number_of_edges()-5) No newline at end of file