Commit 55bc9508 authored by Jay's avatar Jay Committed by jay
Browse files

Updates to subpixel registration and outlier detection

parent de897f40
Loading
Loading
Loading
Loading
+62 −17
Original line number Diff line number Diff line
@@ -258,31 +258,64 @@ class CandidateGraph(nx.Graph):
            attributes['homography'] = transformation_matrix
            attributes['ransac'] = mask

    def compute_subpixel_offsets(self):
    def compute_subpixel_offsets(self, clean_keys=[], threshold=0.8, upsampling=10):
        """
        For the entire graph, compute the subpixel offsets using pattern-matching and add the result
        as an attribute to each edge of the graph.

        Returns
        -------
        subpixel_offsets : ndarray
                           A numpy array containing all the subpixel offsets for the entire graph.
        Parameters
        ----------
        clean_keys : list
             of string keys to masking arrays
             (created by calling outlier detection)

        threshold : float
                    On the range [-1, 1].  Values less than or equal to
                    this threshold are masked and can be considered
                    outliers
        """
        subpixel_offsets = []
        for source, destination, attributes in self.edges_iter(data=True): #for each edge
            matches = attributes['matches'] #grab the matches

        for source, destination, attributes in self.edges_iter(data=True):
            matches = attributes['matches']

            full_offsets = np.zeros((len(matches), 3))

            # Build up a composite mask from all of the user specified masks
            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)

            src_image = self.node[source]['image']
            dest_image = self.node[destination]['image']
            edge_offsets = []
            for i, (idx, row) in enumerate(matches.iterrows()): #for each edge, calculate this for each keypoint pair

            # Preallocate the numpy array to avoid appending and type conversion
            edge_offsets = np.empty((len(matches),3))

            # for each edge, calculate this for each keypoint pair
            for i, (idx, row) in enumerate(matches.iterrows()):
                s_idx = int(row['source_idx'])
                d_idx = int(row['destination_idx'])
                src_keypoint = self.node[source]['keypoints'][s_idx]
                dest_keypoint = self.node[destination]['keypoints'][d_idx]
                edge_offsets.append(sp.subpixel_offset(src_keypoint, dest_keypoint, src_image, dest_image))
            attributes['subpixel_offsets'] = np.array(edge_offsets)
            subpixel_offsets.append(np.array(edge_offsets))
        return subpixel_offsets

                # Compute the subpixel offset
                edge_offsets[i] = sp.subpixel_offset(src_keypoint, dest_keypoint, src_image, dest_image, upsampling=upsampling)

            # Compute the mask for correlations less than the threshold
            threshold_mask = edge_offsets[edge_offsets[:,-1] >= threshold]

            # Convert the truncated mask back into a full length mask
            if clean_keys:
                mask[full_mask] = threshold_mask
                full_offsets[full_mask] = edge_offsets
            else:
                mask = threshold_mask

            attributes['subpixel_offsets'] = pd.DataFrame(full_offsets, columns=['x_offset',
                                                                                 'y_offset',
                                                                                 'correlation'])
            attributes['subpixel'] = mask

    def to_cnet(self, clean_keys=[]):
        """
@@ -338,12 +371,15 @@ class CandidateGraph(nx.Graph):
                mask = np.prod([attributes[i] for i in clean_keys], axis=0, dtype=np.bool)
                matches = matches[mask]

            if 'subpixel' in clean_keys:
                offsets = attributes['subpixel_offsets'][attributes['subpixel']]
                print(offsets)
            kp1 = self.node[source]['keypoints']
            kp2 = self.node[destination]['keypoints']

            pt_idx = 0
            values = []
            for idx, row in matches.iterrows():
            for i, (idx, row) in enumerate(matches.iterrows()):
                # Composite matching key (node_id, point_id)
                m1 = (source, int(row['source_idx']))
                m2 = (destination, int(row['destination_idx']))
@@ -354,8 +390,17 @@ class CandidateGraph(nx.Graph):
                               pt_idx,
                               source])

                values.append([kp2[m2[1]].pt[0],
                               kp2[m2[1]].pt[1],
                kp2x = kp2[m2[1]].pt[0]
                kp2y = kp2[m2[1]].pt[1]

                if 'subpixel' in clean_keys:
                    print(idx)
                    print(kp2x, kp2y)
                    kp2x += offsets['x_offset'].values[i]
                    kp2y += offsets['y_offset'].values[i]
                    print(kp2x, kp2y)
                values.append([kp2x,
                               kp2y,
                               m2,
                               pt_idx,
                               destination])
+9 −7
Original line number Diff line number Diff line
@@ -13,8 +13,9 @@ from .. import network

class TestCandidateGraph(unittest.TestCase):

    def setUp(self):
        self.graph = network.CandidateGraph.from_adjacency_file(get_path('adjacency.json'))
    @classmethod
    def setUpClass(cls):
        cls.graph = network.CandidateGraph.from_adjacency_file(get_path('adjacency.json'))

    def test_get_name(self):
        node_number = self.graph.node_name_map['AS15-M-0297_SML.png']
@@ -28,6 +29,10 @@ class TestCandidateGraph(unittest.TestCase):
    def test_to_json_file(self):
        self.graph.to_json_file('test_graph_to_json.json')
        self.assertTrue(os.path.exists('test_graph_to_json.json'))
        try:
            os.remove('test_graph_to_json.json')
        except:
            pass

    def test_extract_features(self):
        # also tests get_geodataset() and get_keypoints
@@ -42,7 +47,4 @@ class TestCandidateGraph(unittest.TestCase):
        self.assertEquals(self.graph.get_keypoints(node_number), node['keypoints'])

    def tearDown(self):
        try:
            os.remove('test_graph_to_json.json')
        except:
        pass
+1 −0
Original line number Diff line number Diff line
@@ -149,6 +149,7 @@ def compute_homography(kp1, kp2, outlier_algorithm=cv2.RANSAC, reproj_threshold=
    mask = mask.astype(bool)
    return transformation_matrix, mask


def homography_test(kp1, kp2, homography, threshold=3.0):
    """
    Utilize the transformation matrix (homography) to check whether
