Skip to content

Commit 2e52cac

Browse files
committed
update of code and dash
1 parent 20e2182 commit 2e52cac

File tree

8 files changed

+136
-640
lines changed

8 files changed

+136
-640
lines changed

Diff for: README.md

+49-32
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# Анализ трафика на круговом движении (prod версия с множеством камер)
2-
# Версия с тайм сириес базой данных Influx
1+
# Анализ трафика на круговом движении
2+
**production версия с множеством камер и тайм сириес базой данных Influx**
33

44
Данная программа осуществляет анализ входящего трафика на участке кругового движения. Алгоритм определяет загруженность примыкающих дорог и выводит интерактивную статистику.
55

@@ -10,20 +10,48 @@
1010
docker compose -p traffic_analyzer up -d --build
1111
```
1212

13-
Необходимо в главной директории создать файл с переменными окружения, которые будут прокинуты во все контейнеры. Для этого создайте файл `secrets.txt` и положите подобный текст с паролями:
13+
Необходимо в главной директории создать файл с переменными окружения, которые будут прокинуты во все контейнеры. Для этого создайте файл `.env` и положите подобный текст с паролями и логинами к сервисам:
1414
```
15-
POSTGRES_DB=traffic_analyzer_db
16-
POSTGRES_USER=user
17-
POSTGRES_PASSWORD=pwd
15+
INFLUXDB_ADMIN_USER=admin
16+
INFLUXDB_ADMIN_PASSWORD=admin
1817
GF_SECURITY_ADMIN_USER=admin
1918
GF_SECURITY_ADMIN_PASSWORD=admin
2019
```
2120
Каждая новая камера добавляется как +1 инстанс бекенда traffic_analyzer_camera_N в котором надо указать лишь разные scr и конфигурации через переменные окружения
2221

23-
У каждой камеры сой дашборд между которыми можно переходит по кнопке:
22+
У каждой камеры свой дашборд между которыми можно переходит по кнопке:
2423

2524
![grafana](https://github.com/user-attachments/assets/c0c6d602-2026-460f-9c48-64180e87ca8e)
2625

26+
## Как запустить локально без дополнительных микросервисов:
27+
```
28+
# ставим библиотеки:
29+
python -m pip install --upgrade pip
30+
pip install "numpy<2"
31+
pip install cython_bbox==0.1.5 lap==0.4.0
32+
pip install torch==2.3.1 torchvision==0.18.1 --index-url https://download.pytorch.org/whl/cu121
33+
pip install -r requirements.txt
34+
35+
# запускаем код:
36+
python main_optimized.py pipeline.send_info_kafka=False
37+
```
38+
39+
## Рассмотрим, как реализован код:
40+
41+
Каждый кадр последовательно проходит через ноды, и в атрибуты этого объекта постепенно добавляется все больше и больше информации.
42+
43+
```mermaid
44+
graph TD;
45+
A["VideoReader<br>Считывает кадры из видеофайла"] --> B["DetectionTrackingNodes<br>Реализует детектирование машин + трекинг"];
46+
B --> C["TrackerInfoUpdateNode<br>Обновляет информацию об актуальных треках"];
47+
C --> D["CalcStatisticsNode<br>Вычисляет загруженность дорог"];
48+
D --send_info_kafka==False --> F;
49+
D --send_info_kafka==True --> E["KafkaProducerNode<br>Отправляет результаты в Kafka"];
50+
E --> F["ShowNode<br>Отображает результаты на экране"];
51+
F --save_video==True --> H["VideoSaverNode<br>Сохраняет обработанные кадры"];
52+
F --show_in_web==True & save_video==False --> L["FlaskServerVideoNode<br>Обновляет кадры в веб-интерфейсе"];
53+
H --show_in_web==True --> L
54+
```
2755

2856

2957
## Работа с программой:
@@ -55,39 +83,28 @@ __Пример режима демонстрации трекинга машин
5583
![Traffic Tracking](content_for_readme/traffic_tracking.gif)
5684

5785
---
58-
## Включение сторонних сервисов для визуализации результатов:
59-
Программа позволяет вести запись актуальной статистики о машинопотоке в базу данных PostgreSQL и тут же осуществлять визуализацию в виде интерактивного дашборда Grafana.
60-
61-
![image](https://github.com/user-attachments/assets/90844b76-45d0-4223-822d-4e943138c338)
6286

63-
Тем самым у конечного потребителя этого приложения имеется возможность запустить код один раз, подключив на вход RTSP поток или заготовленный видеофайл, и постоянно получать актуальную статистику, а также просматривать историю загруженности участка движения.
6487

88+
## Существующие версии кода:
6589

66-
## Вывод обработанного видеопотока в веб-интерфейс:
90+
В проекте специально предусмотрено множество веток, реализующих разные уровни разработки масштабного Computer Vision проекта.
6791

68-
Обработанные кадры можно отображать в веб-интерфейсе (вместо отдельного окна OpenCV). Бэкенд сайта реализован с использованием Flask.
92+
Например, в главной ветке [**main**](https://github.com/Koldim2001/TrafficAnalyzer/tree/main) Docker Compose позволяет поднять сторонние сервисы (Grafana для визуализации и базу данных PostgreSQL). Однако основной код, реализующий бекенд, необходимо запускать локально с помощью имеющегося на компьютере Python.
6993

70-
Для того, чтобы запустить проект таким образом, необходимо в файле configs/app_config.yaml в разделе pipeline указать show_in_web=True и в show_node указать imshow=False. Далее можно запускать main.py или main_optimized.py и переходить по ссылке http://localhost:8100/
94+
Дальнейшее развитие проекта заключается в реализации полного Docker Compose из всех имеющихся сервисов, включая сам бекенд. Такая версия доступна в ветке [**prod_docker_version**](https://github.com/Koldim2001/TrafficAnalyzer/tree/prod_docker_version). Код из этой ветки очень просто запустить, и не требуется ничего иметь на компьютере, кроме Docker. Проект запускается единственной командой: `docker compose -p traffic_analyzer up -d --build`
7195

72-
Пример того, как можно запустить проект и иметь возможность одновременно смотреть стрим по порту 8100 и наблюдать интерактивный дашборд в Grafana по порту 3111:
96+
Следующим этапом развития проекта стало появление ветки [**multicamera**](https://github.com/Koldim2001/TrafficAnalyzer/tree/multicamera). В ней реализовано всё то же, что и в ветке prod_docker_version, но теперь есть удобная возможность масштабировать проект на большое число камер. Для этого потребуется лишь в файле docker-compose добавить новые контейнеры бекенда с указанием пути до нового видео ресурса. При этом вся обработка будет выполняться нативно внутри контейнеров бекенда, включая инференс самой сети. Под каждую новую камеру автоматически поднимается новый инстанс сети YOLO, реализующий детекцию транспорта.
7397

74-
![web+grafana](content_for_readme/web+grafana.gif)
75-
76-
---
98+
Еще одним дальнейшим вариантом развития стало появление ветки [**feature/triton**](https://github.com/Koldim2001/TrafficAnalyzer/tree/feature/triton). По сути это та же ветка multicamera, но теперь все контейнеры бекенда не реализуют инференс сети внутри, а лишь отправляют запросы по gRPC на дополнительный сервис под названием Triton Inference Server. Благодаря этому можно масштабировать проект без значительного увеличения нагрузки (хотя значения FPS будет чуть ниже из-за того, что теперь для инференса надо отправлять запрос на сервис и получать ответы с него). Однако теперь лишь один контейнер взаимодействует с видеокартой, и инстансы бекенда не требуют GPU для работы.
7799

78-
## Рассмотрим, как реализован код:
100+
Еще одним дальнейшим вариантом развития стало появление ветки [**feature/influx**](https://github.com/Koldim2001/TrafficAnalyzer/tree/feature/influx). Это как раз та ветка в которой вы сейчас находитесь. По сути это та же ветка multicamera, но теперь база данных изменена с PostgreSQL на базу данных рмененных рядов InfluxDB. Данная база данных лучше подходит для работы с потоковыми данными, которые записываются с бекенда. При этом запись в InfluxDB осуществляется с помощью сервиса Telegraf, который читает топик брокера сообщений Kafka, в который отправляет бекенд, и производит автоматическое сохранение данных в Influx.
79101

80-
Каждый кадр последовательно проходит через ноды, и в атрибуты этого объекта постепенно добавляется все больше и больше информации.
102+
Структура ветвления Git проекта представлена ниже:
81103

82-
```mermaid
83-
graph TD;
84-
A["VideoReader<br>Считывает кадры из видеофайла"] --> B["DetectionTrackingNodes<br>Реализует детектирование машин + трекинг"];
85-
B --> C["TrackerInfoUpdateNode<br>Обновляет информацию об актуальных треках"];
86-
C --> D["CalcStatisticsNode<br>Вычисляет загруженность дорог"];
87-
D --sent_info_db==False --> F;
88-
D --sent_info_db==True --> E["SentInfoDBNode<br>Отправляет результаты в базу данных"];
89-
E --> F["ShowNode<br>Отображает результаты на экране"];
90-
F --save_video==True --> H["VideoSaverNode<br>Сохраняет обработанные кадры"];
91-
F --show_in_web==True & save_video==False --> L["FlaskServerVideoNode<br>Обновляет кадры в веб-интерфейсе"];
92-
H --show_in_web==True --> L
93104
```
105+
main
106+
└── prod_docker_version
107+
└── multicamera
108+
├── feature/triton
109+
└── feature/influx
110+
```

