Commit 0e86daa0 authored by Adam Paquette's avatar Adam Paquette
Browse files

Merged the voronoi calculation and voronoi weight calculation into a single...

Merged the voronoi calculation and voronoi weight calculation into a single voronoi function. Moved voronoi function into cg and made a compute weights function for a given edge. Voronoi weights now append to the matches dataframe.
parent bbb37b3c
Loading
Loading
Loading
Loading
+91 −12
Original line number Diff line number Diff line
@@ -2,9 +2,12 @@ import pandas as pd
import numpy as np

from scipy.spatial import ConvexHull
from scipy.spatial import Voronoi
import cv2

from autocnet.utils import utils


def convex_hull_ratio(points, ideal_area):
    """

@@ -103,28 +106,103 @@ def get_area(poly1, poly2):
    return intersection_area


def compute_vor_weight(vor, voronoi_df, intersection_poly, verbose):
def vor(edge, clean_keys=[], s=30):
        """
        Creates a voronoi diagram for an edge using either the coordinate
        transformation or using the homography between source and destination.

        The coordinate transformation uses the footprint of source and destination to
        calculate an intersection between the two images, then transforms the vertices of
        the intersection back into pixel space.

        If a coordinate transform does not exist, use the homography to project the destination image
        onto the source image, producing an area of intersection.

        The intersection vertices are then scaled by a factor of s (default 30), this accounts for the
        areas of the voronoi that would be missed if the scaled vertices were not included into the
        voronoi calculation.


        Parameters
        ----------
        edge : edge
               info

        clean_keys : list
                     Of strings used to apply masks to omit correspondences

        s : int
            offset for the corners of the image

        Returns
        -------
        vor : Voronoi
              Scipy Voronoi object

        voronoi_df : dataframe
                     3 column pandas dataframe of x, y, and weights

    intersection_poly : polygon
                        Intersection polygon to use for
                        clipping the voronoi diagram

    verbose : boolean
              Set to True to display the calculated voronoi diagram
              to the user
        """
    i = 0
        source_corners = edge.source.geodata.xy_corners
        destination_corners = edge.destination.geodata.xy_corners

        matches, _ = edge.clean(clean_keys=clean_keys)

        source_keypoints_pd = edge.source.get_keypoint_coordinates(index=matches['source_idx'],
                                                                   homogeneous=True)
        destination_keypoints_pd = edge.destination.get_keypoint_coordinates(index=matches['destination_idx'],
                                                                             homogeneous=True)

        if edge.source.geodata.coordinate_transformation.this is not None:
            source_footprint_poly = edge.source.geodata.footprint
            destination_footprint_poly = edge.destination.geodata.footprint

            intersection_poly = destination_footprint_poly.Intersection(source_footprint_poly)
            intersection_geom = intersection_poly.GetGeometryRef(0)
            intersect_points = intersection_geom.GetPoints()

            intersection_points = [edge.source.geodata.latlon_to_pixel(lat, lon) for lat, lon in intersect_points]

        else:
            H, mask = cv2.findHomography(destination_keypoints_pd.values,
                                         source_keypoints_pd.values,
                                         cv2.RANSAC,
                                         2.0)

            proj_corners = []
            for c in destination_corners:
                x, y, h = utils.reproj_corner(H, c)
                x /= h
                y /= h
                h /= h
                proj_corners.append((x, y))

            orig_poly = utils.array_to_poly(source_corners)
            proj_poly = utils.array_to_poly(proj_corners)

            intersection_poly = orig_poly.Intersection(proj_poly)
            intersection_geom = intersection_poly.GetGeometryRef(0)
            intersection_points = intersection_geom.GetPoints()

        centroid = intersection_poly.Centroid().GetPoint()

        voronoi_df = pd.DataFrame(data=source_keypoints_pd, columns=["x", "y", "vor_weights"])

        voronoi_df["x"] = source_keypoints_pd['x']
        voronoi_df["y"] = source_keypoints_pd['y']
        keypoints = np.asarray(source_keypoints_pd)

        inters = np.empty((len(intersection_points), 2))
        for g, (i, j) in enumerate(intersection_points):
            scaledx, scaledy = utils.scale_point((i, j), centroid, s)
            point = np.array([scaledx, scaledy])
            inters[g] = point

        keypoints = np.vstack((keypoints[:, :2], inters))
        vor = Voronoi(keypoints)

        poly_array = []
    for region in vor.regions:
        for i, region in enumerate(vor.regions):
            region_point = vor.points[np.argwhere(vor.point_region==i)]
            if -1 not in region:
                polygon_points = [vor.vertices[i] for i in region]
@@ -135,5 +213,6 @@ def compute_vor_weight(vor, voronoi_df, intersection_poly, verbose):
                    polygon_area = intersection.GetArea()
                    voronoi_df.loc[(voronoi_df["x"] == region_point[0][0][0]) &
                                   (voronoi_df["y"] == region_point[0][0][1]),
                               'weights'] = polygon_area
        i += 1
                                   'vor_weights'] = polygon_area

        return vor, voronoi_df
+5 −100
Original line number Diff line number Diff line
@@ -5,8 +5,6 @@ import numpy as np
import pandas as pd

from scipy.spatial.distance import cdist
from scipy.spatial import Voronoi
import cv2

from autocnet.utils import utils
from autocnet.matcher import health
@@ -773,102 +771,9 @@ class Edge(dict, MutableMapping):

        return total_overlap_coverage

    def vor(self, clean_keys=[], s=30, verbose=False):
        """
        Creates a voronoi diagram for an edge using either the coordinate
        transformation or using the homography between source and destination.

        The coordinate transformation uses the footprint of source and destination to
        calculate an intersection between the two images, then transforms the vertices of
        the intersection back into pixel space.

        If a coordinate transform does not exist, use the homography to project the destination image
        onto the source image, producing an area of intersection.

        The intersection vertices are then scaled by a factor of s (default 30), this accounts for the
        areas of the voronoi that would be missed if the scaled vertices were not included into the
        voronoi calculation.


        Parameters
        ----------
        clean_keys : list
                     Of strings used to apply masks to omit correspondences

        s : int
            offset for the corners of the image

        verbose : boolean
                  Set to True plots the voronoi diagram

        Returns
        -------
        vor : Voronoi
              Scipy Voronoi object

        voronoi_df : dataframe
                     3 column pandas dataframe of x, y, and weights

        """
        source_corners = self.source.geodata.xy_corners
        destination_corners = self.destination.geodata.xy_corners

        matches, _ = self.clean(clean_keys=clean_keys)

        source_keypoints_pd = self.source.get_keypoint_coordinates(index=matches['source_idx'],
                                                                   homogeneous=True)
        destination_keypoints_pd = self.destination.get_keypoint_coordinates(index=matches['destination_idx'],
                                                                             homogeneous=True)

        if self.source.geodata.coordinate_transformation.this is not None:
            print("Image has coordinate transform.")
            source_footprint_poly = self.source.geodata.footprint
            destination_footprint_poly = self.destination.geodata.footprint

            intersection_poly = destination_footprint_poly.Intersection(source_footprint_poly)
            intersection_geom = intersection_poly.GetGeometryRef(0)
            intersect_points = intersection_geom.GetPoints()

            intersection_points = [self.source.geodata.latlon_to_pixel(lat, lon) for lat, lon in intersect_points]
    def compute_weights(self, clean_keys, **kwargs):
        if self.matches is None:
            raise AttributeError('Matches have not been computed for this edge')
        voronoi = cg.vor(self, clean_keys, **kwargs)
        self.matches = pd.concat([self.matches, voronoi[1]['vor_weights']], axis=1)
        else:
            print("Other")
            H, mask = cv2.findHomography(destination_keypoints_pd.values,
                                         source_keypoints_pd.values,
                                         cv2.RANSAC,
                                         2.0)

            proj_corners = []
            for c in destination_corners:
                x, y, h = utils.reproj_corner(H, c)
                x /= h
                y /= h
                h /= h
                proj_corners.append((x, y))

            orig_poly = utils.array_to_poly(source_corners)
            proj_poly = utils.array_to_poly(proj_corners)

            intersection_poly = orig_poly.Intersection(proj_poly)
            intersection_geom = intersection_poly.GetGeometryRef(0)
            intersection_points = intersection_geom.GetPoints()

        centroid = intersection_poly.Centroid().GetPoint()

        voronoi_df = pd.DataFrame(data=source_keypoints_pd, columns=["x", "y", "weights"])

        voronoi_df["x"] = source_keypoints_pd['x']
        voronoi_df["y"] = source_keypoints_pd['y']
        keypoints = np.asarray(source_keypoints_pd)

        inters = np.empty((len(intersection_points), 2))
        for g, (i, j) in enumerate(intersection_points):
            scaledx, scaledy = utils.scale_point((i, j), centroid, s)
            point = np.array([scaledx, scaledy])
            inters[g] = point

        keypoints = np.vstack((keypoints[:, :2], inters))
        vor = Voronoi(keypoints)
        cg.compute_vor_weight(vor, voronoi_df, intersection_poly, verbose)

        return vor, voronoi_df
+10 −21
Original line number Diff line number Diff line
@@ -144,6 +144,7 @@ class TestEdge(unittest.TestCase):
        e = edge.Edge()

        e.clean = MagicMock(return_value=(matches_df, None))
        e.matches = matches_df

        source_node = MagicMock(spec=node.Node())
        destination_node = MagicMock(spec=node.Node())
@@ -186,20 +187,13 @@ class TestEdge(unittest.TestCase):

        vals = {(10, 5): (10, 5), (20, 5): (20, 5), (20, 20): (20, 20), (10, 20): (10, 20)}

        data_frame = pd.DataFrame({"x": (15, 18, 18, 12, 12),
                                  "y": (5, 10, 15, 15, 10)})
        weights = pd.DataFrame({"weights": (19, 28, 37.5, 37.5, 28)})

        frames = [data_frame, weights]
        weight_pd = pd.concat(frames, axis=1)
        weights = pd.DataFrame({"vor_weights": (19, 28, 37.5, 37.5, 28)})

        vor = e.vor(clean_keys=[])
        e.compute_weights(clean_keys=[])

        for i in vor[1]:
        k = 0
            for j in vor[1][i]:
                print(i, k, j)
                self.assertAlmostEquals(j, weight_pd[i][k])
        for i in e.matches['vor_weights']:
            self.assertAlmostEquals(i, weights['vor_weights'][k])
            k += 1

    def test_voronoi_homography(self):
@@ -216,6 +210,7 @@ class TestEdge(unittest.TestCase):
        e = edge.Edge()

        e.clean = MagicMock(return_value=(matches_df, None))
        e.matches = matches_df

        source_node = MagicMock(spec=node.Node())
        destination_node = MagicMock(spec=node.Node())
@@ -248,19 +243,13 @@ class TestEdge(unittest.TestCase):
        e.source.geodata.xy_corners = source_corners
        e.destination.geodata.xy_corners = destination_corners

        data_frame = pd.DataFrame({"x": (15, 18, 18, 12, 12),
                                  "y": (5, 10, 15, 15, 10)})
        weights = pd.DataFrame({"weights": (19, 28, 37.5, 37.5, 28)})

        frames = [data_frame, weights]
        weight_pd = pd.concat(frames, axis=1)
        weights = pd.DataFrame({"vor_weights": (19, 28, 37.5, 37.5, 28)})

        vor = e.vor(clean_keys=[])
        e.compute_weights(clean_keys=[])

        for i in vor[1]:
        k = 0
            for j in vor[1][i]:
                self.assertAlmostEquals(j, weight_pd[i][k])
        for i in e.matches['vor_weights']:
            self.assertAlmostEquals(i, weights['vor_weights'][k])
            k += 1


+42 −14

File changed.

Preview size limit exceeded, changes collapsed.