Loading autocnet/camera/camera.py +1 −1 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ try: except: cv2 = None def compute_epipoles(f): """ Compute the epipole and epipolar prime Loading @@ -28,7 +29,6 @@ def compute_epipoles(f): return e, e1 def idealized_camera(): """ Create an idealized camera transformation matrix Loading autocnet/control/control.py +28 −5 Original line number Diff line number Diff line import warnings import networkx as nx import numpy as np import pandas as pd Loading @@ -6,6 +7,7 @@ from shapely.geometry import Point from plio.io.io_controlnetwork import to_isis, write_filelist print('reload') def identify_potential_overlaps(cg, cn, overlap=True): """ Loading Loading @@ -94,7 +96,7 @@ def deepen_correspondences(cg, cn): pass class ControlNetwork(object): measures_keys = ['point_id', 'image_index', 'keypoint_index', 'edge', 'match_idx', 'x', 'y'] measures_keys = ['point_id', 'image_index', 'keypoint_index', 'edge', 'match_idx', 'x', 'y', 'x_off', 'y_off', 'corr', 'valid'] def __init__(self): self._point_id = 0 Loading Loading @@ -150,9 +152,14 @@ class ControlNetwork(object): # The node_id is a composite key (image_id, correspondence_id), so just grab the image image_id = key[0] match_id = key[1] self.data.loc[self._measure_id] = [point_id, image_id, match_id, edge, match_idx, *fields] self.data.loc[self._measure_id] = [point_id, image_id, match_id, edge, match_idx, *fields, 0, 0, np.inf, True] self._measure_id += 1 def remove_measure(self, idx): self.data = self.data.drop(self.data.index[idx]) for r in idx: self.measure_to_point.pop(r, None) def validate_points(self): """ Ensure that all control points currently in the nework are valid. Loading @@ -168,14 +175,21 @@ class ControlNetwork(object): """ def func(g): print(g) # One and only one measure constraint if not g.image_index.duplicated().any(): if g.image_index.duplicated().any(): return True else: return False return self.data.groupby('point_id').apply(func) def clean_singles(self): """ Take the `data` dataframe and return only those points with at least two measures. This is automatically called before writing as functions such as subpixel matching can result in orphaned measures. """ return self.data.groupby('point_id').apply(lambda g: g if len(g) > 1 else None) def to_isis(self, outname, serials, olist, *args, **kwargs): #pragma: no cover """ Write the control network out to the ISIS3 control network format. Loading @@ -185,9 +199,18 @@ class ControlNetwork(object): warnings.warn('Control Network is not ISIS3 compliant. Please run the validate_points method on the control network.') return to_isis(outname + '.net', self.data, serials, *args, **kwargs) # Apply the subpixel shift self.data.x += self.data.x_off self.data.y += self.data.y_off to_isis(outname + '.net', self.data.query('valid == True'), serials, *args, **kwargs) write_filelist(olist, outname + '.lis') # Back out the subpixel shift self.data.x -= self.data.x_off self.data.y -= self.data.y_off def to_bal(self): """ Write the control network out to the Bundle Adjustment in the Large Loading autocnet/graph/edge.py +10 −5 Original line number Diff line number Diff line Loading @@ -318,6 +318,7 @@ class Edge(dict, MutableMapping): source_image = (matches.iloc[0]['source_image']) pts = [] # for each edge, calculate this for each keypoint pair for i, (idx, row) in enumerate(matches.iterrows()): s_idx = int(row['source_idx']) Loading @@ -329,9 +330,12 @@ class Edge(dict, MutableMapping): # Get the template and search window s_template = sp.clip_roi(s_img, s_keypoint, template_size) d_search = sp.clip_roi(d_img, d_keypoint, search_size) if 0 in s_template.shape or 0 in d_search.shape: continue try: x_offset, y_offset, strength = sp.subpixel_offset(s_template, d_search, **kwargs) (x_offset, y_offset, strength),ref = sp.subpixel_offset(s_template, d_search, **kwargs) self.subpixel_matches.loc[idx, ('x_offset', 'y_offset', 'correlation', 'reference')]= [x_offset, y_offset, strength, source_image] pts.append([s_template, d_search, ref, x_offset, y_offset]) except: warnings.warn('Template-Search size mismatch, failing for this correspondence point.') Loading @@ -349,6 +353,7 @@ class Edge(dict, MutableMapping): self.masks['shift'] = shift_mask self.masks['threshold'] = threshold_mask self.masks['subpixel'] = mask return pts def suppress(self, suppression_func=spf.correlation, clean_keys=[], maskname='suppression', **kwargs): """ Loading Loading @@ -521,6 +526,7 @@ class Edge(dict, MutableMapping): buf = -buffer_dist smbr[i] += buf dmbr[i] += buf except: smbr = self.source.geodata.xy_extent dmbr = self.source.geodata.xy_extent Loading @@ -531,11 +537,11 @@ class Edge(dict, MutableMapping): self['source_mbr'] = smbr self['destin_mbr'] = dmbr def get_matches(self): # pragma: no cover def get_matches(self, clean_keys=[]): # pragma: no cover if self.matches.empty: return pd.DataFrame() match, _ = self.clean(clean_keys=list(self.masks.columns)) match, _ = self.clean(clean_keys=clean_keys) match = match[['source_image', 'source_idx', 'destination_image', 'destination_idx']] skps = self.get_keypoints('source', index=match.source_idx) Loading @@ -544,5 +550,4 @@ class Edge(dict, MutableMapping): dkps.columns = ['destination_x', 'destination_y'] match = match.join(skps, on='source_idx') match = match.join(dkps, on='destination_idx') matches.append(match) return matches return match autocnet/graph/node.py +2 −2 Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ class Node(dict, MutableMapping): array = self.geodata.read_array(band=band) return bytescale(array) def get_array(self, band=1): def get_array(self, band=1, **kwargs): """ Get a band as a 32-bit numpy array Loading @@ -196,7 +196,7 @@ class Node(dict, MutableMapping): The band to read, default 1 """ array = self.geodata.read_array(band=band) array = self.geodata.read_array(band=band, **kwargs) return array def get_keypoints(self, index=None): Loading autocnet/matcher/cuda_extractor.py +1 −1 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ def extract_features(array, nfeatures=None, **kwargs): A custom docstring. """ if not nfeatures: nfeatures = int(max(array.shape) / 1.75) nfeatures = int(max(array.shape) / 1.25) else: warnings.warn('NFeatures specified with the CudaSift implementation. Please ensure the distribution of keypoints is what you expect.') Loading Loading
autocnet/camera/camera.py +1 −1 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ try: except: cv2 = None def compute_epipoles(f): """ Compute the epipole and epipolar prime Loading @@ -28,7 +29,6 @@ def compute_epipoles(f): return e, e1 def idealized_camera(): """ Create an idealized camera transformation matrix Loading
autocnet/control/control.py +28 −5 Original line number Diff line number Diff line import warnings import networkx as nx import numpy as np import pandas as pd Loading @@ -6,6 +7,7 @@ from shapely.geometry import Point from plio.io.io_controlnetwork import to_isis, write_filelist print('reload') def identify_potential_overlaps(cg, cn, overlap=True): """ Loading Loading @@ -94,7 +96,7 @@ def deepen_correspondences(cg, cn): pass class ControlNetwork(object): measures_keys = ['point_id', 'image_index', 'keypoint_index', 'edge', 'match_idx', 'x', 'y'] measures_keys = ['point_id', 'image_index', 'keypoint_index', 'edge', 'match_idx', 'x', 'y', 'x_off', 'y_off', 'corr', 'valid'] def __init__(self): self._point_id = 0 Loading Loading @@ -150,9 +152,14 @@ class ControlNetwork(object): # The node_id is a composite key (image_id, correspondence_id), so just grab the image image_id = key[0] match_id = key[1] self.data.loc[self._measure_id] = [point_id, image_id, match_id, edge, match_idx, *fields] self.data.loc[self._measure_id] = [point_id, image_id, match_id, edge, match_idx, *fields, 0, 0, np.inf, True] self._measure_id += 1 def remove_measure(self, idx): self.data = self.data.drop(self.data.index[idx]) for r in idx: self.measure_to_point.pop(r, None) def validate_points(self): """ Ensure that all control points currently in the nework are valid. Loading @@ -168,14 +175,21 @@ class ControlNetwork(object): """ def func(g): print(g) # One and only one measure constraint if not g.image_index.duplicated().any(): if g.image_index.duplicated().any(): return True else: return False return self.data.groupby('point_id').apply(func) def clean_singles(self): """ Take the `data` dataframe and return only those points with at least two measures. This is automatically called before writing as functions such as subpixel matching can result in orphaned measures. """ return self.data.groupby('point_id').apply(lambda g: g if len(g) > 1 else None) def to_isis(self, outname, serials, olist, *args, **kwargs): #pragma: no cover """ Write the control network out to the ISIS3 control network format. Loading @@ -185,9 +199,18 @@ class ControlNetwork(object): warnings.warn('Control Network is not ISIS3 compliant. Please run the validate_points method on the control network.') return to_isis(outname + '.net', self.data, serials, *args, **kwargs) # Apply the subpixel shift self.data.x += self.data.x_off self.data.y += self.data.y_off to_isis(outname + '.net', self.data.query('valid == True'), serials, *args, **kwargs) write_filelist(olist, outname + '.lis') # Back out the subpixel shift self.data.x -= self.data.x_off self.data.y -= self.data.y_off def to_bal(self): """ Write the control network out to the Bundle Adjustment in the Large Loading
autocnet/graph/edge.py +10 −5 Original line number Diff line number Diff line Loading @@ -318,6 +318,7 @@ class Edge(dict, MutableMapping): source_image = (matches.iloc[0]['source_image']) pts = [] # for each edge, calculate this for each keypoint pair for i, (idx, row) in enumerate(matches.iterrows()): s_idx = int(row['source_idx']) Loading @@ -329,9 +330,12 @@ class Edge(dict, MutableMapping): # Get the template and search window s_template = sp.clip_roi(s_img, s_keypoint, template_size) d_search = sp.clip_roi(d_img, d_keypoint, search_size) if 0 in s_template.shape or 0 in d_search.shape: continue try: x_offset, y_offset, strength = sp.subpixel_offset(s_template, d_search, **kwargs) (x_offset, y_offset, strength),ref = sp.subpixel_offset(s_template, d_search, **kwargs) self.subpixel_matches.loc[idx, ('x_offset', 'y_offset', 'correlation', 'reference')]= [x_offset, y_offset, strength, source_image] pts.append([s_template, d_search, ref, x_offset, y_offset]) except: warnings.warn('Template-Search size mismatch, failing for this correspondence point.') Loading @@ -349,6 +353,7 @@ class Edge(dict, MutableMapping): self.masks['shift'] = shift_mask self.masks['threshold'] = threshold_mask self.masks['subpixel'] = mask return pts def suppress(self, suppression_func=spf.correlation, clean_keys=[], maskname='suppression', **kwargs): """ Loading Loading @@ -521,6 +526,7 @@ class Edge(dict, MutableMapping): buf = -buffer_dist smbr[i] += buf dmbr[i] += buf except: smbr = self.source.geodata.xy_extent dmbr = self.source.geodata.xy_extent Loading @@ -531,11 +537,11 @@ class Edge(dict, MutableMapping): self['source_mbr'] = smbr self['destin_mbr'] = dmbr def get_matches(self): # pragma: no cover def get_matches(self, clean_keys=[]): # pragma: no cover if self.matches.empty: return pd.DataFrame() match, _ = self.clean(clean_keys=list(self.masks.columns)) match, _ = self.clean(clean_keys=clean_keys) match = match[['source_image', 'source_idx', 'destination_image', 'destination_idx']] skps = self.get_keypoints('source', index=match.source_idx) Loading @@ -544,5 +550,4 @@ class Edge(dict, MutableMapping): dkps.columns = ['destination_x', 'destination_y'] match = match.join(skps, on='source_idx') match = match.join(dkps, on='destination_idx') matches.append(match) return matches return match
autocnet/graph/node.py +2 −2 Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ class Node(dict, MutableMapping): array = self.geodata.read_array(band=band) return bytescale(array) def get_array(self, band=1): def get_array(self, band=1, **kwargs): """ Get a band as a 32-bit numpy array Loading @@ -196,7 +196,7 @@ class Node(dict, MutableMapping): The band to read, default 1 """ array = self.geodata.read_array(band=band) array = self.geodata.read_array(band=band, **kwargs) return array def get_keypoints(self, index=None): Loading
autocnet/matcher/cuda_extractor.py +1 −1 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ def extract_features(array, nfeatures=None, **kwargs): A custom docstring. """ if not nfeatures: nfeatures = int(max(array.shape) / 1.75) nfeatures = int(max(array.shape) / 1.25) else: warnings.warn('NFeatures specified with the CudaSift implementation. Please ensure the distribution of keypoints is what you expect.') Loading