Commit 37412832 authored by jay's avatar jay
Browse files

Revert "updates to the matchers to reflect the attribute changes on the edges"

This reverts commit 2a595e9a.
parent 933533c9
Loading
Loading
Loading
Loading
+84 −45
Original line number Diff line number Diff line
@@ -6,8 +6,7 @@ from autocnet.matcher.feature_matcher import match
from autocnet.transformation.decompose import coupled_decomposition


def decompose(self, subset=False, k=2, maxiteration=2, size=18,
              buf_dist=3, ndv=None, **kwargs):
def decompose_and_match(self, k=2, maxiteration=3, size=18, buf_dist=3,**kwargs):
    """
    Similar to match, this method first decomposed the image into
    $4^{maxiteration}$ subimages and applys matching between each sub-image.
@@ -22,6 +21,10 @@ def decompose(self, subset=False, k=2, maxiteration=2, size=18,
    k : int
        The number of neighbors to find

    method : {'coupled', 'whole'}
             whether to utilize coupled decomposition
             or match the whole image

    maxiteration : int
                   When using coupled decomposition, the number of recursive
                   divisions to apply.  The total number of resultant
@@ -46,28 +49,26 @@ def decompose(self, subset=False, k=2, maxiteration=2, size=18,
               the (sub)image a point must be in order to be used as a
               partioning point.  The smaller the distance, the more likely
               percision errors can results in erroneous partitions.

    ndv : float
          The no data value that will be masked when computing the radial
          correlation.
    """

    def func(group):
        ratio = 0.8
        res = [False] * len(group)
        if len(res) == 1:
            return [single]
        if group.iloc[0] < group.iloc[1] * ratio:
            res[0] = True
        return res

    # Grab the original image arrays
    sdata = self.source.get_array()
    ddata = self.destination.get_array()

    ssize = sdata.shape
    dsize = ddata.shape

    sdata[sdata == ndv] = np.nan
    ddata[ddata == ndv] = np.nan

    matches, _ = self.clean(['ratio'])
    sidx = matches['source_idx']
    didx = matches['destination_idx']

    # Grab all the available candidate keypoints
    skp = self.source.get_keypoints().loc[sidx]
    dkp = self.destination.get_keypoints().loc[didx]
    skp = self.source.get_keypoints()
    dkp = self.destination.get_keypoints()

    # Set up the membership arrays
    self.smembership = np.zeros(sdata.shape, dtype=np.int16)