Diff for: configs/app_config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ kafka_producer_node: #// камера id
7474
bootstrap_servers: kafka:29092 #127.0.0.1:9092 #kafka:29092
7575
topic_name: ${oc.env:TOPIC_NAME}
7676
how_often_sec: 1 # раз в сколько секунд отправлять результат
77-
camera_id: ${oc.env:CAMERA_ID}
77+
camera_id: ${oc.decode:${oc.env:CAMERA_ID}}
7878

7979

8080
video_server_node:

Diff for: docker-compose.yaml

+59-57
Original file line numberDiff line numberDiff line change
@@ -56,61 +56,6 @@ services:
5656
- kafka
5757
networks:
5858
- prod_network
59-
60-
traffic_analyzer_camera_1:
61-
build: .
62-
image: traffic_analyzer/traffic_analyzer:latest
63-
restart: always
64-
container_name: traffic_analyzer_camera_1
65-
command: python main_optimized.py
66-
environment:
67-
- VIDEO_SRC=test_videos/test_video.mp4
68-
- ROADS_JSON=configs/entry_exit_lanes.json
69-
- TOPIC_NAME=statistic_1
70-
- CAMERA_ID=1
71-
volumes:
72-
- ./configs:/app/configs
73-
- ./weights:/app/weights
74-
- ./test_videos:/app/test_videos
75-
depends_on:
76-
kafka:
77-
condition: service_healthy
78-
deploy:
79-
resources:
80-
reservations:
81-
devices:
82-
- driver: nvidia
83-
count: all
84-
capabilities: [gpu]
85-
networks:
86-
- prod_network
87-
88-
traffic_analyzer_camera_2:
89-
image: traffic_analyzer/traffic_analyzer:latest
90-
restart: always
91-
container_name: traffic_analyzer_camera_2
92-
command: python main_optimized.py
93-
environment:
94-
- VIDEO_SRC=test_videos/longer_example.mp4
95-
- ROADS_JSON=configs/entry_exit_lanes.json
96-
- TOPIC_NAME=statistic_1
97-
- CAMERA_ID=2
98-
depends_on:
99-
kafka:
100-
condition: service_healthy
101-
volumes:
102-
- ./configs:/app/configs
103-
- ./weights:/app/weights
104-
- ./test_videos:/app/test_videos
105-
deploy:
106-
resources:
107-
reservations:
108-
devices:
109-
- driver: nvidia
110-
count: all
111-
capabilities: [gpu]
112-
networks:
113-
- prod_network
11459

