Commit fb5eb22d authored by jay's avatar jay
Browse files

Updates and integrates ring matcher

parent c3d7baa6
Loading
Loading
Loading
Loading
+101 −0
Original line number Diff line number Diff line
@@ -14,12 +14,14 @@ from autocnet.utils import utils
from autocnet.matcher import cpu_outlier_detector as od
from autocnet.matcher import suppression_funcs as spf
from autocnet.matcher import subpixel as sp
from autocnet.matcher import cpu_ring_matcher
from autocnet.transformation import fundamental_matrix as fm
from autocnet.transformation import homography as hm
from autocnet.vis.graph_view import plot_edge, plot_node, plot_edge_decomposition
from autocnet.cg import cg

from plio.io.io_gdal import GeoDataset
from plio.spatial.transformations import reproject


class Edge(dict, MutableMapping):
@@ -78,6 +80,16 @@ class Edge(dict, MutableMapping):
        else:
            raise(TypeError)
    
    @property
    def ring(self):
        if not hasattr(self, '_ring'):
            self._ring = None
        return self._ring

    @ring.setter
    def ring(self, val):
        self._ring = val

    def match(self, k=2, **kwargs):

        """
@@ -114,6 +126,90 @@ class Edge(dict, MutableMapping):
        """
        pass

    def ring_match(self, *args, **kwargs):
        ref_kps =  self.source.keypoints
        ref_desc = self.source.descriptors
        tar_kps = self.destination.keypoints
        tar_desc = self.destination.descriptors

        if not 'xm' in ref_kps.columns:
            warnings.warn('To ring match body centered coordinates (xm, ym, zm) must be in the keypoints')
            return
        ref_feats = ref_kps[['x', 'y', 'xm', 'ym', 'zm']].values
        tar_feats = tar_kps[['x', 'y', 'xm', 'ym', 'zm']].values

        xref, xtar, pidx, ring = cpu_ring_matcher.ring_match(ref_feats, tar_feats,
                                                           ref_desc, tar_desc,
                                                           *args, **kwargs)

        if pidx is None:
            return
        self.ring = ring
        pidx = cpu_ring_matcher.check_pidx_duplicates(pidx)

        #Set the columns of the matches df
        matches = np.empty((pidx.shape[0], 4))
        matches[:,0] = self.source['node_id']
        matches[:,1] = pidx[:,0]
        matches[:,2] = self.destination['node_id']
        matches[:,3] = pidx[:,1]

        matches = pd.DataFrame(matches, columns=['source',
                                                 'source_idx',
                                                 'destination',
                                                 'destination_idx']).astype(np.float32)
        
        self.matches = matches

    def add_coordinates_to_matches(self):
        """
        Add source and destination x/y columns to the matches dataframe. This
        will add to the overall memory needed to store matches, but makes
        access to x,y easier as a join on the keypoints is not requires.
        """
        skps = self.get_keypoints(self.source, index=self.matches.source_idx)
        dkps = self.get_keypoints(self.destination, index=self.matches.destination_idx)
        matches = self.matches
        matches[['source_x', 'source_y']] = skps.values
        matches[['destination_x', 'destination_y']] = dkps.values
        self.matches = matches

    def project_matches(self, semimajor, semiminor, on='source', srid=None):
        """
        Project matches.
        """
        try:
            coords = self.matches[['{}_y'.format(on),'{}_x'.format(on)]].values
        except:
            self.add_coordinates_to_matches()
            coords = self.matches[['{}_y'.format(on),'{}_x'.format(on)]].values

        node = getattr(self, on)
        camera = getattr(node, 'camera')
        if camera is None:
            warnings.warn('Unable to project matches without a sensor model.')
            return
        
        matches = self.matches
        
        gnd = np.empty((len(coords), 3))
        # Project the points to the surface and reproject into latlon space
        for i in range(gnd.shape[0]):
            gnd[i] = camera.imageToGround(coords[i][0], coords[i][1], 0)
        lon, lat, alt = reproject(gnd.T, semimajor, semiminor,
                                    'geocent', 'latlon')
        if srid:
            geoms = []
            for coord in zip(lon, lat, alt):
                geoms.append('SRID={};POINTZ({} {} {})'.format(srid, coord[0],
                                                                     coord[1],
                                                                     coord[2]))
            matches['geom'] = geoms
        
        matches['lat'] = lat
        matches['lon'] = lon
        self.matches = matches

    def decompose(self):
        """
        Apply coupled decomposition to the images and
@@ -198,6 +294,11 @@ class Edge(dict, MutableMapping):
        if not hasattr(index, '__iter__') and index is not None:
            raise TypeError
        keypts = node.get_keypoint_coordinates(index=index, homogeneous=homogeneous)
        # If the index is passed, the results are returned sorted. The index is not
        # necessarily sorted, so 'unsort' so that the return order matches the passed
        # order
        if index is not None:
            keypts = keypts.reindex(index)
        # If we only want keypoints in the overlap
        if overlap:
            if self.source == node:
+18 −1
Original line number Diff line number Diff line
import numpy as np

def check_pidx_duplicates(pidx):
    """
    Given a ring match generted set of indices, 
    apply outlier detection to ensure no duplicates
    exist in either the reference column or the
    source column. If duplicates do exist, remove the 
    rows; the solution is ambiguous.
    """
    # Check for duplicates
    l = pidx[:,1].tolist()
    clean = [i for i, x in enumerate(l) if l.count(x) == 1]
    pidx = pidx[clean, :]

    l = pidx[:,0].tolist()
    clean = [i for i, x in enumerate(l) if l.count(x) == 1]
    pidx = pidx[clean, :]
    return pidx

def ransac_permute(ref_points, tar_points, tolerance_val, target_points):
    """
    Given a set of reference points and target points, compute the
@@ -199,7 +217,6 @@ def ring_match(ref_feats, tar_feats, ref_desc, tar_desc, ring_radius=4000, max_r
    tar_xy = tar_feats[:,:2]
    tar_xmym = tar_feats[:,2:4]

    print('Ring Matcher Started: ', ref_feats.shape, tar_feats.shape)
    # Boolean mask for those reference points that have already been matched
    ref_mask = np.ones(len(ref_xy), dtype=bool)