Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intersection over union on non rectangular quadrilaterals

I am working on the problem of parking space detection. To detect empty parking space I am using intersection over union. But, parking spaces aren't always rectangular. So, I have made a labeling tool that can draw polygons of various shapes. Now, I want to know if there is any python library that provides IOU functionality? If not is there any alternative?

enter image description here

like image 753
h s Avatar asked Oct 17 '19 14:10

h s


2 Answers

You should use the shapely Python library:

from shapely.geometry import box, Polygon

# Define Each polygon 
pol1_xy = [[130, 27], [129.52, 27], [129.45, 27.1], [130.13, 26]]
pol2_xy = [[30, 27.200001], [129.52, 27.34], [129.45, 27.1], [130.13, 26.950001]]
polygon1_shape = Polygon(pol1_xy)
polygon2_shape = Polygon(pol2_xy)

# Calculate Intersection and union, and tne IOU
polygon_intersection = polygon1_shape.intersection(polygon2_shape).area
polygon_union = polygon1_shape.union(polygon2_shape).area
IOU = polygon_intersection / polygon_union 
like image 197
ibarrond Avatar answered Nov 14 '22 22:11

ibarrond


There is a slight improvement that can be made to ibarrond's answer. Finding the union of our two quadrilaterals is a costly operation. Instead, we can find the area of the union by first adding the areas of both quadrilaterals. This will over-count the area where the quadrilaterals overlap, but we can correct this by subtracting the area of the intersect, which we already calculated:

def IOU(pol1_xy, pol2_xy):
    # Define each polygon
    polygon1_shape = Polygon(pol1_xy)
    polygon2_shape = Polygon(pol2_xy)

    # Calculate intersection and union, and the IOU
    polygon_intersection = polygon1_shape.intersection(polygon2_shape).area
    polygon_union = polygon1_shape.area + polygon2_shape.area - polygon_intersection
    return polygon_intersection / polygon_union

The following code verifies that this improvement gives the same result, and then it times both versions. Function IOU1 contain's ibarrond's code, and function IOU2 contains the improvement.

from shapely.geometry import Polygon
from timeit import timeit

def IOU1(pol1_xy, pol2_xy):
    # Define each polygon
    polygon1_shape = Polygon(pol1_xy)
    polygon2_shape = Polygon(pol2_xy)

    # Calculate intersection and union, and the IOU
    polygon_intersection = polygon1_shape.intersection(polygon2_shape).area
    polygon_union = polygon1_shape.union(polygon2_shape).area
    return polygon_intersection / polygon_union

def IOU2(pol1_xy, pol2_xy):
    # Define each polygon
    polygon1_shape = Polygon(pol1_xy)
    polygon2_shape = Polygon(pol2_xy)

    # Calculate intersection and union, and tne IOU
    polygon_intersection = polygon1_shape.intersection(polygon2_shape).area
    polygon_union = polygon1_shape.area + polygon2_shape.area - polygon_intersection
    return polygon_intersection / polygon_union

if __name__ == '__main__':
    # Define test coordinates:
    pol1_xy = [[130, 27], [129.52, 27], [129.45, 27.1], [130.13, 26]]
    pol2_xy = [[30, 27.200001], [129.52, 27.34], [129.45, 27.1], [130.13, 26.950001]]

    # Test that results are the same (except for minor rounding differences):
    assert abs(IOU1(pol1_xy, pol2_xy) - IOU2(pol1_xy, pol2_xy)) < 1e-16

    # Determine speeds of both functions:
    t1=timeit('IOU1(pol1_xy, pol2_xy)', number=100000,
              setup='from __main__ import IOU1, pol1_xy, pol2_xy')
    t2=timeit('IOU2(pol1_xy, pol2_xy)', number=100000,
              setup='from __main__ import IOU2, pol1_xy, pol2_xy')
    print('time for IOU1:  %s' %t1)
    print('time for IOU2:  %s' %t2)

Here's the result I obtained:

time for IOU1:  20.0208661
time for IOU2:  11.0288122

Note that the exact times will vary based on the hardware and the current background activity.

like image 22
Leland Hepworth Avatar answered Nov 14 '22 22:11

Leland Hepworth