Commit fbf76072 authored by jay's avatar jay
Browse files

Incorporates dynamic func loadings for optional CUDA support

parent 69cf4879
Loading
Loading
Loading
Loading
+37 −8
Changes for autocnet/__init__.py: 37 added lines, 8 removed lines.
Original line number Diff line number Diff line
import os
import autocnet

__version__ = "0.1.0"

def get_data(filename):
    packagdir = autocnet.__path__[0]
    dirname = os.path.join(os.path.dirname(packagdir), 'data')
    fullname = os.path.join(dirname, filename)
    return fullname

import autocnet.examples
import autocnet.camera
import autocnet.cg
@@ -18,3 +10,40 @@ import autocnet.matcher
import autocnet.transformation
import autocnet.utils
import autocnet.utils

__version__ = "0.1.0"

def get_data(filename):
    packagdir = autocnet.__path__[0]
    dirname = os.path.join(os.path.dirname(packagdir), 'data')
    fullname = os.path.join(dirname, filename)
    return fullname

def cuda(enable=False, gpu=0):
    # Classes/Methods that can vary if GPU is available
    from autocnet.graph.node import Node
    from autocnet.graph.edge import Edge
    if enable:
        print('Enabling CUDA')
        try:
            import cudasift as cs
            cs.PyInitCuda(gpu)

            # Here is where the GPU methods get patched into the class
            from autocnet.matcher.cuda_extractor import extract_features 
            Node._extract_features = staticmethod(extract_features)

            from autocnet.matcher.cuda_matcher import match
            Edge.match = match
        except Exception:
            print('Failed to enable cuda')
        return

    print('CUDA Disabled')
    # Here is where the CPU methods get patched into the class
    from autocnet.matcher.feature_extractor import extract_features
    Node._extract_features = staticmethod(extract_features)

    from autocnet.matcher.feature_matcher import match
    Edge.match = match
cuda()
+33 −40
Changes for autocnet/graph/edge.py: 33 added lines, 40 removed lines.
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import numpy as np
import pandas as pd
from scipy.spatial.distance import cdist

import autocnet
from autocnet.utils import utils
from autocnet.matcher import health
from autocnet.matcher import outlier_detector as od
@@ -77,9 +78,13 @@ class Edge(dict, MutableMapping):
        # state, dynamically draw the mask from the object.
        for c in self._masks.columns:
            if c in mask_lookup:
                try:
                    truncated_mask = getattr(self, mask_lookup[c]).mask
                    self._masks[c] = False
                    self._masks[c].iloc[truncated_mask.index] = truncated_mask
                except Exception:
                    #TODO: Get rid of state
                    pass
        return self._masks

    @masks.setter
@@ -342,48 +347,36 @@ class Edge(dict, MutableMapping):
        k : int
            The number of neighbors to find
        """
        def mono_matches(a, b, aidx=None, bidx=None):
            """
            Apply the FLANN match_features

            Parameters
            ----------
            a : object
                A node object

            b : object
                A node object

            aidx : iterable
                   An index for the descriptors to subset
        pass

            bidx : iterable
                   An index for the descriptors to subset
    def cuda_match(self, ratio=0.8, **kwargs):
        """
            # Subset if requested
            if aidx is not None:
                ad = a.descriptors[aidx]
            else:
                ad = a.descriptors

            if bidx is not None:
                bd = b.descriptors[bidx]
            else:
                bd = b.descriptors

            # Load, train, and match
            fl.add(ad, a.node_id, index=aidx)
            fl.train()
            matches = fl.query(bd, b.node_id, k, index=bidx)
            self._add_matches(matches)
            fl.clear()

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



        Apply a composite CUDA matcher and ratio check.  If this method is used,
        no additional ratio check is necessary and no symmetry check is required.
        The ratio check is embedded on the cuda side and returned as an
        ambiguity value.  In testing symmetry is not required as it is expensive
        without significant gain in accuracy when using this implementation.
        """
        if not autocnet.cudasift:
            warnings.warn('CudaSift is not available, please use the standard matcher.')
        s_siftdata = autocnet.cs.PySiftData.from_data_frame(self.source.get_keypoints(), self.source.descriptors)
        d_siftdata = autocnet.cs.PySiftData.from_data_frame(self.destination.get_keypoints(), self.destination.descriptors)

        autocnet.cs.PyMatchSiftData(s_siftdata, d_siftdata)
        matches, _ = s_siftdata.to_data_frame()
        source = np.empty(len(matches))
        source[:] = self.source.node_id
        destination = np.empty(len(matches))
        destination[:] = self.destination.node_id


        df = pd.concat([pd.Series(source), pd.Series(matches.index),
                        pd.Series(destination), matches.match,
                        matches.score, matches.ambiguity], axis=1)
        df.columns = ['source_image', 'source_idx', 'destination_image',
                        'destination_idx', 'score', 'ambiguity']
        print(df)
        self.matches = df
    def _add_matches(self, matches):
        """
        Given a dataframe of matches, either append to an existing
+5 −3
Changes for autocnet/graph/network.py: 5 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -206,7 +206,7 @@ class CandidateGraph(nx.Graph):

        raise NotImplementedError

    def extract_features(self, method='orb', extractor_parameters={}):
    def extract_features(self, *args, **kwargs):
        """
        Extracts features from each image in the graph and uses the result to assign the
        node attributes for 'handle', 'image', 'keypoints', and 'descriptors'.
@@ -224,8 +224,7 @@ class CandidateGraph(nx.Graph):
        """
        for i, node in self.nodes_iter(data=True):
            image = node.get_array()
            node.extract_features(image, method=method,
                                  extractor_parameters=extractor_parameters)
            node.extract_features(image, *args, **kwargs),

    def save_features(self, out_path, nodes=[]):
        """
@@ -295,6 +294,9 @@ class CandidateGraph(nx.Graph):
        """
        self.apply_func_to_edges('match', *args, **kwargs)

    def cuda_match(self, *args, **kwargs):
        self.apply_func_to_edges('cuda_match', *args, **kwargs)

    def decompose_and_match_features(self, *args, **kwargs):
        """
        For all edges in the graph, apply coupled decomposition followed by
+6 −2
Changes for autocnet/graph/node.py: 6 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -227,7 +227,8 @@ class Node(dict, MutableMapping):

        return keypoints

    def extract_features(self, array, **kwargs):
    @staticmethod
    def _extract_features(*args, **kwargs):
        """
        Extract features for the node

@@ -239,7 +240,10 @@ class Node(dict, MutableMapping):
                 kwargs passed to autocnet.feature_extractor.extract_features

        """
        self._keypoints, self.descriptors = fe.extract_features(array, **kwargs)
        pass

    def extract_features(self, *args, **kwargs):
        self._keypoints, self.descriptors = Node._extract_features(*args, **kwargs)

    def load_features(self, in_path):
        """
+19 −0
Changes for autocnet/matcher/cuda_extractor.py: 19 added lines, 0 removed lines.
Original line number Diff line number Diff line
import warnings

import cudasift as cs

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)
    keypoints, descriptors = siftdata.to_data_frame()
    keypoints = keypoints[['xpos', 'ypos', 'scale', 'sharpness', 'edgeness', 'orientation', 'score', 'ambiguity']]
    # Set the columns that have unfilled values to zero to avoid confusion
    keypoints['score'] = 0.0
    keypoints['ambiguity'] = 0.0

    return keypoints, descriptors
Loading