Loading autocnet/camera/sensor_model.py +35 −22 Original line number Diff line number Diff line Loading @@ -82,8 +82,14 @@ class BaseSensor: return x_coords, y_coords def _flatten_results(self, x, results): if isinstance(x, (collections.abc.Sequence, np.ndarray)): if isinstance(x, collections.abc.Sequence): # Maintain the return type, if a sequence is passed, # return a sequence. if isinstance(results, np.ndarray): return results.tolist() return results elif isinstance(x, np.ndarray): return np.asarray(results) else: return results[0] Loading Loading @@ -397,13 +403,15 @@ class CSMSensor(BaseSensor): def xyz2sampline(self, x, y, z): x_coords, y_coords, z_coords = self._check_arg(x, y, z) results = [] for coord in zip(x_coords, y_coords, z_coords): results = np.empty((len(x_coords),2)) for i, coord in enumerate(zip(x_coords, y_coords, z_coords)): imagept = generate_image_coordinate(coord, self.sensor) results+=[imagept.samp, imagept.line] return self._flatten_results(x_coords, results) results[i,0] = imagept.samp results[i,1] = imagept.line return (self._flatten_results(x, results[:,0]), self._flatten_results(x, results[:,1])) def lonlat2sampline(self, lon, lat): def lonlat2sampline(self, lon, lat, **kwargs): """ Calculate the sample and line for an csm camera sensor Loading @@ -426,14 +434,15 @@ class CSMSensor(BaseSensor): lint of point """ x_coords, y_coords = self._check_arg(lon, lat) results = [] heights = [] for coord in zip(x_coords, y_coords): # get_height needs lat, lon ordering height = self.dem.get_height(coord[1], coord[0]) x,y,z = og2xyz(lon, lat, height, self.semi_major, self.semi_minor) results += [x,y,z] results = self._flatten_results(lat, results) return self.xyz2sampline(x,y,z) heights.append(self.dem.get_height(coord[1], coord[0])) x,y,z = og2xyz(x_coords, y_coords, heights, self.semi_major, self.semi_minor) return self.xyz2sampline(self._flatten_results(lon, x), self._flatten_results(lon, y), self._flatten_results(lon, z)) def sampline2xyz(self, sample, line): """ Loading Loading @@ -463,24 +472,28 @@ class CSMSensor(BaseSensor): x,y,z : int(s) x,y,z coordinates of the point """ sample, line = self._check_arg(sample, line) results = [] csample, cline = self._check_arg(sample, line) results = np.empty((len(csample),3)) # CSMAPI using line/sample ordering. Swap here. for coord in zip(line, sample): for i, coord in enumerate(zip(cline, csample)): # self.dem is an autocnet surface model dem that has a GeoDataset attribute bcbf = generate_ground_point(self.dem, coord, self.sensor) results += [bcbf.x, bcbf.y, bcbf.z] return self._flatten_results(sample, results) def sampline2lonlat(self, sample, line): results[i,0] = bcbf.x results[i,1] = bcbf.y results[i,2] = bcbf.z return (self._flatten_results(sample, results[:,0]), self._flatten_results(sample, results[:,1]), self._flatten_results(sample, results[:,2])) def sampline2lonlat(self, sample, line, **kwargs): # sampline2xyz handles the CSM iteration, just pass the array through x,y,z = self.sampline2xyz(sample, line) lon, lat = xyz2og(x, y, z, self.semi_major, self.semi_minor) return lon, lat lons, lats = xyz2og(x, y, z, self.semi_major, self.semi_minor) return lons, lats def lonlat2xyz(self, lon, lat): # All size checking and response type code is handled in self.lonlat2sampline sample, line = self.lonlat2sampline(lon, lat) print(sample, line) return self.sampline2xyz(sample, line) Loading autocnet/graph/network.py +4 −23 Original line number Diff line number Diff line Loading @@ -56,7 +56,6 @@ from autocnet.matcher import subpixel from autocnet.matcher import cross_instrument_matcher as cim from autocnet.vis.graph_view import plot_graph, cluster_plot from autocnet.control import control #from autocnet.spatial.isis import point_info from knoten.surface import GdalDem, EllipsoidDem from autocnet.transformation.spatial import reproject, og2oc Loading Loading @@ -106,7 +105,7 @@ class CandidateGraph(nx.Graph): 'keypoint_index' : int } def __init__(self, *args, basepath=None, node_id_map=None, overlaps=False, **kwargs): def __init__(self, *args, basepath=None, node_id_map=None, overlaps=False, cam_type='isis', **kwargs): super(CandidateGraph, self).__init__(*args, **kwargs) self.graph['creationdate'] = strftime("%Y-%m-%d %H:%M:%S", gmtime()) Loading @@ -132,7 +131,7 @@ class CandidateGraph(nx.Graph): node_id = self.graph['node_counter'] self.graph['node_counter'] += 1 n['data'] = self.node_factory( image_name=i, image_path=image_path, node_id=node_id) image_name=i, image_path=image_path, node_id=node_id, cam_type=cam_type) self.graph['node_name_map'][i] = node_id Loading Loading @@ -1597,12 +1596,6 @@ class NetworkCandidateGraph(CandidateGraph): if self.async_watchers == True: self._setup_asynchronous_workers() # Setup the DEM # I dislike having the DEM on the NCG, but in the short term it # is the best solution I think. I don't want to pass the DEM around # for the sensor calls. self._setup_dem() @contextmanager def session_scope(self): """ Loading @@ -1618,17 +1611,6 @@ class NetworkCandidateGraph(CandidateGraph): finally: session.close() def _setup_dem(self): spatial = self.config['spatial'] semi_major = spatial.get('semimajor_rad') semi_minor = spatial.get('semiminor_rad') dem_type = spatial.get('dem_type') dem = spatial.get('dem', False) if dem: self.dem = GdalDem(dem, semi_major, semi_minor, dem_type) else: self.dem = EllipsoidDem(semi_major, semi_minor) @property def Session(self): return self._Session Loading @@ -1638,7 +1620,6 @@ class NetworkCandidateGraph(CandidateGraph): self._Session = Session def _setup_database(self): db = self.config['database'] # A non-linear timeout if the DB is spinning up or loaded with many connections. sleeptime = 2 retries = 0 Loading Loading @@ -2480,7 +2461,7 @@ class NetworkCandidateGraph(CandidateGraph): if overlaps: self._execute_sql(sql.compute_overlaps_sql) def from_database(self, query_string=sql.select_pub_image): def from_database(self, query_string=sql.select_pub_image, cam_type='isis'): """ This is a constructor that takes the results from an arbitrary query string, uses those as a subquery into a standard polygon overlap query and Loading Loading @@ -2528,7 +2509,7 @@ class NetworkCandidateGraph(CandidateGraph): adjacency[spath].append(dpath) # Add nodes that do not overlap any images self.__init__(adjacency, node_id_map=adjacency_lookup) self.__init__(adjacency, node_id_map=adjacency_lookup, cam_type=cam_type) # Setup the edges self._setup_edges() Loading autocnet/graph/node.py +18 −13 Original line number Diff line number Diff line Loading @@ -65,23 +65,22 @@ class Node(dict, MutableMapping): ISIS compatible serial number """ def __init__(self, image_name=None, image_path=None, node_id=None): def __init__(self, image_name=None, image_path=None, node_id=None, cam_type='isis', dem=None, dem_type=None): self['image_name'] = image_name self['image_path'] = image_path self['node_id'] = node_id self['hash'] = image_name self['cam_type'] = cam_type self['dem'] = dem self['dem_type'] = 'radius' if dem_type is None else dem_type self.masks = pd.DataFrame() @property def camera(self): if not hasattr(self, '_camera'): self._camera = None return self._camera @camera.setter def camera(self, camera): self._camera = camera @property def descriptors(self): if not hasattr(self, '_descriptors'): Loading Loading @@ -120,8 +119,11 @@ class Node(dict, MutableMapping): Number Keypoints: {} Available Masks : {} Type: {} Sensor Model Type: {} DEM: {} """.format(self['node_id'], self['image_name'], self['image_path'], self.nkeypoints, self.masks, self.__class__) self.nkeypoints, self.masks, self.__class__, self['cam_type'], self['dem']) def __hash__(self): #pragma: no cover return hash(self['node_id']) Loading Loading @@ -166,7 +168,10 @@ class Node(dict, MutableMapping): @property def geodata(self): if not hasattr(self, '_geodata'): self._geodata = AGeoDataset(self['image_path']) self._geodata = AGeoDataset(self['image_path'], sensortype = self['cam_type'], dem=self['dem'], dem_type=self['dem_type']) return self._geodata @property Loading autocnet/graph/tests/test_node.py +0 −3 Original line number Diff line number Diff line Loading @@ -33,9 +33,6 @@ class TestNode(object): img = get_path('AS15-M-0297_crop.cub') return Node(image_name='AS15-M-0297_crop.cub', image_path=img) def test_get_camera(self, node): assert node.camera == None def test_create(self): assert isinstance(Node.create(None, 1), Node) n = Node.create('foo', 1, basepath='/') Loading autocnet/io/db/model.py +2 −0 Original line number Diff line number Diff line Loading @@ -311,6 +311,8 @@ class Images(BaseMixin, Base): _geom = Column("geom", Geometry('MultiPolygon', srid=latitudinal_srid, dimension=2, spatial_index=True)) footprint_bodyfixed = Column(Geometry('MULTIPOLYGON', dimension=2)) cam_type = Column(String) dem = Column(String) dem_type = Column(String) #footprint_bodyfixed = Column(Geometry('POLYGON',dimension=3)) # Relationships Loading Loading
autocnet/camera/sensor_model.py +35 −22 Original line number Diff line number Diff line Loading @@ -82,8 +82,14 @@ class BaseSensor: return x_coords, y_coords def _flatten_results(self, x, results): if isinstance(x, (collections.abc.Sequence, np.ndarray)): if isinstance(x, collections.abc.Sequence): # Maintain the return type, if a sequence is passed, # return a sequence. if isinstance(results, np.ndarray): return results.tolist() return results elif isinstance(x, np.ndarray): return np.asarray(results) else: return results[0] Loading Loading @@ -397,13 +403,15 @@ class CSMSensor(BaseSensor): def xyz2sampline(self, x, y, z): x_coords, y_coords, z_coords = self._check_arg(x, y, z) results = [] for coord in zip(x_coords, y_coords, z_coords): results = np.empty((len(x_coords),2)) for i, coord in enumerate(zip(x_coords, y_coords, z_coords)): imagept = generate_image_coordinate(coord, self.sensor) results+=[imagept.samp, imagept.line] return self._flatten_results(x_coords, results) results[i,0] = imagept.samp results[i,1] = imagept.line return (self._flatten_results(x, results[:,0]), self._flatten_results(x, results[:,1])) def lonlat2sampline(self, lon, lat): def lonlat2sampline(self, lon, lat, **kwargs): """ Calculate the sample and line for an csm camera sensor Loading @@ -426,14 +434,15 @@ class CSMSensor(BaseSensor): lint of point """ x_coords, y_coords = self._check_arg(lon, lat) results = [] heights = [] for coord in zip(x_coords, y_coords): # get_height needs lat, lon ordering height = self.dem.get_height(coord[1], coord[0]) x,y,z = og2xyz(lon, lat, height, self.semi_major, self.semi_minor) results += [x,y,z] results = self._flatten_results(lat, results) return self.xyz2sampline(x,y,z) heights.append(self.dem.get_height(coord[1], coord[0])) x,y,z = og2xyz(x_coords, y_coords, heights, self.semi_major, self.semi_minor) return self.xyz2sampline(self._flatten_results(lon, x), self._flatten_results(lon, y), self._flatten_results(lon, z)) def sampline2xyz(self, sample, line): """ Loading Loading @@ -463,24 +472,28 @@ class CSMSensor(BaseSensor): x,y,z : int(s) x,y,z coordinates of the point """ sample, line = self._check_arg(sample, line) results = [] csample, cline = self._check_arg(sample, line) results = np.empty((len(csample),3)) # CSMAPI using line/sample ordering. Swap here. for coord in zip(line, sample): for i, coord in enumerate(zip(cline, csample)): # self.dem is an autocnet surface model dem that has a GeoDataset attribute bcbf = generate_ground_point(self.dem, coord, self.sensor) results += [bcbf.x, bcbf.y, bcbf.z] return self._flatten_results(sample, results) def sampline2lonlat(self, sample, line): results[i,0] = bcbf.x results[i,1] = bcbf.y results[i,2] = bcbf.z return (self._flatten_results(sample, results[:,0]), self._flatten_results(sample, results[:,1]), self._flatten_results(sample, results[:,2])) def sampline2lonlat(self, sample, line, **kwargs): # sampline2xyz handles the CSM iteration, just pass the array through x,y,z = self.sampline2xyz(sample, line) lon, lat = xyz2og(x, y, z, self.semi_major, self.semi_minor) return lon, lat lons, lats = xyz2og(x, y, z, self.semi_major, self.semi_minor) return lons, lats def lonlat2xyz(self, lon, lat): # All size checking and response type code is handled in self.lonlat2sampline sample, line = self.lonlat2sampline(lon, lat) print(sample, line) return self.sampline2xyz(sample, line) Loading
autocnet/graph/network.py +4 −23 Original line number Diff line number Diff line Loading @@ -56,7 +56,6 @@ from autocnet.matcher import subpixel from autocnet.matcher import cross_instrument_matcher as cim from autocnet.vis.graph_view import plot_graph, cluster_plot from autocnet.control import control #from autocnet.spatial.isis import point_info from knoten.surface import GdalDem, EllipsoidDem from autocnet.transformation.spatial import reproject, og2oc Loading Loading @@ -106,7 +105,7 @@ class CandidateGraph(nx.Graph): 'keypoint_index' : int } def __init__(self, *args, basepath=None, node_id_map=None, overlaps=False, **kwargs): def __init__(self, *args, basepath=None, node_id_map=None, overlaps=False, cam_type='isis', **kwargs): super(CandidateGraph, self).__init__(*args, **kwargs) self.graph['creationdate'] = strftime("%Y-%m-%d %H:%M:%S", gmtime()) Loading @@ -132,7 +131,7 @@ class CandidateGraph(nx.Graph): node_id = self.graph['node_counter'] self.graph['node_counter'] += 1 n['data'] = self.node_factory( image_name=i, image_path=image_path, node_id=node_id) image_name=i, image_path=image_path, node_id=node_id, cam_type=cam_type) self.graph['node_name_map'][i] = node_id Loading Loading @@ -1597,12 +1596,6 @@ class NetworkCandidateGraph(CandidateGraph): if self.async_watchers == True: self._setup_asynchronous_workers() # Setup the DEM # I dislike having the DEM on the NCG, but in the short term it # is the best solution I think. I don't want to pass the DEM around # for the sensor calls. self._setup_dem() @contextmanager def session_scope(self): """ Loading @@ -1618,17 +1611,6 @@ class NetworkCandidateGraph(CandidateGraph): finally: session.close() def _setup_dem(self): spatial = self.config['spatial'] semi_major = spatial.get('semimajor_rad') semi_minor = spatial.get('semiminor_rad') dem_type = spatial.get('dem_type') dem = spatial.get('dem', False) if dem: self.dem = GdalDem(dem, semi_major, semi_minor, dem_type) else: self.dem = EllipsoidDem(semi_major, semi_minor) @property def Session(self): return self._Session Loading @@ -1638,7 +1620,6 @@ class NetworkCandidateGraph(CandidateGraph): self._Session = Session def _setup_database(self): db = self.config['database'] # A non-linear timeout if the DB is spinning up or loaded with many connections. sleeptime = 2 retries = 0 Loading Loading @@ -2480,7 +2461,7 @@ class NetworkCandidateGraph(CandidateGraph): if overlaps: self._execute_sql(sql.compute_overlaps_sql) def from_database(self, query_string=sql.select_pub_image): def from_database(self, query_string=sql.select_pub_image, cam_type='isis'): """ This is a constructor that takes the results from an arbitrary query string, uses those as a subquery into a standard polygon overlap query and Loading Loading @@ -2528,7 +2509,7 @@ class NetworkCandidateGraph(CandidateGraph): adjacency[spath].append(dpath) # Add nodes that do not overlap any images self.__init__(adjacency, node_id_map=adjacency_lookup) self.__init__(adjacency, node_id_map=adjacency_lookup, cam_type=cam_type) # Setup the edges self._setup_edges() Loading
autocnet/graph/node.py +18 −13 Original line number Diff line number Diff line Loading @@ -65,23 +65,22 @@ class Node(dict, MutableMapping): ISIS compatible serial number """ def __init__(self, image_name=None, image_path=None, node_id=None): def __init__(self, image_name=None, image_path=None, node_id=None, cam_type='isis', dem=None, dem_type=None): self['image_name'] = image_name self['image_path'] = image_path self['node_id'] = node_id self['hash'] = image_name self['cam_type'] = cam_type self['dem'] = dem self['dem_type'] = 'radius' if dem_type is None else dem_type self.masks = pd.DataFrame() @property def camera(self): if not hasattr(self, '_camera'): self._camera = None return self._camera @camera.setter def camera(self, camera): self._camera = camera @property def descriptors(self): if not hasattr(self, '_descriptors'): Loading Loading @@ -120,8 +119,11 @@ class Node(dict, MutableMapping): Number Keypoints: {} Available Masks : {} Type: {} Sensor Model Type: {} DEM: {} """.format(self['node_id'], self['image_name'], self['image_path'], self.nkeypoints, self.masks, self.__class__) self.nkeypoints, self.masks, self.__class__, self['cam_type'], self['dem']) def __hash__(self): #pragma: no cover return hash(self['node_id']) Loading Loading @@ -166,7 +168,10 @@ class Node(dict, MutableMapping): @property def geodata(self): if not hasattr(self, '_geodata'): self._geodata = AGeoDataset(self['image_path']) self._geodata = AGeoDataset(self['image_path'], sensortype = self['cam_type'], dem=self['dem'], dem_type=self['dem_type']) return self._geodata @property Loading
autocnet/graph/tests/test_node.py +0 −3 Original line number Diff line number Diff line Loading @@ -33,9 +33,6 @@ class TestNode(object): img = get_path('AS15-M-0297_crop.cub') return Node(image_name='AS15-M-0297_crop.cub', image_path=img) def test_get_camera(self, node): assert node.camera == None def test_create(self): assert isinstance(Node.create(None, 1), Node) n = Node.create('foo', 1, basepath='/') Loading
autocnet/io/db/model.py +2 −0 Original line number Diff line number Diff line Loading @@ -311,6 +311,8 @@ class Images(BaseMixin, Base): _geom = Column("geom", Geometry('MultiPolygon', srid=latitudinal_srid, dimension=2, spatial_index=True)) footprint_bodyfixed = Column(Geometry('MULTIPOLYGON', dimension=2)) cam_type = Column(String) dem = Column(String) dem_type = Column(String) #footprint_bodyfixed = Column(Geometry('POLYGON',dimension=3)) # Relationships Loading