Commit a7da191d authored by jay's avatar jay
Browse files

Updates for epipolar geometry and subpixel matching

parent d5fbb483
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ try:
except:
    cv2 = None


def compute_epipoles(f):
    """
    Compute the epipole and epipolar prime
@@ -28,7 +29,6 @@ def compute_epipoles(f):

    return e, e1


def idealized_camera():
    """
    Create an idealized camera transformation matrix
+28 −5
Original line number Diff line number Diff line
import warnings
import networkx as nx
import numpy as np
import pandas as pd
@@ -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):
    """
@@ -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
@@ -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.
@@ -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.
@@ -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
+10 −5
Original line number Diff line number Diff line
@@ -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'])
@@ -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.')

@@ -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):
        """
@@ -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
@@ -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)
@@ -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
+2 −2
Original line number Diff line number Diff line
@@ -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

@@ -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):
+1 −1
Original line number Diff line number Diff line
@@ -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