Source code for pedpy.methods.density_calculator
"""Module containing functions to compute densities."""
from typing import Tuple
import numpy as np
import pandas as pd
import shapely
from shapely import Polygon
from pedpy.methods.method_utils import compute_intersecting_polygons
[docs]def compute_classic_density(
*,
traj_data: pd.DataFrame,
measurement_area: Polygon,
) -> pd.DataFrame:
"""Compute the classic density per frame inside the given measurement area.
Args:
traj_data (pd.DataFrame): trajectory data to analyze
measurement_area (shapely.Polygon): area for which the density is computed
Returns:
DataFrame containing the columns: 'frame' and 'classic density'
"""
peds_in_area = traj_data[
shapely.contains(measurement_area, traj_data["points"])
]
peds_in_area_per_frame = _get_num_peds_per_frame(peds_in_area)
density = peds_in_area_per_frame / measurement_area.area
# Rename column and add missing zero values
density.columns = ["classic density"]
density = density.reindex(
list(range(traj_data.frame.min(), traj_data.frame.max() + 1)),
fill_value=0.0,
)
return density
[docs]def compute_voronoi_density(
*,
individual_voronoi_data: pd.DataFrame,
measurement_area: shapely.Polygon,
) -> Tuple[pd.DataFrame, pd.DataFrame]:
"""Compute the voronoi density per frame inside the given measurement area.
Args:
individual_voronoi_data (pd.DataFrame): individual voronoi data per
frame needs to contain the columns: 'ID', 'frame',
'individual voronoi', which holds a shapely.Polygon
measurement_area (shapely.Polygon): area for which the density is
computed
Returns:
DataFrame containing the columns: 'frame' and 'voronoi density',
DataFrame containing the columns: 'ID', 'frame', 'individual voronoi',
'intersecting voronoi'.
"""
df_intersecting = compute_intersecting_polygons(
individual_voronoi_data, measurement_area
)
df_combined = pd.merge(
individual_voronoi_data,
df_intersecting,
on=["ID", "frame"],
how="outer",
)
df_combined["relation"] = shapely.area(
df_combined["intersection voronoi"]
) / shapely.area(df_combined["individual voronoi"])
df_voronoi_density = (
df_combined.groupby("frame")["relation"].sum() / measurement_area.area
).to_frame()
# Rename column and add missing zero values
df_voronoi_density.columns = ["voronoi density"]
df_voronoi_density = df_voronoi_density.reindex(
list(
range(
individual_voronoi_data.frame.min(),
individual_voronoi_data.frame.max() + 1,
)
),
fill_value=0.0,
)
return (
df_voronoi_density,
df_combined.loc[:, df_combined.columns != "relation"],
)
[docs]def compute_passing_density(
*, density_per_frame: pd.DataFrame, frames: pd.DataFrame
) -> pd.DataFrame:
"""Compute the individual density of the pedestrian who pass the area.
Args:
density_per_frame (pd.DataFrame): density per frame, DataFrame
containing the columns: 'frame' (as index) and 'density'
frames (pd.DataFrame): information for each pedestrian in the area,
need to contain the following columns: 'ID','frame_start',
'frame_end'.
Returns:
DataFrame containing the columns: 'ID' and 'density' in 1/m
"""
density = pd.DataFrame(frames["ID"], columns=["ID", "density"])
densities = []
for _, row in frames.iterrows():
densities.append(
density_per_frame[
density_per_frame.index.to_series().between(
int(row.frame_start), int(row.frame_end), inclusive="left"
)
].mean()
)
density["density"] = np.array(densities)
return density
def _get_num_peds_per_frame(traj_data: pd.DataFrame) -> pd.DataFrame:
"""Returns the number of pedestrians in each frame as DataFrame.
Args:
traj_data (pd.DataFrame): trajectory data
Returns:
DataFrame containing the columns: 'frame' (as index) and 'num_peds'.
"""
num_peds_per_frame = traj_data.groupby("frame").agg(
num_peds=("ID", "count")
)
return num_peds_per_frame