11560
grafana:
11661
container_name: grafana_traffic
@@ -119,6 +64,8 @@ services:
11964
TZ: "Europe/Moscow"
12065
GF_ALLOW_EMBEDDING: "true"
12166
GF_PANELS_DISABLE_SANITIZE_HTML: "true"
67+
GF_SECURITY_ADMIN_USER: ${GF_SECURITY_ADMIN_USER}
68+
GF_SECURITY_ADMIN_PASSWORD: ${GF_SECURITY_ADMIN_PASSWORD}
12269
restart: unless-stopped
12370
ports:
12471
- "3111:3000"
@@ -135,8 +82,8 @@ services:
13582
- "8087:8086"
13683
environment:
13784
- INFLUX_DB=influx
138-
- INFLUXDB_ADMIN_USER=admin
139-
- INFLUXDB_ADMIN_PASSWORD=admin
85+
- INFLUXDB_ADMIN_USER=${INFLUXDB_ADMIN_USER}
86+
- INFLUXDB_ADMIN_PASSWORD=${INFLUXDB_ADMIN_PASSWORD}
14087
- INFLUXDB_RETENTION_POLICY_AUTOCREATE=true
14188
- INFLUXDB_RETENTION_DURATION=30d
14289
volumes:
@@ -170,6 +117,61 @@ services:
170117
networks:
171118
- prod_network
172119

