From 1033516712a6d09e6de86d78bc5698547f7408d3 Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Fri, 27 Dec 2024 11:28:16 +0100 Subject: [PATCH] First attempt to provide image map encoder --- README.md | 4 +- test_trajectron_maps.ipynb | 292 +++++++++++++++++++++++++++++++++++++ trap/cv_renderer.py | 8 +- trap/process_data.py | 36 ++++- trap/tools.py | 14 +- trap/utils.py | 78 +++++++++- 6 files changed, 418 insertions(+), 14 deletions(-) create mode 100644 test_trajectron_maps.ipynb diff --git a/README.md b/README.md index b8cda92..26638ab 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,10 @@ These are roughly the steps to go from datagathering to training 3. Run the tracker, e.g. `poetry run tracker --detector ultralytics --homography ../DATASETS/NAME/homography.json --video-src ../DATASETS/NAME/*.mp4 --calibration ../DATASETS/NAME/calibration.json --save-for-training EXPERIMENTS/raw/NAME/` * Note: You can run this right of the camera stream: `poetry run tracker --eval_device cuda:0 --detector ultralytics --video-src rtsp://USER:PW@ADDRESS/STREAM --homography ../DATASETS/NAME/homography.json --calibration ../DATASETS/NAME/calibration.json --save-for-training EXPERIMENTS/raw/NAME/`, each recording adding a new file to the `raw` folder. 4. Parse tracker data to Trajectron format: `poetry run process_data --src-dir EXPERIMENTS/raw/NAME --dst-dir EXPERIMENTS/trajectron-data/ --name NAME` Optionally, smooth tracks: `--smooth-tracks` + * Optionally, add a map: ideally a RGB png: 3 layers of 0-255 + * `poetry run process_data --src-dir EXPERIMENTS/raw/NAME --dst-dir EXPERIMENTS/trajectron-data/ --name NAME --smooth-tracks --camera-fps 12 --homography ../DATASETS/NAME/homography.json --calibration ../DATASETS/NAME/calibration.json --filter-displacement 2 --map-img-path ../DATASETS/NAME/map.png` 5. Train Trajectron model `poetry run trajectron_train --eval_every 10 --vis_every 1 --train_data_dict NAME_train.pkl --eval_data_dict NAME_val.pkl --offline_scene_graph no --preprocess_workers 8 --log_dir EXPERIMENTS/models --log_tag _NAME --train_epochs 100 --conf EXPERIMENTS/config.json --batch_size 256 --data_dir EXPERIMENTS/trajectron-data ` 6. The run! * On a video file (you can use a wildcard) `DISPLAY=:1 poetry run trapserv --remote-log-addr 100.69.123.91 --eval_device cuda:0 --detector ultralytics --homography ../DATASETS/NAME/homography.json --eval_data_dict EXPERIMENTS/trajectron-data/hof2s-m_test.pkl --video-src ../DATASETS/NAME/*.mp4 --model_dir EXPERIMENTS/models/models_DATE_NAME/--smooth-predictions --smooth-tracks --num-samples 3 --render-window --calibration ../DATASETS/NAME/calibration.json` (the DISPLAY environment variable is used here to running over SSH connection and display on local monitor) * or on the RTSP stream. Which uses gstreamer to substantially reduce latency compared to the default ffmpeg bindings in OpenCV. - * To just have a single trajectory pulled from distribution use `--full-dist`. Also try `--z_mode`. \ No newline at end of file + * To just have a single trajectory pulled from distribution use `--full-dist`. Also try `--z_mode`. diff --git a/test_trajectron_maps.ipynb b/test_trajectron_maps.ipynb new file mode 100644 index 0000000..0ebac14 --- /dev/null +++ b/test_trajectron_maps.ipynb @@ -0,0 +1,292 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Trajectron seems to support providing a map for a scene. This might be a way to get better predictions, that actually stay on the pathways instead of go through buildings. However, by default it supports maps from NuScenes, but not images (even though some traces of that remain in the code.) More info about support in trajectron is in [issue #14](https://github.com/StanfordASL/Trajectron-plus-plus/issues/14) on their Github.\n", + "\n", + "This notebook is used to test my implementation to add map support to Trajectron." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CHANGELOG:\n", + "\n", + "* 2024-12-27 : Created\n", + " * Draw the map image\n", + " * Training _sometimes_ (randomly?) gives NaN matrixes since using map encoding.\n", + " * Call Image map and test if converted points of all tracks fall within realistic image bounds (e.g. no negative points)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "from trap.frame_emitter import Camera\n", + "from trap.utils import ImageMap\n", + "import cv2\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "calibration_path = Path(\"../DATASETS/hof3/calibration.json\")\n", + "homography_path = Path(\"../DATASETS/hof3/homography.json\")\n", + "\n", + "camera = Camera.from_paths(calibration_path, homography_path, 12)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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pygvL5daVVWVtP25554TycnJYv/+/eKbb74RI0aMEPfdd5+0va2tTQwaNEhkZGSIo0ePik8//VTExcWJJUuWyLE7fuHTTz8VL730kvjggw8EALF3716X7evWrRNarVZ8+OGH4vjx4+KRRx4RKSkporm5WeozduxYMWTIEPH111+Lv//976Jv375i8uTJ0naTyST0er3IysoSJ0+eFH/84x9FWFiYeP311721mz7tRscgOztbjB071uXfRU1NjUsfHoNbl5mZKd58801x8uRJcezYMfHwww+LHj16iIaGBqmPO373nDt3ToSHh4v58+eLU6dOie3bt4ugoCDx+eefe3V/fdHNHIOf//zn4tlnn3X5d2AymaTt3joGARds7r33XjFr1izpa5vNJhITE0Vubq6MVQWOlStXiiFDhnS4ra6uToSEhIj3339feuz06dMCgCgoKBBC/PQBoVQqhdFolPrs3LlTaDQaYbFYPFp7IGj/oWq324XBYBAbN26UHqurqxNqtVr88Y9/FEIIcerUKQFAFBUVSX0+++wzoVAoxKVLl4QQQrz66qsiOjra5RgsXrxYpKameniP/M+1gs2jjz56zefwGLhXZWWlACAOHjwohHDf755FixaJO++80+V7Pf300yIzM9PTu+R32h8DIX4KNs8///w1n+OtYxBQp6JaW1tRXFyMjIwM6TGlUomMjAwUFBTIWFlg+eGHH5CYmIjevXsjKysLZWVlAIDi4mJYrVaX93/AgAHo0aOH9P4XFBRg8ODB0Ov1Up/MzEyYzWZ8//333t2RAFBaWgqj0ejynmu1WqSlpbm85zqdDsOHD5f6ZGRkQKlUorCwUOrz4IMPQqVSSX0yMzNRUlKC2tpaL+2Nf/vyyy+RkJCA1NRUzJgxA9XV1dI2HgP3MplMAP5vsWN3/e4pKChweQ1HH35+XK39MXB45513EBcXh0GDBmHJkiVoamqStnnrGATUIphXrlyBzWZzedMAQK/X4x//+IdMVQWWtLQ07N69G6mpqSgvL8fq1avxwAMP4OTJkzAajVCpVNDpdC7P0ev1MBqNAACj0djh8XFso85xvGcdvafO73lCQoLL9uDgYMTExLj0SUlJueo1HNuio6M9Un+gGDt2LJ544gmkpKTg7NmzWLp0KcaNG4eCggIEBQXxGLiR3W7H3Llzcf/992PQoEEA4LbfPdfqYzab0dzcjLCwME/skt/p6BgAwK9//Wv07NkTiYmJOHHiBBYvXoySkhJ88MEHALx3DAIq2JDnjRs3Tvr7z372M6SlpaFnz5547733+I+euqxJkyZJfx88eDB+9rOfoU+fPvjyyy8xevRoGSsLPLNmzcLJkydx+PBhuUvpsq51DKZPny79ffDgwejWrRtGjx6Ns2fPok+fPl6rL6BORcXFxSEoKOiqK+ErKipgMBhkqiqw6XQ69O/fH2fOnIHBYEBrayvq6upc+ji//waDocPj49hGneN4z673M28wGFBZWemyva2tDTU1NTwuHtK7d2/ExcXhzJkzAHgM3GX27NnYt28fvvjiC3Tv3l163F2/e67VR6PR8D9u/3KtY9CRtLQ0AHD5d+CNYxBQwUalUmHYsGHYv3+/9Jjdbsf+/fuRnp4uY2WBq6GhAWfPnkW3bt0wbNgwhISEuLz/JSUlKCsrk97/9PR0fPfddy6/5PPz86HRaDBw4ECv1+/vUlJSYDAYXN5zs9mMwsJCl/e8rq4OxcXFUp8DBw7AbrdLv3jS09Nx6NAhWK1WqU9+fj5SU1N5CuQW/Pjjj6iurka3bt0A8BjcLiEEZs+ejb179+LAgQNXnbJz1++e9PR0l9dw9OHnx42PQUeOHTsGAC7/DrxyDG76MmM/sWfPHqFWq8Xu3bvFqVOnxPTp04VOp3O5Cptu3YIFC8SXX34pSktLxf/+7/+KjIwMERcXJyorK4UQP0257NGjhzhw4ID45ptvRHp6ukhPT5ee75juN2bMGHHs2DHx+eefi/j4eE73vo76+npx9OhRcfToUQFAbNq0SRw9elRcuHBBCPHTdG+dTic++ugjceLECfHoo492ON37rrvuEoWFheLw4cOiX79+LlON6+rqhF6vF1OmTBEnT54Ue/bsEeHh4Zxq/C/XOwb19fXihRdeEAUFBaK0tFT87W9/E3fffbfo16+faGlpkV6Dx+DWzZgxQ2i1WvHll1+6TCVuamqS+rjjd49jqvHChQvF6dOnRV5eHqd7/8uNjsGZM2fEmjVrxDfffCNKS0vFRx99JHr37i0efPBB6TW8dQwCLtgIIcT27dtFjx49hEqlEvfee6/4+uuv5S4pYDz99NOiW7duQqVSiaSkJPH000+LM2fOSNubm5vFzJkzRXR0tAgPDxePP/64KC8vd3mN8+fPi3HjxomwsDARFxcnFixYIKxWq7d3xW988cUXAsBVLTs7Wwjx05Tv5cuXC71eL9RqtRg9erQoKSlxeY3q6moxefJkERkZKTQajZg6daqor6936XP8+HExcuRIoVarRVJSkli3bp23dtHnXe8YNDU1iTFjxoj4+HgREhIievbsKZ599tmr/jPFY3DrOnrvAYg333xT6uOu3z1ffPGFGDp0qFCpVKJ3794u36Mru9ExKCsrEw8++KCIiYkRarVa9O3bVyxcuNDlPjZCeOcYKP5VMBEREZHfC6hrbIiIiKhrY7AhIiKigMFgQ0RERAGDwYaIiIgCBoMNERERBQwGGyIiIgoYDDZEREQUMBhsiIiIKGAw2BAREVHAYLAhIiKigMFgQ0RERAGDwYaIiIgCxv8HGPnhXgm7yW0AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_path = Path(\"../DATASETS/hof3/map-undistorted-H.png\")\n", + "\n", + "imgmap = ImageMap(image_path, None, \"hof3-undistorted-H\")\n", + "\n", + "plt.imshow(cv2.imread(image_path))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "path = Path(\"EXPERIMENTS/raw/hof3/\")\n", + "calibration_path = Path(\"../DATASETS/hof3/calibration.json\")\n", + "homography_path = Path(\"../DATASETS/hof3/homography.json\")\n", + "\n", + "camera = Camera.from_paths(calibration_path, homography_path, 12)\n", + "\n", + "imgmap = ImageMap(image_path, None, \"hof3-undistorted\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "img = imgmap.as_image()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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pygvL5daVVWVtP25554TycnJYv/+/eKbb74RI0aMEPfdd5+0va2tTQwaNEhkZGSIo0ePik8//VTExcWJJUuWyLE7fuHTTz8VL730kvjggw8EALF3716X7evWrRNarVZ8+OGH4vjx4+KRRx4RKSkporm5WeozduxYMWTIEPH111+Lv//976Jv375i8uTJ0naTyST0er3IysoSJ0+eFH/84x9FWFiYeP311721mz7tRscgOztbjB071uXfRU1NjUsfHoNbl5mZKd58801x8uRJcezYMfHwww+LHj16iIaGBqmPO373nDt3ToSHh4v58+eLU6dOie3bt4ugoCDx+eefe3V/fdHNHIOf//zn4tlnn3X5d2AymaTt3joGARds7r33XjFr1izpa5vNJhITE0Vubq6MVQWOlStXiiFDhnS4ra6uToSEhIj3339feuz06dMCgCgoKBBC/PQBoVQqhdFolPrs3LlTaDQaYbFYPFp7IGj/oWq324XBYBAbN26UHqurqxNqtVr88Y9/FEIIcerUKQFAFBUVSX0+++wzoVAoxKVLl4QQQrz66qsiOjra5RgsXrxYpKameniP/M+1gs2jjz56zefwGLhXZWWlACAOHjwohHDf755FixaJO++80+V7Pf300yIzM9PTu+R32h8DIX4KNs8///w1n+OtYxBQp6JaW1tRXFyMjIwM6TGlUomMjAwUFBTIWFlg+eGHH5CYmIjevXsjKysLZWVlAIDi4mJYrVaX93/AgAHo0aOH9P4XFBRg8ODB0Ov1Up/MzEyYzWZ8//333t2RAFBaWgqj0ejynmu1WqSlpbm85zqdDsOHD5f6ZGRkQKlUorCwUOrz4IMPQqVSSX0yMzNRUlKC2tpaL+2Nf/vyyy+RkJCA1NRUzJgxA9XV1dI2HgP3MplMAP5vsWN3/e4pKChweQ1HH35+XK39MXB45513EBcXh0GDBmHJkiVoamqStnnrGATUIphXrlyBzWZzedMAQK/X4x//+IdMVQWWtLQ07N69G6mpqSgvL8fq1avxwAMP4OTJkzAajVCpVNDpdC7P0ev1MBqNAACj0djh8XFso85xvGcdvafO73lCQoLL9uDgYMTExLj0SUlJueo1HNuio6M9Un+gGDt2LJ544gmkpKTg7NmzWLp0KcaNG4eCggIEBQXxGLiR3W7H3Llzcf/992PQoEEA4LbfPdfqYzab0dzcjLCwME/skt/p6BgAwK9//Wv07NkTiYmJOHHiBBYvXoySkhJ88MEHALx3DAIq2JDnjRs3Tvr7z372M6SlpaFnz5547733+I+euqxJkyZJfx88eDB+9rOfoU+fPvjyyy8xevRoGSsLPLNmzcLJkydx+PBhuUvpsq51DKZPny79ffDgwejWrRtGjx6Ns2fPok+fPl6rL6BORcXFxSEoKOiqK+ErKipgMBhkqiqw6XQ69O/fH2fOnIHBYEBrayvq6upc+ji//waDocPj49hGneN4z673M28wGFBZWemyva2tDTU1NTwuHtK7d2/ExcXhzJkzAHgM3GX27NnYt28fvvjiC3Tv3l163F2/e67VR6PR8D9u/3KtY9CRtLQ0AHD5d+CNYxBQwUalUmHYsGHYv3+/9Jjdbsf+/fuRnp4uY2WBq6GhAWfPnkW3bt0wbNgwhISEuLz/JSUlKCsrk97/9PR0fPfddy6/5PPz86HRaDBw4ECv1+/vUlJSYDAYXN5zs9mMwsJCl/e8rq4OxcXFUp8DBw7AbrdLv3jS09Nx6NAhWK1WqU9+fj5SU1N5CuQW/Pjjj6iurka3bt0A8BjcLiEEZs+ejb179+LAgQNXnbJz1++e9PR0l9dw9OHnx42PQUeOHTsGAC7/DrxyDG76MmM/sWfPHqFWq8Xu3bvFqVOnxPTp04VOp3O5Cptu3YIFC8SXX34pSktLxf/+7/+KjIwMERcXJyorK4UQP0257NGjhzhw4ID45ptvRHp6ukhPT5ee75juN2bMGHHs2DHx+eefi/j4eE73vo76+npx9OhRcfToUQFAbNq0SRw9elRcuHBBCPHTdG+dTic++ugjceLECfHoo492ON37rrvuEoWFheLw4cOiX79+LlON6+rqhF6vF1OmTBEnT54Ue/bsEeHh4Zxq/C/XOwb19fXihRdeEAUFBaK0tFT87W9/E3fffbfo16+faGlpkV6Dx+DWzZgxQ2i1WvHll1+6TCVuamqS+rjjd49jqvHChQvF6dOnRV5eHqd7/8uNjsGZM2fEmjVrxDfffCNKS0vFRx99JHr37i0efPBB6TW8dQwCLtgIIcT27dtFjx49hEqlEvfee6/4+uuv5S4pYDz99NOiW7duQqVSiaSkJPH000+LM2fOSNubm5vFzJkzRXR0tAgPDxePP/64KC8vd3mN8+fPi3HjxomwsDARFxcnFixYIKxWq7d3xW988cUXAsBVLTs7Wwjx05Tv5cuXC71eL9RqtRg9erQoKSlxeY3q6moxefJkERkZKTQajZg6daqor6936XP8+HExcuRIoVarRVJSkli3bp23dtHnXe8YNDU1iTFjxoj4+HgREhIievbsKZ599tmr/jPFY3DrOnrvAYg333xT6uOu3z1ffPGFGDp0qFCpVKJ3794u36Mru9ExKCsrEw8++KCIiYkRarVa9O3bVyxcuNDlPjZCeOcYKP5VMBEREZHfC6hrbIiIiKhrY7AhIiKigMFgQ0RERAGDwYaIiIgCBoMNERERBQwGGyIiIgoYDDZEREQUMBhsiIiIKGAw2BAREVHAYLAhIiKigMFgQ0RERAGDwYaIiIgCxv8HGPnhXgm7yW0AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "img = np.flipud(img)\n", + "plt.imshow(img)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from trap.tracker import TrackReader\n", + "\n", + "\n", + "reader = TrackReader(path, camera.fps, exclude_whitelisted = False, include_blacklisted=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "from typing import List\n", + "from trap.frame_emitter import Track\n", + "from trap.tracker import FinalDisplacementFilter\n", + "\n", + "\n", + "tracks: List[Track] = [t for t in reader]\n", + "filter = FinalDisplacementFilter(2)\n", + "tracks = filter.apply(tracks, camera)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 12.247 6.8275]\n", + " [ 12.416 6.5942]\n", + " [ 12.528 6.5035]\n", + " [ 12.594 6.4782]\n", + " [ 12.631 6.477]\n", + " [ 12.66 6.424]\n", + " [ 12.706 6.369]\n", + " [ 12.785 6.2094]\n", + " [ 12.849 6.0079]\n", + " [ 12.919 5.7624]\n", + " [ 12.954 5.6717]\n", + " [ 12.979 5.6476]\n", + " [ 12.985 5.613]\n", + " [ 13.027 5.4535]\n", + " [ 13.072 5.2315]\n", + " [ 13.129 4.995]\n", + " [ 13.159 4.894]\n", + " [ 13.167 4.8371]\n", + " [ 13.163 4.8151]\n", + " [ 13.174 4.7545]\n", + " [ 13.2 4.5546]\n", + " [ 13.237 4.2617]\n", + " [ 13.241 4.165]\n", + " [ 13.242 4.1164]\n", + " [ 13.233 4.1089]\n", + " [ 13.238 4.0344]\n", + " [ 13.24 3.967]\n", + " [ 13.318 3.5567]\n", + " [ 13.329 3.4015]\n", + " [ 13.344 3.3385]\n", + " [ 13.357 3.3064]\n", + " [ 13.331 3.3068]\n", + " [ 13.298 3.0786]\n", + " [ 13.35 2.8114]\n", + " [ 13.364 2.6867]\n", + " [ 13.346 2.6791]\n", + " [ 13.326 2.6335]] [[1224 682]\n", + " [1241 659]\n", + " [1252 650]\n", + " [1259 647]\n", + " [1263 647]\n", + " [1266 642]\n", + " [1270 636]\n", + " [1278 620]\n", + " [1284 600]\n", + " [1291 576]\n", + " [1295 567]\n", + " [1297 564]\n", + " [1298 561]\n", + " [1302 545]\n", + " [1307 523]\n", + " [1312 499]\n", + " [1315 489]\n", + " [1316 483]\n", + " [1316 481]\n", + " [1317 475]\n", + " [1319 455]\n", + " [1323 426]\n", + " [1324 416]\n", + " [1324 411]\n", + " [1323 410]\n", + " [1323 403]\n", + " [1324 396]\n", + " [1331 355]\n", + " [1332 340]\n", + " [1334 333]\n", + " [1335 330]\n", + " [1333 330]\n", + " [1329 307]\n", + " [1334 281]\n", + " [1336 268]\n", + " [1334 267]\n", + " [1332 263]]\n" + ] + } + ], + "source": [ + "# track = tracks[0]\n", + "for track in tracks:\n", + " history = track.get_projected_history(None, camera)\n", + " points = imgmap.to_map_points(history)\n", + " print(history, points)\n", + " if not ((points[:,0] > 0 ) & (points[:,0] < 2440) & (points[:,1] > 0) & (points[:,1] < 1440)).all():\n", + " print(\"not all points between limits\")\n", + " print(points)\n", + " break\n", + "\n", + "# track.to_trajectron_node(camera, env)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/trap/cv_renderer.py b/trap/cv_renderer.py index b847641..2d705e8 100644 --- a/trap/cv_renderer.py +++ b/trap/cv_renderer.py @@ -394,8 +394,6 @@ class CvRenderer: img = decorate_frame(frame, tracker_frame, prediction_frame, first_time, self.config, self.tracks, self.predictions) - img_path = (self.config.output_dir / f"{i:05d}.png").resolve() - logger.debug(f"write frame {frame.time - first_time:.3f}s") if self.out_writer: self.out_writer.write(img) @@ -403,6 +401,7 @@ class CvRenderer: self.streaming_process.stdin.write(img.tobytes()) if self.config.render_window: cv2.imshow('frame',cv2.resize(img, (1920, 1080))) + # cv2.imshow('frame',img) cv2.waitKey(1) # clear out old tracks & predictions: @@ -466,7 +465,9 @@ def decorate_frame(frame: Frame, tracker_frame: Frame, prediction_frame: Frame, undistorted_img = cv2.undistort(frame.img, config.camera.mtx, config.camera.dist, None, config.camera.newcameramtx) dst_img = cv2.warpPerspective(undistorted_img,convert_world_space_to_img_space(config.camera.H),(config.camera.w,config.camera.h)) - + # dst_img2 = cv2.warpPerspective(undistorted_img,convert_world_space_to_img_space(config.camera.H), None) + # cv2.imwrite('/home/ruben/suspicion/DATASETS/hof3/camera2.png', dst_img2) + overlay = np.zeros(dst_img.shape, np.uint8) # Fill image with red color(set each pixel to red) overlay[:] = (0, 0, 0) @@ -502,6 +503,7 @@ def decorate_frame(frame: Frame, tracker_frame: Frame, prediction_frame: Frame, anim_position = get_animation_position(track, frame) draw_track_predictions(img, track, int(track.track_id)+1, config.camera, convert_world_points_to_img_points, anim_position=anim_position) cv2.putText(img, f"{len(track.predictor_history) if track.predictor_history else 'none'}", to_point(track.history[0].get_foot_coords()), cv2.FONT_HERSHEY_COMPLEX, 1, (255,255,255), 1) + base_color = (255,)*3 info_color = (255,255,0) diff --git a/trap/process_data.py b/trap/process_data.py index ce3a69c..91c5a25 100644 --- a/trap/process_data.py +++ b/trap/process_data.py @@ -11,7 +11,7 @@ import pandas as pd import dill import tqdm import argparse -from typing import List +from typing import List, Optional from trap.config import CameraAction, HomographyAction from trap.frame_emitter import Camera @@ -22,6 +22,8 @@ from trajectron.environment import Environment, Scene, Node from trajectron.utils import maybe_makedirs from trajectron.environment import derivative_of +from trap.utils import ImageMap + FPS = 12 desired_max_time = 100 pred_indices = [2, 3] @@ -81,9 +83,28 @@ class TrackIteration: # maybe_makedirs('trajectron-data') # for desired_source in [ 'hof2', ]:# ,'hof-maskrcnn', 'hof-yolov8', 'VIRAT-0102-parsed', 'virat-resnet-keypoints-full']: -def process_data(src_dir: Path, dst_dir: Path, name: str, smooth_tracks: bool, cm_to_m: bool, center_data: bool, bin_positions: bool, camera: Camera, step_size: int, filter_displacement:float): +def process_data(src_dir: Path, dst_dir: Path, name: str, smooth_tracks: bool, cm_to_m: bool, center_data: bool, bin_positions: bool, camera: Camera, step_size: int, filter_displacement:float, map_img_path: Optional[Path]): + name += f"-nostep" if step_size == 1 else f"-step{step_size}" + name += f"-conv{smooth_window}" if smooth_tracks else f"-nosmooth" + name += f"-f{filter_displacement}" if filter_displacement > 0 else "" + name += "-map" if map_img_path else "-nomap" name += f"-{datetime.date.today()}" + print(f"Process data in {src_dir}, to {dst_dir}, identified by {name}") + + if map_img_path: + if not map_img_path.exists(): + raise RuntimeError(f"Map image does not exists {map_img_path}") + + type_map = {} + type_map['PEDESTRIAN'] = ImageMap( + map_img_path, + camera.H, + f"Map from {map_img_path.name}" + ) + else: + type_map = None + nl = 0 l = 0 @@ -221,7 +242,8 @@ def process_data(src_dir: Path, dst_dir: Path, name: str, smooth_tracks: bool, c last_ts = max([n.last_timestep for n in nodes]) # print(sorted([n.first_timestep for n in nodes])) - scene = Scene(timesteps=last_ts, dt=(1/camera.fps)*step_size, name=f'{split_id}_{scene_nr}', aug_func=None) + # TODO)) check use of maps: https://github.com/StanfordASL/Trajectron-plus-plus/issues/14 + scene = Scene(timesteps=last_ts, dt=(1/camera.fps)*step_size, name=f'{split_id}_{scene_nr}', aug_func=None, map=type_map) scene.nodes.extend(nodes) scenes.append(scene) # print(scene) @@ -271,6 +293,11 @@ def main(): # type=Path, default=0, type=float) + parser.add_argument("--map-img-path", + help="Image file representing a mask of a map (uses camera homography, assumes: 3 layers, values 0-255)", + # type=Path, + default=None, + type=Path) args = parser.parse_args() @@ -285,6 +312,7 @@ def main(): args.bin_positions, args.camera, args.step_size, - filter_displacement=args.filter_displacement + filter_displacement=args.filter_displacement, + map_img_path=args.map_img_path ) diff --git a/trap/tools.py b/trap/tools.py index bfbfff8..823665f 100644 --- a/trap/tools.py +++ b/trap/tools.py @@ -198,7 +198,10 @@ def transition_path_points(path: np.array, t: float): lengths = np.sqrt(np.sum(np.diff(path, axis=0)**2, axis=1)) cum_lenghts = np.cumsum(lengths) # distance = cum_lenghts[-1] * t - ts = np.concatenate((np.array([0.]), cum_lenghts / cum_lenghts[-1])) + # ts = np.concatenate((np.array([0.]), cum_lenghts / cum_lenghts[-1])) + # print(cum_lenghts[-1]) + DRAW_SPEED = 22 # fixed speed (independent of lenght) TODO)) make variable + ts = np.concatenate((np.array([0.]), cum_lenghts / DRAW_SPEED)) new_path = [path[0]] for a, b, t_a, t_b in zip(path[:-1], path[1:], ts[:-1], ts[1:]): @@ -209,7 +212,6 @@ def transition_path_points(path: np.array, t: float): relative_t = inv_lerp(t_a, t_b, t) x = lerp(a[0], b[0], relative_t) y = lerp(a[1], b[1], relative_t) - print(relative_t, a , b, x, y) new_path.append([x,y]) break return np.array(new_path) @@ -235,12 +237,13 @@ def draw_track_predictions(img: cv2.Mat, track: Track, color_index: int, camera: for pred_i, pred in enumerate(track.predictions): pred_coords = pred #cv2.perspectiveTransform(np.array([pred]), inv_H)[0].tolist() - # line_points = np.concatenate(([current_point], pred_coords)) # 'current point' is amoving target - line_points = pred_coords + # line_points = pred_coords + line_points = np.concatenate(([current_point], pred_coords)) # 'current point' is amoving target # print(pred_coords, current_point, line_points) line_points = transition_path_points(line_points, slide_t) if convert_points: line_points = convert_points(line_points) + line_points = np.rint(line_points).astype(int) # color = (128,0,128) if pred_i else (128,128,0) color = bgr_colors[color_index % len(bgr_colors)] @@ -260,7 +263,8 @@ def draw_track_predictions(img: cv2.Mat, track: Track, color_index: int, camera: # start = [int(p) for p in pred_coords[ci-1]] # end = [int(p) for p in pred_coords[ci]] # print(np.rint(start),np.rint(end).tolist()) - cv2.line(img, np.rint(start).astype(int), np.rint(end).astype(int), color, 1, lineType=cv2.LINE_AA) + cv2.line(img, start, end, color, 1, lineType=cv2.LINE_AA) + pass # cv2.circle(img, end, 2, color, 1, lineType=cv2.LINE_AA) def draw_trackjectron_history(img: cv2.Mat, track: Track, color_index: int, convert_points: Optional[Callable]): diff --git a/trap/utils.py b/trap/utils.py index 37dd9ce..6b6c6d8 100644 --- a/trap/utils.py +++ b/trap/utils.py @@ -1,11 +1,12 @@ # lerp & inverse lerp from https://gist.github.com/laundmo/b224b1f4c8ef6ca5fe47e132c8deab56 import linecache import os +from pathlib import Path import tracemalloc from typing import Iterable import cv2 import numpy as np - +from trajectron.environment.map import GeometricMap def lerp(a: float, b: float, t: float) -> float: """Linear interpolate on the scale given by a to b, using t as the point on that scale. @@ -69,3 +70,78 @@ def display_top(snapshot: tracemalloc.Snapshot, key_type='lineno', limit=5): print("%s other: %.1f KiB" % (len(other), size / 1024)) total = sum(stat.size for stat in top_stats) print("Total allocated size: %.1f KiB" % (total / 1024)) + + +class ImageMap(GeometricMap): # TODO Implement for image maps -> watch flipped coordinate system + def __init__(self, image_path: Path, H_img_to_world: cv2.Mat, description=None): + # homography_matrix = np.loadtxt('H.txt') + # homography_matrix = H_img_to_world.copy() + # homography_matrix /= homography_matrix[2, 2] # normalise? https://github.com/StanfordASL/Trajectron-plus-plus/issues/14#issuecomment-637880857 + # homography_matrix = np.linalg.inv(homography_matrix) + homography_matrix = np.array([ + [100, 0,0], + [0, 100,0], + [0,0,1], + ]) + + # RGB png image has 3 layers + img = cv2.imread(image_path).astype(np.uint8) + img_reverse = img[::-1,:,:] # origin to bottom left, instead of top-left + layers = np.transpose(img_reverse, (2, 1, 0)) # array order: layers, x, y + # layers = + + #scale 255 + + #alternatively: morph image to world space with a scale, as in trajectron/experiments/nuscenes/process_data.py + + super().__init__(layers, homography_matrix, description) + + def to_map_points(self, scene_pts): + org_shape = None + if len(scene_pts.shape) > 2: + org_shape = scene_pts.shape + scene_pts = scene_pts.reshape((-1, 2)) + N, dims = scene_pts.shape + points_with_one = np.ones((dims + 1, N)) + points_with_one[:dims] = scene_pts.T + # map_points = np.fliplr((self.homography @ points_with_one).T[..., :dims]).astype(np.uint32) + # map_points = np.flipud((self.homography @ points_with_one).T[..., :dims]).astype(np.uint32) + map_points = (self.homography @ points_with_one).T[..., :dims].astype(np.uint32) + if org_shape is not None: + map_points = map_points.reshape(org_shape) + # print(scene_pts,'->', map_points) + # exit() + return map_points + + +# nuscener process_data.py +# type_map = dict() +# canvas_size = (np.round(3 * y_size).astype(int), np.round(3 * x_size).astype(int)) +# homography = np.array([[3., 0., 0.], [0., 3., 0.], [0., 0., 3.]]) +# layer_names = ['lane', 'road_segment', 'drivable_area', 'road_divider', 'lane_divider', 'stop_line', +# 'ped_crossing', 'stop_line', 'ped_crossing', 'walkway'] +# map_mask = (nusc_map.get_map_mask(patch_box, patch_angle, layer_names, canvas_size) * 255.0).astype( +# np.uint8) +# map_mask = np.swapaxes(map_mask, 1, 2) # x axis comes first +# # PEDESTRIANS +# map_mask_pedestrian = np.stack((map_mask[9], map_mask[8], np.max(map_mask[:3], axis=0)), axis=0) +# +# type_map['PEDESTRIAN'] = GeometricMap(data=map_mask_pedestrian, homography=homography, description=', '.join(layer_names)) + +# Notes: map_mask is a list of masks +# map_mask = [] +# _line_geom_to_mask +# def mask_for_lines(...): +# map_mask = np.zeros(canvas_size, np.uint8) + +# if layer_name is 'traffic_light': +# return None + +# for line in layer_geom: +# new_line = line.intersection(patch) +# if not new_line.is_empty: +# new_line = affinity.affine_transform(new_line, +# [1.0, 0.0, 0.0, 1.0, trans_x, trans_y]) +# new_line = affinity.scale(new_line, xfact=scale_width, yfact=scale_height, origin=(0, 0)) + +# map_mask = self.mask_for_lines(new_line, map_mask) \ No newline at end of file