├── jrdb_baselines ├── .DS_Store ├── DATA_BLOCK │ └── .DS_Store ├── trajnetbaselines │ ├── __init__.py │ ├── .DS_Store │ ├── __init__.pyc │ ├── augmentation.pyc │ ├── lstm │ │ ├── __pycache__ │ │ │ ├── loss.cpython-310.pyc │ │ │ ├── loss.cpython-37.pyc │ │ │ ├── lstm.cpython-310.pyc │ │ │ ├── lstm.cpython-37.pyc │ │ │ ├── utils.cpython-37.pyc │ │ │ ├── modules.cpython-37.pyc │ │ │ ├── trainer.cpython-37.pyc │ │ │ ├── utils.cpython-310.pyc │ │ │ ├── __init__.cpython-310.pyc │ │ │ ├── __init__.cpython-37.pyc │ │ │ ├── modules.cpython-310.pyc │ │ │ ├── trainer.cpython-310.pyc │ │ │ ├── data_load_utils.cpython-37.pyc │ │ │ ├── data_load_utils.cpython-310.pyc │ │ │ ├── gridbased_pooling.cpython-37.pyc │ │ │ ├── gridbased_pooling.cpython-310.pyc │ │ │ ├── trajnet_evaluator.cpython-310.pyc │ │ │ ├── non_gridbased_pooling.cpython-310.pyc │ │ │ ├── non_gridbased_pooling.cpython-37.pyc │ │ │ ├── more_non_gridbased_pooling.cpython-310.pyc │ │ │ └── more_non_gridbased_pooling.cpython-37.pyc │ │ ├── tools │ │ │ ├── __pycache__ │ │ │ │ ├── data.cpython-37.pyc │ │ │ │ ├── data.cpython-310.pyc │ │ │ │ ├── reader.cpython-37.pyc │ │ │ │ ├── metrics.cpython-37.pyc │ │ │ │ └── reader.cpython-310.pyc │ │ │ ├── data.py │ │ │ ├── reader.py │ │ │ └── metrics.py │ │ ├── __init__.py │ │ ├── profile_train.py │ │ ├── modules.py │ │ ├── data_load_utils.py │ │ ├── loss.py │ │ ├── more_non_gridbased_pooling.py │ │ ├── trajnet_evaluator.py │ │ ├── utils.py │ │ ├── plot_log.py │ │ └── lstm.py │ └── augmentation.py ├── OUTPUT_BLOCK │ └── .DS_Store ├── evaluator │ ├── __pycache__ │ │ └── write_utils.cpython-310.pyc │ └── write_utils.py ├── .pylintrc ├── setup.py ├── create_validation.py └── get_dest.py ├── trajnetplusplusdataset ├── trajnetdataset │ ├── __init__.py │ ├── __pycache__ │ │ ├── scene.cpython-310.pyc │ │ ├── __init__.cpython-310.pyc │ │ ├── convert.cpython-310.pyc │ │ ├── get_type.cpython-310.pyc │ │ ├── readers.cpython-310.pyc │ │ └── orca_helper.cpython-310.pyc │ ├── tools │ │ ├── __pycache__ │ │ │ ├── data.cpython-310.pyc │ │ │ ├── kalman.cpython-310.pyc │ │ │ ├── metrics.cpython-310.pyc │ │ │ ├── reader.cpython-310.pyc │ │ │ ├── writers.cpython-310.pyc │ │ │ └── interactions.cpython-310.pyc │ │ ├── data.py │ │ ├── writers.py │ │ ├── kalman.py │ │ ├── metrics.py │ │ ├── reader.py │ │ └── interactions.py │ ├── orca_helper.py │ ├── scene.py │ ├── get_type.py │ ├── readers.py │ ├── convert_train.py │ └── convert_test.py ├── build │ └── lib │ │ └── trajnetdataset │ │ ├── __init__.py │ │ ├── orca_helper.py │ │ ├── scene.py │ │ ├── readers.py │ │ └── get_type.py ├── data │ └── raw │ │ └── .DS_Store ├── dist │ └── trajnetdataset-0.1.0-py3.10.egg ├── setup_social_force.sh ├── setup_orca.sh ├── setup.py └── scripts │ └── convert_original.py ├── train.sh ├── preprocess.sh ├── eval.sh ├── requirement.sh ├── .gitignore ├── dataload.sh ├── README.md ├── train_traj_extractor.py └── test_traj_extractor.py /jrdb_baselines/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/.DS_Store -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.1.0' 2 | 3 | from . import readers 4 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/build/lib/trajnetdataset/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.1.0' 2 | 3 | from . import readers 4 | -------------------------------------------------------------------------------- /jrdb_baselines/DATA_BLOCK/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/DATA_BLOCK/.DS_Store -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.1.0' 2 | 3 | from . import augmentation 4 | from . import lstm 5 | -------------------------------------------------------------------------------- /jrdb_baselines/OUTPUT_BLOCK/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/OUTPUT_BLOCK/.DS_Store -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/.DS_Store -------------------------------------------------------------------------------- /trajnetplusplusdataset/data/raw/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/data/raw/.DS_Store -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/__init__.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/augmentation.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/augmentation.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/dist/trajnetdataset-0.1.0-py3.10.egg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/dist/trajnetdataset-0.1.0-py3.10.egg -------------------------------------------------------------------------------- /jrdb_baselines/evaluator/__pycache__/write_utils.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/evaluator/__pycache__/write_utils.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/loss.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/loss.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/loss.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/loss.cpython-37.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/lstm.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/lstm.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/lstm.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/lstm.cpython-37.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/utils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/utils.cpython-37.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/modules.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/modules.cpython-37.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/trainer.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/trainer.cpython-37.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/utils.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/utils.cpython-310.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/__pycache__/scene.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/__pycache__/scene.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/modules.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/modules.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/trainer.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/trainer.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/tools/__pycache__/data.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/tools/__pycache__/data.cpython-37.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/__pycache__/convert.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/__pycache__/convert.cpython-310.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/__pycache__/get_type.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/__pycache__/get_type.cpython-310.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/__pycache__/readers.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/__pycache__/readers.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/tools/__pycache__/data.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/tools/__pycache__/data.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/tools/__pycache__/reader.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/tools/__pycache__/reader.cpython-37.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/__pycache__/data.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/tools/__pycache__/data.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/data_load_utils.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/data_load_utils.cpython-37.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/tools/__pycache__/metrics.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/tools/__pycache__/metrics.cpython-37.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/tools/__pycache__/reader.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/tools/__pycache__/reader.cpython-310.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/__pycache__/orca_helper.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/__pycache__/orca_helper.cpython-310.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/__pycache__/kalman.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/tools/__pycache__/kalman.cpython-310.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/__pycache__/metrics.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/tools/__pycache__/metrics.cpython-310.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/__pycache__/reader.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/tools/__pycache__/reader.cpython-310.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/__pycache__/writers.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/tools/__pycache__/writers.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/data_load_utils.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/data_load_utils.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/gridbased_pooling.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/gridbased_pooling.cpython-37.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/gridbased_pooling.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/gridbased_pooling.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/trajnet_evaluator.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/trajnet_evaluator.cpython-310.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/__pycache__/interactions.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/trajnetplusplusdataset/trajnetdataset/tools/__pycache__/interactions.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/non_gridbased_pooling.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/non_gridbased_pooling.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/non_gridbased_pooling.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/non_gridbased_pooling.cpython-37.pyc -------------------------------------------------------------------------------- /train.sh: -------------------------------------------------------------------------------- 1 | cd jrdb_baselines 2 | python -m trajnetbaselines.lstm.trainer --type social --n 10 --layer_dims 1024 --pool_dim 32 --hidden-dim 8 --lr 1e-4 --epochs 15 --path jrdb_traj --augment --loss 'L2' --output jrdb_traj_test 3 | -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/more_non_gridbased_pooling.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/more_non_gridbased_pooling.cpython-310.pyc -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__pycache__/more_non_gridbased_pooling.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vita-epfl/JRDB-Traj/HEAD/jrdb_baselines/trajnetbaselines/lstm/__pycache__/more_non_gridbased_pooling.cpython-37.pyc -------------------------------------------------------------------------------- /trajnetplusplusdataset/setup_social_force.sh: -------------------------------------------------------------------------------- 1 | ## Additional Requirements (Social Force) 2 | wget https://github.com/svenkreiss/socialforce/archive/refs/heads/main.zip 3 | unzip main.zip 4 | rm main.zip 5 | 6 | ## Setting up Social Force 7 | cd socialforce-main/ 8 | pip install -e . 9 | cd ../ 10 | -------------------------------------------------------------------------------- /jrdb_baselines/.pylintrc: -------------------------------------------------------------------------------- 1 | [BASIC] 2 | 3 | variable-rgx=[a-z0-9_]{1,30}$ 4 | good-names=i,n,nx,ny,xy,r 5 | 6 | [TYPECHECK] 7 | 8 | # List of members which are set dynamically and missed by pylint inference 9 | # system, and so shouldn't trigger E1101 when accessed. Python regular 10 | # expressions are accepted. 11 | generated-members=numpy.*,torch.* 12 | 13 | disable=missing-docstring,duplicate-code 14 | -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/__init__.py: -------------------------------------------------------------------------------- 1 | from .loss import L2Loss 2 | from .lstm import LSTM, LSTMPredictor 3 | from .gridbased_pooling import GridBasedPooling 4 | from .non_gridbased_pooling import NN_Pooling, HiddenStateMLPPooling, AttentionMLPPooling, DirectionalMLPPooling 5 | from .non_gridbased_pooling import NN_LSTM, TrajectronPooling, SAttention_fast 6 | from .more_non_gridbased_pooling import NMMP 7 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/setup_orca.sh: -------------------------------------------------------------------------------- 1 | ## Additional Requirements (ORCA) 2 | wget https://github.com/sybrenstuvel/Python-RVO2/archive/master.zip 3 | unzip master.zip 4 | rm master.zip 5 | 6 | ## Setting up ORCA (steps provided in the Python-RVO2 repo) 7 | cd Python-RVO2-main/ 8 | pip install cmake 9 | pip install cython 10 | python setup.py build 11 | python setup.py install 12 | cd ../ 13 | rm -rf Python-RVO2-main/ -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/tools/data.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | 3 | 4 | TrackRow = namedtuple('Row', ['frame', 'pedestrian', 'x', 'y', 'v','prediction_number', 'scene_id']) 5 | TrackRow.__new__.__defaults__ = (None, None, None, None, None,None, None) 6 | SceneRow = namedtuple('Row', ['scene', 'pedestrian', 'start', 'end', 'fps', 'tag']) 7 | SceneRow.__new__.__defaults__ = (None, None, None, None, None, None) 8 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/data.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | 3 | TrackRow = namedtuple('Row', ['frame', 'pedestrian', 'x', 'y', 'v', 'prediction_number', 'scene_id']) 4 | TrackRow.__new__.__defaults__ = (None, None, None, None, None, None, None) 5 | SceneRow = namedtuple('Row', ['scene', 'pedestrian', 'start', 'end', 'fps', 'tag']) 6 | SceneRow.__new__.__defaults__ = (None, None, None, None, None, None) 7 | -------------------------------------------------------------------------------- /preprocess.sh: -------------------------------------------------------------------------------- 1 | cd trajnetplusplusdataset 2 | python -m trajnetdataset.convert_train --acceptance 1.0 1.0 1.0 1.0 --train_fraction 1.0 --val_fraction 0.0 --fps 2.5 --obs_len 9 --pred_len 12 3 | python -m trajnetdataset.convert_test --acceptance 1.0 1.0 1.0 1.0 --train_fraction 0.0 --val_fraction 0.0 --fps 2.5 --obs_len 9 --pred_len 0 --chunk_stride 1 4 | 5 | #This step will give you the training and testing data under 'output' folder, then you need to move the data to the following 6 | mv output ../jrdb_baselines/DATA_BLOCK/jrdb_traj 7 | -------------------------------------------------------------------------------- /eval.sh: -------------------------------------------------------------------------------- 1 | # You can evaluate your saved model with the following command. 2 | # We have also provided the saved checkpoints in the release section. In order to evaluate it, you should put the saved '.pkl' file in the 'jrdb_baselines/OUTPUT_BLOCK/jrdb_traj' 3 | cd jrdb_baselines 4 | python -m trajnetbaselines.lstm.trajnet_evaluator --path jrdb_traj --output OUTPUT_BLOCK/jrdb_traj/lstm_social_baseline.pkl 5 | rm -r DATA_BLOCK/jrdb_traj/test_pred/lstm_social_baseline_modes1/temp 6 | 7 | mv DATA_BLOCK/jrdb_traj/test_pred/lstm_social_baseline_modes1/jrdb_submission .. 8 | -------------------------------------------------------------------------------- /requirement.sh: -------------------------------------------------------------------------------- 1 | cd jrdb_baselines/ 2 | pip install -e . 3 | cd ../trajnetplusplusdataset/ 4 | pip install -e . 5 | pip install -e '.[test, plot]' 6 | !rm -rf Python_RVO2-main/ 7 | wget https://github.com/sybrenstuvel/Python-RVO2/archive/master.zip 8 | unzip master.zip 9 | rm master.zip 10 | cd Python-RVO2-main/ 11 | pip install cmake 12 | pip install cython 13 | python setup.py build 14 | python setup.py install 15 | cd ../ 16 | wget https://github.com/svenkreiss/socialforce/archive/refs/heads/main.zip 17 | unzip main.zip 18 | rm main.zip 19 | cd socialforce-main/ 20 | pip install -e . 21 | cd ../ 22 | cd ../ 23 | pip install python-json-logger 24 | pip install joblib 25 | pip install tqdm 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | trajnetplusplusdataset/Python-RVO2-main/ 3 | trajnetplusplusdataset/data/raw/*.csv 4 | trajnetplusplusdataset/output_pre/ 5 | trajnetplusplusdataset/socialforce-main/ 6 | trajnetplusplusdataset/trajnetdataset/__pycache__ 7 | trajnetplusplusdataset/trajnetdataset/tools/__pycache__/ 8 | trajnetplusplusdataset/trajnetdataset.egg-info/ 9 | jrdb_baselines/trajnetbaselines.egg-info/ 10 | jrdb_baselines/trajnetbaselines/__pycache__/ 11 | jrdb_baselines/trajnetbaselines/lstm/__pycache__/ 12 | jrdb_baselines/trajnetbaselines/lstm/tools/__pycache__/ 13 | jrdb_baselines/evaluator/__pycache__/ 14 | jrdb_submission/ 15 | jrdb_baselines/DATA_BLOCK/jrdb_traj/ 16 | jrdb_baselines/OUTPUT_BLOCK/jrdb_traj/ -------------------------------------------------------------------------------- /dataload.sh: -------------------------------------------------------------------------------- 1 | # After extracting the raw data, you will get the extracted data located at the output_path you set. 2 | jrdb_path="/train_dataset/labels/" 3 | # You should put the "Test Trackings" results downloaded from the JRDB webpage in the following address 4 | jrdb_test_path="/test_trackings/" 5 | 6 | out_path="OUT_tmp" 7 | 8 | python train_traj_extractor.py --out_path $out_path --jrdb_path $jrdb_path 9 | python test_traj_extractor.py --out_path $out_path --jrdb_path $jrdb_test_path 10 | 11 | 12 | # There will also be two temp folders named 'temp' and 'conf_temp', can be removed. 13 | rm -r $out_path/temp $out_path/conf_temp 14 | 15 | # Move the extracted data to 'trajnetplusplusdataset/data/raw/'.) 16 | mv $out_path trajnetplusplusdataset/data/raw 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JRDB-Traj 2 | JRDB Data Preprocessing and Trajectory Prediction Baselines 3 | 4 | ## Prerequisites 5 | Install requirements with `bash requirement.sh`. 6 | 7 | ## Repository Overview 8 | The pipeline encompasses four key steps: 9 | 10 | 1. `bash dataload.sh`: This script preprocesses the JRDB dataset, extracting trajectories for further analysis. 11 | 2. `bash preprocess.sh`: Utilizing the TrajNet++ benchmark, this script categorizes '.csv' files and generates '.ndjson' files for the next step. 12 | 3. `bash train.sh`: This script train baseline trajectory prediction models using the meticulously prepared data. 13 | 4. `bash eval.sh`: This script will generate predictions in JRDB leaderboard format. 14 | Now, you can you submit the "jrdb_submission" directory in the main part of the repo to the leaderboard. 15 | 16 | ## Work in Progress 17 | This repository is being updated so please stay tuned! 18 | -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/profile_train.py: -------------------------------------------------------------------------------- 1 | """Script to profile trianing. 2 | 3 | Run with: 4 | python -m trajnetbaselines.lstm.profile_train 5 | """ 6 | 7 | import torch 8 | import trajnetbaselines.lstm.trainer 9 | import trajnetplusplustools 10 | 11 | 12 | def main(): 13 | device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu') 14 | 15 | scenes = list(trajnetplusplustools.Reader('data/train/biwi_hotel.ndjson').scenes(limit=1)) 16 | 17 | pool = trajnetbaselines.lstm.Pooling(type_='social') 18 | model = trajnetbaselines.lstm.LSTM(pool=pool) 19 | trainer = trajnetbaselines.lstm.trainer.Trainer(model, device=device) 20 | with torch.autograd.profiler.profile(use_cuda=torch.cuda.is_available()) as prof: 21 | trainer.train(scenes, epoch=0) 22 | prof.export_chrome_trace('profile_trace.json') 23 | 24 | 25 | if __name__ == '__main__': 26 | main() 27 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/setup.py: -------------------------------------------------------------------------------- 1 | """setup trajnetplusplusdataset""" 2 | 3 | from setuptools import setup 4 | 5 | # extract version from __init__.py 6 | with open('trajnetdataset/__init__.py', 'r') as f: 7 | VERSION_LINE = [l for l in f if l.startswith('__version__')][0] 8 | VERSION = VERSION_LINE.split('=')[1].strip()[1:-1] 9 | 10 | 11 | setup( 12 | name='trajnetdataset', 13 | version=VERSION, 14 | packages=[ 15 | 'trajnetdataset', 16 | ], 17 | license='MIT', 18 | description='Trajnet++ dataset.', 19 | url='https://github.com/vita-epfl/trajnetplusplusdataset', 20 | 21 | install_requires=[ 22 | 'pysparkling', 23 | 'scipy', 24 | 'trajnetplusplustools', 25 | ], 26 | extras_require={ 27 | 'test': [ 28 | 'pylint', 29 | 'pytest', 30 | ], 31 | 'plot': [ 32 | 'matplotlib', 33 | ] 34 | }, 35 | ) 36 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/writers.py: -------------------------------------------------------------------------------- 1 | import json 2 | from .data import SceneRow, TrackRow 3 | 4 | 5 | def trajnet_tracks(row): 6 | x = row.x 7 | y = row.y 8 | v = row.v 9 | 10 | if row.prediction_number is None: 11 | return json.dumps({'track': {'f': row.frame, 'p': row.pedestrian, 'x': x, 'y': y, 'v' : v}}) 12 | 13 | return json.dumps({'track': {'f': row.frame, 'p': row.pedestrian, 'x': x, 'y': y, 'v' : v, 14 | 15 | 'prediction_number': row.prediction_number, 16 | 'scene_id': row.scene_id}}) 17 | 18 | 19 | 20 | def trajnet_scenes(row): 21 | return json.dumps( 22 | {'scene': {'id': row.scene, 'p': row.pedestrian, 's': row.start, 'e': row.end, 23 | 'fps': row.fps, 'tag': row.tag}}) 24 | 25 | 26 | def trajnet(row): 27 | if isinstance(row, TrackRow): 28 | return trajnet_tracks(row) 29 | if isinstance(row, SceneRow): 30 | return trajnet_scenes(row) 31 | 32 | raise Exception('unknown row type') 33 | -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/modules.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | class InputEmbedding(torch.nn.Module): 5 | """Linear embedding, ReLU non-linearity, input scaling. 6 | 7 | Input scaling is important for ReLU activation combined with the initial 8 | bias distribution. Otherwise some units will never be active. 9 | """ 10 | def __init__(self, input_dim, embedding_dim, scale, use_tags=True): 11 | super(InputEmbedding, self).__init__() 12 | self.embedding_dim = embedding_dim 13 | self.scale = scale 14 | self.use_tags = use_tags 15 | 16 | linear_embedding_dim = self.embedding_dim 17 | if use_tags: 18 | linear_embedding_dim -= 3 19 | self.input_embeddings = torch.nn.Sequential( 20 | torch.nn.Linear(input_dim, linear_embedding_dim), 21 | torch.nn.ReLU(), 22 | ) 23 | 24 | def forward(self, vel): 25 | if self.use_tags: 26 | return torch.cat([ 27 | self.input_embeddings(vel * self.scale), 28 | torch.zeros(vel.size(0),3, device=vel.device), 29 | ], dim=1) 30 | return self.input_embeddings(vel * self.scale) 31 | 32 | 33 | class Hidden2Normal(torch.nn.Module): 34 | def __init__(self, hidden_dim): 35 | super(Hidden2Normal, self).__init__() 36 | self.linear = torch.nn.Linear(hidden_dim, 3) 37 | 38 | def forward(self, hidden_state): 39 | normal = self.linear(hidden_state) 40 | normal[:,2] = torch.sigmoid(normal[:,2]) 41 | 42 | return normal 43 | -------------------------------------------------------------------------------- /jrdb_baselines/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | # extract version from __init__.py 4 | with open('trajnetbaselines/__init__.py', 'r') as f: 5 | VERSION_LINE = [l for l in f if l.startswith('__version__')][0] 6 | VERSION = VERSION_LINE.split('=')[1].strip()[1:-1] 7 | 8 | 9 | setup( 10 | name='trajnetbaselines', 11 | version=VERSION, 12 | packages=[ 13 | 'trajnetbaselines', 14 | 'trajnetbaselines.lstm', 15 | ], 16 | license='MIT', 17 | description='Trajnet baselines.', 18 | 19 | install_requires=[ 20 | 'numpy', 21 | 'pykalman', 22 | 'python-json-logger', 23 | 'scipy', 24 | 'torch==1.10.0', 25 | 'trajnetplusplustools', 26 | 'pysparkling', 27 | 'joblib', 28 | 'pandas', 29 | 'matplotlib', 30 | 'tqdm', 31 | ], 32 | extras_require={ 33 | 'test': [ 34 | 'pylint', 35 | 'pytest', 36 | ], 37 | 'plot': [ 38 | 'matplotlib', 39 | ], 40 | }, 41 | 42 | classifiers=[ 43 | 'Development Status :: 4 - Beta', 44 | 'Intended Audience :: Developers', 45 | 'Natural Language :: English', 46 | 'License :: OSI Approved :: MIT License', 47 | 'Operating System :: OS Independent', 48 | 'Programming Language :: Python', 49 | 'Programming Language :: Python :: 2.7', 50 | 'Programming Language :: Python :: 3.4', 51 | 'Programming Language :: Python :: 3.5', 52 | 'Programming Language :: Python :: 3.6', 53 | 'Programming Language :: Python :: Implementation :: PyPy', 54 | ] 55 | ) 56 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/scripts/convert_original.py: -------------------------------------------------------------------------------- 1 | """Trying to reproduce original Trajnet dataset.""" 2 | 3 | import pysparkling 4 | import trajnetdataset 5 | import trajnetplusplustools 6 | 7 | 8 | def main(): 9 | sc = pysparkling.Context() 10 | 11 | biwi_train = (sc 12 | .textFile('data/raw/biwi/seq_hotel/obsmat.txt') 13 | .map(trajnetdataset.readers.biwi) 14 | .cache()) 15 | 16 | good_start_frames = set(biwi_train 17 | .groupBy(lambda r: r.pedestrian) 18 | .filter(lambda kv: len(kv[1]) >= 20) 19 | .values() 20 | .map(lambda rs: rs[0].frame) 21 | .collect()) 22 | 23 | # good_start_frames_filtered = [] 24 | # for f in sorted(good_start_frames): 25 | # if good_start_frames_filtered and \ 26 | # f <= good_start_frames_filtered[-1] + 20: 27 | # continue 28 | # good_start_frames_filtered.append(f) 29 | # print(len(good_start_frames), len(good_start_frames_filtered)) 30 | # print(good_start_frames_filtered) 31 | good_start_frames_filtered = good_start_frames 32 | 33 | good_frames = {f 34 | for s in good_start_frames_filtered 35 | for f in range(s, s + 200, 10)} 36 | print(sorted(good_frames)) 37 | 38 | (biwi_train 39 | .filter(lambda r: r.frame in good_frames) 40 | 41 | # filter out short pedestrian paths 42 | .groupBy(lambda r: r.pedestrian) 43 | .filter(lambda kv: len(kv[1]) >= 20) 44 | .mapValues(lambda rs: rs[:20]) 45 | .values() 46 | .flatMap(lambda v: v) 47 | 48 | # write output 49 | .sortBy(lambda r: (r.pedestrian, r.frame)) 50 | .map(trajnetplusplustools.writers.trajnet_tracks) 51 | .saveAsTextFile('data/train/biwi/biwi_hotel.ndjson')) 52 | 53 | 54 | if __name__ == '__main__': 55 | main() 56 | -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/data_load_utils.py: -------------------------------------------------------------------------------- 1 | # import trajnetplusplustools 2 | from .tools.reader import Reader 3 | import os 4 | import pickle 5 | 6 | def prepare_data(path, subset='/train/', sample=1.0, goals=True): 7 | """ Prepares the train/val scenes and corresponding goals 8 | 9 | Parameters 10 | ---------- 11 | subset: String ['/train/', '/val/'] 12 | Determines the subset of data to be processed 13 | sample: Float (0.0, 1.0] 14 | Determines the ratio of data to be sampled 15 | goals: Bool 16 | If true, the goals of each track are extracted 17 | The corresponding goal file must be present in the 'goal_files' folder 18 | The name of the goal file must be the same as the name of the training file 19 | 20 | Returns 21 | ------- 22 | all_scenes: List 23 | List of all processed scenes 24 | all_goals: Dictionary 25 | Dictionary of goals corresponding to each dataset file. 26 | None if 'goals' argument is False. 27 | Flag: Bool 28 | True if the corresponding folder exists else False. 29 | """ 30 | 31 | ## Check if folder exists 32 | if not os.path.isdir(path + subset): 33 | if 'train' in subset: 34 | print("Train folder does NOT exist") 35 | exit() 36 | if 'val' in subset: 37 | print("Validation folder does NOT exist") 38 | return None, None, False 39 | 40 | ## read goal files 41 | all_goals = {} 42 | all_scenes = [] 43 | 44 | ## List file names 45 | files = [f.split('.')[-2] for f in os.listdir(path + subset) if f.endswith('.ndjson')] 46 | ## Iterate over file names 47 | for file in files: 48 | reader = Reader(path + subset + file + '.ndjson', scene_type='paths') 49 | ## Necessary modification of train scene to add filename 50 | scene = [(file, s_id, s) for s_id, s in reader.scenes(sample=sample)] 51 | if goals: 52 | goal_dict = pickle.load(open('goal_files/' + subset + file +'.pkl', "rb")) 53 | ## Get goals corresponding to train scene 54 | all_goals[file] = {s_id: [goal_dict[path[0].pedestrian] for path in s] for _, s_id, s in scene} 55 | all_scenes += scene 56 | 57 | if goals: 58 | return all_scenes, all_goals, True 59 | return all_scenes, None, True 60 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/orca_helper.py: -------------------------------------------------------------------------------- 1 | import rvo2 2 | import numpy as np 3 | 4 | def predict_all(input_paths, goals, mode, pred_length): 5 | fps = 100 6 | sampling_rate = fps / 2.5 7 | if mode == 'trajnet': 8 | sim = rvo2.PyRVOSimulator(1/fps, 4, 10, 4, 5, 0.6, 1.5) ## (TrajNet++) 9 | else: 10 | sim = rvo2.PyRVOSimulator(1/fps, 10, 10, 5, 5, 0.3, 1) ## Default 11 | 12 | # initialize 13 | trajectories = [[(p[0], p[1])] for p in input_paths[-1]] 14 | [sim.addAgent((p[0], p[1])) for p in input_paths[-1]] 15 | num_ped = len(trajectories) 16 | 17 | for i in range(num_ped): 18 | velocity = np.array((input_paths[-1][i][0] - input_paths[-3][i][0], input_paths[-1][i][1] - input_paths[-3][i][1])) 19 | velocity = velocity/0.8 20 | sim.setAgentVelocity(i, tuple(velocity.tolist())) 21 | velocity = np.array((goals[i][0] - input_paths[-1][i][0], goals[i][1] - input_paths[-1][i][1])) 22 | speed = np.linalg.norm(velocity) 23 | pref_vel = 1 * velocity / speed if speed > 1 else velocity 24 | sim.setAgentPrefVelocity(i, tuple(pref_vel.tolist())) 25 | 26 | reaching_goal_by_ped = [False] * num_ped 27 | count = 0 28 | end_range = 1.0 29 | done = False 30 | ##Simulate a scene 31 | while count < sampling_rate * pred_length + 1: 32 | count += 1 33 | sim.doStep() 34 | reaching_goal = [] 35 | for i in range(num_ped): 36 | if count == 1: 37 | trajectories[i].pop(0) 38 | position = sim.getAgentPosition(i) 39 | 40 | ## Append only if Goal not reached 41 | if not reaching_goal_by_ped[i]: 42 | if count % sampling_rate == 0: 43 | trajectories[i].append(position) 44 | 45 | # check if this agent reaches the goal 46 | if np.linalg.norm(np.array(position) - np.array(goals[i])) < end_range: 47 | reaching_goal.append(True) 48 | sim.setAgentPrefVelocity(i, (0, 0)) 49 | reaching_goal_by_ped[i] = True 50 | else: 51 | reaching_goal.append(False) 52 | velocity = np.array((goals[i][0] - position[0], goals[i][1] - position[1])) 53 | speed = np.linalg.norm(velocity) 54 | pref_vel = 1 * velocity / speed if speed > 1 else velocity 55 | sim.setAgentPrefVelocity(i, tuple(pref_vel.tolist())) 56 | 57 | # states = np.array(trajectories[0]) 58 | # return states 59 | return trajectories -------------------------------------------------------------------------------- /trajnetplusplusdataset/build/lib/trajnetdataset/orca_helper.py: -------------------------------------------------------------------------------- 1 | import rvo2 2 | import numpy as np 3 | 4 | def predict_all(input_paths, goals, mode, pred_length): 5 | fps = 100 6 | sampling_rate = fps / 2.5 7 | if mode == 'trajnet': 8 | sim = rvo2.PyRVOSimulator(1/fps, 4, 10, 4, 5, 0.6, 1.5) ## (TrajNet++) 9 | else: 10 | sim = rvo2.PyRVOSimulator(1/fps, 10, 10, 5, 5, 0.3, 1) ## Default 11 | 12 | # initialize 13 | trajectories = [[(p[0], p[1])] for p in input_paths[-1]] 14 | [sim.addAgent((p[0], p[1])) for p in input_paths[-1]] 15 | num_ped = len(trajectories) 16 | 17 | for i in range(num_ped): 18 | velocity = np.array((input_paths[-1][i][0] - input_paths[-3][i][0], input_paths[-1][i][1] - input_paths[-3][i][1])) 19 | velocity = velocity/0.8 20 | sim.setAgentVelocity(i, tuple(velocity.tolist())) 21 | velocity = np.array((goals[i][0] - input_paths[-1][i][0], goals[i][1] - input_paths[-1][i][1])) 22 | speed = np.linalg.norm(velocity) 23 | pref_vel = 1 * velocity / speed if speed > 1 else velocity 24 | sim.setAgentPrefVelocity(i, tuple(pref_vel.tolist())) 25 | 26 | reaching_goal_by_ped = [False] * num_ped 27 | count = 0 28 | end_range = 1.0 29 | done = False 30 | ##Simulate a scene 31 | while count < sampling_rate * pred_length + 1: 32 | count += 1 33 | sim.doStep() 34 | reaching_goal = [] 35 | for i in range(num_ped): 36 | if count == 1: 37 | trajectories[i].pop(0) 38 | position = sim.getAgentPosition(i) 39 | 40 | ## Append only if Goal not reached 41 | if not reaching_goal_by_ped[i]: 42 | if count % sampling_rate == 0: 43 | trajectories[i].append(position) 44 | 45 | # check if this agent reaches the goal 46 | if np.linalg.norm(np.array(position) - np.array(goals[i])) < end_range: 47 | reaching_goal.append(True) 48 | sim.setAgentPrefVelocity(i, (0, 0)) 49 | reaching_goal_by_ped[i] = True 50 | else: 51 | reaching_goal.append(False) 52 | velocity = np.array((goals[i][0] - position[0], goals[i][1] - position[1])) 53 | speed = np.linalg.norm(velocity) 54 | pref_vel = 1 * velocity / speed if speed > 1 else velocity 55 | sim.setAgentPrefVelocity(i, tuple(pref_vel.tolist())) 56 | 57 | # states = np.array(trajectories[0]) 58 | # return states 59 | return trajectories -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/loss.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | class L2Loss(torch.nn.Module): 4 | """L2 Loss (deterministic version of PredictionLoss) 5 | 6 | This Loss penalizes only the primary trajectories 7 | """ 8 | def __init__(self, keep_batch_dim=False): 9 | super(L2Loss, self).__init__() 10 | self.loss = torch.nn.MSELoss(reduction='none') 11 | self.keep_batch_dim = keep_batch_dim 12 | self.loss_multiplier = 100 13 | 14 | def col_loss(self, primary, neighbours, batch_split, gamma=2.0): 15 | """ 16 | Penalizes model when primary pedestrian prediction comes close 17 | to the neighbour predictions 18 | primary: Tensor [pred_length, 1, 2] 19 | neighbours: Tensor [pred_length, num_neighbours, 2] 20 | """ 21 | 22 | neighbours[neighbours != neighbours] = -1000 23 | exponential_loss = 0.0 24 | for (start, end) in zip(batch_split[:-1], batch_split[1:]): 25 | batch_primary = primary[:, start:start+1] 26 | batch_neigh = neighbours[:, start:end] 27 | distance_to_neigh = torch.norm(batch_neigh - batch_primary, dim=2) 28 | mask_far = (distance_to_neigh < 0.25).detach() 29 | distance_to_neigh = -gamma * distance_to_neigh * mask_far 30 | exponential_loss += distance_to_neigh.exp().sum() 31 | return exponential_loss.sum() 32 | 33 | def forward(self, inputs, targets, batch_split): 34 | ## Extract primary pedestrians 35 | targets = targets.transpose(0, 1) 36 | targets = targets[batch_split[:-1]] 37 | targets = targets.transpose(0, 1) 38 | inputs = inputs.transpose(0, 1) 39 | inputs = inputs[batch_split[:-1]] 40 | inputs = inputs.transpose(0, 1) 41 | 42 | mask_gt = ~torch.isnan(targets[:,:,0]) 43 | mask_pred = ~torch.isnan(inputs[:,:,0]) 44 | mask = mask_pred*mask_gt 45 | 46 | loss_vis = self.loss(inputs[mask], targets[mask]) 47 | if inputs[~mask].size(0) == 0: 48 | loss = loss_vis 49 | else: 50 | loss_invis = self.loss(inputs[~mask][:,-1], targets[~mask][:,-1]) 51 | loss_invis = torch.cat((loss_invis.unsqueeze(1),torch.zeros(loss_invis.size(0),2).to(loss_invis.device)),dim=1) 52 | loss = torch.cat((loss_vis, loss_invis),dim=0) 53 | 54 | ## Used in variety loss (SGAN) 55 | if self.keep_batch_dim: 56 | return loss.mean(dim=0).mean(dim=1) * self.loss_multiplier 57 | 58 | return torch.mean(loss) * self.loss_multiplier 59 | 60 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/kalman.py: -------------------------------------------------------------------------------- 1 | """ Kalman filter Prediction """ 2 | 3 | import numpy as np 4 | import pykalman 5 | from .data import TrackRow 6 | 7 | def predict(paths, obs_len, pred_len, predict_all=False): 8 | multimodal_outputs = {} 9 | neighbours_tracks = [] 10 | 11 | ## Single Prediction 12 | if not predict_all: 13 | paths = paths[0:1] 14 | 15 | for i, path in enumerate(paths): 16 | path = paths[i] 17 | initial_state_mean = [path[0].x, 0, path[0].y, 0] 18 | 19 | transition_matrix = [[1, 1, 0, 0], 20 | [0, 1, 0, 0], 21 | [0, 0, 1, 1], 22 | [0, 0, 0, 1]] 23 | 24 | observation_matrix = [[1, 0, 0, 0], 25 | [0, 0, 1, 0]] 26 | 27 | kf = pykalman.KalmanFilter(transition_matrices=transition_matrix, 28 | observation_matrices=observation_matrix, 29 | transition_covariance=1e-5 * np.eye(4), 30 | observation_covariance=0.05**2 * np.eye(2), 31 | initial_state_mean=initial_state_mean) 32 | # kf.em([(r.x, r.y) for r in path[:9]], em_vars=['transition_matrices', 33 | # 'observation_matrices']) 34 | 35 | kf.em([(r.x, r.y) for r in path[:obs_len]]) 36 | observed_states, _ = kf.smooth([(r.x, r.y) for r in path[:obs_len]]) 37 | 38 | # prepare predictions 39 | frame_diff = path[1].frame - path[0].frame 40 | first_frame = path[obs_len - 1].frame + frame_diff 41 | ped_id = path[obs_len - 1].pedestrian 42 | 43 | # sample predictions (first sample corresponds to last state) 44 | # average 5 sampled predictions 45 | predictions = None 46 | for _ in range(5): 47 | _, pred = kf.sample(pred_len + 1, initial_state=observed_states[-1]) 48 | if predictions is None: 49 | predictions = pred 50 | else: 51 | predictions += pred 52 | predictions /= 5.0 53 | if i == 0: 54 | primary_track = [TrackRow(first_frame + j * frame_diff, ped_id, x, y) 55 | for j, (x, y) in enumerate(predictions[1:])] 56 | else: 57 | neighbours_tracks.append([TrackRow(first_frame + j * frame_diff, ped_id, x, y) 58 | for j, (x, y) in enumerate(predictions[1:])]) 59 | multimodal_outputs[0] = primary_track, neighbours_tracks 60 | return multimodal_outputs 61 | -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/augmentation.py: -------------------------------------------------------------------------------- 1 | import math 2 | import random 3 | 4 | import numpy 5 | import trajnetplusplustools 6 | 7 | 8 | def rotate_path(path, theta): 9 | ct = math.cos(theta) 10 | st = math.sin(theta) 11 | 12 | return [trajnetplusplustools.TrackRow(r.frame, r.pedestrian, ct * r.x + st * r.y, -st * r.x + ct * r.y) 13 | for r in path] 14 | 15 | 16 | def random_rotation_of_paths(paths): 17 | theta = random.random() * 2.0 * math.pi 18 | return [rotate_path(path, theta) for path in paths] 19 | 20 | 21 | def random_rotation(xy): 22 | theta = random.random() * 2.0 * math.pi 23 | ct = math.cos(theta) 24 | st = math.sin(theta) 25 | 26 | r = numpy.array([[ct, st], [-st, ct]]) 27 | return numpy.einsum('ptc,ci->pti', xy, r) 28 | 29 | 30 | def rotate_path(path, theta): 31 | ct = math.cos(theta) 32 | st = math.sin(theta) 33 | 34 | return [trajnetplusplustools.TrackRow(r.frame, r.pedestrian, ct * r.x + st * r.y, -st * r.x + ct * r.y) 35 | for r in path] 36 | 37 | 38 | def theta_rotation(xy, theta): 39 | # theta = random.random() * 2.0 * math.pi 40 | ct = math.cos(theta) 41 | st = math.sin(theta) 42 | 43 | r = numpy.array([[ct, st], [-st, ct]]) 44 | return numpy.einsum('ptc,ci->pti', xy, r) 45 | 46 | def shift(xy, center): 47 | # theta = random.random() * 2.0 * math.pi 48 | xy = xy - center[numpy.newaxis, numpy.newaxis, :] 49 | return xy 50 | 51 | def center_scene(xy, obs_length=9, ped_id=0): 52 | ## Center 53 | center = xy[obs_length-1, ped_id] ## Last Observation 54 | xy = shift(xy, center) 55 | ## Rotate 56 | last_obs = xy[obs_length-1, ped_id] 57 | second_last_obs = xy[obs_length-2, ped_id] 58 | diff = numpy.array([last_obs[0] - second_last_obs[0], last_obs[1] - second_last_obs[1]]) 59 | thet = numpy.arctan2(diff[1], diff[0]) 60 | rotation = -thet + numpy.pi/2 61 | xy = theta_rotation(xy, rotation) 62 | return xy, rotation, center 63 | 64 | 65 | def inverse_scene(xy, rotation, center): 66 | xy = theta_rotation(xy, -rotation) 67 | xy = shift(xy, -center) 68 | return xy 69 | 70 | def drop_unobserved(xy, obs_length=9): 71 | loc_at_obs = xy[obs_length-1] 72 | absent_at_obs = numpy.isnan(loc_at_obs).any(axis=1) 73 | mask = ~absent_at_obs 74 | return xy[:, mask], mask 75 | 76 | def neigh_nan(xy): 77 | return numpy.isnan(xy).all() 78 | 79 | def add_noise(observation, thresh=0.005, obs_length=9, ped='primary'): 80 | if ped=='primary': 81 | observation[:obs_length, 0] += numpy.random.uniform(-thresh, thresh, observation[:obs_length, 0].shape) 82 | elif ped=='neigh': 83 | observation[:obs_length, 1:] += numpy.random.uniform(-thresh, thresh, observation[:obs_length, 1:].shape) 84 | else: 85 | raise ValueError 86 | 87 | return observation -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/more_non_gridbased_pooling.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | class NMMP(torch.nn.Module): 4 | """ Interaction vector is obtained by message passing between 5 | hidden-state of all neighbours. Proposed in NMMP, CVPR 2020 6 | Parameters: 7 | mlp_dim: embedding size of hidden-state 8 | k: number of iterations of message passing 9 | out_dim: dimension of resultant interaction vector 10 | 11 | Attributes 12 | ---------- 13 | mlp_dim : Scalar 14 | Embedding dimension of hidden-state of LSTM 15 | k : Scalar 16 | Number of iterations of message passing 17 | out_dim: Scalar 18 | Dimension of resultant interaction vector 19 | """ 20 | def __init__(self, hidden_dim=128, mlp_dim=32, k=5, out_dim=None): 21 | super(NMMP, self).__init__() 22 | self.out_dim = out_dim or hidden_dim 23 | 24 | self.hidden_embedding = torch.nn.Sequential( 25 | torch.nn.Linear(hidden_dim, mlp_dim), 26 | torch.nn.ReLU(), 27 | ) 28 | 29 | self.mlp_dim = mlp_dim 30 | self.node_to_edge_embedding = torch.nn.Linear(2*mlp_dim, mlp_dim) 31 | self.edge_to_node_embedding = torch.nn.Linear(2*mlp_dim, mlp_dim) 32 | 33 | self.out_projection = torch.nn.Linear(mlp_dim, self.out_dim) 34 | self.k = k 35 | 36 | def message_pass(self, node_embeddings): 37 | # Perform a single iteration of message passing 38 | n = node_embeddings.size(0) 39 | arrange1 = node_embeddings.repeat(n, 1, 1) ## c 40 | arrange2 = arrange1.transpose(0, 1) ## d 41 | 42 | ## e_out 43 | e_out_all = torch.cat([arrange2, arrange1], dim=2) 44 | e_out_neighbours = e_out_all[~torch.eye(n).bool()].reshape(n, n-1, 2*self.mlp_dim) 45 | e_out_edges = self.node_to_edge_embedding(e_out_neighbours) 46 | e_out_sumpool = torch.mean(e_out_edges, dim=1) 47 | 48 | ## e_in 49 | e_in_all = torch.cat([arrange1, arrange2], dim=2) 50 | e_in_neighbours = e_in_all[~torch.eye(n).bool()].reshape(n, n-1, 2*self.mlp_dim) 51 | e_in_edges = self.node_to_edge_embedding(e_in_neighbours) 52 | e_in_sumpool = torch.mean(e_in_edges, dim=1) 53 | 54 | ## [e_in; e_out] 55 | concat_nodes = torch.cat([e_in_sumpool, e_out_sumpool], dim=1) 56 | 57 | ## refined node 58 | refined_embeddings = self.edge_to_node_embedding(concat_nodes) 59 | return refined_embeddings 60 | 61 | def reset(self, _, device): 62 | self.track_mask = None 63 | 64 | def forward(self, hidden_states, _, obs2): 65 | 66 | ## If only primary present 67 | num_tracks = obs2.size(0) 68 | if num_tracks == 1: 69 | return torch.zeros(1, self.out_dim, device=obs2.device) 70 | 71 | ## Embed hidden-state 72 | node_embeddings = self.hidden_embedding(hidden_states) 73 | ## Iterative Message Passing 74 | for _ in range(self.k): 75 | node_embeddings = self.message_pass(node_embeddings) 76 | 77 | return self.out_projection(node_embeddings) 78 | -------------------------------------------------------------------------------- /jrdb_baselines/create_validation.py: -------------------------------------------------------------------------------- 1 | import random 2 | import argparse 3 | import os 4 | import shutil 5 | 6 | random.seed() 7 | 8 | def main(): 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument('--path', default='trajdata', 11 | help='glob expression for data files') 12 | parser.add_argument('--val_ratio', default=0.2, type=float, 13 | help='sample ratio of val set given the train set') 14 | args = parser.parse_args() 15 | 16 | args.path = 'DATA_BLOCK/' + args.path 17 | 18 | ## Prepare destination folder containing dataset with train and val split 19 | args.dest_path = args.path + '_split' 20 | 21 | if not os.path.exists(args.dest_path): 22 | os.makedirs(args.dest_path) 23 | 24 | if not os.path.exists('{}/train/'.format(args.dest_path)): 25 | os.makedirs('{}/train/'.format(args.dest_path)) 26 | 27 | if not os.path.exists('{}/val/'.format(args.dest_path)): 28 | os.makedirs('{}/val/'.format(args.dest_path)) 29 | 30 | ## List train file names 31 | files = [f.split('.')[-2] for f in os.listdir(args.path + '/train/') if f.endswith('.ndjson')] 32 | print(files) 33 | # exit() 34 | 35 | for file in files: 36 | ## Read All Samples 37 | orig_train_file = args.path + '/train/' + file + '.ndjson' 38 | with open(orig_train_file, "r") as f: 39 | lines = f.readlines() 40 | 41 | ## Split scenes into train and val 42 | train_file = open(args.dest_path + '/train/' + file + ".ndjson", "w") 43 | val_file = open(args.dest_path + '/val/' + file + ".ndjson", "w") 44 | for line in lines: 45 | ## Sample Scenes 46 | if 'scene' in line: 47 | if random.random() < args.val_ratio: 48 | val_file.write(line) 49 | else: 50 | train_file.write(line) 51 | continue 52 | ## Write All tracks 53 | train_file.write(line) 54 | val_file.write(line) 55 | 56 | train_file.close() 57 | val_file.close() 58 | 59 | # ## Assert val folder does not exist 60 | # if os.path.isdir(args.path + '/val'): 61 | # print("Validation folder already exists") 62 | # exit() 63 | 64 | if __name__ == '__main__': 65 | main() 66 | 67 | # ## Iterate over file names 68 | # for file in files: 69 | # with open("DATA_BLOCK/honda/test/honda_v1.ndjson", "r") as f 70 | # reader = trajnetplusplustools.Reader(path + '/train/' + file + '.ndjson', scene_type='paths') 71 | # ## Necessary modification of train scene to add filename 72 | # scene = [(file, s_id, s) for s_id, s in reader.scenes()] 73 | # all_scenes += scene 74 | 75 | # with open("test_dummy1.ndjson", "w") as f: 76 | # for line in lines: 77 | # if 'scene' in line and random.random() < 0.8: 78 | # continue 79 | # f.write(line) 80 | 81 | 82 | # ## read goal files 83 | # all_goals = {} 84 | # all_scenes = [] 85 | 86 | # ## List file names 87 | # files = [f.split('.')[-2] for f in os.listdir(path + subset) if f.endswith('.ndjson')] 88 | # ## Iterate over file names 89 | # for file in files: 90 | # reader = trajnetplusplustools.Reader(path + subset + file + '.ndjson', scene_type='paths') 91 | # ## Necessary modification of train scene to add filename 92 | # scene = [(file, s_id, s) for s_id, s in reader.scenes(sample=sample)] 93 | # if goals: 94 | # goal_dict = pickle.load(open('goal_files/' + subset + file +'.pkl', "rb")) 95 | # ## Get goals corresponding to train scene 96 | # all_goals[file] = {s_id: [goal_dict[path[0].pedestrian] for path in s] for _, s_id, s in scene} 97 | # all_scenes += scene 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /jrdb_baselines/evaluator/write_utils.py: -------------------------------------------------------------------------------- 1 | # import pickle 2 | # import numpy as np 3 | import json 4 | import pickle 5 | import numpy as np 6 | import sys, os 7 | currentdir = os.path.dirname(os.path.realpath(__file__)) 8 | parentdir = os.path.dirname(currentdir) 9 | sys.path.append(parentdir) 10 | 11 | from trajnetbaselines.lstm.tools.reader import Reader 12 | 13 | def load_test_datasets(dataset, goal_flag, args): 14 | """Load Test Prediction file with goals (optional)""" 15 | all_goals = {} 16 | dataset_name = dataset.replace(args.path.replace('_pred', '') + 'test/', '') + '.ndjson' 17 | print('Dataset Name: ', dataset_name) 18 | 19 | # Read Scenes from 'test' folder 20 | reader = Reader(args.path.replace('_pred', '') + dataset + '.ndjson', scene_type='paths') 21 | ## Necessary modification of train scene to add filename (for goals) 22 | scenes = [(dataset, s_id, s) for s_id, s in reader.scenes()] 23 | 24 | if goal_flag: 25 | print("Loading Goal File: ", 'goal_files/test_private/' + dataset +'.pkl') 26 | goal_dict = pickle.load(open('goal_files/test_private/' + dataset +'.pkl', "rb")) 27 | all_goals[dataset] = {s_id: [goal_dict[path[0].pedestrian] for path in s] for _, s_id, s in scenes} 28 | scene_goals = [np.array(all_goals[filename][scene_id]) for filename, scene_id, _ in scenes] 29 | else: 30 | scene_goals = [np.zeros((len(paths), 2)) for _, scene_id, paths in scenes] 31 | 32 | return dataset_name, scenes, scene_goals 33 | 34 | 35 | def preprocess_test(scene, obs_len): 36 | """Remove pedestrian trajectories that appear post observation period. 37 | Can occur when the test set has overlapping scenes.""" 38 | obs_frames = [primary_row.frame for primary_row in scene[0]][:obs_len] 39 | last_obs_frame = obs_frames[-1] 40 | scene = [[row for row in ped if row.frame <= last_obs_frame] 41 | for ped in scene if ped[0].frame <= last_obs_frame] 42 | 43 | return scene 44 | 45 | 46 | def write_predictions(pred_list, scenes, model_name, dataset_name, dataset_index, args): 47 | """Write predictions corresponding to the scenes in the respective file""" 48 | dataset_name = dataset_name.replace('.ndjson','_temp.txt') 49 | 50 | path_temp = args.path+model_name+'/'+'temp/'+dataset_name 51 | path_pred = args.path+model_name+'/'+'jrdb_submission/' 52 | 53 | with open(path_temp, "a") as myfile: 54 | ## Write All Predictions 55 | for (predictions, (_, scene_id, paths)) in zip(pred_list, scenes): 56 | ## Extract 1) first_frame, 2) frame_diff 3) ped_ids for writing predictions 57 | observed_path = paths[0] 58 | frame_diff = observed_path[1].frame - observed_path[0].frame 59 | first_frame = observed_path[args.obs_length-1].frame + frame_diff 60 | ped_id = observed_path[0].pedestrian 61 | 62 | for m in range(len(predictions)): 63 | prediction, _ = predictions[m] 64 | ## Write Primary 65 | for i in range(len(prediction)): 66 | 67 | data = [first_frame + i * frame_diff, ped_id,prediction[i, 0].item(), prediction[i, 1].item(), prediction[i,2].item()] 68 | for d in data: 69 | myfile.write(str(d)) 70 | myfile.write(' ') 71 | myfile.write('\n') 72 | 73 | txt_name = path_temp 74 | 75 | trajs = np.loadtxt(txt_name, dtype=str) 76 | trajs = np.array(trajs).astype(float) 77 | with open(path_pred+ str(dataset_index).zfill(4)+'.txt', 'a') as txtfile: 78 | for pred_id in range(12): 79 | for row_id in range(trajs.shape[0]): 80 | if trajs[row_id,0] == trajs[pred_id,0]: 81 | 82 | data_final = [int(trajs[row_id,0]),int(trajs[row_id,1]), 'Pedestrian', 0, 0, -1 ,-1, -1, -1, -1, trajs[row_id,2], trajs[row_id,3]] 83 | 84 | for d_final in data_final: 85 | txtfile.write(str(d_final)) 86 | txtfile.write(' ') 87 | txtfile.write('\n') 88 | 89 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/metrics.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import numpy as np 3 | from scipy.stats import gaussian_kde 4 | 5 | def final_l2(path1, path2): 6 | row1 = path1[-1] 7 | row2 = path2[-1] 8 | return np.linalg.norm((row2.x - row1.x, row2.y - row1.y)) 9 | 10 | 11 | def average_l2(path1, path2, n_predictions=12): 12 | assert len(path1) >= n_predictions 13 | assert len(path2) >= n_predictions 14 | path1 = path1[-n_predictions:] 15 | path2 = path2[-n_predictions:] 16 | 17 | return sum(np.linalg.norm((r1.x - r2.x, r1.y - r2.y)) 18 | for r1, r2 in zip(path1, path2)) / n_predictions 19 | 20 | 21 | def collision(path1, path2, n_predictions=12, person_radius=0.1, inter_parts=2): 22 | """Check if there is collision or not""" 23 | 24 | assert len(path1) >= n_predictions 25 | path1 = path1[-n_predictions:] 26 | frames1 = set(f1.frame for f1 in path1) 27 | frames2 = set(f2.frame for f2 in path2) 28 | common_frames = frames1.intersection(frames2) 29 | 30 | # If there is no interaction, there is no collision 31 | if not common_frames: 32 | return False 33 | 34 | path1 = [path1[i] for i in range(len(path1)) if path1[i].frame in common_frames] 35 | path2 = [path2[i] for i in range(len(path2)) if path2[i].frame in common_frames] 36 | 37 | def getinsidepoints(p1, p2, parts=2): 38 | """return: equally distanced points between starting and ending "control" points""" 39 | 40 | return np.array((np.linspace(p1[0], p2[0], parts + 1), 41 | np.linspace(p1[1], p2[1], parts + 1))) 42 | 43 | for i in range(len(path1) - 1): 44 | p1, p2 = [path1[i].x, path1[i].y], [path1[i + 1].x, path1[i + 1].y] 45 | p3, p4 = [path2[i].x, path2[i].y], [path2[i + 1].x, path2[i + 1].y] 46 | if np.min(np.linalg.norm(getinsidepoints(p1, p2, inter_parts) - getinsidepoints(p3, p4, inter_parts), axis=0)) \ 47 | <= 2 * person_radius: 48 | return True 49 | 50 | return False 51 | 52 | def topk(primary_tracks, ground_truth, n_predictions=12, k_samples=3): 53 | ## TopK multimodal 54 | ## The Prediction closest to the GT in terms of ADE is considered 55 | 56 | l2 = 1e10 57 | ## preds: Pred_len x Num_preds x 2 58 | for pred_num in range(k_samples): 59 | primary_prediction = [t for t in primary_tracks if t.prediction_number == pred_num] 60 | tmp_score = average_l2(ground_truth, primary_prediction, n_predictions=n_predictions) 61 | if tmp_score < l2: 62 | l2 = tmp_score 63 | topk_ade = tmp_score 64 | topk_fde = final_l2(ground_truth, primary_prediction) 65 | 66 | return topk_ade, topk_fde 67 | 68 | def nll(primary_tracks, ground_truth, n_predictions=12, log_pdf_lower_bound=-20, n_samples=100): 69 | """ 70 | Inspired from https://github.com/StanfordASL/Trajectron. 71 | """ 72 | 73 | gt = np.array([[t.x, t.y] for t in ground_truth][-n_predictions:]) 74 | frame_gt = [t.frame for t in ground_truth][-n_predictions:] 75 | preds = np.array([[[t.x, t.y] for t in primary_tracks if t.frame == frame] for frame in frame_gt]) 76 | ## preds: Pred_len x Num_preds x 2 77 | 78 | ## To verify atleast n_samples predictions 79 | if preds.shape[1] < n_samples: 80 | raise Exception('Need {} predictions'.format(n_samples)) 81 | preds = preds[:, :n_samples] 82 | 83 | pred_len = len(frame_gt) 84 | 85 | ll = 0.0 86 | same_pred = 0 87 | for timestep in range(pred_len): 88 | curr_gt = gt[timestep] 89 | ## If identical prediction at particular time-step, skip 90 | if np.all(preds[timestep][1:] == preds[timestep][:-1]): 91 | same_pred += 1 92 | continue 93 | try: 94 | scipy_kde = gaussian_kde(preds[timestep].T) 95 | # We need [0] because it's a (1,)-shaped numpy array. 96 | log_pdf = np.clip(scipy_kde.logpdf(curr_gt.T), a_min=log_pdf_lower_bound, a_max=None)[0] 97 | if np.isnan(log_pdf) or np.isinf(log_pdf) or log_pdf > 100: ## Difficulties in computing Gaussian_KDE 98 | same_pred += 1 99 | continue 100 | ll += log_pdf 101 | except: ## Difficulties in computing Gaussian_KDE 102 | same_pred += 1 103 | 104 | if same_pred == pred_len: 105 | raise Exception('All Predictions are Identical') 106 | 107 | ll = ll / (pred_len - same_pred) 108 | return ll 109 | -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/tools/reader.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | import itertools 3 | import json 4 | import random 5 | 6 | import numpy as np 7 | 8 | from .data import SceneRow, TrackRow 9 | 10 | 11 | class Reader(object): 12 | """Read trajnet files. 13 | 14 | :param scene_type: None -> numpy.array, 'rows' -> TrackRow and SceneRow, 'paths': grouped rows (primary pedestrian first), 'tags': numpy.array and scene tag 15 | :param image_file: Associated image file of the scene 16 | """ 17 | def __init__(self, input_file, scene_type=None, image_file=None): 18 | if scene_type is not None and scene_type not in {'rows', 'paths', 'tags'}: 19 | raise Exception('scene_type not supported') 20 | self.scene_type = scene_type 21 | 22 | self.tracks_by_frame = defaultdict(list) 23 | self.scenes_by_id = dict() 24 | 25 | self.read_file(input_file) 26 | 27 | def read_file(self, input_file): 28 | with open(input_file, 'r') as f: 29 | for line in f: 30 | line = json.loads(line) 31 | 32 | track = line.get('track') 33 | if track is not None: 34 | row = TrackRow(track['f'], track['p'], track['x'], track['y'], track['v'],\ 35 | track.get('prediction_number'), track.get('scene_id')) 36 | self.tracks_by_frame[row.frame].append(row) 37 | continue 38 | 39 | scene = line.get('scene') 40 | if scene is not None: 41 | row = SceneRow(scene['id'], scene['p'], scene['s'], scene['e'], \ 42 | scene.get('fps'), scene.get('tag')) 43 | self.scenes_by_id[row.scene] = row 44 | 45 | def scenes(self, randomize=False, limit=0, ids=None, sample=None): 46 | scene_ids = self.scenes_by_id.keys() 47 | if ids is not None: 48 | scene_ids = ids 49 | if randomize: 50 | scene_ids = list(scene_ids) 51 | random.shuffle(scene_ids) 52 | if limit: 53 | scene_ids = itertools.islice(scene_ids, limit) 54 | if sample is not None: 55 | scene_ids = random.sample(scene_ids, int(len(scene_ids) * sample)) 56 | for scene_id in scene_ids: 57 | yield self.scene(scene_id) 58 | 59 | @staticmethod 60 | def track_rows_to_paths(primary_pedestrian, track_rows): 61 | primary_path = [] 62 | other_paths = defaultdict(list) 63 | for row in track_rows: 64 | if row.pedestrian == primary_pedestrian: 65 | primary_path.append(row) 66 | continue 67 | other_paths[row.pedestrian].append(row) 68 | 69 | return [primary_path] + list(other_paths.values()) 70 | 71 | @staticmethod 72 | def paths_to_xy(paths): 73 | """Convert paths to numpy array with nan as blanks.""" 74 | frames = set(r.frame for r in paths[0]) 75 | pedestrians = set(row.pedestrian 76 | for path in paths 77 | for row in path if row.frame in frames) 78 | paths = [path for path in paths if path[0].pedestrian in pedestrians] 79 | frames = sorted(frames) 80 | pedestrians = list(pedestrians) 81 | 82 | frame_to_index = {frame: i for i, frame in enumerate(frames)} 83 | xy = np.full((len(frames), len(pedestrians), 3), np.nan) 84 | 85 | for ped_index, path in enumerate(paths): 86 | for row in path: 87 | if row.frame not in frame_to_index: 88 | continue 89 | entry = xy[frame_to_index[row.frame]][ped_index] 90 | entry[0] = row.x 91 | entry[1] = row.y 92 | entry[2] = row.v 93 | 94 | return xy 95 | 96 | def scene(self, scene_id): 97 | scene = self.scenes_by_id.get(scene_id) 98 | if scene is None: 99 | raise Exception('scene with that id not found') 100 | 101 | frames = range(scene.start, scene.end + 1) 102 | track_rows = [r 103 | for frame in frames 104 | for r in self.tracks_by_frame.get(frame, [])] 105 | 106 | # return as rows 107 | if self.scene_type == 'rows': 108 | return scene_id, scene.pedestrian, track_rows 109 | 110 | # return as paths 111 | paths = self.track_rows_to_paths(scene.pedestrian, track_rows) 112 | if self.scene_type == 'paths': 113 | return scene_id, paths 114 | 115 | ## return with scene tag 116 | if self.scene_type == 'tags': 117 | return scene_id, scene.tag, self.paths_to_xy(paths) 118 | 119 | # return a numpy array 120 | return scene_id, self.paths_to_xy(paths) 121 | -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/trajnet_evaluator.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | import pickle 4 | 5 | from joblib import Parallel, delayed 6 | import scipy 7 | import torch 8 | from tqdm import tqdm 9 | 10 | from evaluator.write_utils import load_test_datasets, write_predictions 11 | from .lstm import LSTMPredictor 12 | 13 | def predict_scene(predictor, model_name, paths, scene_goal, args): 14 | """For each scene, get model predictions""" 15 | 16 | predictions = predictor(paths, n_predict=args.pred_length, obs_length=args.obs_length, modes=args.modes, args=args) 17 | return predictions 18 | 19 | 20 | def load_predictor(model, device='cpu'): 21 | """Loading the APPROPRIATE model""" 22 | predictor = LSTMPredictor.load(model) 23 | predictor.model.to(torch.device(device)) 24 | return predictor 25 | 26 | 27 | def get_predictions(args): 28 | """Get model predictions for each test scene and write the predictions in appropriate folders""" 29 | ## List of .json file inside the args.path (waiting to be predicted by the testing model) 30 | datasets = sorted([f.split('.')[-2] for f in os.listdir(args.path.replace('_pred', '')) if not f.startswith('.') and f.endswith('.ndjson')]) 31 | 32 | ## Extract Model names from arguments and create its own folder in 'test_pred' for storing predictions 33 | ## WARNING: If Model predictions already exist from previous run, this process SKIPS WRITING 34 | for model in args.output: 35 | model_name = model.split('/')[-1].replace('.pkl', '') 36 | model_name = model_name + '_modes' + str(args.modes) 37 | 38 | ## Check if model predictions already exist 39 | if not os.path.exists(args.path): 40 | os.makedirs(args.path) 41 | if not os.path.exists(args.path + model_name): 42 | os.makedirs(args.path + model_name) 43 | if not os.path.exists(args.path + model_name+'/temp'): 44 | os.makedirs(args.path + model_name+'/temp') 45 | if not os.path.exists(args.path + model_name+'/jrdb_submission'): 46 | os.makedirs(args.path + model_name+'/jrdb_submission') 47 | else: 48 | print('Predictions corresponding to {} already exist.'.format(model_name)) 49 | print('Delete the existing {} under test_pred/.'.format(model_name)) 50 | continue 51 | 52 | print("Model Name: ", model_name) 53 | predictor = load_predictor(model) 54 | goal_flag = predictor.model.goal_flag 55 | 56 | # Iterate over test datasets 57 | dataset_index = 0 58 | 59 | for dataset in datasets: 60 | # Load dataset 61 | dataset_name, scenes, scene_goals = load_test_datasets(dataset, goal_flag, args) 62 | scenes = tqdm(scenes) 63 | 64 | pred_list = Parallel(n_jobs=12)(delayed(predict_scene)(predictor, model_name, paths, scene_goal, args) 65 | for (_, _, paths), scene_goal in zip(scenes, scene_goals)) 66 | 67 | # Write all predictions 68 | write_predictions(pred_list, scenes, model_name, dataset_name, dataset_index,args) 69 | dataset_index+=1 70 | 71 | 72 | def main(): 73 | parser = argparse.ArgumentParser() 74 | parser.add_argument('--path', default='trajdata', 75 | help='directory of data to test') 76 | parser.add_argument('--output', nargs='+', 77 | help='relative path to saved model') 78 | parser.add_argument('--obs_length', default=9, type=int, 79 | help='observation length') 80 | parser.add_argument('--pred_length', default=12, type=int, 81 | help='prediction length') 82 | parser.add_argument('--write_only', action='store_true', 83 | help='disable writing new files') 84 | parser.add_argument('--disable-collision', action='store_true', 85 | help='disable collision metrics') 86 | parser.add_argument('--labels', required=False, nargs='+', 87 | help='labels of models') 88 | parser.add_argument('--normalize_scene', action='store_true', 89 | help='augment scenes') 90 | parser.add_argument('--modes', default=1, type=int, 91 | help='number of modes to predict') 92 | parser.add_argument('--output_name', default='Results.png', 93 | help='name of outputed evaluation results') 94 | args = parser.parse_args() 95 | 96 | scipy.seterr('ignore') 97 | 98 | args.output = args.output if args.output is not None else [] 99 | args.path = 'DATA_BLOCK/' + args.path + '/test_pred/' 100 | 101 | ## Does NOT overwrite existing predictions if they already exist ## 102 | get_predictions(args) 103 | if args.write_only: # For submission to AICrowd. 104 | print("Predictions written in test_pred folder") 105 | exit() 106 | 107 | 108 | 109 | 110 | if __name__ == '__main__': 111 | main() 112 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/build/lib/trajnetdataset/scene.py: -------------------------------------------------------------------------------- 1 | """ Preparng Scenes for TrajNet """ 2 | import os 3 | from collections import defaultdict 4 | 5 | import trajnetplusplustools 6 | from trajnetplusplustools import SceneRow 7 | 8 | 9 | class Scenes(object): 10 | def __init__(self, fps, start_scene_id=0, args=None): 11 | self.scene_id = start_scene_id 12 | self.chunk_size = args.obs_len + args.pred_len 13 | self.chunk_stride = args.chunk_stride 14 | self.obs_len = args.obs_len 15 | self.visible_chunk = None 16 | self.frames = set() 17 | self.fps = fps 18 | self.min_length = args.min_length 19 | 20 | @staticmethod 21 | def euclidean_distance_2(row1, row2): 22 | """Euclidean distance squared between two rows.""" 23 | return (row1.x - row2.x)**2 + (row1.y - row2.y)**2 24 | 25 | @staticmethod 26 | def close_pedestrians(rows, cell_size=10): 27 | """Fast computation of spatially close pedestrians. 28 | 29 | By frame, get the list of pedestrian ids that or close to other 30 | pedestrians. Approximate with multi-occupancy of discrete grid cells. 31 | """ 32 | sparse_occupancy = defaultdict(list) 33 | for row in rows: 34 | x = int(row.x // cell_size * cell_size) 35 | y = int(row.y // cell_size * cell_size) 36 | sparse_occupancy[(x, y)].append(row.pedestrian) 37 | return {ped_id 38 | for cell in sparse_occupancy.values() if len(cell) > 1 39 | for ped_id in cell} 40 | 41 | @staticmethod 42 | def continuous_frames(frames, tolerance=1.5): 43 | increments = [f2 - f1 for f1, f2 in zip(frames[:-1], frames[1:])] 44 | median_increment = sorted(increments)[int(len(increments) / 2)] 45 | ok = median_increment * tolerance > max(increments) 46 | 47 | # if not ok: 48 | # print('!!!!!!!!! DETECTED GAP IN FRAMES') 49 | # print(increments) 50 | 51 | return ok 52 | 53 | def from_rows(self, rows): 54 | count_by_frame = rows.groupBy(lambda r: r.frame).mapValues(len).collectAsMap() 55 | occupancy_by_frame = (rows 56 | .groupBy(lambda r: r.frame) 57 | .mapValues(self.close_pedestrians) 58 | .collectAsMap()) 59 | 60 | def to_scene_row(ped_frames): 61 | ped_id, scene_frames = ped_frames 62 | row = SceneRow(self.scene_id, ped_id, scene_frames[0], scene_frames[-1], self.fps, 0) 63 | self.scene_id += 1 64 | return row 65 | 66 | # scenes: pedestrian of interest, [frames] 67 | scenes = ( 68 | rows 69 | .groupBy(lambda r: r.pedestrian) 70 | .filter(lambda p_path: len(p_path[1]) >= self.chunk_size) 71 | .mapValues(lambda path: sorted(path, key=lambda p: p.frame)) 72 | .flatMapValues(lambda path: [ 73 | [path[ii].frame for ii in range(i, i + self.chunk_size)] 74 | for i in range(0, len(path) - self.chunk_size + 1, self.chunk_stride) 75 | # filter for pedestrians moving by more than min_length meter 76 | if self.euclidean_distance_2(path[i], path[i+self.chunk_size-1]) > self.min_length 77 | ]) 78 | 79 | # filter out scenes with large gaps in frame numbers 80 | .filter(lambda ped_frames: self.continuous_frames(ped_frames[1])) 81 | 82 | # filter for scenes that have some activity 83 | .filter(lambda ped_frames: 84 | sum(count_by_frame[f] for f in ped_frames[1]) >= 2.0 * self.chunk_size) 85 | 86 | # require some proximity to other pedestrians 87 | .filter(lambda ped_frames: 88 | ped_frames[0] in {p 89 | for frame in ped_frames[1] 90 | for p in occupancy_by_frame[frame]}) 91 | 92 | .cache() 93 | ) 94 | 95 | self.frames |= set(scenes 96 | .flatMap(lambda ped_frames: 97 | ped_frames[1] 98 | if self.visible_chunk is None 99 | else ped_frames[1][:self.visible_chunk]) 100 | .toLocalIterator()) 101 | 102 | return scenes.map(to_scene_row) 103 | 104 | 105 | def rows_to_file(self, rows, output_file): 106 | if '/test/' in output_file: 107 | print('Output File: ', output_file) 108 | self.visible_chunk = self.obs_len 109 | else: 110 | self.visible_chunk = None 111 | scenes = self.from_rows(rows) 112 | tracks = rows.filter(lambda r: r.frame in self.frames) 113 | all_data = rows.context.union((scenes, tracks)) 114 | 115 | ## removes the file, if previously generated 116 | if os.path.isfile(output_file): 117 | os.remove(output_file) 118 | 119 | ## write scenes and tracks 120 | all_data.map(trajnetplusplustools.writers.trajnet).saveAsTextFile(output_file) 121 | 122 | return self 123 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/scene.py: -------------------------------------------------------------------------------- 1 | """ Preparng Scenes for TrajNet """ 2 | import os 3 | from collections import defaultdict 4 | import math 5 | 6 | from .tools.data import SceneRow 7 | from .tools.writers import trajnet 8 | 9 | class Scenes(object): 10 | def __init__(self, fps, start_scene_id=0, args=None): 11 | self.scene_id = start_scene_id 12 | self.chunk_size = args.obs_len + args.pred_len 13 | self.chunk_stride = args.chunk_stride 14 | self.obs_len = args.obs_len 15 | self.visible_chunk = None 16 | self.frames = set() 17 | self.fps = fps 18 | self.min_length = args.min_length 19 | 20 | @staticmethod 21 | def euclidean_distance_2(row1, row2): 22 | """Euclidean distance squared between two rows.""" 23 | return (row1.x - row2.x)**2 + (row1.y - row2.y)**2 24 | 25 | @staticmethod 26 | def close_pedestrians(rows, cell_size=10): 27 | """Fast computation of spatially close pedestrians. 28 | 29 | By frame, get the list of pedestrian ids that or close to other 30 | pedestrians. Approximate with multi-occupancy of discrete grid cells. 31 | """ 32 | sparse_occupancy = defaultdict(list) 33 | for row in rows: 34 | if math.isnan(row.x) == False: 35 | 36 | x = int(row.x // cell_size * cell_size) 37 | y = int(row.y // cell_size * cell_size) 38 | sparse_occupancy[(x, y)].append(row.pedestrian) 39 | else: 40 | sparse_occupancy[(-10,0)].append(row.pedestrian) 41 | 42 | 43 | return {ped_id 44 | for cell in sparse_occupancy.values() if len(cell) > 1 45 | for ped_id in cell} 46 | 47 | @staticmethod 48 | def continuous_frames(frames, tolerance=1.5): 49 | increments = [f2 - f1 for f1, f2 in zip(frames[:-1], frames[1:])] 50 | median_increment = sorted(increments)[int(len(increments) / 2)] 51 | ok = median_increment * tolerance > max(increments) 52 | 53 | return ok 54 | 55 | def from_rows(self, rows): 56 | 57 | count_by_frame = rows.groupBy(lambda r: r.frame).mapValues(len).collectAsMap() 58 | 59 | occupancy_by_frame = (rows 60 | .groupBy(lambda r: r.frame) 61 | .mapValues(self.close_pedestrians) 62 | .collectAsMap()) 63 | 64 | def to_scene_row(ped_frames): 65 | ped_id, scene_frames = ped_frames 66 | 67 | row = SceneRow(self.scene_id, ped_id, scene_frames[0], scene_frames[-1], self.fps, 0) 68 | self.scene_id += 1 69 | return row 70 | 71 | 72 | # scenes: pedestrian of interest, [frames] 73 | scenes = ( 74 | rows 75 | .groupBy(lambda r: r.pedestrian) 76 | .filter(lambda p_path: len(p_path[1]) >= self.chunk_size) 77 | .mapValues(lambda path: sorted(path, key=lambda p: p.frame)) 78 | .flatMapValues(lambda path: [ 79 | [path[ii].frame for ii in range(i, i + self.chunk_size)] 80 | for i in range(0, len(path) - self.chunk_size + 1, self.chunk_stride) 81 | # filter for pedestrians moving by more than min_length meter 82 | # if self.euclidean_distance_2(path[i], path[i+self.chunk_size-1]) > self.min_length 83 | ]) 84 | 85 | # filter out scenes with large gaps in frame numbers 86 | .filter(lambda ped_frames: self.continuous_frames(ped_frames[1])) 87 | 88 | # filter for scenes that have some activity 89 | .filter(lambda ped_frames: 90 | sum(count_by_frame[f] for f in ped_frames[1]) >= 2.0 * self.chunk_size) 91 | 92 | # require some proximity to other pedestrians 93 | .filter(lambda ped_frames: 94 | ped_frames[0] in {p 95 | for frame in ped_frames[1] 96 | for p in occupancy_by_frame[frame]}) 97 | 98 | .cache() 99 | ) 100 | 101 | 102 | 103 | self.frames |= set(scenes 104 | .flatMap(lambda ped_frames: 105 | ped_frames[1] 106 | if self.visible_chunk is None 107 | else ped_frames[1][:self.visible_chunk]) 108 | .toLocalIterator()) 109 | 110 | return scenes.map(to_scene_row) 111 | 112 | 113 | def rows_to_file(self, rows, output_file): 114 | if '/test/' in output_file: 115 | print('Output File: ', output_file) 116 | self.visible_chunk = self.obs_len 117 | else: 118 | self.visible_chunk = None 119 | 120 | scenes = self.from_rows(rows) 121 | 122 | tracks = rows.filter(lambda r: r.frame in self.frames) 123 | 124 | all_data = rows.context.union((scenes, tracks)) 125 | 126 | ## removes the file, if previously generated 127 | if os.path.isfile(output_file): 128 | os.remove(output_file) 129 | 130 | ## write scenes and tracks 131 | all_data.map(trajnet).saveAsTextFile(output_file) 132 | 133 | return self 134 | -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/tools/metrics.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import numpy as np 3 | from scipy.stats import gaussian_kde 4 | 5 | def final_l2(path1, path2): 6 | row1 = path1[-1] 7 | row2 = path2[-1] 8 | return np.linalg.norm((row2.x - row1.x, row2.y - row1.y)) 9 | 10 | 11 | def average_l2(path1, path2, n_predictions=12): 12 | assert len(path1) >= n_predictions 13 | assert len(path2) >= n_predictions 14 | path1 = path1[-n_predictions:] 15 | path2 = path2[-n_predictions:] 16 | 17 | return sum(np.linalg.norm((r1.x - r2.x, r1.y - r2.y)) 18 | for r1, r2 in zip(path1, path2)) / n_predictions 19 | 20 | 21 | def collision(path1, path2, n_predictions=12, person_radius=0.1, inter_parts=2): 22 | """Check if there is collision or not""" 23 | 24 | assert len(path1) >= n_predictions 25 | path1 = path1[-n_predictions:] 26 | frames1 = set(f1.frame for f1 in path1) 27 | frames2 = set(f2.frame for f2 in path2) 28 | common_frames = frames1.intersection(frames2) 29 | 30 | # If there is no interaction, there is no collision 31 | if not common_frames: 32 | return False 33 | 34 | path1 = [path1[i] for i in range(len(path1)) if path1[i].frame in common_frames] 35 | path2 = [path2[i] for i in range(len(path2)) if path2[i].frame in common_frames] 36 | 37 | def getinsidepoints(p1, p2, parts=2): 38 | """return: equally distanced points between starting and ending "control" points""" 39 | 40 | return np.array((np.linspace(p1[0], p2[0], parts + 1), 41 | np.linspace(p1[1], p2[1], parts + 1))) 42 | 43 | for i in range(len(path1) - 1): 44 | p1, p2 = [path1[i].x, path1[i].y], [path1[i + 1].x, path1[i + 1].y] 45 | p3, p4 = [path2[i].x, path2[i].y], [path2[i + 1].x, path2[i + 1].y] 46 | if np.min(np.linalg.norm(getinsidepoints(p1, p2, inter_parts) - getinsidepoints(p3, p4, inter_parts), axis=0)) \ 47 | <= 2 * person_radius: 48 | return True 49 | 50 | return False 51 | 52 | def drop_collision_in_gt(path1, path2, n_predictions=12, person_radius=0.1, inter_parts=2): 53 | """Check if there is collision or not""" 54 | 55 | def getinsidepoints(p1, p2, parts=2): 56 | """return: equally distanced points between starting and ending "control" points""" 57 | 58 | return np.array((np.linspace(p1[0], p2[0], parts + 1), 59 | np.linspace(p1[1], p2[1], parts + 1))) 60 | 61 | for i in range(len(path1) - 1): 62 | p1, p2 = [path1[i, 0], path1[i, 1]], [path1[i + 1, 0], path1[i + 1, 1]] 63 | p3, p4 = [path2[i, 0], path2[i, 1]], [path2[i + 1, 0], path2[i + 1, 1]] 64 | if np.min(np.linalg.norm(getinsidepoints(p1, p2, inter_parts) - getinsidepoints(p3, p4, inter_parts), axis=0)) \ 65 | <= 2 * person_radius: 66 | return True 67 | 68 | return False 69 | 70 | def topk(primary_tracks, ground_truth, n_predictions=12, k_samples=3): 71 | ## TopK multimodal 72 | ## The Prediction closest to the GT in terms of ADE is considered 73 | 74 | l2 = 1e10 75 | ## preds: Pred_len x Num_preds x 2 76 | for pred_num in range(k_samples): 77 | primary_prediction = [t for t in primary_tracks if t.prediction_number == pred_num] 78 | tmp_score = average_l2(ground_truth, primary_prediction, n_predictions=n_predictions) 79 | if tmp_score < l2: 80 | l2 = tmp_score 81 | topk_ade = tmp_score 82 | topk_fde = final_l2(ground_truth, primary_prediction) 83 | 84 | return topk_ade, topk_fde 85 | 86 | def nll(primary_tracks, ground_truth, n_predictions=12, log_pdf_lower_bound=-20, n_samples=100): 87 | """ 88 | Inspired from https://github.com/StanfordASL/Trajectron. 89 | """ 90 | 91 | gt = np.array([[t.x, t.y] for t in ground_truth][-n_predictions:]) 92 | frame_gt = [t.frame for t in ground_truth][-n_predictions:] 93 | preds = np.array([[[t.x, t.y] for t in primary_tracks if t.frame == frame] for frame in frame_gt]) 94 | ## preds: Pred_len x Num_preds x 2 95 | 96 | ## To verify atleast n_samples predictions 97 | if preds.shape[1] < n_samples: 98 | raise Exception('Need {} predictions'.format(n_samples)) 99 | preds = preds[:, :n_samples] 100 | 101 | pred_len = len(frame_gt) 102 | 103 | ll = 0.0 104 | same_pred = 0 105 | for timestep in range(pred_len): 106 | curr_gt = gt[timestep] 107 | ## If identical prediction at particular time-step, skip 108 | if np.all(preds[timestep][1:] == preds[timestep][:-1]): 109 | same_pred += 1 110 | continue 111 | try: 112 | scipy_kde = gaussian_kde(preds[timestep].T) 113 | # We need [0] because it's a (1,)-shaped numpy array. 114 | log_pdf = np.clip(scipy_kde.logpdf(curr_gt.T), a_min=log_pdf_lower_bound, a_max=None)[0] 115 | if np.isnan(log_pdf) or np.isinf(log_pdf) or log_pdf > 100: ## Difficulties in computing Gaussian_KDE 116 | same_pred += 1 117 | continue 118 | ll += log_pdf 119 | except: ## Difficulties in computing Gaussian_KDE 120 | same_pred += 1 121 | 122 | if same_pred == pred_len: 123 | raise Exception('All Predictions are Identical') 124 | 125 | ll = ll / (pred_len - same_pred) 126 | return ll 127 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/reader.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | import itertools 3 | import json 4 | import random 5 | 6 | import numpy as np 7 | 8 | from .data import SceneRow, TrackRow 9 | 10 | 11 | class Reader(object): 12 | """Read trajnet files. 13 | 14 | :param scene_type: None -> numpy.array, 'rows' -> TrackRow and SceneRow, 'paths': grouped rows (primary pedestrian first), 'tags': numpy.array and scene tag 15 | :param image_file: Associated image file of the scene 16 | """ 17 | def __init__(self, input_file, scene_type=None, image_file=None): 18 | if scene_type is not None and scene_type not in {'rows', 'paths', 'tags'}: 19 | raise Exception('scene_type not supported') 20 | self.scene_type = scene_type 21 | 22 | self.tracks_by_frame = defaultdict(list) 23 | self.scenes_by_id = dict() 24 | 25 | self.read_file(input_file) 26 | 27 | def read_file(self, input_file): 28 | with open(input_file, 'r') as f: 29 | for line in f: 30 | line = json.loads(line) 31 | 32 | track = line.get('track') 33 | if track is not None: 34 | row = TrackRow(track['f'], track['p'], track['x'], track['y'], track['v'], 35 | # track['h'], track['w'], track['l'], track['rot_z'], 36 | # track['bb_left'], track['bb_top'], track['bb_width'], track['bb_height'], 37 | track.get('prediction_number'), track.get('scene_id')) 38 | self.tracks_by_frame[row.frame].append(row) 39 | continue 40 | 41 | scene = line.get('scene') 42 | if scene is not None: 43 | row = SceneRow(scene['id'], scene['p'], scene['s'], scene['e'], \ 44 | scene.get('fps'), scene.get('tag')) 45 | self.scenes_by_id[row.scene] = row 46 | 47 | def scenes(self, randomize=False, limit=0, ids=None, sample=None): 48 | scene_ids = self.scenes_by_id.keys() 49 | if ids is not None: 50 | scene_ids = ids 51 | if randomize: 52 | scene_ids = list(scene_ids) 53 | random.shuffle(scene_ids) 54 | if limit: 55 | scene_ids = itertools.islice(scene_ids, limit) 56 | if sample is not None: 57 | scene_ids = random.sample(scene_ids, int(len(scene_ids) * sample)) 58 | for scene_id in scene_ids: 59 | yield self.scene(scene_id) 60 | 61 | @staticmethod 62 | def track_rows_to_paths(primary_pedestrian, track_rows): 63 | primary_path = [] 64 | other_paths = defaultdict(list) 65 | for row in track_rows: 66 | if row.pedestrian == primary_pedestrian: 67 | primary_path.append(row) 68 | continue 69 | other_paths[row.pedestrian].append(row) 70 | 71 | return [primary_path] + list(other_paths.values()) 72 | 73 | @staticmethod 74 | def paths_to_xy(paths): 75 | """Convert paths to numpy array with nan as blanks.""" 76 | frames = set(r.frame for r in paths[0]) 77 | pedestrians = set(row.pedestrian 78 | for path in paths 79 | for row in path if row.frame in frames) 80 | paths = [path for path in paths if path[0].pedestrian in pedestrians] 81 | frames = sorted(frames) 82 | pedestrians = list(pedestrians) 83 | 84 | frame_to_index = {frame: i for i, frame in enumerate(frames)} 85 | xy = np.full((len(frames), len(pedestrians), 3), np.nan) 86 | 87 | for ped_index, path in enumerate(paths): 88 | for row in path: 89 | if row.frame not in frame_to_index: 90 | continue 91 | entry = xy[frame_to_index[row.frame]][ped_index] 92 | entry[0] = row.x 93 | entry[1] = row.y 94 | entry[2] = row.v 95 | 96 | # entry[3] = row.h 97 | # entry[4] = row.w 98 | # entry[5] = row.l 99 | # entry[6] = row.rot_z 100 | 101 | # entry[7] = row.bb_left 102 | # entry[8] = row.bb_top 103 | # entry[9] = row.bb_width 104 | # entry[10] = row.bb_height 105 | 106 | 107 | return xy 108 | 109 | def scene(self, scene_id): 110 | scene = self.scenes_by_id.get(scene_id) 111 | if scene is None: 112 | raise Exception('scene with that id not found') 113 | 114 | frames = range(scene.start, scene.end + 1) 115 | track_rows = [r 116 | for frame in frames 117 | for r in self.tracks_by_frame.get(frame, [])] 118 | 119 | # return as rows 120 | if self.scene_type == 'rows': 121 | return scene_id, scene.pedestrian, track_rows 122 | 123 | # return as paths 124 | paths = self.track_rows_to_paths(scene.pedestrian, track_rows) 125 | if self.scene_type == 'paths': 126 | return scene_id, paths 127 | 128 | ## return with scene tag 129 | if self.scene_type == 'tags': 130 | return scene_id, scene.tag, self.paths_to_xy(paths) 131 | 132 | # return a numpy array 133 | return scene_id, self.paths_to_xy(paths) 134 | -------------------------------------------------------------------------------- /train_traj_extractor.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import json 3 | import csv 4 | import os 5 | from csv import reader, writer 6 | import argparse 7 | 8 | 9 | # Function to process the JSON files and generate CSV output 10 | def process_files(file_names, jrdb_3d, out_path): 11 | for file_name in file_names: 12 | # Create file paths for 3D and 2D JSON files 13 | fname = os.path.join(jrdb_3d, file_name + '.json') 14 | 15 | # Load data from 3D JSON file 16 | with open(fname) as json_file: 17 | orig_labels = json.load(json_file) 18 | 19 | # Create and open the CSV file for writing 20 | with open(os.path.join(out_path, file_name + '.csv'), 'w', newline='') as result: 21 | writer = csv.writer(result) 22 | 23 | # Iterate through 3D and 2D data to match and process 24 | for pcd_id, pcd_data in orig_labels['labels'].items(): 25 | # for twod_box_id, twod_box_data in orig_labels_2dbox['labels'].items(): 26 | # Downsample the frames and check for matching IDs 27 | if int(pcd_id[:6]) % 6 == 0: 28 | for target in pcd_data: 29 | # Write the combined data to the CSV file 30 | writer.writerow(( 31 | int(pcd_id[:6]), int(target['label_id'][11:]), 32 | target['box']['cx'], target['box']['cy'], 33 | )) 34 | 35 | def add_confidence_score(input_file, output_file): 36 | with open(input_file, 'r') as input_csv, open(output_file, 'w', newline='') as output_csv: 37 | csv_reader = reader(input_csv) 38 | csv_writer = writer(output_csv) 39 | for row in csv_reader: 40 | row.insert(4, 1) 41 | csv_writer.writerow(row) 42 | 43 | def extract_pedestrian_ids(input_file): 44 | p_id_list = [] 45 | with open(input_file, 'r') as input_csv: 46 | csv_reader = reader(input_csv) 47 | for row in csv_reader: 48 | if row[1] not in p_id_list: 49 | p_id_list.append(row[1]) 50 | return p_id_list 51 | 52 | def add_nan(file_name, output_path, conf_path, nan_path): 53 | input_path = os.path.join(output_path, file_name + '.csv') 54 | conf_output_path = os.path.join(conf_path, file_name + '.csv') 55 | nan_output_path = os.path.join(nan_path, file_name + '.csv') 56 | 57 | add_confidence_score(input_path, conf_output_path) 58 | p_id_list = extract_pedestrian_ids(conf_output_path) 59 | 60 | with open(conf_output_path, 'r') as input_csv, open(nan_output_path, 'w', newline='') as output_csv: 61 | csv_reader = reader(input_csv) 62 | csv_writer = writer(output_csv, delimiter=',') 63 | p_id_list_temp = [] 64 | last_frame_id = -1 65 | for row in csv_reader: 66 | if int(row[0]) == last_frame_id: 67 | p_id_list_temp.append(row[1]) 68 | csv_writer.writerow(row) 69 | else: 70 | nan_id = [x for x in p_id_list if x not in p_id_list_temp] 71 | if nan_id and last_frame_id != -1: 72 | for i in nan_id: 73 | row_temp = [last_frame_id, i, 'nan', 'nan', 0] 74 | csv_writer.writerow(row_temp) 75 | p_id_list_temp.clear() 76 | p_id_list_temp.append(row[1]) 77 | last_frame_id = int(row[0]) 78 | csv_writer.writerow(row) 79 | 80 | def main(out_path, jrdb_path): 81 | 82 | temp_down_sample_path = os.path.join(out_path,'temp/') 83 | conf_path = os.path.join(out_path,'conf_temp/') 84 | nan_path = out_path 85 | jrdb_3d = os.path.join(jrdb_path, 'labels_3d/') 86 | 87 | # Check if the path exists 88 | if not os.path.exists(conf_path): 89 | os.makedirs(conf_path) 90 | if not os.path.exists(temp_down_sample_path): 91 | os.makedirs(temp_down_sample_path) 92 | 93 | # List of file names to process 94 | file_names = [ 95 | 'bytes-cafe-2019-02-07_0', 96 | 'huang-lane-2019-02-12_0', 97 | 'gates-basement-elevators-2019-01-17_1', 98 | 'hewlett-packard-intersection-2019-01-24_0', 99 | 'jordan-hall-2019-04-22_0', 100 | 'packard-poster-session-2019-03-20_2', 101 | 'stlc-111-2019-04-19_0', 102 | 'svl-meeting-gates-2-2019-04-08_0', 103 | 'svl-meeting-gates-2-2019-04-08_1', 104 | 'tressider-2019-03-16_1', 105 | 'gates-ai-lab-2019-02-08_0', 106 | 'packard-poster-session-2019-03-20_1', 107 | 'tressider-2019-03-16_0', 108 | ] 109 | print('Extracting trajectories (1/2) ...') 110 | process_files(file_names, jrdb_3d, temp_down_sample_path) 111 | 112 | print('Add nan to missed ones (2/2) ...') 113 | for file_name in file_names: 114 | add_nan(file_name, temp_down_sample_path, conf_path, nan_path) 115 | print('All done!') 116 | 117 | if __name__ == "__main__": 118 | parser = argparse.ArgumentParser() 119 | parser.add_argument('--out_path', type=str, help='Output data path') 120 | parser.add_argument('--jrdb_path', type=str, help='JRDB data path') 121 | args = parser.parse_args() 122 | 123 | main(args.out_path, args.jrdb_path) 124 | 125 | -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/utils.py: -------------------------------------------------------------------------------- 1 | import math 2 | import random 3 | 4 | import numpy 5 | import matplotlib.pyplot as plt 6 | 7 | import trajnetplusplustools 8 | from trajnetplusplustools import show 9 | 10 | def drop_distant(xy, r=6.0): 11 | """ 12 | Drops pedestrians more than r meters away from primary ped 13 | """ 14 | distance_2 = numpy.sum(numpy.square(xy - xy[:, 0:1]), axis=2) 15 | mask = numpy.argsort(distance_2)[0] 16 | return mask 17 | 18 | def random_rotation(xy): 19 | theta = random.random() * 2.0 * math.pi 20 | ct = math.cos(theta) 21 | st = math.sin(theta) 22 | r = numpy.array([[ct, st], [-st, ct]]) 23 | # if goals is None: 24 | # return numpy.einsum('ptc,ci->pti', xy, r) 25 | # return numpy.einsum('ptc,ci->pti', xy, r), numpy.einsum('tc,ci->ti', goals, r) 26 | return numpy.einsum('ptc,ci->pti', xy, r) 27 | 28 | def shift(xy, center): 29 | # theta = random.random() * 2.0 * math.pi 30 | xy = xy - center[numpy.newaxis, numpy.newaxis, :] 31 | return xy 32 | 33 | def theta_rotation(xy, theta): 34 | # theta = random.random() * 2.0 * math.pi 35 | ct = math.cos(theta) 36 | st = math.sin(theta) 37 | 38 | r = numpy.array([[ct, st], [-st, ct]]) 39 | return numpy.einsum('ptc,ci->pti', xy, r) 40 | 41 | def center_scene(xy, obs_length=9, ped_id=0, goals=None): 42 | if goals is not None: 43 | goals = goals[numpy.newaxis, :, :] 44 | ## Center 45 | center = xy[obs_length-1, ped_id] ## Last Observation 46 | xy = shift(xy, center) 47 | if goals is not None: 48 | goals = shift(goals, center) 49 | 50 | ## Rotate 51 | last_obs = xy[obs_length-1, ped_id] 52 | second_last_obs = xy[obs_length-2, ped_id] 53 | diff = numpy.array([last_obs[0] - second_last_obs[0], last_obs[1] - second_last_obs[1]]) 54 | thet = numpy.arctan2(diff[1], diff[0]) 55 | rotation = -thet + numpy.pi/2 56 | xy = theta_rotation(xy, rotation) 57 | if goals is not None: 58 | goals = theta_rotation(goals, rotation) 59 | return xy, rotation, center, goals[0] 60 | return xy, rotation, center 61 | 62 | def visualize_scene(scene, goal=None, weights=None, pool_weight=None, show=True): 63 | 64 | for t in reversed(range(scene.shape[1])): 65 | path = scene[:, t] 66 | color = 'b' if t == 0 else 'orange' 67 | linewidth = 3.0 if t == 0 else 2.0 68 | 69 | plt.plot(path[:-1, 0], path[:-1, 1], c=color, linewidth=linewidth) 70 | 71 | if t == 0 and weights is not None: 72 | ## Past velocity weights 73 | # plt.scatter(path[:-1, 0], path[:-1, 1], c=weights[:-2], cmap='Blues', vmin=0.0, vmax=1.5) 74 | pass 75 | elif t != 0 and pool_weight is not None: 76 | plt.scatter(path[:-1, 0], path[:-1, 1], color=color, alpha=pool_weight[t-1], vmin=0.0, vmax=1.5, s=60.0) 77 | else: 78 | plt.scatter(path[:-1, 0], path[:-1, 1], c=color) 79 | plt.arrow(path[-2, 0], path[-2, 1], path[-1, 0] - path[-2, 0], path[-1, 1] - path[-2, 1], width=0.05, color='g') 80 | 81 | 82 | plt.gca().set_aspect('equal') 83 | xmin = numpy.round(2 * numpy.nanmin(scene[:, :, 0])) * 0.5 84 | xmax = numpy.round(2 * numpy.nanmax(scene[:, :, 0])) * 0.5 85 | # xcent = 0.5*(xmin + xmax) 86 | ymin = numpy.round(2 * numpy.nanmin(scene[:, :, 1])) * 0.5 87 | ymax = numpy.round(2 * numpy.nanmax(scene[:, :, 1])) * 0.5 88 | 89 | ycent = 0.5*(ymin + ymax) 90 | length_plot = 0.5*(max(xmax - xmin, ymax - ymin) + 1) 91 | plt.xticks(numpy.arange(xmin - 1, xmax + 2), fontsize=10) 92 | plt.yticks(numpy.arange(ymin - 1, ymax + 2), fontsize=10) 93 | plt.tight_layout(pad=0.05) 94 | 95 | if show: 96 | plt.show() 97 | plt.close() 98 | 99 | def xy_to_paths(xy_paths): 100 | return [trajnetplusplustools.TrackRow(i, 0, xy_paths[i, 0].item(), xy_paths[i, 1].item(), 0, 0) 101 | for i in range(len(xy_paths))] 102 | 103 | 104 | def visualize_lrp(output_scenes, vel_weights, neigh_weights, TIME_STEPS): 105 | for t in range(8, TIME_STEPS): 106 | visualize_scene(output_scenes[:t+2], weights=vel_weights[t-7], pool_weight=neigh_weights[t-7]) 107 | 108 | def visualize_grid(grid): 109 | sum_grid = numpy.abs(grid.numpy().sum(axis=0)) 110 | ax = plt.gca() 111 | fig = plt.gcf() 112 | viridis = cm.get_cmap('viridis', 256) 113 | psm = ax.pcolormesh(sum_grid, cmap=viridis, rasterized=True) 114 | fig.colorbar(psm, ax=ax) 115 | plt.show() 116 | plt.close() 117 | print("Showed Grid") 118 | 119 | 120 | def viz(groundtruth, prediction, visualize, output_file=None): 121 | pred_paths = {} 122 | 123 | groundtruth = groundtruth.cpu().numpy().transpose(1, 0, 2) 124 | prediction = prediction.cpu().numpy().transpose(1, 0, 2) 125 | gt_paths = [xy_to_paths(path) for path in groundtruth] 126 | pred = [xy_to_paths(path) for path in prediction] 127 | 128 | pred_paths[0] = pred[0] 129 | pred_neigh_paths = None 130 | if visualize: 131 | pred_neigh_paths = {} 132 | pred_neigh_paths[0] = pred[1:] 133 | 134 | with show.predicted_paths(gt_paths, pred_paths, pred_neigh_paths, output_file): 135 | pass 136 | 137 | def animate_lrp(output_scenes, vel_weights, neigh_weights, TIME_STEPS, scene_id=0, pool_type='directional'): 138 | fig = plt.figure() ## Scene 41: figsize=(7.5, 4) 139 | camera = Camera(fig) 140 | for t in range(8, TIME_STEPS): 141 | visualize_scene(output_scenes[:t+2], weights=vel_weights[t-7], pool_weight=neigh_weights[t-7], show=False) 142 | camera.snap() 143 | 144 | animation = camera.animate() 145 | animation.save('anims/lrp_crowds_{}_scene{}.mp4'.format(pool_type, scene_id), fps=2, writer='ffmpeg') 146 | plt.close() 147 | -------------------------------------------------------------------------------- /test_traj_extractor.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | import csv 4 | 5 | import os 6 | 7 | import argparse 8 | 9 | 10 | 11 | def create_directories(output_path, down_sample_path, conf_path): 12 | 13 | if not os.path.exists(output_path): 14 | os.makedirs(output_path) 15 | 16 | if not os.path.exists(down_sample_path): 17 | os.makedirs(down_sample_path) 18 | 19 | if not os.path.exists(conf_path): 20 | os.makedirs(conf_path) 21 | 22 | 23 | def process_jrdb_data(jrdb_path, output_path, down_sample_path, conf_path): 24 | 25 | # List of file names, shifts, benchmark frames, and final frames 26 | 27 | file_names = [ 28 | ######alphabeta-order of test set 29 | 'cubberly-auditorium-2019-04-22_1', 30 | 'discovery-walk-2019-02-28_0', 31 | 'discovery-walk-2019-02-28_1', 32 | 'food-trucks-2019-02-12_0', 33 | 'gates-ai-lab-2019-04-17_0', 34 | 'gates-basement-elevators-2019-01-17_0', 35 | 'gates-foyer-2019-01-17_0', 36 | 'gates-to-clark-2019-02-28_0', 37 | 'hewlett-class-2019-01-23_0', 38 | 'hewlett-class-2019-01-23_1', 39 | 'huang-2-2019-01-25_1', 40 | 'huang-intersection-2019-01-22_0', 41 | 'indoor-coupa-cafe-2019-02-06_0', 42 | 'lomita-serra-intersection-2019-01-30_0', 43 | 'meyer-green-2019-03-16_1', 44 | 'nvidia-aud-2019-01-25_0', 45 | 'nvidia-aud-2019-04-18_1', 46 | 'nvidia-aud-2019-04-18_2', 47 | 'outdoor-coupa-cafe-2019-02-06_0', 48 | 'quarry-road-2019-02-28_0', 49 | 'serra-street-2019-01-30_0', 50 | 'stlc-111-2019-04-19_1', 51 | 'stlc-111-2019-04-19_2', 52 | 'tressider-2019-03-16_2', 53 | 'tressider-2019-04-26_0', 54 | 'tressider-2019-04-26_1', 55 | 'tressider-2019-04-26_3' 56 | ] 57 | 58 | 59 | 60 | shifts = [2, 0, 4, 5, 3, 5, 0, 2, 2, 0, 2, 4, 1, 0, 3, 4, 2, 1, 0, 5, 0, 1, 0, 1, 3, 2, 4] 61 | 62 | benchmark_frames = [1030, 666, 740, 1555, 1173, 589, 1614, 376, 742, 738, 520, 1610, 1619, 1128, 957, 1178, 454, 449, 63 | 1602, 385, 1350, 449, 426, 593, 1173, 1612, 1610] 64 | 65 | 66 | for dataset_index, file_name in enumerate(file_names): 67 | shift = shifts[dataset_index] 68 | fname = f"{jrdb_path}{str(dataset_index).zfill(4)}.txt" 69 | 70 | # Delete the 'pedestrian' column and convert data to float 71 | 72 | trajs = np.loadtxt(fname, dtype=str) 73 | trajs = np.delete(trajs, 2, 1) 74 | trajs = np.array(trajs).astype(float) 75 | 76 | 77 | # Downsample and select specific frames for leaderboard 78 | 79 | with open(f"{down_sample_path}{file_name}.csv", 'w', newline='') as result: 80 | writer = csv.writer(result) 81 | for row in range(trajs.shape[0]): 82 | if (trajs[row, 0] + shift) < benchmark_frames[dataset_index]: 83 | continue 84 | 85 | if (trajs[row, 0] + shift) % 6 == 0: 86 | writer.writerow((int(trajs[row, 0]), int(trajs[row, 1]), trajs[row, -2], trajs[row, -1])) 87 | 88 | 89 | # Add confidence score column 90 | with open(f"{down_sample_path}{file_name}.csv") as input_file: 91 | with open(f"{conf_path}{file_name}.csv", 'w', newline='') as output_file: 92 | csv_reader = csv.reader(input_file) 93 | csv_writer = csv.writer(output_file) 94 | 95 | for row in csv_reader: 96 | row.insert(4, 1) 97 | csv_writer.writerow(row) 98 | 99 | p_id_list = [] 100 | 101 | # Get all pedestrian IDs in this video 102 | with open(f"{conf_path}{file_name}.csv") as input_file: 103 | csv_reader = csv.reader(input_file) 104 | for row_temp in csv_reader: 105 | if row_temp[1] in p_id_list: 106 | pass 107 | else: 108 | p_id_list.append(row_temp[1]) 109 | 110 | 111 | # Add 'nan' to missed pedestrians 112 | with open(f"{conf_path}{file_name}.csv") as input_file: 113 | with open(os.path.join(output_path, file_name + '.csv'), 'w', newline='') as output_file: 114 | 115 | csv_reader = csv.reader(input_file) 116 | csv_writer = csv.writer(output_file, delimiter=',') 117 | last_frame_id = benchmark_frames[dataset_index] 118 | p_id_list_temp = [] 119 | 120 | for row in csv_reader: 121 | if int(row[0]) == last_frame_id: 122 | p_id_list_temp.append(row[1]) 123 | csv_writer.writerow(row) 124 | else: 125 | nan_id = [x for x in p_id_list if x not in p_id_list_temp] 126 | if len(nan_id) != 0: 127 | for i in nan_id: 128 | row_temp = [last_frame_id, i, 'nan', 'nan', 0] 129 | csv_writer.writerow(row_temp) 130 | 131 | p_id_list_temp.clear() 132 | p_id_list_temp.append(row[1]) 133 | last_frame_id = int(row[0]) 134 | csv_writer.writerow(row) 135 | 136 | 137 | def main(out_path, jrdb_path): 138 | 139 | down_sample_path = os.path.join(out_path,'temp/') 140 | conf_path = os.path.join(out_path, 'conf_temp/') 141 | 142 | create_directories(out_path, down_sample_path, conf_path) 143 | 144 | process_jrdb_data(jrdb_path, out_path, down_sample_path, conf_path) 145 | 146 | 147 | 148 | if __name__ == "__main__": 149 | 150 | parser = argparse.ArgumentParser() 151 | 152 | parser.add_argument('--out_path', type=str, help='Output data path') 153 | 154 | parser.add_argument('--jrdb_path', type=str, help='JRDB test data path') 155 | 156 | args = parser.parse_args() 157 | 158 | 159 | 160 | main(args.out_path, args.jrdb_path) 161 | 162 | -------------------------------------------------------------------------------- /jrdb_baselines/get_dest.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import pysparkling 3 | import scipy.io 4 | import json 5 | import numpy as np 6 | from operator import itemgetter 7 | import pickle 8 | 9 | from trajnetplusplustools import TrackRow 10 | 11 | ## read file trackrows 12 | def trackrows(line): 13 | line = json.loads(line) 14 | track = line.get('track') 15 | if track is not None: 16 | return [track['f'], track['p'], track['x'], track['y']] 17 | return None 18 | 19 | def get_trackrows(sc, input_file): 20 | print('processing ' + input_file) 21 | return (sc 22 | .textFile(input_file) 23 | .map(trackrows) 24 | .filter(lambda r: r is not None) 25 | .cache()) 26 | 27 | def get_dest(rows): 28 | """ Ensure that the last frame is the GOAL """ 29 | L = rows.collect() 30 | dict_frames = {} 31 | for ind in range(len(L)): 32 | f, ped_id, x, y = L[ind] 33 | if ped_id in dict_frames: 34 | dict_frames[ped_id].append([f, x, y]) 35 | else: 36 | dict_frames[ped_id] = [[f, x, y]] 37 | 38 | dict_dest = {} 39 | for ped_id in dict_frames: 40 | ped_presence = dict_frames[ped_id] 41 | ped_presence_sorted = sorted(ped_presence, key=lambda x: x[0]) 42 | if ped_presence[-1][-2:] != ped_presence_sorted[-1][-2:]: 43 | import pdb 44 | pdb.set_trace() 45 | dict_dest[ped_id] = (ped_presence_sorted[-1][-2:]) 46 | 47 | return dict_dest 48 | 49 | def generate_dest(sc, input_file): 50 | rows = get_trackrows(sc, input_file) 51 | dict_dest = get_dest(rows) 52 | # dataset = input_file.replace('./DATA_BLOCK/data/train/real_data/', '').replace('.ndjson', '') 53 | dataset_type = input_file.split('/')[-2] 54 | dataset = input_file.split('/')[-1].replace('.ndjson', '') 55 | # dataset = input_file.replace('./DATA_BLOCK/data/groundtruth/real_data/', '').replace('.ndjson', '') 56 | print(dataset) 57 | print(dict_dest) 58 | with open('goal_files/' + dataset_type + '/' + dataset + '.pkl', 'wb') as f: 59 | pickle.dump(dict_dest, f) 60 | 61 | 62 | sc = pysparkling.Context() 63 | input_file = './DATA_BLOCK/trajdata/train/biwi_hotel.ndjson' 64 | generate_dest(sc, input_file) 65 | input_file = './DATA_BLOCK/trajdata/train/crowds_zara01.ndjson' 66 | generate_dest(sc, input_file) 67 | input_file = './DATA_BLOCK/trajdata/train/crowds_zara03.ndjson' 68 | generate_dest(sc, input_file) 69 | input_file = './DATA_BLOCK/trajdata/train/crowds_students001.ndjson' 70 | generate_dest(sc, input_file) 71 | input_file = './DATA_BLOCK/trajdata/train/crowds_students003.ndjson' 72 | generate_dest(sc, input_file) 73 | input_file = './DATA_BLOCK/trajdata/train/lcas.ndjson' 74 | generate_dest(sc, input_file) 75 | input_file = './DATA_BLOCK/trajdata/train/wildtrack.ndjson' 76 | generate_dest(sc, input_file) 77 | input_file = './DATA_BLOCK/trajdata/val/biwi_eth.ndjson' 78 | generate_dest(sc, input_file) 79 | input_file = './DATA_BLOCK/trajdata/val/crowds_uni_examples.ndjson' 80 | generate_dest(sc, input_file) 81 | input_file = './DATA_BLOCK/trajdata/val/crowds_zara02.ndjson' 82 | generate_dest(sc, input_file) 83 | # input_file = './DATA_BLOCK/data/train/real_data/biwi_hotel.ndjson' 84 | # generate_dest(sc, input_file) 85 | # input_file = './DATA_BLOCK/data/train/real_data/crowds_zara01.ndjson' 86 | # generate_dest(sc, input_file) 87 | # input_file = './DATA_BLOCK/data/train/real_data/crowds_zara03.ndjson' 88 | # generate_dest(sc, input_file) 89 | # input_file = './DATA_BLOCK/data/train/real_data/crowds_students001.ndjson' 90 | # generate_dest(sc, input_file) 91 | # input_file = './DATA_BLOCK/data/train/real_data/crowds_students003.ndjson' 92 | # generate_dest(sc, input_file) 93 | # input_file = './DATA_BLOCK/data/train/real_data/lcas.ndjson' 94 | # generate_dest(sc, input_file) 95 | # input_file = './DATA_BLOCK/data/train/real_data/wildtrack.ndjson' 96 | # generate_dest(sc, input_file) 97 | # input_file = './DATA_BLOCK/synth_single/train/orca_circle_crossing_6ped_single.ndjson' 98 | # generate_dest(sc, input_file) 99 | # input_file = './DATA_BLOCK/synth_single/val/orca_circle_crossing_6ped_single.ndjson' 100 | # generate_dest(sc, input_file) 101 | # input_file = './DATA_BLOCK/synth_small/train/orca_circle_crossing_6ped_small.ndjson' 102 | # generate_dest(sc, input_file) 103 | # input_file = './DATA_BLOCK/synth_small/val/orca_circle_crossing_6ped_small.ndjson' 104 | # generate_dest(sc, input_file) 105 | # input_file = './DATA_BLOCK/synth_clean/synth_medium/train/orca_circle_crossing_6ped_medium.ndjson' 106 | # generate_dest(sc, input_file) 107 | # input_file = './DATA_BLOCK/synth_clean/synth_medium/val/orca_circle_crossing_6ped_medium.ndjson' 108 | # generate_dest(sc, input_file) 109 | # input_file = './DATA_BLOCK/synth_circle_data/train/orca_circle_crossing_5ped.ndjson' 110 | # generate_dest(sc, input_file) 111 | # input_file = './DATA_BLOCK/synth_circle_data/val/orca_circle_crossing_5ped.ndjson' 112 | # generate_dest(sc, input_file) 113 | # input_file = './DATA_BLOCK/synth_circle_data/val_original/orca_circle_crossing_5ped.ndjson' 114 | # generate_dest(sc, input_file) 115 | # input_file = './DATA_BLOCK/synth_circle_all/val/orca_circle_crossing_synth_again.ndjson' 116 | # generate_dest(sc, input_file) 117 | # input_file = './DATA_BLOCK/test_synth_circle/test_private/orca_circle_crossing_5ped.ndjson' 118 | # generate_dest(sc, input_file) 119 | # input_file = './DATA_BLOCK/synth_huge/train/orca_circle_crossing_synth_big.ndjson' 120 | # generate_dest(sc, input_file) 121 | # input_file = './DATA_BLOCK/synth_huge/val/orca_circle_crossing_synth_big.ndjson' 122 | # generate_dest(sc, input_file) 123 | # input_file = './DATA_BLOCK/synth_traj/synth_traj_medium/train/orca_circle_crossing_11ped_small.ndjson' 124 | # generate_dest(sc, input_file) 125 | # input_file = './DATA_BLOCK/synth_traj/synth_traj_medium/val/orca_circle_crossing_11ped_small.ndjson' 126 | # generate_dest(sc, input_file) 127 | # input_file = './DATA_BLOCK/data/groundtruth/real_data/biwi_eth.ndjson' 128 | # generate_dest(sc, input_file) 129 | # input_file = './DATA_BLOCK/data/groundtruth/real_data/crowds_uni_examples.ndjson' 130 | # generate_dest(sc, input_file) 131 | # input_file = './DATA_BLOCK/data/groundtruth/real_data/crowds_zara02.ndjson' 132 | # generate_dest(sc, input_file) 133 | # input_file = './DATA_BLOCK/test_synth_circle/test_private/orca_circle_crossing_5ped.ndjson' 134 | # generate_dest(sc, input_file) -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/plot_log.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import datetime 3 | import json 4 | 5 | import numpy as np 6 | import pysparkling 7 | import trajnetplusplustools.show 8 | 9 | 10 | def read_log(path): 11 | sc = pysparkling.Context() 12 | return (sc 13 | .textFile(path) 14 | .filter(lambda line: line.startswith(('{', 'json:'))) 15 | .map(lambda line: json.loads(line.strip('json:'))) 16 | .groupBy(lambda data: data.get('type')) 17 | .collectAsMap()) 18 | 19 | 20 | def plots(log_files, output_prefix, labels=None): 21 | if not labels: 22 | labels = log_files 23 | datas = [read_log(log_file) for log_file in log_files] 24 | 25 | with trajnetplusplustools.show.canvas(output_prefix + 'time.png') as ax: 26 | for data, label in zip(datas, labels): 27 | if 'train' in data: 28 | x = np.array([row.get('epoch') + row.get('batch') / row.get('n_batches') 29 | for row in data['train']]) 30 | y = [datetime.datetime.strptime(row.get('asctime')[:-4], '%Y-%m-%d %H:%M:%S') 31 | for row in data['train']] 32 | y = [(yi - y[0]).total_seconds() / 3600.0 for yi in y] 33 | ax.plot(x, y, label=label) 34 | 35 | ax.set_xlabel('epoch') 36 | ax.set_ylabel('time [h]') 37 | ax.legend() 38 | 39 | with trajnetplusplustools.show.canvas(output_prefix + 'epoch-time.png') as ax: 40 | for data, label in zip(datas, labels): 41 | if 'train-epoch' in data: 42 | x = np.array([row.get('epoch') for row in data['train-epoch']]) 43 | y = [datetime.datetime.strptime(row.get('asctime')[:-4], '%Y-%m-%d %H:%M:%S') 44 | for row in data['train-epoch']] 45 | y = [(yi - prev_yi).total_seconds() / 60.0 46 | for prev_yi, yi in zip(y[:-1], y[1:])] 47 | ax.plot(x[1:], y, label=label) 48 | 49 | ax.set_xlabel('epoch') 50 | ax.set_ylabel('epoch-time [min]') 51 | ax.legend() 52 | 53 | with trajnetplusplustools.show.canvas(output_prefix + 'lr.png') as ax: 54 | for data, label in zip(datas, labels): 55 | if 'train' in data: 56 | x = [row.get('epoch') for row in data['train']] 57 | y = [row.get('lr') for row in data['train']] 58 | ax.plot(x, y, label=label) 59 | 60 | ax.set_xlabel('epoch') 61 | ax.set_ylabel('learning rate') 62 | ax.set_yscale('log', nonpositive='clip') 63 | ax.legend() 64 | 65 | with trajnetplusplustools.show.canvas(output_prefix + 'val.png') as ax: 66 | for data, label in zip(datas, labels): 67 | if 'val' in data: 68 | x = [row.get('epoch') for row in data['val']] 69 | y = [row.get('accuracy', row.get('prec@1')) for row in data['val']] 70 | ax.plot(x, y, label=label) 71 | 72 | ax.set_xlabel('epoch') 73 | ax.set_ylabel('accuracy') 74 | ax.legend() 75 | 76 | with trajnetplusplustools.show.canvas(output_prefix + 'epoch-loss.png') as ax: 77 | for data, label in zip(datas, labels): 78 | val_color = None 79 | if 'val-epoch' in data: 80 | x = [row.get('epoch') for row in data['val-epoch'] if row.get('epoch') < 100] 81 | y = [row.get('loss') for row in data['val-epoch'] if row.get('epoch') < 100] 82 | val_line, = ax.plot(x, y, label=label) 83 | val_color = val_line.get_color() 84 | if 'train-epoch' in data: 85 | x = [row.get('epoch') for row in data['train-epoch'] if row.get('epoch') < 100] 86 | y = [row.get('loss') for row in data['train-epoch'] if row.get('epoch') < 100] 87 | ax.plot(x, y, color=val_color, linestyle='dotted') 88 | 89 | ax.set_xlabel('epoch') 90 | ax.set_ylabel('start-loss') 91 | # ax.set_ylim(0.05, 0.3) 92 | # if min(y) > -0.1: 93 | # ax.set_yscale('log', nonpositive='clip') 94 | ax.legend(loc=1) 95 | 96 | with trajnetplusplustools.show.canvas(output_prefix + 'seq-loss.png') as ax: 97 | for data, label in zip(datas, labels): 98 | val_color = None 99 | if 'val-epoch' in data: 100 | x = [row.get('epoch') for row in data['val-epoch'] if row.get('epoch') < 100] 101 | y = [row.get('test_loss') for row in data['val-epoch'] if row.get('epoch') < 100] 102 | val_line, = ax.plot(x, y, label=label) 103 | val_color = val_line.get_color() 104 | if 'train-epoch' in data: 105 | x = [row.get('epoch') for row in data['train-epoch'] if row.get('epoch') < 100] 106 | y = [row.get('seq_loss') for row in data['train-epoch'] if row.get('epoch') < 100] 107 | ax.plot(x, y, color=val_color, linestyle='dotted') 108 | 109 | ax.set_xlabel('epoch') 110 | ax.set_ylabel('seq-loss') 111 | # ax.set_ylim(0.0, 5.0) 112 | # if min(y) > -0.1: 113 | # ax.set_yscale('log', nonpositive='clip') 114 | ax.legend(loc=1) 115 | 116 | 117 | with trajnetplusplustools.show.canvas(output_prefix + 'train.png') as ax: 118 | for data, label in zip(datas, labels): 119 | if 'train' in data: 120 | x = np.array([row.get('epoch') + row.get('batch') / row.get('n_batches') 121 | for row in data['train']]) 122 | y = np.array([row.get('loss') 123 | for row in data['train']]) 124 | stride = int(len(x) / (x[-1] - x[0]) / 3.0) # 3 per epoch 125 | if x[-1] - x[0] > 1.0 and stride > 5: 126 | x_binned = np.array([x[i] for i in range(0, len(x), stride)][:-1]) 127 | y_binned = np.stack([y[i:i + stride] for i in range(0, len(x), stride)][:-1]) 128 | y_mean = np.mean(y_binned, axis=1) 129 | y_min = np.min(y_binned, axis=1) 130 | y_max = np.max(y_binned, axis=1) 131 | ax.fill_between(x_binned, y_min, y_max, alpha=0.2) 132 | ax.plot(x_binned, y_mean, label=label) 133 | else: 134 | y_mean = [0, 0] 135 | ax.plot(x, y, label=label) 136 | 137 | ax.set_xlabel('epoch') 138 | ax.set_ylabel('training loss') 139 | # ax.set_ylim(-5, 6) 140 | # if min(y_mean) > -0.1: 141 | # ax.set_yscale('log', nonpositive='clip') 142 | ax.legend() 143 | 144 | 145 | def main(): 146 | parser = argparse.ArgumentParser() 147 | parser.add_argument('log_file', nargs='+', 148 | help='path to log file') 149 | parser.add_argument('--label', nargs='+', 150 | help='labels in the same order as files') 151 | parser.add_argument('-o', '--output', default=None, 152 | help='output prefix (default is log_file + .)') 153 | args = parser.parse_args() 154 | 155 | if args.output is None: 156 | args.output = args.log_file[-1] + '.' 157 | 158 | plots(args.log_file, args.output, args.label) 159 | 160 | 161 | if __name__ == '__main__': 162 | main() 163 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/tools/interactions.py: -------------------------------------------------------------------------------- 1 | """ Categorizes the Interaction """ 2 | 3 | import numpy as np 4 | 5 | from . import kalman 6 | from . import metrics 7 | 8 | ####################################### 9 | ## Helper Functions for interactions ## 10 | ####################################### 11 | 12 | def compute_velocity_interaction(path, neigh_path, obs_len=9, stride=3): 13 | ## Computes the angle between velocity of neighbours and velocity of pp 14 | 15 | prim_vel = path[obs_len:] - path[obs_len-stride:-stride] 16 | theta1 = np.arctan2(prim_vel[:, 1], prim_vel[:, 0]) 17 | neigh_vel = neigh_path[obs_len:] - neigh_path[obs_len-stride:-stride] 18 | vel_interaction = np.zeros(neigh_vel.shape[0:2]) 19 | sign_interaction = np.zeros(neigh_vel.shape[0:2]) 20 | 21 | for n in range(neigh_vel.shape[1]): 22 | theta2 = np.arctan2(neigh_vel[:, n, 1], neigh_vel[:, n, 0]) 23 | theta_diff = (theta2 - theta1) * 180 / np.pi 24 | theta_diff = theta_diff % 360 25 | theta_sign = theta_diff > 180 26 | sign_interaction[:, n] = theta_sign 27 | vel_interaction[:, n] = theta_diff 28 | return vel_interaction, sign_interaction 29 | 30 | 31 | def compute_theta_interaction(path, neigh_path, obs_len=9, stride=3): 32 | ## Computes the angle between line joining pp to neighbours and velocity of pp 33 | 34 | prim_vel = path[obs_len:] - path[obs_len-stride:-stride] 35 | theta1 = np.arctan2(prim_vel[:, 1], prim_vel[:, 0]) 36 | rel_dist = neigh_path[obs_len:] - path[obs_len:][:, np.newaxis, :] 37 | theta_interaction = np.zeros(rel_dist.shape[0:2]) 38 | sign_interaction = np.zeros(rel_dist.shape[0:2]) 39 | 40 | for n in range(rel_dist.shape[1]): 41 | theta2 = np.arctan2(rel_dist[:, n, 1], rel_dist[:, n, 0]) 42 | theta_diff = (theta2 - theta1) * 180 / np.pi 43 | theta_diff = theta_diff % 360 44 | theta_sign = theta_diff > 180 45 | sign_interaction[:, n] = theta_sign 46 | theta_interaction[:, n] = theta_diff 47 | return theta_interaction, sign_interaction 48 | 49 | def compute_dist_rel(path, neigh_path, obs_len=9): 50 | ## Distance between pp and neighbour 51 | 52 | dist_rel = np.linalg.norm((neigh_path[obs_len:] - path[obs_len:][:, np.newaxis, :]), axis=2) 53 | return dist_rel 54 | 55 | 56 | def compute_interaction(theta_rel_orig, dist_rel, angle, dist_thresh, angle_range): 57 | ## Interaction is defined as 58 | ## 1. distance < threshold and 59 | ## 2. angle between velocity of pp and line joining pp to neighbours 60 | 61 | theta_rel = np.copy(theta_rel_orig) 62 | angle_low = (angle - angle_range) 63 | angle_high = (angle + angle_range) 64 | if (angle - angle_range) < 0: 65 | theta_rel[np.where(theta_rel > 180)] = theta_rel[np.where(theta_rel > 180)] - 360 66 | if (angle + angle_range) > 360: 67 | raise ValueError 68 | interaction_matrix = (angle_low < theta_rel) & (theta_rel <= angle_high) \ 69 | & (dist_rel < dist_thresh) & (theta_rel < 500) == 1 70 | print('interaction_matrix: ', interaction_matrix) 71 | return interaction_matrix 72 | 73 | def interaction_length(interaction_matrix, length=1): 74 | interaction_sum = np.sum(interaction_matrix, axis=0) 75 | return interaction_sum >= length 76 | 77 | def check_interaction(rows, pos_range=15, dist_thresh=5, choice='pos', \ 78 | pos_angle=0, vel_angle=0, vel_range=15, output='matrix', obs_len=9): 79 | 80 | path = rows[:, 0] 81 | neigh_path = rows[:, 1:] 82 | theta_interaction, _ = compute_theta_interaction(path, neigh_path, obs_len) 83 | vel_interaction, _ = compute_velocity_interaction(path, neigh_path, obs_len) 84 | dist_rel = compute_dist_rel(path, neigh_path, obs_len) 85 | 86 | ## str choice 87 | if choice == 'pos': 88 | interaction_matrix = compute_interaction(theta_interaction, dist_rel, \ 89 | pos_angle, dist_thresh, pos_range) 90 | chosen_interaction = theta_interaction 91 | 92 | elif choice == 'vel': 93 | interaction_matrix = compute_interaction(vel_interaction, dist_rel, \ 94 | vel_angle, dist_thresh, vel_range) 95 | chosen_interaction = vel_interaction 96 | 97 | elif choice == 'bothpos': 98 | pos_matrix = compute_interaction(theta_interaction, dist_rel, \ 99 | pos_angle, dist_thresh, pos_range) 100 | vel_matrix = compute_interaction(vel_interaction, dist_rel, \ 101 | vel_angle, dist_thresh, vel_range) 102 | interaction_matrix = pos_matrix & vel_matrix 103 | chosen_interaction = theta_interaction 104 | 105 | elif choice == 'bothvel': 106 | pos_matrix = compute_interaction(theta_interaction, dist_rel, \ 107 | pos_angle, dist_thresh, pos_range) 108 | vel_matrix = compute_interaction(vel_interaction, dist_rel, \ 109 | vel_angle, dist_thresh, vel_range) 110 | interaction_matrix = pos_matrix & vel_matrix 111 | chosen_interaction = vel_interaction 112 | else: 113 | raise NotImplementedError 114 | 115 | chosen_true = chosen_interaction[interaction_matrix] 116 | dist_true = dist_rel[interaction_matrix] 117 | 118 | if output == 'matrix': 119 | return interaction_matrix 120 | if output == 'all': 121 | return interaction_matrix, chosen_true, dist_true 122 | 123 | return np.any(interaction_matrix) 124 | 125 | def check_group(rows, dist_thresh=0.8, std_thresh=0.2, obs_len=9): 126 | ## Identify Groups 127 | ## dist_thresh: Distance threshold to be withinin a group 128 | ## std_thresh: Std deviation threshold for variation of distance 129 | 130 | path = rows[:, 0] 131 | neigh_path = rows[:, 1:] 132 | 133 | ## Horizontal Position 134 | interaction_matrix_1 = check_interaction(rows, pos_angle=90, pos_range=45, obs_len=obs_len) 135 | interaction_matrix_2 = check_interaction(rows, pos_angle=270, pos_range=45, obs_len=obs_len) 136 | neighs_side = np.any(interaction_matrix_1, axis=0) | np.any(interaction_matrix_2, axis=0) 137 | 138 | ## Distance Maintain 139 | dist_rel = np.linalg.norm((neigh_path - path[:, np.newaxis, :]), axis=2) 140 | mean_dist = np.mean(dist_rel, axis=0) 141 | std_dist = np.std(dist_rel, axis=0) 142 | 143 | group_matrix = (mean_dist < dist_thresh) & (std_dist < std_thresh) & neighs_side 144 | 145 | return group_matrix 146 | 147 | ##################################### 148 | ## Functions for Interaction types ## 149 | ##################################### 150 | 151 | ## Type 2 152 | def non_linear(scene, obs_len=9, pred_len=12): 153 | primary_prediction, _ = kalman.predict(scene, obs_len, pred_len)[0] 154 | score = metrics.final_l2(scene[0], primary_prediction) 155 | return score > 0.5, primary_prediction 156 | 157 | ## Type 3a 158 | def leader_follower(rows, pos_range=15, dist_thresh=5, obs_len=9): 159 | """ Identifying Leader Follower Behavior """ 160 | interaction_matrix = check_interaction(rows, pos_range=pos_range, dist_thresh=dist_thresh, 161 | choice='bothpos', obs_len=obs_len) 162 | interaction_index = interaction_length(interaction_matrix, length=5) 163 | return interaction_index 164 | 165 | ## Type 3b 166 | def collision_avoidance(rows, pos_range=15, dist_thresh=5, obs_len=9): 167 | """ Identifying Collision Avoidance Behavior """ 168 | interaction_matrix = check_interaction(rows, pos_range=pos_range, dist_thresh=dist_thresh, \ 169 | choice='bothpos', vel_angle=180, obs_len=obs_len) 170 | interaction_index = interaction_length(interaction_matrix, length=1) 171 | return interaction_index 172 | 173 | ## Type 3c 174 | def group(rows, dist_thresh=0.8, std_thresh=0.2, obs_len=9): 175 | """ Identifying Group Behavior """ 176 | # print("HERE") 177 | interaction_index = check_group(rows, dist_thresh, std_thresh, obs_len) 178 | return interaction_index 179 | 180 | ## Get Type 181 | def get_interaction_type(rows, pos_range=15, dist_thresh=5, obs_len=9): 182 | interaction_type = [] 183 | if np.any(leader_follower(rows, pos_range, dist_thresh, obs_len)): 184 | interaction_type.append(1) 185 | if np.any(collision_avoidance(rows, pos_range, dist_thresh, obs_len)): 186 | interaction_type.append(2) 187 | if np.any(group(rows, obs_len=obs_len)): 188 | interaction_type.append(3) 189 | if interaction_type == []: 190 | interaction_type.append(4) 191 | return interaction_type 192 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/get_type.py: -------------------------------------------------------------------------------- 1 | """ Categorization of Primary Pedestrian """ 2 | 3 | import numpy as np 4 | import pysparkling 5 | 6 | import trajnetplusplustools 7 | 8 | from .tools.writers import trajnet 9 | from .tools.reader import Reader 10 | from .tools.metrics import final_l2, collision 11 | from .tools.data import SceneRow 12 | from .tools.interactions import get_interaction_type 13 | import pickle 14 | from .orca_helper import predict_all 15 | 16 | def get_type(scene, args): 17 | ''' 18 | Categorization of Single Scene 19 | :param scene: All trajectories as TrackRows, args 20 | :return: The type of the traj 21 | ''' 22 | 23 | ## Get xy-coordinates from trackRows 24 | scene_xy = trajnetplusplustools.Reader.paths_to_xy(scene) 25 | 26 | ## Type 1 27 | def euclidean_distance(row1, row2): 28 | """Euclidean distance squared between two rows.""" 29 | return np.sqrt((row1.x - row2.x) ** 2 + (row1.y - row2.y) ** 2) 30 | 31 | ## Category Tags 32 | mult_tag = [] 33 | sub_tag = [] 34 | 35 | # Static 36 | if euclidean_distance(scene[0][0], scene[0][-1]) < args.static_threshold: 37 | mult_tag.append(1) 38 | 39 | 40 | # Non-Linear (No explainable reason) 41 | else: 42 | mult_tag.append(4) 43 | 44 | # Interaction Types 45 | if mult_tag[0] == 3: 46 | sub_tag = get_interaction_type(scene_xy, args.inter_pos_range, 47 | args.inter_dist_thresh, args.obs_len) 48 | else: 49 | sub_tag = [] 50 | 51 | return mult_tag[0], mult_tag, sub_tag 52 | 53 | def check_collision(scene, n_predictions): 54 | ''' 55 | Skip the track if collision occurs between primanry and others 56 | return: True if collision occurs 57 | ''' 58 | ped_interest = scene[0] 59 | for ped_other in scene[1:]: 60 | if collision(ped_interest, ped_other, n_predictions): 61 | return True 62 | return False 63 | 64 | def add_noise(observation): 65 | ## Last Position Noise 66 | # observation[0][-1] += np.random.uniform(0, 0.04, (2,)) 67 | 68 | ## Last Position Noise 69 | thresh = 0.005 ## 0.01 for num_ped 3 70 | observation += np.random.uniform(-thresh, thresh, observation.shape) 71 | return observation 72 | 73 | def orca_validity(scene, goals, pred_len=12, obs_len=9, mode='trajnet', iters=15): 74 | ''' 75 | Check ORCA can reconstruct scene on rounding (To clean in future) 76 | ''' 77 | scene_xy = Reader.paths_to_xy(scene) 78 | for _ in range(iters): 79 | observation = add_noise(scene_xy[:obs_len].copy()) 80 | orca_pred = predict_all(observation, goals, mode, pred_len) 81 | if len(orca_pred[0]) != pred_len: 82 | # print("Length Invalid") 83 | return True 84 | for m, _ in enumerate(orca_pred): 85 | if len(orca_pred[m]) != pred_len: 86 | continue 87 | diff_ade = np.mean(np.linalg.norm(np.array(scene_xy[-pred_len:, m]) - np.array(orca_pred[m]), axis=1)) 88 | diff_fde = np.linalg.norm(np.array(scene_xy[-1, m]) - np.array(orca_pred[m][-1])) 89 | if diff_ade > 0.11 or diff_fde > 0.2: ## (0.08, 0.1) for num_ped 3 90 | # print("ORCA Invalid") 91 | return True 92 | return False 93 | 94 | def all_ped_present(scene): 95 | """ 96 | Consider only those scenes where all pedestrians are present 97 | Note: Different from removing incomplete trajectories 98 | Useful for generating dataset for fast_parallel code: https://github.com/vita-epfl/trajnetplusplusbaselines/tree/fast_parallel 99 | """ 100 | scene_xy = Reader.paths_to_xy(scene) 101 | return (not np.isnan(scene_xy).any()) 102 | 103 | def write(rows, path, new_scenes, new_frames): 104 | """ Writing scenes with categories """ 105 | output_path = path.replace('output_pre', 'output') 106 | pysp_tracks = rows.filter(lambda r: r.frame in new_frames).map(trajnet) 107 | pysp_scenes = pysparkling.Context().parallelize(new_scenes).map(trajnet) 108 | pysp_scenes.union(pysp_tracks).saveAsTextFile(output_path) 109 | 110 | def trajectory_type(rows, path, fps, track_id=0, args=None): 111 | """ Categorization of all scenes """ 112 | 113 | ## Read 114 | reader = Reader(path, scene_type='paths') 115 | scenes = [s for _, s in reader.scenes()] 116 | ## Filtered Frames and Scenes 117 | new_frames = set() 118 | new_scenes = [] 119 | 120 | start_frames = set() 121 | ########################################################################### 122 | # scenes_test helps to handle both test and test_private simultaneously 123 | # scenes_test correspond to Test 124 | ########################################################################### 125 | test = 'test' in path 126 | if test: 127 | path_test = path.replace('test_private', 'test') 128 | reader_test = Reader(path_test, scene_type='paths') 129 | scenes_test = [s for _, s in reader_test.scenes()] 130 | ## Filtered Test Frames and Test Scenes 131 | new_frames_test = set() 132 | new_scenes_test = [] 133 | 134 | ## For ORCA (Sensitivity) 135 | orca_sensitivity = False 136 | if args.goal_file is not None: 137 | goal_dict = pickle.load(open(args.goal_file, "rb")) 138 | orca_sensitivity = True 139 | print("Checking sensitivity to initial conditions") 140 | 141 | ## Initialize Tag Stats to be collected 142 | tags = {1: [], 2: [], 3: [], 4: []} 143 | mult_tags = {1: [], 2: [], 3: [], 4: []} 144 | sub_tags = {1: [], 2: [], 3: [], 4: []} 145 | col_count = 0 146 | 147 | # if not scenes: 148 | # raise Exception('No scenes found') 149 | ## fix random seed to easily reproduce 150 | np.random.seed(0) 151 | 152 | for index, scene in enumerate(scenes): 153 | # if (index+1) % 50 == 0: 154 | # print(index) 155 | 156 | ## Primary Path 157 | ped_interest = scene[0] 158 | 159 | # if ped_interest[0].frame in start_frames: 160 | # # print("Got common start") 161 | # continue 162 | 163 | # Assert Test Scene length 164 | if test: 165 | assert len(scenes_test[index][0]) >= args.obs_len, \ 166 | 'Scene Test not adequate length' 167 | 168 | ## Check Collision 169 | ## Used in CFF Datasets to account for imperfect tracking 170 | # if check_collision(scene, args.pred_len): 171 | # col_count += 1 172 | # continue 173 | 174 | # ## Consider only those scenes where all pedestrians are present 175 | # # Note: Different from removing incomplete trajectories 176 | if args.all_present and (not all_ped_present(scene)): 177 | continue 178 | 179 | ## Get Tag 180 | tag, mult_tag, sub_tag = get_type(scene, args) 181 | 182 | if np.random.uniform() < args.acceptance[tag - 1]: 183 | ## Check Validity 184 | ## Used in ORCA Datasets to account for rounding sensitivity 185 | if orca_sensitivity: 186 | goals = [goal_dict[path[0].pedestrian] for path in scene] 187 | # print('Type III') 188 | if orca_validity(scene, goals, args.pred_len, args.obs_len, args.mode): 189 | col_count += 1 190 | continue 191 | 192 | ## Update Tags 193 | tags[tag].append(track_id) 194 | for tt in mult_tag: 195 | mult_tags[tt].append(track_id) 196 | for st in sub_tag: 197 | sub_tags[st].append(track_id) 198 | 199 | ## Define Scene_Tag 200 | scene_tag = [] 201 | scene_tag.append(tag) 202 | scene_tag.append(sub_tag) 203 | 204 | ## Filtered scenes and Frames 205 | # start_frames |= set(ped_interest[i].frame for i in range(len(ped_interest[0:1]))) 206 | # print(start_frames) 207 | new_frames |= set(ped_interest[i].frame for i in range(len(ped_interest))) 208 | new_scenes.append( 209 | SceneRow(track_id, ped_interest[0].pedestrian, 210 | ped_interest[0].frame, ped_interest[-1].frame, 211 | fps, scene_tag)) 212 | 213 | ## Append to list of scenes_test as well if Test Set 214 | if test: 215 | new_frames_test |= set(ped_interest[i].frame for i in range(args.obs_len)) 216 | new_scenes_test.append( 217 | SceneRow(track_id, ped_interest[0].pedestrian, 218 | ped_interest[0].frame, ped_interest[-1].frame, 219 | fps, 0)) 220 | 221 | track_id += 1 222 | 223 | 224 | # Writes the Final Scenes and Frames 225 | write(rows, path, new_scenes, new_frames) 226 | if test: 227 | write(rows, path_test, new_scenes_test, new_frames_test) 228 | 229 | ## Stats 230 | 231 | # Number of collisions found 232 | print("Col Count: ", col_count) 233 | 234 | if scenes: 235 | print("Total Scenes: ", index) 236 | 237 | # Types: 238 | print("Main Tags") 239 | print("Type 1: ", len(tags[1]), "Type 2: ", len(tags[2]), 240 | "Type 3: ", len(tags[3]), "Type 4: ", len(tags[4])) 241 | print("Sub Tags") 242 | print("LF: ", len(sub_tags[1]), "CA: ", len(sub_tags[2]), 243 | "Group: ", len(sub_tags[3]), "Others: ", len(sub_tags[4])) 244 | 245 | return track_id 246 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/build/lib/trajnetdataset/readers.py: -------------------------------------------------------------------------------- 1 | """ Read Raw files as TrackRows """ 2 | 3 | import json 4 | import os 5 | import xml.etree.ElementTree 6 | 7 | import numpy as np 8 | import scipy.interpolate 9 | 10 | from trajnetplusplustools import TrackRow 11 | 12 | def jta(line): 13 | line = [e for e in line.split(',') if e != ''] 14 | return TrackRow(int(float(line[0])), 15 | int(float(line[1])), 16 | float(line[2]), 17 | float(line[3])) 18 | 19 | def biwi(line): 20 | line = [e for e in line.split(' ') if e != ''] 21 | return TrackRow(int(float(line[0]) - 1), # shift from 1-index to 0-index 22 | int(float(line[1])), 23 | float(line[2]), 24 | float(line[4])) 25 | 26 | def crowds_interpolate_person(ped_id, person_xyf): 27 | ## Earlier 28 | # xs = np.array([x for x, _, _ in person_xyf]) / 720 * 12 # 0.0167 29 | # ys = np.array([y for _, y, _ in person_xyf]) / 576 * 12 # 0.0208 30 | 31 | ## Pixel-to-meter scale conversion according to 32 | ## https://github.com/agrimgupta92/sgan/issues/5 33 | xs = np.array([x for x, _, _ in person_xyf]) * 0.0210 34 | ys = np.array([y for _, y, _ in person_xyf]) * 0.0239 35 | 36 | fs = np.array([f for _, _, f in person_xyf]) 37 | 38 | kind = 'linear' 39 | if len(fs) > 5: 40 | kind = 'cubic' 41 | 42 | x_fn = scipy.interpolate.interp1d(fs, xs, kind=kind) 43 | y_fn = scipy.interpolate.interp1d(fs, ys, kind=kind) 44 | 45 | frames = np.arange(min(fs) // 10 * 10 + 10, max(fs), 10) 46 | return [TrackRow(int(f), ped_id, x, y) 47 | for x, y, f in np.stack([x_fn(frames), y_fn(frames), frames]).T] 48 | 49 | 50 | def crowds(whole_file): 51 | pedestrians = [] 52 | current_pedestrian = [] 53 | for line in whole_file.split('\n'): 54 | if '- Num of control points' in line or \ 55 | '- the number of splines' in line: 56 | if current_pedestrian: 57 | pedestrians.append(current_pedestrian) 58 | current_pedestrian = [] 59 | continue 60 | 61 | # strip comments 62 | if ' - ' in line: 63 | line = line[:line.find(' - ')] 64 | 65 | # tokenize 66 | entries = [e for e in line.split(' ') if e] 67 | if len(entries) != 4: 68 | continue 69 | 70 | x, y, f, _ = entries 71 | current_pedestrian.append([float(x), float(y), int(f)]) 72 | 73 | if current_pedestrian: 74 | pedestrians.append(current_pedestrian) 75 | 76 | return [row 77 | for i, p in enumerate(pedestrians) 78 | for row in crowds_interpolate_person(i, p)] 79 | 80 | 81 | def mot_xml(file_name): 82 | """PETS2009 dataset. 83 | 84 | Original frame rate is 7 frames / sec. 85 | """ 86 | tree = xml.etree.ElementTree.parse(file_name) 87 | root = tree.getroot() 88 | for frame in root: 89 | f = int(frame.attrib['number']) 90 | if f % 2 != 0: # reduce to 3.5 rows / sec 91 | continue 92 | 93 | for ped in frame.find('objectlist'): 94 | p = ped.attrib['id'] 95 | box = ped.find('box') 96 | x = box.attrib['xc'] 97 | y = box.attrib['yc'] 98 | 99 | yield TrackRow(f, int(p), float(x) / 100.0, float(y) / 100.0) 100 | 101 | 102 | def mot(line): 103 | """Line reader for MOT files. 104 | 105 | MOT format: 106 | , , , , , , , , , 107 | """ 108 | line = [e for e in line.split(',') if e != ''] 109 | return TrackRow(int(float(line[0])), 110 | int(float(line[1])), 111 | float(line[7]), 112 | float(line[8])) 113 | 114 | 115 | def edinburgh(filename_content_index): 116 | """Edinburgh Informatics Forum data reader. 117 | 118 | Original frame rate is 9fps. 119 | Every pixel corresponds to 24.7mm. 120 | http://homepages.inf.ed.ac.uk/rbf/FORUMTRACKING/ 121 | """ 122 | (_, whole_file), index = filename_content_index 123 | 124 | for line in whole_file.splitlines(): 125 | line = line.strip() 126 | if not line.startswith('TRACK.R'): 127 | continue 128 | 129 | # get to track id 130 | line = line[7:] 131 | track_id, _, coordinates = line.partition('=') 132 | track_id = int(track_id) + index * 1000000 133 | 134 | # parse track 135 | for coordinates in coordinates.split(';'): 136 | if not coordinates: 137 | continue 138 | x, y, frame = coordinates.strip('[] ').split(' ') 139 | frame = int(frame) + index * 1000000 140 | if frame % 3 != 0: # downsample frame rate 141 | continue 142 | yield TrackRow(frame, track_id, float(x) * 0.0247, float(y) * 0.0247) 143 | 144 | 145 | def syi(filename_content): 146 | """Tracking dataset in Grand Central. 147 | 148 | Yi_Pedestrian_Travel_Time_ICCV_2015_paper.pdf states that original 149 | frame rate is 25fps. 150 | 151 | Input rows are sampled every 20 frames. Assuming 25fps at recording, 152 | need to interpolate an additional row to get to 2.5 rows per second. 153 | """ 154 | filename, whole_file = filename_content 155 | track_id = int(os.path.basename(filename).replace('.txt', '')) 156 | 157 | chunk = [] 158 | last_row = None 159 | for line in whole_file.split('\n'): 160 | if not line: 161 | continue 162 | chunk.append(int(line)) 163 | if len(chunk) < 3: 164 | continue 165 | 166 | # rough approximation of mapping to world coordinates (main concourse is 37m x 84m) 167 | new_row = TrackRow(chunk[2], track_id, chunk[0] * 30.0 / 1920, chunk[1] * 70.0 / 1080) 168 | 169 | # interpolate one row to increase frame rate 170 | if last_row is not None: 171 | interpolated_row = TrackRow( 172 | int((last_row.frame + new_row.frame) / 2), 173 | track_id, 174 | (last_row.x + new_row.x) / 2, 175 | (last_row.y + new_row.y) / 2, 176 | ) 177 | yield interpolated_row 178 | 179 | yield new_row 180 | chunk = [] 181 | last_row = new_row 182 | 183 | 184 | def dukemtmc(input_array, query_camera=5): 185 | """DukeMTMC dataset. 186 | 187 | Recorded at 59.940059 fps. 188 | 189 | Line format: 190 | [camera, ID, frame, left, top, width, height, worldX, worldY, feetX, feetyY] 191 | """ 192 | for line in input_array: 193 | camera, person, frame, _, _, _, _, world_x, world_y, _, _ = line 194 | 195 | camera = int(camera) 196 | if camera != query_camera: 197 | continue 198 | 199 | frame = int(frame) 200 | if frame % 24 != 0: 201 | continue 202 | 203 | yield TrackRow(frame, int(person), world_x, world_y) 204 | 205 | 206 | def wildtrack(filename_content): 207 | filename, content = filename_content 208 | 209 | frame = int(os.path.basename(filename).replace('.json', '')) 210 | for entry in json.loads(content): 211 | ped_id = entry['personID'] 212 | position_id = entry['positionID'] 213 | 214 | x = -3.0 + 0.025 * (position_id % 480) 215 | y = -9.0 + 0.025 * (position_id / 480) 216 | 217 | yield TrackRow(frame, ped_id, x, y) 218 | 219 | 220 | def trajnet_original(line): 221 | line = [e for e in line.split(' ') if e != ''] 222 | return TrackRow(int(float(line[0])), 223 | int(float(line[1])), 224 | float(line[2]), 225 | float(line[3])) 226 | 227 | def cff(line): 228 | line = [e for e in line.split(';') if e != ''] 229 | 230 | ## Time Stamp 231 | time = [t for t in line[0].split(':') if t != ''] 232 | 233 | ## Check Line Entry Valid 234 | if len(line) != 5: 235 | return None 236 | 237 | ## Check Time Entry Valid 238 | if len(time) != 4: 239 | return None 240 | 241 | ## Check Location 242 | if line[1] != 'PIW': 243 | return None 244 | 245 | ## Check Time Format 246 | if time[0][-3:] == 'T07': 247 | ped_id = int(line[4]) 248 | f = 0 249 | elif time[0][-3:] == 'T17': 250 | ped_id = 100000 + int(line[4]) 251 | f = 100000 252 | else: 253 | # "Time Format Incorrect" 254 | return None 255 | 256 | ## Extract Frame 257 | f += int(time[-3])*1000 + int(time[-2])*10 + int(time[-1][0]) 258 | 259 | if f % 4 == 0: 260 | return TrackRow(f, # shift from 1-index to 0-index 261 | ped_id, 262 | float(line[2])/1000, 263 | float(line[3])/1000) 264 | return None 265 | 266 | 267 | def lcas(line): 268 | line = [e for e in line.split(',') if e != ''] 269 | return TrackRow(int(float(line[0])), 270 | int(float(line[1])), 271 | float(line[2]), 272 | float(line[3])) 273 | 274 | def controlled(line): 275 | line = [e for e in line.split(', ') if e != ''] 276 | return TrackRow(int(float(line[0])), 277 | int(float(line[1])), 278 | float(line[2]), 279 | float(line[3])) 280 | 281 | def get_trackrows(line): 282 | line = json.loads(line) 283 | track = line.get('track') 284 | if track is not None: 285 | return TrackRow(track['f'], track['p'], track['x'], track['y'], 286 | track.get('prediction_number')) 287 | return None 288 | 289 | def standard(line): 290 | line = [e for e in line.split('\t') if e != ''] 291 | return TrackRow(int(float(line[0])), 292 | int(float(line[1])), 293 | float(line[2]), 294 | float(line[3])) 295 | 296 | def car_data(filename_content): 297 | frame_id = int(filename_content[0].split('.')[0].split('/')[-1]) 298 | ratio = 5.0 / 162 ## 162 pix = 5 m 299 | lines = filename_content[1].split('\n') 300 | ## First Line: ID, Front1x, Front1y, Front2x, Front2y, Back1x, Back1y, Back2x, Back2y, Type, Occlusion 301 | assert lines[0] == 'ID,Front1x,Front1y,Front2x,Front2y,Back1x,Back1y,Back2x,Back2y,Type,Occlusion' 302 | ## Last Line: "" 303 | assert lines[-1] == '' 304 | 305 | for line in lines[1:-1]: 306 | id_, F1x, F1y, F2x, F2y, B1x, B1y, B2x, B2y, type_, occ = line.split(',') 307 | 308 | if int(type_) != 2: 309 | continue 310 | 311 | if int(frame_id) % 12 != 0: 312 | continue 313 | 314 | yield TrackRow(frame_id, int(id_), ratio * float(F1x), ratio * float(F1y)) -------------------------------------------------------------------------------- /trajnetplusplusdataset/build/lib/trajnetdataset/get_type.py: -------------------------------------------------------------------------------- 1 | """ Categorization of Primary Pedestrian """ 2 | 3 | import numpy as np 4 | import pysparkling 5 | 6 | import trajnetplusplustools 7 | from trajnetplusplustools.kalman import predict as kalman_predict 8 | from trajnetplusplustools.interactions import check_interaction, group 9 | from trajnetplusplustools.interactions import get_interaction_type 10 | 11 | import pickle 12 | from .orca_helper import predict_all 13 | 14 | def get_type(scene, args): 15 | ''' 16 | Categorization of Single Scene 17 | :param scene: All trajectories as TrackRows, args 18 | :return: The type of the traj 19 | ''' 20 | 21 | ## Get xy-coordinates from trackRows 22 | scene_xy = trajnetplusplustools.Reader.paths_to_xy(scene) 23 | 24 | ## Type 1 25 | def euclidean_distance(row1, row2): 26 | """Euclidean distance squared between two rows.""" 27 | return np.sqrt((row1.x - row2.x) ** 2 + (row1.y - row2.y) ** 2) 28 | 29 | ## Type 2 30 | def linear_system(scene, obs_len, pred_len): 31 | ''' 32 | return: True if the traj is linear according to Kalman 33 | ''' 34 | kalman_prediction, _ = kalman_predict(scene, obs_len, pred_len)[0] 35 | return trajnetplusplustools.metrics.final_l2(scene[0], kalman_prediction) 36 | 37 | ## Type 3 38 | def interaction(rows, pos_range, dist_thresh, obs_len): 39 | ''' 40 | :return: Determine if interaction exists and type (optionally) 41 | ''' 42 | interaction_matrix = check_interaction(rows, pos_range=pos_range, \ 43 | dist_thresh=dist_thresh, obs_len=obs_len) 44 | return np.any(interaction_matrix) 45 | 46 | ## Category Tags 47 | mult_tag = [] 48 | sub_tag = [] 49 | 50 | # Static 51 | if euclidean_distance(scene[0][0], scene[0][-1]) < args.static_threshold: 52 | mult_tag.append(1) 53 | 54 | # Linear 55 | elif linear_system(scene, args.obs_len, args.pred_len) < args.linear_threshold: 56 | mult_tag.append(2) 57 | 58 | # Interactions 59 | elif interaction(scene_xy, args.inter_pos_range, args.inter_dist_thresh, args.obs_len) \ 60 | or np.any(group(scene_xy, args.grp_dist_thresh, args.grp_std_thresh, args.obs_len)): 61 | mult_tag.append(3) 62 | 63 | # Non-Linear (No explainable reason) 64 | else: 65 | mult_tag.append(4) 66 | 67 | # Interaction Types 68 | if mult_tag[0] == 3: 69 | sub_tag = get_interaction_type(scene_xy, args.inter_pos_range, 70 | args.inter_dist_thresh, args.obs_len) 71 | else: 72 | sub_tag = [] 73 | 74 | return mult_tag[0], mult_tag, sub_tag 75 | 76 | def check_collision(scene, n_predictions): 77 | ''' 78 | Skip the track if collision occurs between primanry and others 79 | return: True if collision occurs 80 | ''' 81 | ped_interest = scene[0] 82 | for ped_other in scene[1:]: 83 | if trajnetplusplustools.metrics.collision(ped_interest, ped_other, n_predictions): 84 | return True 85 | return False 86 | 87 | def add_noise(observation): 88 | ## Last Position Noise 89 | # observation[0][-1] += np.random.uniform(0, 0.04, (2,)) 90 | 91 | ## Last Position Noise 92 | thresh = 0.005 ## 0.01 for num_ped 3 93 | observation += np.random.uniform(-thresh, thresh, observation.shape) 94 | return observation 95 | 96 | def orca_validity(scene, goals, pred_len=12, obs_len=9, mode='trajnet', iters=15): 97 | ''' 98 | Check ORCA can reconstruct scene on rounding (To clean in future) 99 | ''' 100 | scene_xy = trajnetplusplustools.Reader.paths_to_xy(scene) 101 | for _ in range(iters): 102 | observation = add_noise(scene_xy[:obs_len].copy()) 103 | orca_pred = predict_all(observation, goals, mode, pred_len) 104 | if len(orca_pred[0]) != pred_len: 105 | # print("Length Invalid") 106 | return True 107 | for m, _ in enumerate(orca_pred): 108 | if len(orca_pred[m]) != pred_len: 109 | continue 110 | diff_ade = np.mean(np.linalg.norm(np.array(scene_xy[-pred_len:, m]) - np.array(orca_pred[m]), axis=1)) 111 | diff_fde = np.linalg.norm(np.array(scene_xy[-1, m]) - np.array(orca_pred[m][-1])) 112 | if diff_ade > 0.11 or diff_fde > 0.2: ## (0.08, 0.1) for num_ped 3 113 | # print("ORCA Invalid") 114 | return True 115 | return False 116 | 117 | def all_ped_present(scene): 118 | """ 119 | Consider only those scenes where all pedestrians are present 120 | Note: Different from removing incomplete trajectories 121 | Useful for generating dataset for fast_parallel code: https://github.com/vita-epfl/trajnetplusplusbaselines/tree/fast_parallel 122 | """ 123 | scene_xy = trajnetplusplustools.Reader.paths_to_xy(scene) 124 | return (not np.isnan(scene_xy).any()) 125 | 126 | def write(rows, path, new_scenes, new_frames): 127 | """ Writing scenes with categories """ 128 | output_path = path.replace('output_pre', 'output') 129 | pysp_tracks = rows.filter(lambda r: r.frame in new_frames).map(trajnetplusplustools.writers.trajnet) 130 | pysp_scenes = pysparkling.Context().parallelize(new_scenes).map(trajnetplusplustools.writers.trajnet) 131 | pysp_scenes.union(pysp_tracks).saveAsTextFile(output_path) 132 | 133 | def trajectory_type(rows, path, fps, track_id=0, args=None): 134 | """ Categorization of all scenes """ 135 | 136 | ## Read 137 | reader = trajnetplusplustools.Reader(path, scene_type='paths') 138 | scenes = [s for _, s in reader.scenes()] 139 | ## Filtered Frames and Scenes 140 | new_frames = set() 141 | new_scenes = [] 142 | 143 | start_frames = set() 144 | ########################################################################### 145 | # scenes_test helps to handle both test and test_private simultaneously 146 | # scenes_test correspond to Test 147 | ########################################################################### 148 | test = 'test' in path 149 | if test: 150 | path_test = path.replace('test_private', 'test') 151 | reader_test = trajnetplusplustools.Reader(path_test, scene_type='paths') 152 | scenes_test = [s for _, s in reader_test.scenes()] 153 | ## Filtered Test Frames and Test Scenes 154 | new_frames_test = set() 155 | new_scenes_test = [] 156 | 157 | ## For ORCA (Sensitivity) 158 | orca_sensitivity = False 159 | if args.goal_file is not None: 160 | goal_dict = pickle.load(open(args.goal_file, "rb")) 161 | orca_sensitivity = True 162 | print("Checking sensitivity to initial conditions") 163 | 164 | ## Initialize Tag Stats to be collected 165 | tags = {1: [], 2: [], 3: [], 4: []} 166 | mult_tags = {1: [], 2: [], 3: [], 4: []} 167 | sub_tags = {1: [], 2: [], 3: [], 4: []} 168 | col_count = 0 169 | 170 | if not scenes: 171 | raise Exception('No scenes found') 172 | 173 | for index, scene in enumerate(scenes): 174 | # if (index+1) % 50 == 0: 175 | # print(index) 176 | 177 | ## Primary Path 178 | ped_interest = scene[0] 179 | 180 | # if ped_interest[0].frame in start_frames: 181 | # # print("Got common start") 182 | # continue 183 | 184 | # Assert Test Scene length 185 | if test: 186 | assert len(scenes_test[index][0]) >= args.obs_len, \ 187 | 'Scene Test not adequate length' 188 | 189 | ## Check Collision 190 | ## Used in CFF Datasets to account for imperfect tracking 191 | # if check_collision(scene, args.pred_len): 192 | # col_count += 1 193 | # continue 194 | 195 | # ## Consider only those scenes where all pedestrians are present 196 | # # Note: Different from removing incomplete trajectories 197 | if args.all_present and (not all_ped_present(scene)): 198 | continue 199 | 200 | ## Get Tag 201 | tag, mult_tag, sub_tag = get_type(scene, args) 202 | 203 | if np.random.uniform() < args.acceptance[tag - 1]: 204 | ## Check Validity 205 | ## Used in ORCA Datasets to account for rounding sensitivity 206 | if orca_sensitivity: 207 | goals = [goal_dict[path[0].pedestrian] for path in scene] 208 | # print('Type III') 209 | if orca_validity(scene, goals, args.pred_len, args.obs_len, args.mode): 210 | col_count += 1 211 | continue 212 | 213 | ## Update Tags 214 | tags[tag].append(track_id) 215 | for tt in mult_tag: 216 | mult_tags[tt].append(track_id) 217 | for st in sub_tag: 218 | sub_tags[st].append(track_id) 219 | 220 | ## Define Scene_Tag 221 | scene_tag = [] 222 | scene_tag.append(tag) 223 | scene_tag.append(sub_tag) 224 | 225 | ## Filtered scenes and Frames 226 | # start_frames |= set(ped_interest[i].frame for i in range(len(ped_interest[0:1]))) 227 | # print(start_frames) 228 | new_frames |= set(ped_interest[i].frame for i in range(len(ped_interest))) 229 | new_scenes.append( 230 | trajnetplusplustools.data.SceneRow(track_id, ped_interest[0].pedestrian, 231 | ped_interest[0].frame, ped_interest[-1].frame, 232 | fps, scene_tag)) 233 | 234 | ## Append to list of scenes_test as well if Test Set 235 | if test: 236 | new_frames_test |= set(ped_interest[i].frame for i in range(args.obs_len)) 237 | new_scenes_test.append( 238 | trajnetplusplustools.data.SceneRow(track_id, ped_interest[0].pedestrian, 239 | ped_interest[0].frame, ped_interest[-1].frame, 240 | fps, 0)) 241 | 242 | track_id += 1 243 | 244 | 245 | # Writes the Final Scenes and Frames 246 | write(rows, path, new_scenes, new_frames) 247 | if test: 248 | write(rows, path_test, new_scenes_test, new_frames_test) 249 | 250 | ## Stats 251 | 252 | # Number of collisions found 253 | print("Col Count: ", col_count) 254 | 255 | if scenes: 256 | print("Total Scenes: ", index) 257 | 258 | # Types: 259 | print("Main Tags") 260 | print("Type 1: ", len(tags[1]), "Type 2: ", len(tags[2]), 261 | "Type 3: ", len(tags[3]), "Type 4: ", len(tags[4])) 262 | print("Sub Tags") 263 | print("LF: ", len(sub_tags[1]), "CA: ", len(sub_tags[2]), 264 | "Group: ", len(sub_tags[3]), "Others: ", len(sub_tags[4])) 265 | 266 | return track_id 267 | -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/readers.py: -------------------------------------------------------------------------------- 1 | """ Read Raw files as TrackRows """ 2 | 3 | import json 4 | import os 5 | import xml.etree.ElementTree 6 | 7 | import numpy as np 8 | import scipy.interpolate 9 | 10 | from .tools.data import TrackRow 11 | def jrdb(line): 12 | line = [e for e in line.split(',') if e != ''] 13 | 14 | return TrackRow(int(float(line[0])), 15 | int(float(line[1])), 16 | float(line[2]),float(line[3]),float(line[4])) 17 | 18 | 19 | def biwi(line): 20 | line = [e for e in line.split(' ') if e != ''] 21 | return TrackRow(int(float(line[0]) - 1), # shift from 1-index to 0-index 22 | int(float(line[1])), 23 | float(line[2]), 24 | float(line[4])) 25 | 26 | def crowds_interpolate_person(ped_id, person_xyf): 27 | ## Earlier 28 | # xs = np.array([x for x, _, _ in person_xyf]) / 720 * 12 # 0.0167 29 | # ys = np.array([y for _, y, _ in person_xyf]) / 576 * 12 # 0.0208 30 | 31 | ## Pixel-to-meter scale conversion according to 32 | ## https://github.com/agrimgupta92/sgan/issues/5 33 | xs = np.array([x for x, _, _ in person_xyf]) * 0.0210 34 | ys = np.array([y for _, y, _ in person_xyf]) * 0.0239 35 | 36 | fs = np.array([f for _, _, f in person_xyf]) 37 | 38 | kind = 'linear' 39 | if len(fs) > 5: 40 | kind = 'cubic' 41 | 42 | x_fn = scipy.interpolate.interp1d(fs, xs, kind=kind) 43 | y_fn = scipy.interpolate.interp1d(fs, ys, kind=kind) 44 | 45 | frames = np.arange(min(fs) // 10 * 10 + 10, max(fs), 10) 46 | return [TrackRow(int(f), ped_id, x, y) 47 | for x, y, f in np.stack([x_fn(frames), y_fn(frames), frames]).T] 48 | 49 | 50 | def crowds(whole_file): 51 | pedestrians = [] 52 | current_pedestrian = [] 53 | for line in whole_file.split('\n'): 54 | if '- Num of control points' in line or \ 55 | '- the number of splines' in line: 56 | if current_pedestrian: 57 | pedestrians.append(current_pedestrian) 58 | current_pedestrian = [] 59 | continue 60 | 61 | # strip comments 62 | if ' - ' in line: 63 | line = line[:line.find(' - ')] 64 | 65 | # tokenize 66 | entries = [e for e in line.split(' ') if e] 67 | if len(entries) != 4: 68 | continue 69 | 70 | x, y, f, _ = entries 71 | current_pedestrian.append([float(x), float(y), int(f)]) 72 | 73 | if current_pedestrian: 74 | pedestrians.append(current_pedestrian) 75 | 76 | return [row 77 | for i, p in enumerate(pedestrians) 78 | for row in crowds_interpolate_person(i, p)] 79 | 80 | 81 | def mot_xml(file_name): 82 | """PETS2009 dataset. 83 | 84 | Original frame rate is 7 frames / sec. 85 | """ 86 | tree = xml.etree.ElementTree.parse(file_name) 87 | root = tree.getroot() 88 | for frame in root: 89 | f = int(frame.attrib['number']) 90 | if f % 2 != 0: # reduce to 3.5 rows / sec 91 | continue 92 | 93 | for ped in frame.find('objectlist'): 94 | p = ped.attrib['id'] 95 | box = ped.find('box') 96 | x = box.attrib['xc'] 97 | y = box.attrib['yc'] 98 | 99 | yield TrackRow(f, int(p), float(x) / 100.0, float(y) / 100.0) 100 | 101 | 102 | def mot(line): 103 | """Line reader for MOT files. 104 | 105 | MOT format: 106 | , , , , , , , , , 107 | """ 108 | line = [e for e in line.split(',') if e != ''] 109 | return TrackRow(int(float(line[0])), 110 | int(float(line[1])), 111 | float(line[7]), 112 | float(line[8])) 113 | 114 | 115 | def edinburgh(filename_content_index): 116 | """Edinburgh Informatics Forum data reader. 117 | 118 | Original frame rate is 9fps. 119 | Every pixel corresponds to 24.7mm. 120 | http://homepages.inf.ed.ac.uk/rbf/FORUMTRACKING/ 121 | """ 122 | (_, whole_file), index = filename_content_index 123 | 124 | for line in whole_file.splitlines(): 125 | line = line.strip() 126 | if not line.startswith('TRACK.R'): 127 | continue 128 | 129 | # get to track id 130 | line = line[7:] 131 | track_id, _, coordinates = line.partition('=') 132 | track_id = int(track_id) + index * 1000000 133 | 134 | # parse track 135 | for coordinates in coordinates.split(';'): 136 | if not coordinates: 137 | continue 138 | x, y, frame = coordinates.strip('[] ').split(' ') 139 | frame = int(frame) + index * 1000000 140 | if frame % 3 != 0: # downsample frame rate 141 | continue 142 | yield TrackRow(frame, track_id, float(x) * 0.0247, float(y) * 0.0247) 143 | 144 | 145 | def syi(filename_content): 146 | """Tracking dataset in Grand Central. 147 | 148 | Yi_Pedestrian_Travel_Time_ICCV_2015_paper.pdf states that original 149 | frame rate is 25fps. 150 | 151 | Input rows are sampled every 20 frames. Assuming 25fps at recording, 152 | need to interpolate an additional row to get to 2.5 rows per second. 153 | """ 154 | filename, whole_file = filename_content 155 | track_id = int(os.path.basename(filename).replace('.txt', '')) 156 | 157 | chunk = [] 158 | last_row = None 159 | for line in whole_file.split('\n'): 160 | if not line: 161 | continue 162 | chunk.append(int(line)) 163 | if len(chunk) < 3: 164 | continue 165 | 166 | # rough approximation of mapping to world coordinates (main concourse is 37m x 84m) 167 | new_row = TrackRow(chunk[2], track_id, chunk[0] * 30.0 / 1920, chunk[1] * 70.0 / 1080) 168 | 169 | # interpolate one row to increase frame rate 170 | if last_row is not None: 171 | interpolated_row = TrackRow( 172 | int((last_row.frame + new_row.frame) / 2), 173 | track_id, 174 | (last_row.x + new_row.x) / 2, 175 | (last_row.y + new_row.y) / 2, 176 | ) 177 | yield interpolated_row 178 | 179 | yield new_row 180 | chunk = [] 181 | last_row = new_row 182 | 183 | 184 | def dukemtmc(input_array, query_camera=5): 185 | """DukeMTMC dataset. 186 | 187 | Recorded at 59.940059 fps. 188 | 189 | Line format: 190 | [camera, ID, frame, left, top, width, height, worldX, worldY, feetX, feetyY] 191 | """ 192 | for line in input_array: 193 | camera, person, frame, _, _, _, _, world_x, world_y, _, _ = line 194 | 195 | camera = int(camera) 196 | if camera != query_camera: 197 | continue 198 | 199 | frame = int(frame) 200 | if frame % 24 != 0: 201 | continue 202 | 203 | yield TrackRow(frame, int(person), world_x, world_y) 204 | 205 | 206 | def wildtrack(filename_content): 207 | filename, content = filename_content 208 | 209 | frame = int(os.path.basename(filename).replace('.json', '')) 210 | for entry in json.loads(content): 211 | ped_id = entry['personID'] 212 | position_id = entry['positionID'] 213 | 214 | x = -3.0 + 0.025 * (position_id % 480) 215 | y = -9.0 + 0.025 * (position_id / 480) 216 | 217 | yield TrackRow(frame, ped_id, x, y) 218 | 219 | 220 | def trajnet_original(line): 221 | line = [e for e in line.split(' ') if e != ''] 222 | return TrackRow(int(float(line[0])), 223 | int(float(line[1])), 224 | float(line[2]), 225 | float(line[3])) 226 | 227 | def cff(line): 228 | line = [e for e in line.split(';') if e != ''] 229 | 230 | ## Time Stamp 231 | time = [t for t in line[0].split(':') if t != ''] 232 | 233 | ## Check Line Entry Valid 234 | if len(line) != 5: 235 | return None 236 | 237 | ## Check Time Entry Valid 238 | if len(time) != 4: 239 | return None 240 | 241 | ## Check Location 242 | if line[1] != 'PIW': 243 | return None 244 | 245 | ## Check Time Format 246 | if time[0][-3:] == 'T07': 247 | ped_id = int(line[4]) 248 | f = 0 249 | elif time[0][-3:] == 'T17': 250 | ped_id = 100000 + int(line[4]) 251 | f = 100000 252 | else: 253 | # "Time Format Incorrect" 254 | return None 255 | 256 | ## Extract Frame 257 | f += int(time[-3])*1000 + int(time[-2])*10 + int(time[-1][0]) 258 | 259 | if f % 4 == 0: 260 | return TrackRow(f, # shift from 1-index to 0-index 261 | ped_id, 262 | float(line[2])/1000, 263 | float(line[3])/1000) 264 | return None 265 | 266 | 267 | def lcas(line): 268 | line = [e for e in line.split(',') if e != ''] 269 | return TrackRow(int(float(line[0])), 270 | int(float(line[1])), 271 | float(line[2]), 272 | float(line[3])) 273 | 274 | def controlled(line): 275 | line = [e for e in line.split(', ') if e != ''] 276 | return TrackRow(int(float(line[0])), 277 | int(float(line[1])), 278 | float(line[2]), 279 | float(line[3])) 280 | 281 | def get_trackrows(line): 282 | line = json.loads(line) 283 | track = line.get('track') 284 | if track is not None: 285 | return TrackRow(track['f'], track['p'], track['x'], track['y'], track['v'], 286 | # track['h'], track['w'], track['l'], track['rot_z'], 287 | # track['bb_left'], track['bb_top'], track['bb_width'], track['bb_height'], 288 | track.get('prediction_number')) 289 | return None 290 | 291 | def standard(line): 292 | line = [e for e in line.split('\t') if e != ''] 293 | return TrackRow(int(float(line[0])), 294 | int(float(line[1])), 295 | float(line[2]), 296 | float(line[3])) 297 | 298 | def car_data(filename_content): 299 | frame_id = int(filename_content[0].split('.')[0].split('/')[-1]) 300 | ratio = 5.0 / 162 ## 162 pix = 5 m 301 | lines = filename_content[1].split('\n') 302 | ## First Line: ID, Front1x, Front1y, Front2x, Front2y, Back1x, Back1y, Back2x, Back2y, Type, Occlusion 303 | assert lines[0] == 'ID,Front1x,Front1y,Front2x,Front2y,Back1x,Back1y,Back2x,Back2y,Type,Occlusion' 304 | ## Last Line: "" 305 | assert lines[-1] == '' 306 | 307 | for line in lines[1:-1]: 308 | id_, F1x, F1y, F2x, F2y, B1x, B1y, B2x, B2y, type_, occ = line.split(',') 309 | 310 | if int(type_) != 2: 311 | continue 312 | 313 | if int(frame_id) % 12 != 0: 314 | continue 315 | 316 | yield TrackRow(frame_id, int(id_), ratio * float(F1x), ratio * float(F1y)) -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/convert_train.py: -------------------------------------------------------------------------------- 1 | """Create Trajnet data from original datasets.""" 2 | import argparse 3 | import shutil 4 | 5 | import pysparkling 6 | import scipy.io 7 | 8 | from . import readers 9 | from .scene import Scenes 10 | from .get_type import trajectory_type 11 | 12 | import warnings 13 | warnings.filterwarnings("ignore") 14 | 15 | def jrdb(sc, input_file): 16 | print('processing ' + input_file) 17 | 18 | return (sc 19 | .textFile(input_file) 20 | .map(readers.jrdb) 21 | .cache()) 22 | 23 | 24 | def biwi(sc, input_file): 25 | print('processing ' + input_file) 26 | return (sc 27 | .textFile(input_file) 28 | .map(readers.biwi) 29 | .cache()) 30 | 31 | 32 | def crowds(sc, input_file): 33 | print('processing ' + input_file) 34 | return (sc 35 | .wholeTextFiles(input_file) 36 | .values() 37 | .flatMap(readers.crowds) 38 | .cache()) 39 | 40 | 41 | def mot(sc, input_file): 42 | """Was 7 frames per second in original recording.""" 43 | print('processing ' + input_file) 44 | return (sc 45 | .textFile(input_file) 46 | .map(readers.mot) 47 | .filter(lambda r: r.frame % 2 == 0) 48 | .cache()) 49 | 50 | 51 | def edinburgh(sc, input_file): 52 | print('processing ' + input_file) 53 | return (sc 54 | .wholeTextFiles(input_file) 55 | .zipWithIndex() 56 | .flatMap(readers.edinburgh) 57 | .cache()) 58 | 59 | 60 | def syi(sc, input_file): 61 | print('processing ' + input_file) 62 | return (sc 63 | .wholeTextFiles(input_file) 64 | .flatMap(readers.syi) 65 | .cache()) 66 | 67 | 68 | def dukemtmc(sc, input_file): 69 | print('processing ' + input_file) 70 | contents = scipy.io.loadmat(input_file)['trainData'] 71 | return (sc 72 | .parallelize(readers.dukemtmc(contents)) 73 | .cache()) 74 | 75 | 76 | def wildtrack(sc, input_file): 77 | print('processing ' + input_file) 78 | return (sc 79 | .wholeTextFiles(input_file) 80 | .flatMap(readers.wildtrack) 81 | .cache()) 82 | 83 | def cff(sc, input_file): 84 | print('processing ' + input_file) 85 | return (sc 86 | .textFile(input_file) 87 | .map(readers.cff) 88 | .filter(lambda r: r is not None) 89 | .cache()) 90 | 91 | def lcas(sc, input_file): 92 | print('processing ' + input_file) 93 | return (sc 94 | .textFile(input_file) 95 | .map(readers.lcas) 96 | .cache()) 97 | 98 | def controlled(sc, input_file): 99 | print('processing ' + input_file) 100 | return (sc 101 | .textFile(input_file) 102 | .map(readers.controlled) 103 | .cache()) 104 | 105 | def get_trackrows(sc, input_file): 106 | print('processing ' + input_file) 107 | return (sc 108 | .textFile(input_file) 109 | .map(readers.get_trackrows) 110 | .filter(lambda r: r is not None) 111 | .cache()) 112 | 113 | def standard(sc, input_file): 114 | print('processing ' + input_file) 115 | return (sc 116 | .textFile(input_file) 117 | .map(readers.standard) 118 | .cache()) 119 | 120 | def car_data(sc, input_file): 121 | print('processing ' + input_file) 122 | return (sc 123 | .wholeTextFiles(input_file) 124 | .flatMap(readers.car_data) 125 | .cache()) 126 | 127 | def write(input_rows, output_file, args): 128 | """ Write Valid Scenes without categorization """ 129 | 130 | print(" Entering Writing ") 131 | ## To handle two different time stamps 7:00 and 17:00 of cff 132 | if args.order_frames: 133 | frames = sorted(set(input_rows.map(lambda r: r.frame).toLocalIterator()), 134 | key=lambda frame: frame % 100000) 135 | else: 136 | frames = sorted(set(input_rows.map(lambda r: r.frame).toLocalIterator())) 137 | 138 | # split 139 | train_split_index = int(len(frames) * args.train_fraction) 140 | val_split_index = train_split_index + int(len(frames) * args.val_fraction) 141 | train_frames = set(frames[:train_split_index]) 142 | val_frames = set(frames[train_split_index:val_split_index]) 143 | test_frames = set(frames[val_split_index:]) 144 | 145 | # train dataset 146 | train_rows = input_rows.filter(lambda r: r.frame in train_frames) 147 | train_output = output_file.format(split='train') 148 | train_scenes = Scenes(fps=args.fps, start_scene_id=0, args=args).rows_to_file(train_rows, train_output) 149 | 150 | # validation dataset 151 | val_rows = input_rows.filter(lambda r: r.frame in val_frames) 152 | val_output = output_file.format(split='val') 153 | val_scenes = Scenes(fps=args.fps, start_scene_id=train_scenes.scene_id, args=args).rows_to_file(val_rows, val_output) 154 | 155 | # public test dataset 156 | test_rows = input_rows.filter(lambda r: r.frame in test_frames) 157 | test_output = output_file.format(split='test') 158 | test_scenes = Scenes(fps=args.fps, start_scene_id=val_scenes.scene_id, args=args) # !!! Chunk Stride 159 | test_scenes.rows_to_file(test_rows, test_output) 160 | 161 | # private test dataset 162 | private_test_output = output_file.format(split='test_private') 163 | private_test_scenes = Scenes(fps=args.fps, start_scene_id=val_scenes.scene_id, args=args) 164 | private_test_scenes.rows_to_file(test_rows, private_test_output) 165 | 166 | def categorize(sc, input_file, args): 167 | """ Categorize the Scenes """ 168 | 169 | print(" Entering Categorizing ") 170 | test_fraction = 1 - args.train_fraction - args.val_fraction 171 | 172 | train_id = 0 173 | if args.train_fraction: 174 | print("Categorizing Training Set") 175 | train_rows = get_trackrows(sc, input_file.replace('split', '').format('train')) 176 | train_id = trajectory_type(train_rows, input_file.replace('split', '').format('train'), 177 | fps=args.fps, track_id=0, args=args) 178 | 179 | val_id = train_id 180 | if args.val_fraction: 181 | print("Categorizing Validation Set") 182 | val_rows = get_trackrows(sc, input_file.replace('split', '').format('val')) 183 | val_id = trajectory_type(val_rows, input_file.replace('split', '').format('val'), 184 | fps=args.fps, track_id=train_id, args=args) 185 | 186 | 187 | if test_fraction: 188 | print("Categorizing Test Set") 189 | test_rows = get_trackrows(sc, input_file.replace('split', '').format('test_private')) 190 | _ = trajectory_type(test_rows, input_file.replace('split', '').format('test_private'), 191 | fps=args.fps, track_id=val_id, args=args) 192 | 193 | def edit_goal_file(old_filename, new_filename): 194 | """ Rename goal files. 195 | The name of goal files should be identical to the data files 196 | """ 197 | 198 | shutil.copy("goal_files/train/" + old_filename, "goal_files/train/" + new_filename) 199 | shutil.copy("goal_files/val/" + old_filename, "goal_files/val/" + new_filename) 200 | shutil.copy("goal_files/test_private/" + old_filename, "goal_files/test_private/" + new_filename) 201 | 202 | def main(): 203 | 204 | 205 | parser = argparse.ArgumentParser() 206 | parser.add_argument('--obs_len', type=int, default=9, 207 | help='Length of observation') 208 | parser.add_argument('--pred_len', type=int, default=12, 209 | help='Length of prediction') 210 | parser.add_argument('--train_fraction', default=0.6, type=float, 211 | help='Training set fraction') 212 | parser.add_argument('--val_fraction', default=0.2, type=float, 213 | help='Validation set fraction') 214 | parser.add_argument('--fps', default=2.5, type=float, 215 | help='fps') 216 | parser.add_argument('--order_frames', action='store_true', 217 | help='For CFF') 218 | parser.add_argument('--chunk_stride', type=int, default=2, 219 | help='Sampling Stride') 220 | parser.add_argument('--min_length', default=0.0, type=float, 221 | help='Min Length of Primary Trajectory') 222 | parser.add_argument('--synthetic', action='store_true', 223 | help='convert synthetic datasets (if false, convert real)') 224 | parser.add_argument('--all_present', action='store_true', 225 | help='filter scenes where all pedestrians present at all times') 226 | parser.add_argument('--goal_file', default=None, 227 | help='Pkl file for goals (required for ORCA sensitive scene filtering)') 228 | parser.add_argument('--mode', default='default', choices=('default', 'trajnet'), 229 | help='mode of ORCA scene generation (required for ORCA sensitive scene filtering)') 230 | 231 | ## For Trajectory categorizing and filtering 232 | categorizers = parser.add_argument_group('categorizers') 233 | categorizers.add_argument('--static_threshold', type=float, default=1.0, 234 | help='Type I static threshold') 235 | categorizers.add_argument('--linear_threshold', type=float, default=0.5, 236 | help='Type II linear threshold (0.3 for Synthetic)') 237 | categorizers.add_argument('--inter_dist_thresh', type=float, default=5, 238 | help='Type IIId distance threshold for cone') 239 | categorizers.add_argument('--inter_pos_range', type=float, default=15, 240 | help='Type IIId angle threshold for cone (degrees)') 241 | categorizers.add_argument('--grp_dist_thresh', type=float, default=0.8, 242 | help='Type IIIc distance threshold for group') 243 | categorizers.add_argument('--grp_std_thresh', type=float, default=0.2, 244 | help='Type IIIc std deviation for group') 245 | categorizers.add_argument('--acceptance', nargs='+', type=float, default=[0.1, 1, 1, 1], 246 | help='acceptance ratio of different trajectory (I, II, III, IV) types') 247 | 248 | args = parser.parse_args() 249 | sc = pysparkling.Context() 250 | 251 | # Real datasets conversion 252 | if not args.synthetic: 253 | 254 | 255 | file_names = [ 256 | 'bytes-cafe-2019-02-07_0', 257 | 'huang-lane-2019-02-12_0', 258 | 'gates-ai-lab-2019-02-08_0', 259 | 'gates-basement-elevators-2019-01-17_1', 260 | 'hewlett-packard-intersection-2019-01-24_0', 261 | 'jordan-hall-2019-04-22_0', 262 | 'packard-poster-session-2019-03-20_1', 263 | 'packard-poster-session-2019-03-20_2', 264 | 'stlc-111-2019-04-19_0', 265 | 'svl-meeting-gates-2-2019-04-08_0', 266 | 'svl-meeting-gates-2-2019-04-08_1', 267 | 'tressider-2019-03-16_0', 268 | 'tressider-2019-03-16_1', 269 | 270 | ] 271 | 272 | 273 | for file_name in file_names: 274 | write(jrdb(sc,'data/raw/'+file_name+'.csv'), 275 | 'output_pre/{split}/'+file_name+'.ndjson', args) 276 | categorize(sc, 'output_pre/{split}/'+file_name+'.ndjson', args) 277 | 278 | 279 | # Synthetic datasets conversion 280 | else: 281 | # Note: Generate Trajectories First! See command below 282 | ## 'python -m trajnetdataset.controlled_data ' 283 | write(controlled(sc, 'data/raw/controlled/orca_circle_crossing_5ped_1000scenes_.txt'), 284 | 'output_pre/{split}/orca_five_synth.ndjson', args) 285 | categorize(sc, 'output_pre/{split}/orca_five_synth.ndjson', args) 286 | edit_goal_file('orca_circle_crossing_5ped_1000scenes_.pkl', 'orca_five_synth.pkl') 287 | 288 | if __name__ == '__main__': 289 | main() -------------------------------------------------------------------------------- /trajnetplusplusdataset/trajnetdataset/convert_test.py: -------------------------------------------------------------------------------- 1 | """Create Trajnet data from original datasets.""" 2 | import argparse 3 | import shutil 4 | 5 | import pysparkling 6 | import scipy.io 7 | 8 | from . import readers 9 | from .scene import Scenes 10 | from .get_type import trajectory_type 11 | 12 | import warnings 13 | warnings.filterwarnings("ignore") 14 | 15 | def jrdb(sc, input_file): 16 | print('processing ' + input_file) 17 | 18 | return (sc 19 | .textFile(input_file) 20 | .map(readers.jrdb) 21 | .cache()) 22 | 23 | 24 | def biwi(sc, input_file): 25 | print('processing ' + input_file) 26 | return (sc 27 | .textFile(input_file) 28 | .map(readers.biwi) 29 | .cache()) 30 | 31 | 32 | def crowds(sc, input_file): 33 | print('processing ' + input_file) 34 | return (sc 35 | .wholeTextFiles(input_file) 36 | .values() 37 | .flatMap(readers.crowds) 38 | .cache()) 39 | 40 | 41 | def mot(sc, input_file): 42 | """Was 7 frames per second in original recording.""" 43 | print('processing ' + input_file) 44 | return (sc 45 | .textFile(input_file) 46 | .map(readers.mot) 47 | .filter(lambda r: r.frame % 2 == 0) 48 | .cache()) 49 | 50 | 51 | def edinburgh(sc, input_file): 52 | print('processing ' + input_file) 53 | return (sc 54 | .wholeTextFiles(input_file) 55 | .zipWithIndex() 56 | .flatMap(readers.edinburgh) 57 | .cache()) 58 | 59 | 60 | def syi(sc, input_file): 61 | print('processing ' + input_file) 62 | return (sc 63 | .wholeTextFiles(input_file) 64 | .flatMap(readers.syi) 65 | .cache()) 66 | 67 | 68 | def dukemtmc(sc, input_file): 69 | print('processing ' + input_file) 70 | contents = scipy.io.loadmat(input_file)['trainData'] 71 | return (sc 72 | .parallelize(readers.dukemtmc(contents)) 73 | .cache()) 74 | 75 | 76 | def wildtrack(sc, input_file): 77 | print('processing ' + input_file) 78 | return (sc 79 | .wholeTextFiles(input_file) 80 | .flatMap(readers.wildtrack) 81 | .cache()) 82 | 83 | def cff(sc, input_file): 84 | print('processing ' + input_file) 85 | return (sc 86 | .textFile(input_file) 87 | .map(readers.cff) 88 | .filter(lambda r: r is not None) 89 | .cache()) 90 | 91 | def lcas(sc, input_file): 92 | print('processing ' + input_file) 93 | return (sc 94 | .textFile(input_file) 95 | .map(readers.lcas) 96 | .cache()) 97 | 98 | def controlled(sc, input_file): 99 | print('processing ' + input_file) 100 | return (sc 101 | .textFile(input_file) 102 | .map(readers.controlled) 103 | .cache()) 104 | 105 | def get_trackrows(sc, input_file): 106 | print('processing ' + input_file) 107 | return (sc 108 | .textFile(input_file) 109 | .map(readers.get_trackrows) 110 | .filter(lambda r: r is not None) 111 | .cache()) 112 | 113 | def standard(sc, input_file): 114 | print('processing ' + input_file) 115 | return (sc 116 | .textFile(input_file) 117 | .map(readers.standard) 118 | .cache()) 119 | 120 | def car_data(sc, input_file): 121 | print('processing ' + input_file) 122 | return (sc 123 | .wholeTextFiles(input_file) 124 | .flatMap(readers.car_data) 125 | .cache()) 126 | 127 | def write(input_rows, output_file, args): 128 | """ Write Valid Scenes without categorization """ 129 | 130 | print(" Entering Writing ") 131 | ## To handle two different time stamps 7:00 and 17:00 of cff 132 | if args.order_frames: 133 | frames = sorted(set(input_rows.map(lambda r: r.frame).toLocalIterator()), 134 | key=lambda frame: frame % 100000) 135 | else: 136 | frames = sorted(set(input_rows.map(lambda r: r.frame).toLocalIterator())) 137 | 138 | # split 139 | train_split_index = int(len(frames) * args.train_fraction) 140 | val_split_index = train_split_index + int(len(frames) * args.val_fraction) 141 | train_frames = set(frames[:train_split_index]) 142 | val_frames = set(frames[train_split_index:val_split_index]) 143 | test_frames = set(frames[val_split_index:]) 144 | 145 | # train dataset 146 | train_rows = input_rows.filter(lambda r: r.frame in train_frames) 147 | train_output = output_file.format(split='train') 148 | train_scenes = Scenes(fps=args.fps, start_scene_id=0, args=args).rows_to_file(train_rows, train_output) 149 | 150 | # validation dataset 151 | val_rows = input_rows.filter(lambda r: r.frame in val_frames) 152 | val_output = output_file.format(split='val') 153 | val_scenes = Scenes(fps=args.fps, start_scene_id=train_scenes.scene_id, args=args).rows_to_file(val_rows, val_output) 154 | 155 | # public test dataset 156 | test_rows = input_rows.filter(lambda r: r.frame in test_frames) 157 | test_output = output_file.format(split='test') 158 | test_scenes = Scenes(fps=args.fps, start_scene_id=val_scenes.scene_id, args=args) # !!! Chunk Stride 159 | test_scenes.rows_to_file(test_rows, test_output) 160 | 161 | # private test dataset 162 | private_test_output = output_file.format(split='test_private') 163 | private_test_scenes = Scenes(fps=args.fps, start_scene_id=val_scenes.scene_id, args=args) 164 | private_test_scenes.rows_to_file(test_rows, private_test_output) 165 | 166 | def categorize(sc, input_file, args): 167 | """ Categorize the Scenes """ 168 | 169 | print(" Entering Categorizing ") 170 | test_fraction = 1 - args.train_fraction - args.val_fraction 171 | 172 | train_id = 0 173 | if args.train_fraction: 174 | print("Categorizing Training Set") 175 | train_rows = get_trackrows(sc, input_file.replace('split', '').format('train')) 176 | train_id = trajectory_type(train_rows, input_file.replace('split', '').format('train'), 177 | fps=args.fps, track_id=0, args=args) 178 | 179 | val_id = train_id 180 | if args.val_fraction: 181 | print("Categorizing Validation Set") 182 | val_rows = get_trackrows(sc, input_file.replace('split', '').format('val')) 183 | val_id = trajectory_type(val_rows, input_file.replace('split', '').format('val'), 184 | fps=args.fps, track_id=train_id, args=args) 185 | 186 | 187 | if test_fraction: 188 | print("Categorizing Test Set") 189 | test_rows = get_trackrows(sc, input_file.replace('split', '').format('test_private')) 190 | _ = trajectory_type(test_rows, input_file.replace('split', '').format('test_private'), 191 | fps=args.fps, track_id=val_id, args=args) 192 | 193 | def edit_goal_file(old_filename, new_filename): 194 | """ Rename goal files. 195 | The name of goal files should be identical to the data files 196 | """ 197 | 198 | shutil.copy("goal_files/train/" + old_filename, "goal_files/train/" + new_filename) 199 | shutil.copy("goal_files/val/" + old_filename, "goal_files/val/" + new_filename) 200 | shutil.copy("goal_files/test_private/" + old_filename, "goal_files/test_private/" + new_filename) 201 | 202 | def main(): 203 | 204 | 205 | parser = argparse.ArgumentParser() 206 | parser.add_argument('--obs_len', type=int, default=9, 207 | help='Length of observation') 208 | parser.add_argument('--pred_len', type=int, default=12, 209 | help='Length of prediction') 210 | parser.add_argument('--train_fraction', default=0.6, type=float, 211 | help='Training set fraction') 212 | parser.add_argument('--val_fraction', default=0.2, type=float, 213 | help='Validation set fraction') 214 | parser.add_argument('--fps', default=2.5, type=float, 215 | help='fps') 216 | parser.add_argument('--order_frames', action='store_true', 217 | help='For CFF') 218 | parser.add_argument('--chunk_stride', type=int, default=2, 219 | help='Sampling Stride') 220 | parser.add_argument('--min_length', default=0.0, type=float, 221 | help='Min Length of Primary Trajectory') 222 | parser.add_argument('--synthetic', action='store_true', 223 | help='convert synthetic datasets (if false, convert real)') 224 | parser.add_argument('--all_present', action='store_true', 225 | help='filter scenes where all pedestrians present at all times') 226 | parser.add_argument('--goal_file', default=None, 227 | help='Pkl file for goals (required for ORCA sensitive scene filtering)') 228 | parser.add_argument('--mode', default='default', choices=('default', 'trajnet'), 229 | help='mode of ORCA scene generation (required for ORCA sensitive scene filtering)') 230 | 231 | ## For Trajectory categorizing and filtering 232 | categorizers = parser.add_argument_group('categorizers') 233 | categorizers.add_argument('--static_threshold', type=float, default=1.0, 234 | help='Type I static threshold') 235 | categorizers.add_argument('--linear_threshold', type=float, default=0.5, 236 | help='Type II linear threshold (0.3 for Synthetic)') 237 | categorizers.add_argument('--inter_dist_thresh', type=float, default=5, 238 | help='Type IIId distance threshold for cone') 239 | categorizers.add_argument('--inter_pos_range', type=float, default=15, 240 | help='Type IIId angle threshold for cone (degrees)') 241 | categorizers.add_argument('--grp_dist_thresh', type=float, default=0.8, 242 | help='Type IIIc distance threshold for group') 243 | categorizers.add_argument('--grp_std_thresh', type=float, default=0.2, 244 | help='Type IIIc std deviation for group') 245 | categorizers.add_argument('--acceptance', nargs='+', type=float, default=[0.1, 1, 1, 1], 246 | help='acceptance ratio of different trajectory (I, II, III, IV) types') 247 | 248 | args = parser.parse_args() 249 | sc = pysparkling.Context() 250 | 251 | # Real datasets conversion 252 | if not args.synthetic: 253 | 254 | 255 | file_names = [ 256 | 'cubberly-auditorium-2019-04-22_1', 257 | 'discovery-walk-2019-02-28_0', 258 | 'discovery-walk-2019-02-28_1', 259 | 'food-trucks-2019-02-12_0', 260 | 'gates-ai-lab-2019-04-17_0', 261 | 'gates-basement-elevators-2019-01-17_0', 262 | 'gates-foyer-2019-01-17_0', 263 | 'gates-to-clark-2019-02-28_0', 264 | 'hewlett-class-2019-01-23_0', 265 | 'hewlett-class-2019-01-23_1', 266 | 'huang-2-2019-01-25_1', 267 | 'huang-intersection-2019-01-22_0', 268 | 'indoor-coupa-cafe-2019-02-06_0', 269 | 'lomita-serra-intersection-2019-01-30_0', 270 | 'meyer-green-2019-03-16_1', 271 | 'nvidia-aud-2019-01-25_0', 272 | 'nvidia-aud-2019-04-18_1', 273 | 'nvidia-aud-2019-04-18_2', 274 | 'outdoor-coupa-cafe-2019-02-06_0', 275 | 'quarry-road-2019-02-28_0', 276 | 'serra-street-2019-01-30_0', 277 | 'stlc-111-2019-04-19_1', 278 | 'stlc-111-2019-04-19_2', 279 | 'tressider-2019-03-16_2', 280 | 'tressider-2019-04-26_0', 281 | 'tressider-2019-04-26_1', 282 | 'tressider-2019-04-26_3' 283 | 284 | ] 285 | 286 | 287 | for file_name in file_names: 288 | write(jrdb(sc,'data/raw/'+file_name+'.csv'), 289 | 'output_pre/{split}/'+file_name+'.ndjson', args) 290 | categorize(sc, 'output_pre/{split}/'+file_name+'.ndjson', args) 291 | 292 | 293 | # Synthetic datasets conversion 294 | else: 295 | # Note: Generate Trajectories First! See command below 296 | ## 'python -m trajnetdataset.controlled_data ' 297 | write(controlled(sc, 'data/raw/controlled/orca_circle_crossing_5ped_1000scenes_.txt'), 298 | 'output_pre/{split}/orca_five_synth.ndjson', args) 299 | categorize(sc, 'output_pre/{split}/orca_five_synth.ndjson', args) 300 | edit_goal_file('orca_circle_crossing_5ped_1000scenes_.pkl', 'orca_five_synth.pkl') 301 | 302 | if __name__ == '__main__': 303 | main() -------------------------------------------------------------------------------- /jrdb_baselines/trajnetbaselines/lstm/lstm.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import copy 3 | 4 | import numpy as np 5 | import torch 6 | from .tools.reader import Reader 7 | 8 | from .modules import Hidden2Normal, InputEmbedding 9 | 10 | NAN = float('nan') 11 | 12 | def keep_valid_neigh(xy): 13 | xy_n_t = np.transpose(xy, (1, 0, 2)) 14 | mask = np.ones(xy_n_t.shape[0], dtype=bool) 15 | for n in range(xy_n_t.shape[0]): 16 | if xy_n_t[n,7,-1]==0 or xy_n_t[n,8,-1]==0: 17 | ## need at least 2 last frames 18 | mask[n] = False 19 | 20 | return np.transpose(xy_n_t[mask], (1, 0, 2)) 21 | 22 | 23 | def drop_distant_far(xy, r=6.0): 24 | """ 25 | Drops pedestrians more than r meters away from primary ped 26 | """ 27 | distance_2 = np.sum(np.square(xy[:, :, 0:2] - xy[:, 0:1, 0:2]), axis=2) 28 | mask = np.nanmin(distance_2, axis=0) < r**2 29 | 30 | return xy[:, mask], mask 31 | 32 | 33 | class LSTM(torch.nn.Module): 34 | def __init__(self, embedding_dim=64, hidden_dim=128, pool=None, pool_to_input=True, goal_dim=None, goal_flag=False): 35 | """ Initialize the LSTM forecasting model 36 | 37 | Attributes 38 | ---------- 39 | embedding_dim : Embedding dimension of location coordinates 40 | hidden_dim : Dimension of hidden state of LSTM 41 | pool : interaction module 42 | pool_to_input : Bool 43 | if True, the interaction vector is concatenated to the input embedding of LSTM [preferred] 44 | if False, the interaction vector is added to the LSTM hidden-state 45 | goal_dim : Embedding dimension of the unit vector pointing towards the goal 46 | goal_flag: Bool 47 | if True, the embedded goal vector is concatenated to the input embedding of LSTM 48 | """ 49 | 50 | super(LSTM, self).__init__() 51 | self.hidden_dim = hidden_dim 52 | self.embedding_dim = embedding_dim 53 | self.pool = pool 54 | self.pool_to_input = pool_to_input 55 | 56 | ## Location 57 | scale = 4.0 58 | self.input_embedding = InputEmbedding(3, self.embedding_dim, scale) 59 | 60 | ## Goal 61 | self.goal_flag = goal_flag 62 | self.goal_dim = goal_dim or embedding_dim 63 | self.goal_embedding = InputEmbedding(2, self.goal_dim, scale) 64 | goal_rep_dim = self.goal_dim if self.goal_flag else 0 65 | 66 | ## Pooling 67 | pooling_dim = 0 68 | if pool is not None and self.pool_to_input: 69 | pooling_dim = self.pool.out_dim 70 | 71 | ## LSTMs 72 | self.encoder = torch.nn.LSTMCell(self.embedding_dim + goal_rep_dim + pooling_dim, self.hidden_dim) 73 | self.decoder = torch.nn.LSTMCell(self.embedding_dim + goal_rep_dim + pooling_dim, self.hidden_dim) 74 | 75 | self.hidden2normal = Hidden2Normal(self.hidden_dim) 76 | 77 | def step(self, lstm, hidden_cell_state, obs1, obs2, batch_split): 78 | """Do one step of prediction: two inputs to one normal prediction. 79 | 80 | Parameters 81 | ---------- 82 | lstm: torch nn module [Encoder / Decoder] 83 | The module responsible for prediction 84 | hidden_cell_state : tuple (hidden_state, cell_state) 85 | Current hidden_cell_state of the pedestrians 86 | obs1 : Tensor [num_tracks, 2] 87 | Previous x-y positions of the pedestrians 88 | obs2 : Tensor [num_tracks, 2] 89 | Current x-y positions of the pedestrians 90 | goals : Tensor [num_tracks, 2] 91 | Goal coordinates of the pedestrians 92 | 93 | Returns 94 | ------- 95 | hidden_cell_state : tuple (hidden_state, cell_state) 96 | Updated hidden_cell_state of the pedestrians 97 | normals : Tensor [num_tracks, 5] 98 | Parameters of a multivariate normal of the predicted position 99 | with respect to the current position 100 | """ 101 | num_tracks = len(obs2) 102 | track_mask = (torch.isnan(obs1[:, 0]) + torch.isnan(obs2[:, 0])) == 0 103 | 104 | 105 | 106 | ## Masked Hidden Cell State 107 | hidden_cell_stacked = [ 108 | torch.stack([h for m, h in zip(track_mask, hidden_cell_state[0]) if m], dim=0), 109 | torch.stack([c for m, c in zip(track_mask, hidden_cell_state[1]) if m], dim=0), 110 | ] 111 | 112 | ## Mask current velocity & embed 113 | obs1_temp = obs1.clone() 114 | obs1_temp[:,-1]=0 115 | curr_velocity = obs2 - obs1_temp # visibility depends on obs2 116 | curr_velocity = curr_velocity[track_mask] 117 | 118 | input_emb = self.input_embedding(curr_velocity) 119 | 120 | ## Mask & Pool per scene 121 | if self.pool is not None: 122 | hidden_states_to_pool = torch.stack(hidden_cell_state[0]).clone() # detach? 123 | batch_pool = [] 124 | ## Iterate over scenes 125 | for (start, end) in zip(batch_split[:-1], batch_split[1:]): 126 | ## Mask for the scene 127 | scene_track_mask = track_mask[start:end] 128 | ## Get observations and hidden-state for the scene 129 | prev_position = obs1[start:end][scene_track_mask] 130 | curr_position = obs2[start:end][scene_track_mask] 131 | curr_hidden_state = hidden_states_to_pool[start:end][scene_track_mask] 132 | 133 | ## Provide track_mask to the interaction encoders 134 | ## Everyone absent by default. Only those visible in current scene are present 135 | interaction_track_mask = torch.zeros(num_tracks, device=obs1.device).bool() 136 | interaction_track_mask[start:end] = track_mask[start:end] 137 | self.pool.track_mask = interaction_track_mask 138 | 139 | ## Pool 140 | pool_sample = self.pool(curr_hidden_state, prev_position, curr_position) 141 | batch_pool.append(pool_sample) 142 | 143 | pooled = torch.cat(batch_pool) 144 | 145 | if self.pool_to_input: 146 | input_emb = torch.cat([input_emb, pooled], dim=1) 147 | else: 148 | hidden_cell_stacked[0] += pooled 149 | 150 | # LSTM step 151 | hidden_cell_stacked = lstm(input_emb, hidden_cell_stacked) 152 | normal_masked = self.hidden2normal(hidden_cell_stacked[0]) 153 | 154 | # unmask [Update hidden-states and next velocities of pedestrians] 155 | normal = torch.full((track_mask.size(0),3), NAN, device=obs1.device) 156 | mask_index = [i for i, m in enumerate(track_mask) if m] 157 | for i, h, c, n in zip(mask_index, 158 | hidden_cell_stacked[0], 159 | hidden_cell_stacked[1], 160 | normal_masked): 161 | hidden_cell_state[0][i] = h 162 | hidden_cell_state[1][i] = c 163 | normal[i] = n 164 | 165 | return hidden_cell_state, normal 166 | 167 | def forward(self, observed, batch_split, prediction_truth=None, n_predict=None): 168 | """Forecast the entire sequence 169 | 170 | Parameters 171 | ---------- 172 | observed : Tensor [obs_length, num_tracks, 2] 173 | Observed sequences of x-y coordinates of the pedestrians 174 | goals : Tensor [num_tracks, 2] 175 | Goal coordinates of the pedestrians 176 | batch_split : Tensor [batch_size + 1] 177 | Tensor defining the split of the batch. 178 | Required to identify the tracks of to the same scene 179 | prediction_truth : Tensor [pred_length - 1, num_tracks, 2] 180 | Prediction sequences of x-y coordinates of the pedestrians 181 | Helps in teacher forcing wrt neighbours positions during training 182 | n_predict: Int 183 | Length of sequence to be predicted during test time 184 | 185 | Returns 186 | ------- 187 | rel_pred_scene : Tensor [pred_length, num_tracks, 5] 188 | Predicted velocities of pedestrians as multivariate normal 189 | i.e. positions relative to previous positions 190 | pred_scene : Tensor [pred_length, num_tracks, 2] 191 | Predicted positions of pedestrians i.e. absolute positions 192 | """ 193 | 194 | assert ((prediction_truth is None) + (n_predict is None)) == 1 195 | if n_predict is not None: 196 | # -1 because one prediction is done by the encoder already 197 | prediction_truth = [None for _ in range(n_predict - 1)] 198 | 199 | ego_invis_frames = np.argwhere((observed[:,batch_split[:-1],-1].cpu()==0)) 200 | 201 | if ego_invis_frames.size(1) != 0: 202 | for f in range(ego_invis_frames.size(1)): 203 | temp_t = ego_invis_frames[0,-(f+1)] 204 | temp_id = ego_invis_frames[1,-(f+1)] 205 | observed[temp_t,batch_split[:-1][temp_id]] = observed[temp_t+1,batch_split[:-1][temp_id]] 206 | 207 | # initialize: Because of tracks with different lengths and the masked 208 | # update, the hidden state for every LSTM needs to be a separate object 209 | # in the backprop graph. Therefore: list of hidden states instead of 210 | # a single higher rank Tensor. 211 | num_tracks = observed.size(1) 212 | hidden_cell_state = ( 213 | [torch.zeros(self.hidden_dim, device=observed.device) for _ in range(num_tracks)], 214 | [torch.zeros(self.hidden_dim, device=observed.device) for _ in range(num_tracks)], 215 | ) 216 | 217 | ## Reset LSTMs of Interaction Encoders. 218 | if self.pool is not None: 219 | self.pool.reset(num_tracks, device=observed.device) 220 | 221 | # list of predictions 222 | normals = [] # predicted normal parameters for both phases 223 | positions = [] # true (during obs phase) and predicted positions 224 | 225 | if len(observed) == 2: 226 | positions = [observed[-1]] 227 | 228 | # encoder 229 | for obs1, obs2 in zip(observed[:-1], observed[1:]): 230 | ##LSTM Step 231 | 232 | hidden_cell_state, normal = self.step(self.encoder, hidden_cell_state, obs1, obs2, batch_split) 233 | 234 | normals.append(normal) 235 | obs2_temp = obs2.clone() 236 | obs2_temp[:,-1] = 0 237 | positions.append(obs2_temp + normal[:, :3]) # no sampling, just mean 238 | 239 | # initialize predictions with last position to form velocity. DEEP COPY !!! 240 | prediction_truth = copy.deepcopy(list(itertools.chain.from_iterable( 241 | (observed[-1:], prediction_truth) 242 | ))) 243 | 244 | # decoder, predictions 245 | for obs1, obs2 in zip(prediction_truth[:-1], prediction_truth[1:]): 246 | if obs1 is None: 247 | obs1 = positions[-2].detach() # DETACH!!! 248 | else: 249 | for primary_id in batch_split[:-1]: 250 | obs1[primary_id] = positions[-2][primary_id].detach() # DETACH!!! 251 | if obs2 is None: 252 | obs2 = positions[-1].detach() 253 | else: 254 | for primary_id in batch_split[:-1]: 255 | obs2[primary_id] = positions[-1][primary_id].detach() # DETACH!!! 256 | 257 | hidden_cell_state, normal = self.step(self.decoder, hidden_cell_state, obs1, obs2, batch_split) 258 | 259 | normals.append(normal) 260 | obs2_temp = obs2.clone() 261 | obs2_temp[:,-1] = 0 262 | positions.append(obs2_temp + normal[:, :3]) # no sampling, just mean 263 | 264 | rel_pred_scene = torch.stack(normals, dim=0) 265 | pred_scene = torch.stack(positions, dim=0) 266 | return rel_pred_scene, pred_scene 267 | 268 | class LSTMPredictor(object): 269 | def __init__(self, model): 270 | self.model = model 271 | 272 | def save(self, state, filename): 273 | with open(filename, 'wb') as f: 274 | torch.save(self, f) 275 | 276 | # # during development, good for compatibility across API changes: 277 | # # Save state for optimizer to continue training in future 278 | with open(filename + '.state', 'wb') as f: 279 | torch.save(state, f) 280 | 281 | @staticmethod 282 | def load(filename): 283 | with open(filename, 'rb') as f: 284 | return torch.load(f, map_location='cpu') 285 | 286 | 287 | def __call__(self, paths, n_predict=12, modes=1, predict_all=True, obs_length=9, start_length=0, args=None): 288 | 289 | 290 | self.model.eval() 291 | with torch.no_grad(): 292 | xy = Reader.paths_to_xy(paths) 293 | if xy[obs_length-2,0,-1]==0 or xy[obs_length-1,0,-1]==0: 294 | return {} 295 | xy = keep_valid_neigh(xy) 296 | observed_xy = xy 297 | batch_split = [0, observed_xy.shape[1]] 298 | observed_xy = torch.Tensor(observed_xy) 299 | batch_split = torch.Tensor(batch_split).long() 300 | 301 | multimodal_outputs = {} 302 | for num_p in range(modes): 303 | _, output_scenes = self.model(observed_xy[start_length:obs_length], batch_split, n_predict=n_predict) 304 | output_scenes = output_scenes.numpy() 305 | 306 | output_primary = output_scenes[-n_predict:, 0] 307 | output_neighs = output_scenes[-n_predict:, 1:] 308 | ## Dictionary of predictions. Each key corresponds to one mode 309 | multimodal_outputs[num_p] = [output_primary, output_neighs] 310 | 311 | 312 | ## Return Dictionary of predictions. Each key corresponds to one mode 313 | return multimodal_outputs 314 | --------------------------------------------------------------------------------