Commit 44d4ce37 authored by jlaura's avatar jlaura Committed by GitHub
Browse files

Merge pull request #218 from evindunn/dev

cpu/cuda_matcher.match() is static & clears Edge.masks
parents f2242f97 3782a1b3
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ def cuda(enable=False, gpu=0):
            Node._extract_features = staticmethod(extract_features)

            from autocnet.matcher.cuda_matcher import match
            Edge.match = match
            Edge._match = staticmethod(match)

            from autocnet.matcher.cuda_decompose import decompose_and_match
            Edge.decompose_and_match = decompose_and_match
@@ -52,7 +52,7 @@ def cuda(enable=False, gpu=0):
    Node._extract_features = staticmethod(extract_features)

    from autocnet.matcher.cpu_matcher import match
    Edge.match = match
    Edge._match = staticmethod(match)

    from autocnet.matcher.cpu_decompose import decompose_and_match
    Edge.decompose_and_match = decompose_and_match
+15 −4
Original line number Diff line number Diff line
@@ -107,11 +107,22 @@ class Edge(dict, MutableMapping):
        ----------
        k : int
            The number of neighbors to find
        """
        Edge._match(self, k, **kwargs)

    @staticmethod
    def _match(edge, k=2, **kwargs):
        """
        Patches the static cpu_matcher.match(edge) or cuda_match.match(edge)
        into the member method Edge.match()

        overlap : boolean
                  Apply the matcher only to the overlapping area defined by
                  the source_mbr and destin_mbr attributes (stored in the
                  edge dict).
        Parameters
        ----------
        edge : Edge
               The edge object to compute matches for; Edge.match() calls this
               with self
        k : int
            The number of neighbors to find
        """
        pass

+14 −20
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ FLANN_INDEX_KDTREE = 1 # Algorithm to set centers,
DEFAULT_FLANN_PARAMETERS = dict(algorithm=FLANN_INDEX_KDTREE, trees=3)


def match(self, k=2, **kwargs):
def match(edge, k=2, **kwargs):
    """
    Given two sets of descriptors, utilize a FLANN (Approximate Nearest
    Neighbor KDTree) matcher to find the k nearest matches.  Nearness is
@@ -32,11 +32,11 @@ def match(self, k=2, **kwargs):
        matches : dataframe
                  A dataframe of matches
        """
        if self.matches is None:
            self.matches = matches
        if edge.matches.empty:
            edge.matches = matches
        else:
            df = self.matches
            self.matches = df.append(matches,
            df = edge.matches
            edge.matches = df.append(matches,
                                     ignore_index=True,
                                     verify_integrity=True)

@@ -78,25 +78,19 @@ def match(self, k=2, **kwargs):

    fl = FlannMatcher()

    # Get the correct descriptors
    # TODO: Extract into a helper function
    if 'aidx' in kwargs.keys():
        aidx = kwargs['aidx']
        kwargs.pop('aidx')
    else:
        aidx = None
    # Reset the edge.masks attrib; New matches would mean masks have to be
    # re-calculated
    edge.masks = pd.DataFrame()
    
    if 'bidx' in kwargs.keys():
        bidx = kwargs['bidx']
        kwargs.pop('bidx')
    else:
        bidx = None
    # Get the correct descriptors
    aidx = kwargs.pop('aidx', None)
    bidx = kwargs.pop('bidx', None)

    mono_matches(self.source, self.destination, aidx=aidx, bidx=bidx, **kwargs)
    mono_matches(edge.source, edge.destination, aidx=aidx, bidx=bidx)
    # Swap the indices since mono_matches is generic and source/destin are
    # swapped
    mono_matches(self.destination, self.source, aidx=bidx, bidx=aidx, **kwargs)
    self.matches.sort_values(by=['distance'])
    mono_matches(edge.destination, edge.source, aidx=bidx, bidx=aidx)
    edge.matches.sort_values(by=['distance'])


class FlannMatcher(object):
+10 −9
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ import cudasift as cs
import numpy as np
import pandas as pd

def match(self, ratio=0.8, **kwargs):
def match(edge, ratio=0.8, **kwargs):

    """
    Apply a composite CUDA matcher and ratio check.  If this method is used,
@@ -14,11 +14,11 @@ def match(self, ratio=0.8, **kwargs):
    without significant gain in accuracy when using this implementation.
    """

    source_kps = self.source.get_keypoints()
    source_des = self.source.descriptors
    source_kps = edge.source.get_keypoints()
    source_des = edge.source.descriptors

    destin_kps = self.destination.get_keypoints()
    destin_des = self.destination.descriptors
    destin_kps = edge.destination.get_keypoints()
    destin_des = edge.destination.descriptors

    s_siftdata = cs.PySiftData.from_data_frame(source_kps, source_des)
    d_siftdata = cs.PySiftData.from_data_frame(destin_kps, destin_des)
@@ -26,9 +26,9 @@ def match(self, ratio=0.8, **kwargs):
    cs.PyMatchSiftData(s_siftdata, d_siftdata)
    matches, _ = s_siftdata.to_data_frame()
    source = np.empty(len(matches))
    source[:] = self.source['node_id']
    source[:] = edge.source['node_id']
    destination = np.empty(len(matches))
    destination[:] = self.destination['node_id']
    destination[:] = edge.destination['node_id']

    df = pd.concat([pd.Series(source), pd.Series(matches.index),
            pd.Series(destination), matches.match,
@@ -37,5 +37,6 @@ def match(self, ratio=0.8, **kwargs):
            'destination_idx', 'score', 'ambiguity']

    # Set the matches and set the 'ratio' (ambiguity) mask
    self.matches = df
    self.masks['ratio'] =  df['ambiguity'] <= ratio
    edge.matches = df
    edge.masks = pd.DataFrame()
    edge.masks['ratio'] = df['ambiguity'] <= ratio
+47 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ import cv2

from .. import cpu_matcher
from autocnet.examples import get_path
from autocnet.graph.network import CandidateGraph

sys.path.append(os.path.abspath('..'))

@@ -38,5 +39,51 @@ class TestMatcher(unittest.TestCase):
            self.assertEqual(len(w), 1)
            self.assertEqual(w[0].category, UserWarning)

    def test_cpu_match(self):
        # Build a graph
        adjacency = get_path('two_image_adjacency.json')
        basepath = get_path('Apollo15')
        cang = CandidateGraph.from_adjacency(adjacency, basepath=basepath)

        # Extract features
        cang.extract_features(extractor_parameters={'nfeatures': 700})

        # Make sure cpu matcher is used for test
        edges = list()
        from autocnet.matcher.cpu_matcher import match as match
        for s, d in cang.edges():
            cang[s][d]._match = match
            edges.append(cang[s][d])

        # Assert none of the edges have masks yet
        for edge in edges:
            self.assertTrue(edge.masks.empty)

        # Match & outlier detect
        cang.match()
        cang.symmetry_checks()

        # Grab the length of a matches df
        match_len = len(edges[0].matches.index)

        # Assert symmetry check is now in all edge masks
        for edge in edges:
            self.assertTrue('symmetry' in edge.masks)

        # Assert matches have been populated
        for edge in edges:
            self.assertTrue(not edge.matches.empty)

        # Re-match
        cang.match()

        # Assert that new matches have been added on to old ones
        self.assertEqual(len(edges[0].matches.index), match_len * 2)

        # Assert that the match cleared the masks df
        for edge in edges:
            self.assertTrue(edge.masks.empty)


    def tearDown(self):
        pass