Source code for ollin.estimation.occupancy.voronoi_areas

from __future__ import division

import numpy as np
from scipy.spatial import Voronoi
from shapely.geometry import box, Polygon

from ..estimation import EstimationModel
from .base import OccupancyEstimate


[docs]class Model(EstimationModel): name = 'Voronoi Areas Method'
[docs] def estimate(self, detection, **kwargs): camera = detection.camera_configuration vor = Voronoi(camera.positions) regions, vertices = _voronoi_finite_polygons_2d(vor) voronoi_areas = [] range_box = box(0, 0, camera.range[0], camera.range[1]) for reg in regions: polygon = Polygon(vertices[reg]) area = polygon.intersection(range_box).area voronoi_areas.append(area) voronoi_areas = np.array(voronoi_areas) camera_area = np.pi * camera.cone_angle * camera.cone_range**2 / 360.0 area_ratios = voronoi_areas / camera_area steps = detection.detections.shape[-1] estimated_detection_nums = detection.detection_nums * area_ratios occupancy = min(1, np.mean(estimated_detection_nums / steps)) return OccupancyEstimate(occupancy, self, detection)
def _voronoi_finite_polygons_2d(vor, radius=None): """ Reconstruct infinite voronoi regions in a 2D diagram to finite regions. Parameters ---------- vor : Voronoi Input diagram radius : float, optional Distance to 'points at infinity'. Returns ------- regions : list of tuples Indices of vertices in each revised Voronoi regions. vertices : list of tuples Coordinates for revised Voronoi vertices. Same as coordinates of input vertices, with 'points at infinity' appended to the end. """ if vor.points.shape[1] != 2: raise ValueError("Requires 2D input") new_regions = [] new_vertices = vor.vertices.tolist() center = vor.points.mean(axis=0) if radius is None: radius = vor.points.ptp().max() # Construct a map containing all ridges for a given point all_ridges = {} for (p1, p2), (v1, v2) in zip(vor.ridge_points, vor.ridge_vertices): all_ridges.setdefault(p1, []).append((p2, v1, v2)) all_ridges.setdefault(p2, []).append((p1, v1, v2)) # Reconstruct infinite regions for p1, region in enumerate(vor.point_region): vertices = vor.regions[region] if all(v >= 0 for v in vertices): # finite region new_regions.append(vertices) continue # reconstruct a non-finite region ridges = all_ridges[p1] new_region = [v for v in vertices if v >= 0] for p2, v1, v2 in ridges: if v2 < 0: v1, v2 = v2, v1 if v1 >= 0: # finite ridge: already in the region continue # Compute the missing endpoint of an infinite ridge t = vor.points[p2] - vor.points[p1] # tangent t /= np.linalg.norm(t) n = np.array([-t[1], t[0]]) # normal midpoint = vor.points[[p1, p2]].mean(axis=0) direction = np.sign(np.dot(midpoint - center, n)) * n far_point = vor.vertices[v2] + direction * radius new_region.append(len(new_vertices)) new_vertices.append(far_point.tolist()) # sort region counterclockwise vs = np.asarray([new_vertices[v] for v in new_region]) c = vs.mean(axis=0) angles = np.arctan2(vs[:, 1] - c[1], vs[:, 0] - c[0]) new_region = np.array(new_region)[np.argsort(angles)] # finish new_regions.append(new_region.tolist()) return new_regions, np.asarray(new_vertices)