+4 −2
Original line number Diff line number Diff line
import pandas as pd
from autocnet.matcher import matcher

from scipy.misc import imresize

# TODO: look into KeyPoint.size and perhaps use to determine an appropriately-sized search/template.
# TODO: do not allow even sizes

@@ -31,7 +33,7 @@ Parameters
      The returned tuple is of form: (x_offset, y_offset, strength). The offsets are from the search to the template
      keypoint.
    """
def subpixel_offset(template_kp, search_kp, template_img, search_img, template_size=9, search_size=27):
def subpixel_offset(template_kp, search_kp, template_img, search_img, template_size=9, search_size=27, upsampling=10):
    # Get the x,y coordinates
    temp_x, temp_y = map(int, template_kp.pt)
    search_x, search_y = map(int, search_kp.pt)
@@ -46,7 +48,7 @@ def subpixel_offset(template_kp, search_kp, template_img, search_img, template_s
    results = (None, None, None)

    try:
        results = matcher.pattern_match(template, search)
        results = matcher.pattern_match(template, search, upsampling=upsampling)
    except ValueError:
        # the match fails if the template or search point is near an edge of the image
        # TODO: come up with a better solution?
+4 −4
Original line number Diff line number Diff line
@@ -75,14 +75,14 @@ class TestTwoImageMatching(unittest.TestCase):
            mask = np.array(ratio_mask * symmetry_mask)
            self.assertIn(len(matches.loc[mask]), range(75,101))

        # Step: Compute the homographies and apply RANSAC
        cg.compute_homographies(clean_keys=['symmetry', 'ratio'])

        #compute subpixel offsets for the entire graph
        offsets = cg.compute_subpixel_offsets()
        self.assertEqual(len(offsets), cg.number_of_edges())
        # Step: Compute subpixel offsets for candidate points
        cg.compute_subpixel_offsets(clean_keys=['symmetry', 'ratio', 'ransac'])

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