Commit 27e669bc authored by jcwbacker's avatar jcwbacker
Browse files

Merge remote-tracking branch 'upstream/master'

parents 5de1ccfe 2a29104e
Loading
Loading
Loading
Loading
+40 −43
Original line number Diff line number Diff line
import operator
from functools import reduce
import operator as op
import os

import networkx as nx
@@ -12,6 +13,7 @@ from autocnet.control.control import C
from autocnet.fileio import io_json
from autocnet.fileio.io_gdal import GeoDataset
from autocnet.matcher import feature_extractor as fe # extract features from image
from autocnet.matcher import outlier_detector as od

class CandidateGraph(nx.Graph):
    """
@@ -206,7 +208,7 @@ class CandidateGraph(nx.Graph):
                destination_key = dest_group['destination_image'].values[0]
                try:
                    edge = self[source_key][destination_key]
                except:
                except: # pragma: no cover
                    edge = self[destination_key][source_key]

                if 'matches' in edge.keys():
@@ -215,18 +217,17 @@ class CandidateGraph(nx.Graph):
                else:
                    edge['matches'] = dest_group

    def compute_homography(self, source_key, destination_key, outlier_algorithm=cv2.RANSAC):
    def compute_homographies(self, outlier_algorithm=cv2.RANSAC, clean_keys=[]):
        """

        For each edge in the (sub) graph, compute the homography
        Parameters
        ----------
        source_key : str
                     The identifier for the source node
        destination_key : str
                          The identifier for the destination node

        outlier_algorithm : object
                            An openCV outlier detections algorithm, e.g. cv2.RANSAC

        clean_keys : list
                     of string keys to masking arrays
                     (created by calling outlier detection)
        Returns
        -------
        transformation_matrix : ndarray
