From a500e8a446e6a68c44cfe93b2b33577f9d692d30 Mon Sep 17 00:00:00 2001 From: schroedtert Date: Fri, 23 Feb 2024 14:38:35 +0100 Subject: [PATCH 1/7] Add intrusion computation --- pedpy/__init__.py | 3 ++ pedpy/column_identifier.py | 2 ++ pedpy/methods/foo_calculator.py | 52 +++++++++++++++++++++++++++++++++ pedpy/methods/method_utils.py | 20 +++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 pedpy/methods/foo_calculator.py diff --git a/pedpy/__init__.py b/pedpy/__init__.py index 0720dc01..d4286876 100644 --- a/pedpy/__init__.py +++ b/pedpy/__init__.py @@ -55,6 +55,7 @@ compute_passing_speed, compute_voronoi_speed, ) +from .methods.foo_calculator import compute_intrusion, IntrusionMethod from .plotting.plotting import ( PEDPY_BLUE, PEDPY_GREEN, @@ -116,6 +117,8 @@ "compute_mean_speed_per_frame", "compute_passing_speed", "compute_voronoi_speed", + "compute_intrusion", + "IntrusionMethod", "PEDPY_BLUE", "PEDPY_GREEN", "PEDPY_GREY", diff --git a/pedpy/column_identifier.py b/pedpy/column_identifier.py index 430183e9..7cc7ca6a 100644 --- a/pedpy/column_identifier.py +++ b/pedpy/column_identifier.py @@ -29,3 +29,5 @@ START_POSITION_COL: Final = "start_position" END_POSITION_COL: Final = "end_position" WINDOW_SIZE_COL: Final = "window_size" + +INTRUSION_COL: Final = "intrusion" diff --git a/pedpy/methods/foo_calculator.py b/pedpy/methods/foo_calculator.py new file mode 100644 index 00000000..dcc8d4fa --- /dev/null +++ b/pedpy/methods/foo_calculator.py @@ -0,0 +1,52 @@ +"""Foo.""" + + +from enum import Enum + +from pedpy.data.trajectory_data import TrajectoryData +from .method_utils import _compute_individual_distances +from pedpy.column_identifier import FRAME_COL, ID_COL, INTRUSION_COL +import pandas + + +class IntrusionMethod(Enum): # pylint: disable=too-few-public-methods + """Identifier of method to compute the intrusion.""" + + MAX = "max" + """Use the max value in neighborhood as intrusion.""" + SUM = "sum" + """Use the sum of all values in neighborhood as intrusion.""" + + +def compute_intrusion( + *, + traj_data: TrajectoryData, + r_soc: float = 0.8, + l_min: float = 0.2, + method: IntrusionMethod = IntrusionMethod.SUM, +) -> pandas.DataFrame: + """_summary_. + + TODO add documentation here + Args: + traj_data (TrajectoryData): _description_ + r_soc (float): _description_ + l_min (float): _description_ + method (IntrusionMethod, optional): _description_. Defaults to IntrusionMethod.SUM. + + Returns: + pandas.DataFrame: _description_ + """ + intrusion = _compute_individual_distances(traj_data=traj_data) + intrusion[INTRUSION_COL] = ( + (r_soc - l_min) / (intrusion.distance - l_min) + ) ** 2 + intrusion = ( + intrusion.groupby(by=[ID_COL, FRAME_COL]) + .agg( + intrusion=(INTRUSION_COL, method.value), + ) + .reset_index() + ) + + return intrusion diff --git a/pedpy/methods/method_utils.py b/pedpy/methods/method_utils.py index 727384be..657b8e6f 100644 --- a/pedpy/methods/method_utils.py +++ b/pedpy/methods/method_utils.py @@ -947,3 +947,23 @@ def _check_crossing_in_frame_range( crossed[column_name] = crossed[column_name] == "both" crossed = crossed[crossed[column_name]] return crossed + + +def _compute_individual_distances(*, traj_data: TrajectoryData) -> pd.DataFrame: + matrix = pd.merge( + traj_data.data[["id", "frame", "point"]], + traj_data.data[["id", "frame", "point"]], + how="outer", + on="frame", + suffixes=("", "_neighbor"), + ) + matrix = matrix[matrix.id != matrix.id_neighbor] + matrix["distance"] = np.linalg.norm( + shapely.get_coordinates(matrix.point) + - shapely.get_coordinates(matrix.point_neighbor), + axis=1, + ) + + matrix = matrix.drop(columns=["point", "point_neighbor"]) + matrix = matrix.rename(columns={"id_neighbor": "neighbor"}) + return matrix.reset_index(drop=True) From 221a4c3188a14fb0c5f18f31c15abf5a6fa072c3 Mon Sep 17 00:00:00 2001 From: schroedtert Date: Fri, 23 Feb 2024 14:51:29 +0100 Subject: [PATCH 2/7] Add avoidance computation --- pedpy/__init__.py | 7 ++- pedpy/column_identifier.py | 1 + pedpy/methods/foo_calculator.py | 108 +++++++++++++++++++++++++++++++- 3 files changed, 112 insertions(+), 4 deletions(-) diff --git a/pedpy/__init__.py b/pedpy/__init__.py index d4286876..8e09135f 100644 --- a/pedpy/__init__.py +++ b/pedpy/__init__.py @@ -29,6 +29,11 @@ compute_voronoi_density, ) from .methods.flow_calculator import compute_flow, compute_n_t +from .methods.foo_calculator import ( + IntrusionMethod, + compute_avoidance, + compute_intrusion, +) from .methods.method_utils import ( Cutoff, compute_frame_range_in_area, @@ -55,7 +60,6 @@ compute_passing_speed, compute_voronoi_speed, ) -from .methods.foo_calculator import compute_intrusion, IntrusionMethod from .plotting.plotting import ( PEDPY_BLUE, PEDPY_GREEN, @@ -119,6 +123,7 @@ "compute_voronoi_speed", "compute_intrusion", "IntrusionMethod", + "compute_avoidance", "PEDPY_BLUE", "PEDPY_GREEN", "PEDPY_GREY", diff --git a/pedpy/column_identifier.py b/pedpy/column_identifier.py index 7cc7ca6a..df6310fe 100644 --- a/pedpy/column_identifier.py +++ b/pedpy/column_identifier.py @@ -31,3 +31,4 @@ WINDOW_SIZE_COL: Final = "window_size" INTRUSION_COL: Final = "intrusion" +AVOIDANCE_COL: Final = "avoidance" diff --git a/pedpy/methods/foo_calculator.py b/pedpy/methods/foo_calculator.py index dcc8d4fa..25b8198a 100644 --- a/pedpy/methods/foo_calculator.py +++ b/pedpy/methods/foo_calculator.py @@ -3,10 +3,22 @@ from enum import Enum -from pedpy.data.trajectory_data import TrajectoryData -from .method_utils import _compute_individual_distances -from pedpy.column_identifier import FRAME_COL, ID_COL, INTRUSION_COL +import numpy as np import pandas +import shapely + +from pedpy.column_identifier import ( + AVOIDANCE_COL, + FRAME_COL, + ID_COL, + INTRUSION_COL, +) +from pedpy.data.trajectory_data import TrajectoryData +from pedpy.methods.method_utils import ( + SpeedCalculation, + _compute_individual_distances, +) +from pedpy.methods.speed_calculator import compute_individual_speed class IntrusionMethod(Enum): # pylint: disable=too-few-public-methods @@ -50,3 +62,93 @@ def compute_intrusion( ) return intrusion + + +def compute_avoidance( + *, + traj_data: TrajectoryData, + frame_step: int, + radius: float = 0.2, + tau_0: float, +) -> pandas.DataFrame: + """_summary_. + + TODO add documentation here + + Args: + traj_data (TrajectoryData): _description_ + frame_step (int): _description_ + radius (float): _description_ + tau_0 (float): _description_ + + Returns: + pandas.DataFrame: _description_ + """ + velocity = compute_individual_speed( + traj_data=traj_data, + frame_step=frame_step, + compute_velocity=True, + speed_calculation=SpeedCalculation.BORDER_SINGLE_SIDED, + ) + + data = pandas.merge(traj_data.data, velocity, on=[ID_COL, FRAME_COL]) + data["velocity"] = shapely.points(data.v_x, data.v_y) + + matrix = pandas.merge( + data, data, how="outer", on=FRAME_COL, suffixes=("", "_neighbor") + ) + matrix = matrix[matrix.id != matrix.id_neighbor] + + distance = np.linalg.norm( + shapely.get_coordinates(matrix.point) + - shapely.get_coordinates(matrix.point_neighbor), + axis=1, + ) + + e_v = ( + shapely.get_coordinates(matrix.point) + - shapely.get_coordinates(matrix.point_neighbor) + ) / distance[:, np.newaxis] + + v_rel = shapely.get_coordinates(matrix.velocity) - shapely.get_coordinates( + matrix.velocity_neighbor + ) / np.linalg.norm( + shapely.get_coordinates(matrix.velocity) + - shapely.get_coordinates(matrix.velocity_neighbor) + ) + + v_rel_norm = np.linalg.norm(v_rel, axis=1) + + dot_product = np.sum( + np.array(np.array(e_v.tolist())) * np.array(np.array(v_rel.tolist())), + axis=1, + ) + + cos_alpha = dot_product / (distance * v_rel_norm) + + ttc = np.full(matrix.shape[0], np.inf) + + capital_a = (cos_alpha**2 - 1) * distance**2 + radius**2 + + # (0.5 * l_a + 0.5 * l_b)**2 in paper + sqrt_a_safe = np.where( + capital_a >= 0, np.sqrt(np.where(capital_a >= 0, capital_a, 0)), np.nan + ) + + valid_conditions = ( + (capital_a >= 0) + & (-cos_alpha * distance - sqrt_a_safe >= 0) + & (v_rel_norm != 0) + ) + + ttc[valid_conditions] = ( + -cos_alpha[valid_conditions] * distance[valid_conditions] + - np.sqrt(capital_a[valid_conditions]) + ) / v_rel_norm[valid_conditions] + + matrix[AVOIDANCE_COL] = tau_0 / ttc + + avoidance = matrix.groupby(by=[ID_COL, FRAME_COL], as_index=False).agg( + avoidance=(AVOIDANCE_COL, "max") + ) + return avoidance From 6bfa513fd248ac6e71d836f2cd50d54e493abcf3 Mon Sep 17 00:00:00 2001 From: schroedtert Date: Mon, 25 Mar 2024 15:04:26 +0100 Subject: [PATCH 3/7] Show new functions in API reference --- docs/source/api/methods.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/source/api/methods.rst b/docs/source/api/methods.rst index 37469736..9596ffa7 100644 --- a/docs/source/api/methods.rst +++ b/docs/source/api/methods.rst @@ -41,3 +41,11 @@ Utils :members: :no-private-members: :no-special-members: + +Other +******** + +.. autoapimodule:: foo_calculator + :members: + :no-private-members: + :no-special-members: From 31fcbb272b24475365639756c05b19852b3cd797 Mon Sep 17 00:00:00 2001 From: schroedtert Date: Mon, 25 Mar 2024 15:14:30 +0100 Subject: [PATCH 4/7] Fix stuff --- pedpy/methods/method_utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pedpy/methods/method_utils.py b/pedpy/methods/method_utils.py index 657b8e6f..0c8df687 100644 --- a/pedpy/methods/method_utils.py +++ b/pedpy/methods/method_utils.py @@ -949,8 +949,10 @@ def _check_crossing_in_frame_range( return crossed -def _compute_individual_distances(*, traj_data: TrajectoryData) -> pd.DataFrame: - matrix = pd.merge( +def _compute_individual_distances( + *, traj_data: TrajectoryData +) -> pandas.DataFrame: + matrix = pandas.merge( traj_data.data[["id", "frame", "point"]], traj_data.data[["id", "frame", "point"]], how="outer", From 4c3c6a8de7c1fde8317f6615a8a8415a0c3aee43 Mon Sep 17 00:00:00 2001 From: schroedtert Date: Mon, 25 Mar 2024 15:25:23 +0100 Subject: [PATCH 5/7] Fix stuff --- docs/source/api/methods.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/api/methods.rst b/docs/source/api/methods.rst index 9596ffa7..f44fba04 100644 --- a/docs/source/api/methods.rst +++ b/docs/source/api/methods.rst @@ -43,7 +43,7 @@ Utils :no-special-members: Other -******** +***** .. autoapimodule:: foo_calculator :members: From a7d635c3bb0f1c0c94ac4ac4969677d075534227 Mon Sep 17 00:00:00 2001 From: schroedtert Date: Mon, 25 Mar 2024 15:35:33 +0100 Subject: [PATCH 6/7] Fix stuff --- pedpy/methods/foo_calculator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pedpy/methods/foo_calculator.py b/pedpy/methods/foo_calculator.py index 25b8198a..0f247921 100644 --- a/pedpy/methods/foo_calculator.py +++ b/pedpy/methods/foo_calculator.py @@ -40,6 +40,7 @@ def compute_intrusion( """_summary_. TODO add documentation here + Args: traj_data (TrajectoryData): _description_ r_soc (float): _description_ From c404ed6bec704ee7e7bcb534b9eb85a407cdbea5 Mon Sep 17 00:00:00 2001 From: schroedtert Date: Wed, 27 Mar 2024 09:08:52 +0100 Subject: [PATCH 7/7] What's going on here? --- pedpy/methods/foo_calculator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pedpy/methods/foo_calculator.py b/pedpy/methods/foo_calculator.py index 0f247921..91ba0b3a 100644 --- a/pedpy/methods/foo_calculator.py +++ b/pedpy/methods/foo_calculator.py @@ -1,4 +1,4 @@ -"""Foo.""" +"""We need a proper name here ...""" from enum import Enum