@@ -75,9 +76,12 @@ def decompose(self, subset=False, k=2, maxiteration=2, size=18,
    self.smembership[:] = -1
    self.dmembership[:] = -1
    pcounter = 0

    # FLANN Matcher
    fl= FlannMatcher()

    for k in range(maxiteration):
        partitions = np.unique(self.smembership)
        npartitions = len(partitions)
        for p in partitions:
            sy_part, sx_part = np.where(self.smembership == p)
            dy_part, dx_part = np.where(self.dmembership == p)
@@ -94,55 +98,90 @@ def decompose(self, subset=False, k=2, maxiteration=2, size=18,
            mindx = np.min(dx_part)
            maxdx = np.max(dx_part) + 1

            # Clip the sub image from the full images (this is a MBR)
            # Clip the sub image from the full images
            asub = sdata[minsy:maxsy, minsx:maxsx]
            bsub = ddata[mindy:maxdy, mindx:maxdx]

            # Approximate the mid point of the partition as the mean of the matched keypoints
            sub_skp = skp.query('x >= {} and x <= {} and y >= {} and y <= {}'.format(minsx, maxsx,
                                                                                 minsy, maxsy))
            # Utilize the FLANN matcher to find a match to approximate a center
            fl.add(self.destination.descriptors, self.destination['node_id'])
            fl.train()

            scounter = 0
            decompose = False
            while True:
                sub_skp = skp.query('x >= {} and x <= {} and y >= {} and y <= {}'.format(minsx, maxsx, minsy, maxsy))
                # Check the size to ensure a valid return
                if len(sub_skp) == 0:
                    break # No valid keypoints in this (sub)image
                if size > len(sub_skp):
                    size = len(sub_skp)
                candidate_idx = np.random.choice(sub_skp.index, size=size, replace=False)
                candidates = self.source.descriptors[candidate_idx]
                matches = fl.query(candidates, self.source['node_id'], k=3, index=candidate_idx)

                # Apply Lowe's ratio test to try to find a 'good' starting point
                mask = matches.groupby('source_idx')['distance'].transform(func).astype('bool')
                candidate_matches = matches[mask]
                match_idx = candidate_matches['source_idx'].astype(np.int)

                # Extract those matches that pass the ratio check
                sub_skp = skp.iloc[match_idx]

                # Check that valid points remain
                if len(sub_skp) == 0:
                    break

                # Locate the candidate closest to the middle of all of the matches
                smx, smy = sub_skp[['x', 'y']].mean()
                mid = np.array([[smx, smy]])
                dists = cdist(mid, sub_skp[['x', 'y']])

                closest = sub_skp.iloc[np.argmin(dists)]
                closest_idx = closest.name
                soriginx, soriginy = closest[['x', 'y']]

                # Grab the corresponding point in the destination
            dest_idx = matches[matches['source_idx'] == closest_idx]['destination_idx']
            dest_pt = dkp.loc[dest_idx]
            doriginx, doriginy = dest_pt[['x', 'y']].values[0]

            # Sub image origin is assumed to be 0,0 (local sub-image space), while match point origins are
            # in the full image space.  Shift the match point orign to be in the sub-image space if needed
            soriginx -= minsx
            soriginy -= minsy
            doriginx -= mindx
            doriginy -= mindy

            # Apply coupled decomposition
                q = candidate_matches.query('source_idx == {}'.format(closest.name))
                dest_idx = int(q['destination_idx'].iat[0])
                doriginx = dkp.at[dest_idx, 'x']
                doriginy = dkp.at[dest_idx, 'y']

                if mindy + buf_dist <= doriginy <= maxdy - buf_dist\
                 and mindx + 3 <= doriginx <= maxdx - 3:
                    # Point is good to split on
                    decompose = True
                    break
                else:
                    scounter += 1
                    if scounter >= maxiteration:
                        break

            # Clear the Flann matcher for reuse
            fl.clear()

            # Check that the identified match falls within the (sub)image
            # This catches most bad matches that have passed the ratio check
            if not (buf_dist <= doriginx - mindx <= bsub.shape[1] - buf_dist) or not\
                   (buf_dist <= doriginy - mindy <= bsub.shape[0] - buf_dist):
                   decompose = False

            if decompose:
                # Apply coupled decomposition, shifting the origin to the sub-image
                s_submembership, d_submembership = coupled_decomposition(asub, bsub,
                                                                     sorigin=(soriginx, soriginy),
                                                                     dorigin=(doriginx, doriginy))
                                                                     sorigin=(soriginx - minsx, soriginy - minsy),
                                                                     dorigin=(doriginx - mindx, doriginy - mindy),
                                                                     **kwargs)

                # Shift the returned membership counters to a set of unique numbers
                s_submembership += pcounter
                d_submembership += pcounter

                # And assign membership
                self.smembership[minsy:maxsy,
                            minsx:maxsx] = s_submembership

            sdy = dy_part - min(dy_part)
            sdx = dx_part - min(dx_part)
            self.dmembership[dy_part, dx_part] = d_submembership[sdy, sdx]
                self.dmembership[mindy:maxdy,
                            mindx:maxdx] = d_submembership
                pcounter += 4


def decompose_and_match(self, **kwargs):

    decompose(self, **kwargs)

    # Now match the decomposed segments to one another
    for p in np.unique(self.smembership):
        sy_part, sx_part = np.where(self.smembership == p)
+3 −2
Original line number Diff line number Diff line
import warnings

import cudasift as cs
def extract_features(array, nfeatures=None, **kwargs):

def extract_features(array, nfeatures=None):
    if not nfeatures:
        nfeatures = int(max(array.shape) / 1.75)
    else:
        warnings.warn('NFeatures specified with the CudaSift implementation.  Please ensure the distribution of keypoints is what you expect.')

    siftdata = cs.PySiftData(nfeatures)
    cs.ExtractKeypoints(array, siftdata, **kwargs)
    cs.ExtractKeypoints(array, siftdata)
    keypoints, descriptors = siftdata.to_data_frame()
    keypoints = keypoints[['x', 'y', 'scale', 'sharpness', 'edgeness', 'orientation', 'score', 'ambiguity']]
    # Set the columns that have unfilled values to zero to avoid confusion
+1 −1
Original line number Diff line number Diff line
@@ -33,4 +33,4 @@ def match(self, ratio=0.8, **kwargs):

    # Set the matches and set the 'ratio' (ambiguity) mask
    self.matches = df
    self.masks['ratio'] = df['ambiguity'] <= ratio
    self.masks = ('ratio', df['ambiguity'] <= ratio)
+0 −12
Original line number Diff line number Diff line
import pandas as pd
from autocnet.matcher.feature import FlannMatcher

def match(self, k=2, **kwargs):
@@ -69,19 +68,8 @@ def match(self, k=2, **kwargs):
        _add_matches(matches)
        fl.clear()

    # TODO: This should be converted to a decorator on the class
    # TODO: This entire method should never have access to the class
    self.masks = pd.DataFrame()

    fl = FlannMatcher()
    mono_matches(self.source, self.destination, **kwargs)

    # Since this matches bidirectionally
    if 'aidx' in kwargs.keys():
        if not 'bidx' in kwargs.keys():
            kwargs['bidx'] = None
        kwargs['aidx'], kwargs['bidx'] = kwargs['bidx'], kwargs['aidx']

    mono_matches(self.destination, self.source, **kwargs)

    self.matches.sort_values(by=['distance'])