@@ -234,43 +235,39 @@ class CandidateGraph(nx.Graph):

        mask : ndarray
               Boolean array of the outliers
        """

           A tuple of the form (transformation matrix, bad entry mask)
           The returned tuple is empty if there is no edge between the source and destination nodes or
           if it exists, but has not been populated with a matches dataframe.
        for source, destination, attributes in self.edges_iter(data=True):
            matches = attributes['matches']

        """
        if self.has_edge(source_key, destination_key):
            try:
                edge = self[source_key][destination_key]
            except:
                edge = self[destination_key][source_key]
            if 'matches' in edge.keys():
                source_keypoints = []
                destination_keypoints = []

                for i, row in edge['matches'].iterrows():
                    source_idx = row['source_idx']
                    src_keypoint = [self.node[source_key]['keypoints'][int(source_idx)].pt[0],
                                    self.node[source_key]['keypoints'][int(source_idx)].pt[1]]
                    destination_idx = row['destination_idx']
                    dest_keypoint = [self.node[destination_key]['keypoints'][int(destination_idx)].pt[0],
                                     self.node[destination_key]['keypoints'][int(destination_idx)].pt[1]]

                    source_keypoints.append(src_keypoint)
                    destination_keypoints.append(dest_keypoint)
                transformation_matrix, mask = cv2.findHomography(np.array(source_keypoints),
                                                                 np.array(destination_keypoints),
                                                                 outlier_algorithm,
                                                                 5.0)
                mask = mask.astype(bool)
                return transformation_matrix, mask
            else:
                return ('', '')
        else:
            return ('','')
            if clean_keys:
                mask = np.prod([attributes[i] for i in clean_keys], axis=0, dtype=np.bool)
                matches = matches[mask]

                full_mask = np.where(mask == True)

            s_coords = np.empty((len(matches), 2))
            d_coords = np.empty((len(matches), 2))

            for i, (idx, row) in enumerate(matches.iterrows()):
                s_idx = int(row['source_idx'])
                d_idx = int(row['destination_idx'])

                s_coords[i] = self.node[source]['keypoints'][s_idx].pt
                d_coords[i] = self.node[destination]['keypoints'][d_idx].pt

            transformation_matrix, ransac_mask = od.compute_homography(s_coords,
                                                                       d_coords)

            ransac_mask = ransac_mask.ravel()
            # Convert the truncated RANSAC mask back into a full length mask
            if clean_keys:
                mask[full_mask] = ransac_mask
            else:
                mask = ransac_mask

            attributes['homography'] = transformation_matrix
            attributes['ransac'] = mask

    def to_cnet(self, clean_keys=[]):
        """
@@ -291,7 +288,7 @@ class CandidateGraph(nx.Graph):

            # Merge all of the masks
            if clean_keys:
                mask = np.array(list(map(operator.mul, *[attributes[i] for i in clean_keys])))
                mask = np.prod([attributes[i] for i in clean_keys], axis=0, dtype=np.bool)
                matches = matches[mask]

            kp1 = self.node[source]['keypoints']
+36 −0
Original line number Diff line number Diff line
import cv2
import numpy as np


@@ -112,3 +113,38 @@ def mirroring_test(matches):
    duplicates.astype(bool, copy=False)
    return duplicates


def compute_homography(kp1, kp2, outlier_algorithm=cv2.RANSAC, reproj_threshold=5.0):
    """
    Given two arrays of keypoints compute a homography

    Parameters
    ----------
    kp1 : ndarray
          (n, 2) of coordinates from the source image

    kp2 : ndarray
          (n, 2) of coordinates from the destination image

    outlier_algorithm : object
                        The openCV algorithm to use for outlier detection

    reproj_threshold : float
                       The RANSAC reprojection threshold


    Returns
    -------
    transformation_matrix : ndarray
                            The 3x3 transformation matrix

    mask : ndarray
           Boolean array of the outliers
    """

    transformation_matrix, mask = cv2.findHomography(kp1,
                                                     kp2,
                                                     outlier_algorithm,
                                                     reproj_threshold)
    mask = mask.astype(bool)
    return transformation_matrix, mask
 No newline at end of file
+9 −7
Original line number Diff line number Diff line
@@ -46,9 +46,9 @@ class TestTwoImageMatching(unittest.TestCase):
        self.assertEqual(1, cg.number_of_edges())

        # Step: Extract image data and attribute nodes
        cg.extract_features(50)
        cg.extract_features(500)
        for node, attributes in cg.nodes_iter(data=True):
            self.assertIn(len(attributes['keypoints']), [49, 50, 51])
            self.assertIn(len(attributes['keypoints']), range(490, 511))

        # Step: Then apply a FLANN matcher
        fl = FlannMatcher()
@@ -65,19 +65,21 @@ class TestTwoImageMatching(unittest.TestCase):
            matches = attributes['matches']
            # Perform the symmetry check
            symmetry_mask = od.mirroring_test(matches)
            self.assertIn(symmetry_mask.sum(), range(45, 50))
            self.assertIn(symmetry_mask.sum(), range(430, 461))
            attributes['symmetry'] = symmetry_mask

            # Perform the ratio test
            ratio_mask = od.distance_ratio(matches, ratio=0.95)
            self.assertIn(ratio_mask.sum(), range(30,45))
            self.assertIn(ratio_mask.sum(), range(400, 451))
            attributes['ratio'] = ratio_mask

            mask = np.array(ratio_mask * symmetry_mask)
            self.assertIn(len(matches.loc[mask]), range(4,10))
        # Step: And create a C object
        cnet = cg.to_cnet(clean_keys=['symmetry', 'ratio'])
            self.assertIn(len(matches.loc[mask]), range(75,101))

            cg.compute_homographies(clean_keys=['symmetry', 'ratio'])

        # Step: And create a C object
        cnet = cg.to_cnet(clean_keys=['symmetry', 'ratio', 'ransac'])
        # Step update the serial numbers
        nid_to_serial = {}
        for node, attributes in cg.nodes_iter(data=True):