120+
traffic_analyzer_camera_1:
121+
build: .
122+
image: traffic_analyzer/traffic_analyzer:latest
123+
restart: always
124+
container_name: traffic_analyzer_camera_1
125+
command: python main_optimized.py
126+
environment:
127+
- VIDEO_SRC=test_videos/test_video.mp4
128+
- ROADS_JSON=configs/entry_exit_lanes.json
129+
- TOPIC_NAME=statistic_1
130+
- CAMERA_ID=1
131+
volumes:
132+
- ./configs:/app/configs
133+
- ./weights:/app/weights
134+
- ./test_videos:/app/test_videos
135+
depends_on:
136+
kafka:
137+
condition: service_healthy
138+
deploy:
139+
resources:
140+
reservations:
141+
devices:
142+
- driver: nvidia
143+
count: all
144+
capabilities: [gpu]
145+
networks:
146+
- prod_network
147+
148+
traffic_analyzer_camera_2:
149+
image: traffic_analyzer/traffic_analyzer:latest
150+
restart: always
151+
container_name: traffic_analyzer_camera_2
152+
command: python main_optimized.py
153+
environment:
154+
- VIDEO_SRC=test_videos/longer_example.mp4
155+
- ROADS_JSON=configs/entry_exit_lanes.json
156+
- TOPIC_NAME=statistic_1
157+
- CAMERA_ID=2
158+
depends_on:
159+
kafka:
160+
condition: service_healthy
161+
volumes:
162+
- ./configs:/app/configs
163+
- ./weights:/app/weights
164+
- ./test_videos:/app/test_videos
165+
deploy:
166+
resources:
167+
reservations:
168+
devices:
169+
- driver: nvidia
170+
count: all
171+
capabilities: [gpu]
172+
networks:
173+
- prod_network
174+
173175
networks:
174176
prod_network:
175177
driver: bridge

Diff for: main.py

+6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@
88
from nodes.FlaskServerVideoNode import VideoServer
99
from elements.VideoEndBreakElement import VideoEndBreakElement
1010
from nodes.KafkaProducerNode import KafkaProducerNode
11+
from utils_local.utils import check_and_set_env_var
1112

13+
# Проверяем и устанавливаем переменные окружения если их нет
14+
check_and_set_env_var("VIDEO_SRC", "test_videos/test_video.mp4")
15+
check_and_set_env_var("ROADS_JSON", "configs/entry_exit_lanes.json")
16+
check_and_set_env_var("TOPIC_NAME", "statistic_1")
17+
check_and_set_env_var("CAMERA_ID", 1)
1218

1319
@hydra.main(version_base=None, config_path="configs", config_name="app_config")
1420
def main(config) -> None:

Diff for: main_optimized.py

+7
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,16 @@
1313
from nodes.FlaskServerVideoNode import VideoServer
1414
from nodes.KafkaProducerNode import KafkaProducerNode
1515
from elements.VideoEndBreakElement import VideoEndBreakElement
16+
from utils_local.utils import check_and_set_env_var
1617

1718
PRINT_PROFILE_INFO = False
1819

20+
# Проверяем и устанавливаем переменные окружения если их нет
21+
check_and_set_env_var("VIDEO_SRC", "test_videos/test_video.mp4")
22+
check_and_set_env_var("ROADS_JSON", "configs/entry_exit_lanes.json")
23+
check_and_set_env_var("TOPIC_NAME", "statistic_1")
24+
check_and_set_env_var("CAMERA_ID", 1)
25+
1926

2027
def proc_frame_reader_and_detection(queue_out: Queue, config: dict, time_sleep_start: int):
2128
sleep_message = f"Система разогревается.. sleep({time_sleep_start})"

Diff for: services/grafana/grafana.db

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)