0% found this document useful (0 votes)
4 views31 pages

Codebase

The document outlines a complete codebase for a traffic monitoring system that includes a pipeline, PostgreSQL database, Django REST framework backend, and a React frontend. It supports two modes: a four-zone intersection mode and a two-point mode, with detailed folder structures and code snippets provided for each component. Users can log in, select modes, and visualize traffic data through charts after the pipeline ingests video data and stores counts in the database.

Uploaded by

aadarshsunam4
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views31 pages

Codebase

The document outlines a complete codebase for a traffic monitoring system that includes a pipeline, PostgreSQL database, Django REST framework backend, and a React frontend. It supports two modes: a four-zone intersection mode and a two-point mode, with detailed folder structures and code snippets provided for each component. Users can log in, select modes, and visualize traffic data through charts after the pipeline ingests video data and stores counts in the database.

Uploaded by

aadarshsunam4
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Below is a complete end-to-end codebase (pipeline → PostgreSQL → Django DRF → React

frontend) that supports both the four-zone intersection mode and a two-point (front/back) mode.
We’ll show:

1. Folder structure
2. Pipeline script (standalone Python) with modular direction logic
3. [Link] (defines both modes)
4. Django project
o [Link] (with DRF/JWT, PostgreSQL)
o traffic/[Link]
o traffic/[Link]
o traffic/[Link]
o traffic/[Link]
o backend/[Link]
o traffic/management/commands/ingest_to_pg.py
o [Link]
5. React frontend (created via create-react-app)
o src/[Link] (Axios + JWT)
o src/contexts/[Link] (login state)
o src/components/[Link]
o src/components/[Link] (per-minute counts)
o src/components/[Link] (directional flows)
o src/[Link] (routing, protected routes)
o src/[Link]
o [Link] (dependencies)

Everything is wired so that:

 Pipeline (ingest_to_pg.py) reads local MP4s, uses TrafficPipeline with --mode


intersection4 or --mode point2, and writes (timestamp, vehicle_class,
direction, count, scenario) into PostgreSQL.
 Django exposes /api/traffic/counts/ with JWT auth.
 React allows users to log in, select a time‐range and mode, and see charts.

You can clone, drop into each subfolder, install dependencies, and run each piece independently.

1. Folder Structure
markdown
CopyEdit
smart_traffic/
├── pipeline/ # → Standalone ingestion pipeline
│ ├── ingest_to_pg.py
│ ├── traffic_pipeline/
│ │ ├── __init__.py
│ │ └── [Link]
│ └── config/
│ └── [Link]

├── backend/ # → Django project
│ ├── backend/
│ │ ├── __init__.py
│ │ ├── [Link]
│ │ ├── [Link]
│ │ ├── [Link]
│ │ └── [Link]
│ │
│ ├── traffic/
│ │ ├── __init__.py
│ │ ├── [Link]
│ │ ├── [Link]
│ │ ├── management/
│ │ │ └── commands/
│ │ │ └── ingest_to_pg.py
│ │ ├── migrations/
│ │ │ └── __init__.py
│ │ ├── [Link]
│ │ ├── [Link]
│ │ ├── [Link]
│ │ ├── [Link]
│ │ └── [Link]
│ │
│ ├── [Link]
│ └── [Link]

└── frontend/ # → React app (create-react-app)
├── public/
│ ├── [Link]
│ └── ...
├── src/
│ ├── [Link]
│ ├── contexts/
│ │ └── [Link]
│ ├── components/
│ │ ├── [Link]
│ │ ├── [Link]
│ │ ├── [Link]
│ │ └── [Link]
│ ├── [Link]
│ ├── [Link]
│ └── ...
└── [Link]

2. Pipeline (Standalone Ingestion)


2.1 config/[Link]
yaml
CopyEdit
# pipeline/config/[Link]
intersection4:
type: zones
zones:
Koteshwor:
x1_frac: 0.10; y1_frac: 0.00; x2_frac: 0.90; y2_frac: 0.10
Kalanki:
x1_frac: 0.10; y1_frac: 0.90; x2_frac: 0.90; y2_frac: 1.00
Lagankhel:
x1_frac: 0.00; y1_frac: 0.10; x2_frac: 0.10; y2_frac: 0.90
Godawari:
x1_frac: 0.90; y1_frac: 0.10; x2_frac: 1.00; y2_frac: 0.90

point2:
type: points
front:
x1_frac: 0.45; y1_frac: 0.00; x2_frac: 0.55; y2_frac: 0.05
back:
x1_frac: 0.45; y1_frac: 0.95; x2_frac: 0.55; y2_frac: 1.00

 intersection4: Four rectangular zones (fractions of full frame).


 point2: Two small “points” (rectangular strips) at top (“front”) and bottom (“back”).

2.2 traffic_pipeline/[Link]
python
CopyEdit
# pipeline/traffic_pipeline/[Link]

import cv2
import yaml
from ultralytics import YOLO
from collections import defaultdict

class TrafficPipeline:
"""
Unified pipeline that supports both:
- 4-way intersection mode ("intersection4")
- 2-point front/back mode ("point2")
Load scenario definitions from YAML, then run YOLOv8 + ByteTrack,
draw boxes, and count when centroid hits a zone.
"""

def __init__(self, model_path, data_yaml, scenarios_yaml, mode,


min_conf=0.1, iou=0.2):
# 1) Load class names
with open(data_yaml, 'r') as f:
self.class_names = yaml.safe_load(f)['names']

# 2) Load YOLOv8 model


[Link] = YOLO(model_path)

# 3) Load scenario definitions


with open(scenarios_yaml, 'r') as f:
all_scenarios = yaml.safe_load(f)
if mode not in all_scenarios:
raise ValueError(f"Mode '{mode}' not found in {scenarios_yaml}")
[Link] = all_scenarios[mode]
[Link] = mode # either "intersection4" or "point2"

# 4) Internal counting state


self.last_centroid = {} # tid → (cx, cy, cls_name, bbox)
[Link] = set()
[Link] = defaultdict(lambda: defaultdict(int))

# 5) YOLO thresholds
self.min_conf = min_conf
[Link] = iou

# 6) Zone rectangles (populated on first frame)


[Link] = {} # name → (x1,y1,x2,y2)
self.frame_shape = None

def _init_zones(self, H, W):


"""
Build pixel rectangles from fraction definitions in YAML.
"""
scen = [Link]
if scen['type'] == 'zones':
for name, frac in scen['zones'].items():
x1 = int(frac['x1_frac'] * W)
y1 = int(frac['y1_frac'] * H)
x2 = int(frac['x2_frac'] * W)
y2 = int(frac['y2_frac'] * H)
[Link][name] = (x1, y1, x2, y2)
elif scen['type'] == 'points':
for key, frac in [Link]():
if key == 'type':
continue
x1 = int(frac['x1_frac'] * W)
y1 = int(frac['y1_frac'] * H)
x2 = int(frac['x2_frac'] * W)
y2 = int(frac['y2_frac'] * H)
[Link][key] = (x1, y1, x2, y2)
else:
raise ValueError(f"Unknown scenario type: {scen['type']}")

self.frame_shape = (H, W)

def get_direction(self, cx, cy):


"""
Return the zone name (or point name) containing (cx,cy), else None.
"""
for name, (x1,y1,x2,y2) in [Link]():
if x1 <= cx < x2 and y1 <= cy < y2:
return name
return None

def process_frame(self, frame):


"""
Run YOLOv8+ByteTrack on 'frame', draw bounding boxes and count
vehicles
when their centroid enters any defined zone/point.
"""
H, W = [Link][:2]
if self.frame_shape is None:
# On first invocation, initialize pixel-based zones
self._init_zones(H, W)

# Draw zone outlines for debugging


for name, (x1,y1,x2,y2) in [Link]():
if [Link]['type'] == 'points':
clr = (0,255,0) # green for front/back
else:
# distinct colors for four intersection zones
clr_map = {
'Koteshwor': (255,255,0),
'Kalanki': (0,255,255),
'Lagankhel': (255,0,255),
'Godawari': (0,255,0),
}
clr = clr_map.get(name, (0,0,255))
[Link](frame, (x1,y1),(x2,y2), clr, 2)
[Link](frame, name, (x1+5, y1+20),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, clr, 2)

# A) Detection + Tracking (YOLOv8 + ByteTrack)


res = [Link](
frame,
tracker="[Link]",
persist=True,
conf=self.min_conf,
iou=[Link]
)[0]

# B) Update centroids & draw default green box


for box in [Link]:
tid = int([Link][0])
cid = int([Link][0])
cls_nm = self.class_names[cid]
x1,y1,x2,y2 = map(int, [Link][0])
cx, cy = (x1+x2)//2, (y1+y2)//2

self.last_centroid[tid] = (cx, cy, cls_nm, (x1,y1,x2,y2))

[Link](frame, (x1,y1),(x2,y2), (0,255,0), 2)


[Link](frame, f"{cls_nm} ID:{tid}",
(x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX,
0.5, (0,255,0), 1)

# C) Count vehicles that enter a zone/point


for tid, (cx, cy, cls_nm, bb) in list(self.last_centroid.items()):
if tid in [Link]:
continue
dir_name = self.get_direction(cx, cy)
if dir_name:
[Link][cls_nm][dir_name] += 1
[Link](tid)

# Recolor counted box


x1,y1,x2,y2 = bb
if [Link]['type'] == 'points':
clr = (0,0,255) # red for front/back
else:
clr_map = {
'Koteshwor': (255,255,0),
'Kalanki': (0,255,255),
'Lagankhel': (255,0,255),
'Godawari': (0,255,0),
}
clr = clr_map[dir_name]
[Link](frame, (x1,y1),(x2,y2), clr, 3)
[Link](frame, f"{cls_nm}:{dir_name}",
(x1, y1-10),
cv2.FONT_HERSHEY_SIMPLEX,
0.5, clr, 2)

return frame

def reset_minute(self):
"""
Snapshot per-minute counts and reset counting state.
Returns: {cls→{direction→count}}.
"""
snapshot = dict([Link])
[Link]()
[Link]()
return snapshot

 __init__ takes:
o model_path & data_yaml for YOLO
o scenarios_yaml (path to [Link])
o mode = "intersection4" or "point2"
o thresholds min_conf & iou
 _init_zones builds pixel rectangles from fractional definitions.
 process_frame: draws zones, runs detection+tracking, draws green boxes, counts when
centroid enters a zone/point, recolors counted boxes.
 reset_minute returns the aggregated dictionary and clears counters.

2.3 ingest_to_pg.py
python
CopyEdit
# pipeline/ingest_to_pg.py

import os
import time
import cv2
import yaml
import argparse
import psycopg2
from [Link] import execute_values
from collections import defaultdict
from datetime import datetime, timedelta

from traffic_pipeline.core import TrafficPipeline

#
─────────────────────────────────────────────────────────────────────────────
# 1) CONFIGURATION
#
─────────────────────────────────────────────────────────────────────────────

# 1.1 Command-line arguments


parser = [Link]()
parser.add_argument('--mode', choices=['intersection4','point2'],
default='intersection4',
help="Choose counting mode: 'intersection4' or 'point2'")
parser.add_argument('--video_folder', default=[Link]([Link](),
"videos"),
help="Folder containing MP4 files to process")
parser.add_argument('--model', default=[Link]([Link](),
"[Link]"),
help="Path to YOLOv8 weights (.pt)")
parser.add_argument('--data_yaml', default=[Link]([Link](),
"[Link]"),
help="Path to data YAML (with class names)")
parser.add_argument('--scenarios', default=[Link]([Link](),
"config/[Link]"),
help="Path to [Link]")
parser.add_argument('--min_conf', type=float, default=0.1, help="YOLO
confidence threshold")
parser.add_argument('--iou', type=float, default=0.2, help="YOLO IoU
threshold")
parser.add_argument('--pg_host', default="localhost", help="Postgres host")
parser.add_argument('--pg_port', type=int, default=5432, help="Postgres port")
parser.add_argument('--pg_db', default="smart_traffic_db", help="Postgres DB
name")
parser.add_argument('--pg_user', default="traffic_user", help="Postgres user")
parser.add_argument('--pg_pass', default="traffic_pass", help="Postgres
password")
args = parser.parse_args()

VIDEO_FOLDER = args.video_folder
MODEL_PATH = [Link]
DATA_YAML = args.data_yaml
SCENARIOS_YAML= [Link]
MIN_CONF = args.min_conf
IOU = [Link]

PG_HOST = args.pg_host
PG_PORT = args.pg_port
PG_DB = args.pg_db
PG_USER = args.pg_user
PG_PASSWORD = args.pg_pass
#
─────────────────────────────────────────────────────────────────────────────
# 2) Database Helper
#
─────────────────────────────────────────────────────────────────────────────

def connect_db():
return [Link](
host = PG_HOST,
port = PG_PORT,
dbname = PG_DB,
user = PG_USER,
password = PG_PASSWORD
)

def insert_counts(conn, intersection_name, minute_dt, minute_counts,


scenario_name):
"""
Bulk-insert (cls, direction, count) rows for a single minute timestamp.
minute_counts: {cls_name: {dir_name: count, …}, …}
We also insert `scenario_name` to track mode.
"""
with [Link]() as cur:
# 2.1 Get or create Intersection
[Link]("SELECT id FROM traffic_intersection WHERE name = %s;",
(intersection_name,))
row = [Link]()
if row:
intersection_id = row[0]
else:
[Link]("INSERT INTO traffic_intersection(name) VALUES(%s)
RETURNING id;", (intersection_name,))
intersection_id = [Link]()[0]

# 2.2 Get or create VehicleClass ids


vc_ids = {}
for cls_nm in minute_counts:
[Link]("SELECT id FROM traffic_vehicleclass WHERE name =
%s;", (cls_nm,))
r = [Link]()
if r:
vc_ids[cls_nm] = r[0]
else:
[Link]("INSERT INTO traffic_vehicleclass(name) VALUES(%s)
RETURNING id;", (cls_nm,))
vc_ids[cls_nm] = [Link]()[0]

# 2.3 Build rows: each row → (intersection_id, vehicle_class_id,


direction, timestamp, count, scenario)
rows = []
for cls_nm, dirs in minute_counts.items():
for dir_name, cnt in [Link]():
[Link]((
intersection_id,
vc_ids[cls_nm],
dir_name,
minute_dt,
cnt,
scenario_name
))

# 2.4 Bulk insert


sql = """
INSERT INTO traffic_vehiclecount
(intersection_id, vehicle_class_id, direction, timestamp, count,
scenario)
VALUES %s
ON CONFLICT DO NOTHING;
"""
execute_values(cur, sql, rows)
[Link]()

#
─────────────────────────────────────────────────────────────────────────────
# 3) MAIN: Process All MP4 Files
#
─────────────────────────────────────────────────────────────────────────────

def main():
conn = connect_db()
pipeline = TrafficPipeline(MODEL_PATH, DATA_YAML, SCENARIOS_YAML,
[Link], MIN_CONF, IOU)

# List MP4s in VIDEO_FOLDER


mp4s = sorted([f for f in [Link](VIDEO_FOLDER) if
[Link]().endswith(".mp4")])

for filename in mp4s:


video_path = [Link](VIDEO_FOLDER, filename)
print(f"=== Processing video: {video_path} (mode={[Link]}) ===")
cap = [Link](video_path)
if not [Link]():
print(f"❌ Could not open {video_path}, skipping.")
continue

# Per-minute scheduling
next_min = [Link]().replace(second=0, microsecond=0) +
timedelta(minutes=1)
buffer = [] # collect (cls, direction, count) every frame

while True:
ret, frame = [Link]()
if not ret:
print("☑️ End of this video.")
break

# Process: annotate and update counts


annotated_frame = pipeline.process_frame(frame)

# Collect all new counts this frame


for cls_nm, dirs in [Link]():
for dir_name, cnt in [Link]():
[Link]((cls_nm, dir_name, cnt))

# When we cross the minute boundary:


if [Link]() >= next_min:
# 1) Aggregate buffer into per-minute dictionary
agg = defaultdict(lambda: defaultdict(int))
for cls_nm, dir_nm, cnt in buffer:
agg[cls_nm][dir_nm] += cnt

# 2) Insert to Postgres with scenario name


insert_counts(conn, "MainStreet", next_min, agg, [Link])

# 3) Clear state for next minute


[Link]()
[Link]()
[Link]()
next_min += timedelta(minutes=1)

[Link]()

[Link]()
print("✅ All videos processed. Pipeline complete.")

if __name__ == "__main__":
main()

How to Run the Pipeline:

1. Put all your MP4 files into a local folder named videos/ (same level as
ingest_to_pg.py).
2. Place your [Link] (YOLOv8 weights) and [Link] (with class names) in the
same directory (or adjust paths).
3. Ensure you have a PostgreSQL database called smart_traffic_db, user traffic_user
with password traffic_pass, and tables will be created automatically by Django (see
next section).
4. From pipeline/, run:

bash
CopyEdit
python ingest_to_pg.py --mode intersection4

or:

bash
CopyEdit
python ingest_to_pg.py --mode point2

The script will loop through every .mp4 in videos/, process frames, and bulk‐insert
counts per minute into the traffic_vehiclecount table.
3. Django DRF Backend
Create a Django project in smart_traffic/backend/. Below are all the necessary files.

3.1 backend/[Link]
php
CopyEdit
Django>=4.2
djangorestframework
djangorestframework-simplejwt
psycopg2-binary
celery
redis

(You may install extra packages if you use Celery for ingestion.)

3.2 backend/backend/[Link]
python
CopyEdit
# backend/backend/[Link]

from pathlib import Path


from datetime import timedelta

BASE_DIR = Path(__file__).resolve().[Link]

SECRET_KEY = 'replace-with-your-secret-key'
DEBUG = True
ALLOWED_HOSTS = []

INSTALLED_APPS = [
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'rest_framework',
'traffic',
]

MIDDLEWARE = [
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
'[Link]',
]
ROOT_URLCONF = '[Link]'

TEMPLATES = [
{
'BACKEND': '[Link]',
'DIRS': [], # no templates needed
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'[Link].context_processors.debug',
'[Link].context_processors.request',
'[Link].context_processors.auth',
'[Link].context_processors.messages',
],
},
},
]

WSGI_APPLICATION = '[Link]'

# PostgreSQL settings
DATABASES = {
'default': {
'ENGINE': '[Link]',
'NAME': 'smart_traffic_db',
'USER': 'traffic_user',
'PASSWORD': 'traffic_pass',
'HOST': 'localhost',
'PORT': '5432',
}
}

AUTH_PASSWORD_VALIDATORS = [
{
'NAME':
'[Link].password_validation.UserAttributeSimilarityValidator',
},
# (Add other validators as desired)
]

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True

STATIC_URL = 'static/'

# DRF + JWT configuration


REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.[Link]',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.[Link]',
),
}
from datetime import timedelta

SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
}

3.3 backend/backend/[Link]
python
CopyEdit
# backend/backend/[Link]

from [Link] import admin


from [Link] import path, include
from rest_framework.routers import DefaultRouter
from [Link] import VehicleCountViewSet
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)

router = DefaultRouter()
[Link](r'traffic/counts', VehicleCountViewSet, basename='counts')

urlpatterns = [
path('admin/', [Link]),
path('api/', include([Link])),
path('api/auth/token/', TokenObtainPairView.as_view(),
name='token_obtain_pair'),
path('api/auth/refresh/', TokenRefreshView.as_view(),
name='token_refresh'),
]

3.4 backend/traffic/[Link]
python
CopyEdit
# backend/traffic/[Link]

from [Link] import models

class Intersection([Link]):
name = [Link](max_length=100, unique=True)
def __str__(self):
return [Link]

class VehicleClass([Link]):
name = [Link](max_length=50, unique=True)
def __str__(self):
return [Link]

class VehicleCount([Link]):
intersection = [Link](Intersection, on_delete=[Link])
vehicle_class = [Link](VehicleClass, on_delete=[Link])
direction = [Link](max_length=50)
timestamp = [Link]()
count = [Link]()
scenario = [Link](max_length=50, default='intersection4')

class Meta:
unique_together =
('intersection','vehicle_class','direction','timestamp','scenario')
indexes = [
[Link](fields=['intersection','timestamp']),
[Link](fields=['vehicle_class','timestamp']),
[Link](fields=['scenario','timestamp']),
]

 Changed direction to a free CharField(50).


 Added scenario (mode) to track which mode was active.
 Ensure unique_together includes scenario so we don’t clash across modes.

3.5 backend/traffic/[Link]
python
CopyEdit
# backend/traffic/[Link]

from rest_framework import serializers


from .models import VehicleCount

class VehicleCountSerializer([Link]):
class Meta:
model = VehicleCount
fields = '__all__'

3.6 backend/traffic/[Link]
python
CopyEdit
# backend/traffic/[Link]

from rest_framework import viewsets


from .models import VehicleCount
from .serializers import VehicleCountSerializer

class VehicleCountViewSet([Link]):
"""
List / retrieve VehicleCount records.
Supports filters: ?
intersection=<id>&start=<ISO>&end=<ISO>&class=<name>&direction=<name>&scenario
=<name>
"""
queryset = [Link]().order_by('-timestamp')
serializer_class = VehicleCountSerializer

def get_queryset(self):
qs = super().get_queryset()
f = [Link].query_params

# Filter by intersection id
if 'intersection' in f:
qs = [Link](intersection__id=f['intersection'])

# Filter by timestamp range


if 'start' in f and 'end' in f:
qs = [Link](timestamp__range=[f['start'], f['end']])

# Filter by vehicle_class name


if 'class' in f:
qs = [Link](vehicle_class__name=f['class'])

# Filter by direction name


if 'direction' in f:
qs = [Link](direction=f['direction'])

# Filter by scenario
if 'scenario' in f:
qs = [Link](scenario=f['scenario'])

return qs

3.7 backend/traffic/[Link]
python
CopyEdit
# backend/traffic/[Link]

# (No extra URLs needed since we use router in backend/[Link])

(This file can remain empty or omitted.)

3.8 backend/traffic/management/commands/ingest_to_pg.py

We’re reusing the same ingestion script but as a Django command. This allows python
[Link] ingest_to_pg --mode intersection4. Create:

python
CopyEdit
# backend/traffic/management/commands/ingest_to_pg.py

import os
import cv2
import yaml
from [Link] import BaseCommand
from [Link] import timezone
from collections import defaultdict
from datetime import datetime, timedelta
from traffic_pipeline.core import TrafficPipeline
from [Link] import Intersection, VehicleClass, VehicleCount
from [Link] import execute_values
from [Link] import connection

class Command(BaseCommand):
help = "Run TrafficPipeline on MP4s in 'videos/' folder and insert counts
into Postgres."

def add_arguments(self, parser):


parser.add_argument('--mode', choices=['intersection4','point2'],
default='intersection4')
parser.add_argument('--video_folder',
default=[Link]([Link](), 'videos'))

def handle(self, *args, **options):


mode = options['mode']
video_folder = options['video_folder']

# 1) Set up pipeline
model_path = [Link]([Link](), '[Link]')
data_yaml = [Link]([Link](), '[Link]')
scenarios = [Link]([Link](), 'config/[Link]')

pipeline = TrafficPipeline(model_path, data_yaml, scenarios, mode,


min_conf=0.1, iou=0.2)

# 2) List MP4s
mp4s = sorted([f for f in [Link](video_folder) if
[Link]().endswith('.mp4')])

# 3) Process each video


for fname in mp4s:
vpath = [Link](video_folder, fname)
[Link]([Link](f"Processing {vpath}
(mode={mode})"))
cap = [Link](vpath)
if not [Link]():
[Link]([Link](f"Cannot open {vpath},
skipping."))
continue

next_min = [Link]().replace(second=0, microsecond=0) +


timedelta(minutes=1)
buffer = []

while True:
ret, frame = [Link]()
if not ret:
break

_ = pipeline.process_frame(frame)
# Collect current minute’s counts
for cls_nm, dirs in [Link]():
for dir_nm, cnt in [Link]():
[Link]((cls_nm, dir_nm, cnt))

# When the clock crosses next_min:


if [Link]() >= next_min:
# Aggregate
agg = defaultdict(lambda: defaultdict(int))
for cls_nm, dir_nm, cnt in buffer:
agg[cls_nm][dir_nm] += cnt

# Bulk insert via Django ORM


self._bulk_insert(minute_dt=next_min, minute_counts=agg,
scenario=mode)

[Link]()
[Link]()
[Link]()
next_min += timedelta(minutes=1)

[Link]()
[Link]([Link](f"Finished {vpath}"))

[Link]([Link]("All videos processed."))

def _bulk_insert(self, minute_dt, minute_counts, scenario):


"""
Insert records into traffic_vehiclecount using raw SQL.
"""
with [Link]() as cur:
# 1) Intersection
inter_name = "MainStreet"
[Link]("SELECT id FROM traffic_intersection WHERE name=%s;",
(inter_name,))
row = [Link]()
if row:
inter_id = row[0]
else:
[Link]("INSERT INTO traffic_intersection(name) VALUES
(%s) RETURNING id;", (inter_name,))
inter_id = [Link]()[0]

# 2) VehicleClass
vc_ids = {}
for cls_nm in minute_counts:
[Link]("SELECT id FROM traffic_vehicleclass WHERE name=
%s;", (cls_nm,))
r = [Link]()
if r:
vc_ids[cls_nm] = r[0]
else:
[Link]("INSERT INTO traffic_vehicleclass(name)
VALUES(%s) RETURNING id;", (cls_nm,))
vc_ids[cls_nm] = [Link]()[0]

# 3) Build rows
rows = []
for cls_nm, dirs in minute_counts.items():
for dir_nm, cnt in [Link]():
[Link]((
inter_id,
vc_ids[cls_nm],
dir_nm,
minute_dt,
cnt,
scenario
))

# 4) Bulk insert
sql = """
INSERT INTO traffic_vehiclecount
(intersection_id, vehicle_class_id, direction, timestamp, count,
scenario)
VALUES %s
ON CONFLICT DO NOTHING;
"""
execute_values(cur, sql, rows)

[Link]()

 This is effectively the same as our standalone script but integrated into Django’s
management command system.
 Run it via:

bash
CopyEdit
python [Link] ingest_to_pg --mode intersection4

or:

bash
CopyEdit
python [Link] ingest_to_pg --mode point2

4. React Frontend
Below is a create-react-app–style frontend that:

 Logs in via JWT to /api/auth/token/


 Stores the token in AuthContext
 Fetches /api/traffic/counts/ with appropriate query params
 Displays a LineChart (per-minute counts) and a StackedBar (direction flows)
 Allows selecting mode (intersection4 vs point2) and date/time range

4.1 frontend/[Link]
json
CopyEdit
{
"name": "smart-traffic-frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.4.0",
"[Link]": "^4.3.0",
"react": "^18.2.0",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.0",
"react-scripts": "5.0.1"
},
"scripts": {
"start": "PORT=3000 react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test"
}
}

4.2 frontend/src/[Link]
js
CopyEdit
// frontend/src/[Link]

import axios from 'axios';

// Base Axios instance


export const api = [Link]({
baseURL: '[Link] // adjust if Django is elsewhere
});

// Interceptor to append JWT access token to every request


export function attachTokenToHeader(token) {
[Link]['Authorization'] = `Bearer ${token}`;
}

export function clearTokenHeader() {


delete [Link]['Authorization'];
}

4.3 frontend/src/contexts/[Link]
jsx
CopyEdit
// frontend/src/contexts/[Link]

import React, { createContext, useState, useEffect } from 'react';


import { api, attachTokenToHeader, clearTokenHeader } from '../api';
export const AuthContext = createContext();

export function AuthProvider({ children }) {


const [token, setToken] = useState(() => [Link]('accessToken')
|| '');
const [user, setUser] = useState(null);

// Whenever token changes, update Axios header


useEffect(() => {
if (token) {
[Link]('accessToken', token);
attachTokenToHeader(token);
// Optionally decode token or fetch user info
setUser({ username: 'Authenticated User' });
} else {
[Link]('accessToken');
clearTokenHeader();
setUser(null);
}
}, [token]);

const login = async (username, password) => {


try {
const res = await [Link]('auth/token/', { username, password });
setToken([Link]);
return true;
} catch (err) {
[Link]("Login failed:", err);
return false;
}
};

const logout = () => {


setToken('');
};

return (
<[Link] value={{ token, user, login, logout }}>
{children}
</[Link]>
);
}

 login(...) calls /api/auth/token/ with credentials → sets access token.


 Token stored in localStorage and attached to all api calls.
 logout() clears token.

4.4 frontend/src/components/[Link]
jsx
CopyEdit
// frontend/src/components/[Link]

import React, { useState, useContext } from 'react';


import { AuthContext } from '../contexts/AuthContext';
import { useNavigate } from 'react-router-dom';

export default function Login() {


const { login } = useContext(AuthContext);
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const navigate = useNavigate();

const handleSubmit = async (e) => {


[Link]();
const success = await login(username, password);
if (success) {
navigate('/dashboard');
} else {
setError('Invalid credentials');
}
};

return (
<div style={{ maxWidth: 400, margin: '50px auto' }}>
<h2>Login</h2>
<form onSubmit={handleSubmit}>
<div>
<label>Username:</label><br/>
<input
type="text"
value={username}
onChange={e => setUsername([Link])}
required
/>
</div>
<div style={{ marginTop: 10 }}>
<label>Password:</label><br/>
<input
type="password"
value={password}
onChange={e => setPassword([Link])}
required
/>
</div>
{error && <p style={{ color: 'red' }}>{error}</p>}
<button type="submit" style={{ marginTop: 15 }}>Log In</button>
</form>
</div>
);
}

4.5 frontend/src/components/[Link]
jsx
CopyEdit
// frontend/src/components/[Link]

import React from 'react';


import { Line } from 'react-chartjs-2';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
} from '[Link]';

[Link](
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
);

export default function LineChart({ series, labels, title }) {


// `series` is an array of { label: 'SUV', data: […, …], borderColor:
'rgb(...)', backgroundColor: 'rgba(...)' }
const data = {
labels,
datasets: series
};

const options = {
responsive: true,
plugins: {
title: { display: true, text: title },
legend: { position: 'bottom' }
}
};

return <Line options={options} data={data} />;


}

 Expects:
o labels: e.g. ['15:00','15:01','15:02',...]
o series: e.g.

js
CopyEdit
[
{ label:'SUV', data:[12,15,9,...], borderColor:'blue',
backgroundColor:'rgba(0,0,255,0.2)' },
{ label:'bus', data:[3,4,2,...], borderColor:'red',
backgroundColor:'rgba(255,0,0,0.2)' }
]

 Renders a simple line chart.

4.6 frontend/src/components/[Link]
jsx
CopyEdit
// frontend/src/components/[Link]

import React from 'react';


import { Bar } from 'react-chartjs-2';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
} from '[Link]';

[Link](
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
);

export default function StackedBar({ series, labels, title }) {


// `series` is an array of { label:'Front', data:[5,4,3,...],
backgroundColor:'rgba(...)' }
const data = {
labels,
datasets: series
};

const options = {
responsive: true,
plugins: {
title: { display: true, text: title }
},
scales: {
x: { stacked: true },
y: { stacked: true }
}
};

return <Bar options={options} data={data} />;


}

4.7 frontend/src/components/[Link]
jsx
CopyEdit
// frontend/src/components/[Link]

import React, { useState, useEffect, useContext } from 'react';


import { AuthContext } from '../contexts/AuthContext';
import { api } from '../api';
import LineChart from './LineChart';
import StackedBar from './StackedBar';
import { useNavigate } from 'react-router-dom';

export default function Dashboard() {


const { user, logout } = useContext(AuthContext);
const navigate = useNavigate();

const [mode, setMode] = useState('intersection4');


const [start, setStart] = useState('');
const [end, setEnd] = useState('');
const [counts, setCounts] = useState([]); // raw API data
const [loading, setLoading] = useState(false);

// If not logged in, redirect


useEffect(() => {
if (!user) {
navigate('/login');
}
}, [user]);

const fetchData = async () => {


if (!start || !end) return;
setLoading(true);
try {
const res = await [Link]('traffic/counts/', {
params: { scenario: mode, start, end }
});
setCounts([Link]);
} catch (err) {
[Link]("Fetch error:", err);
}
setLoading(false);
};

// Transform raw `counts` into chart data


const buildChartData = () => {
const byTimestamp = {};
const classSet = new Set();
const directionSet = new Set();

[Link](item => {
const ts = [Link]; // e.g. "2025-05-10T15:07:00Z"
if (!byTimestamp[ts]) byTimestamp[ts] = {};
const key = `${item.vehicle_class}:${[Link]}`;
byTimestamp[ts][key] = [Link];
[Link](item.vehicle_class);
[Link]([Link]);
});

const sortedTimestamps = [Link](byTimestamp).sort();

// Build series for line chart (one line per vehicle_class)


const classSeries = [];
[Link](cls => {
const data = [Link](ts => {
// sum counts of all directions for this class
let total = 0;
for (let dir of directionSet) {
const key = `${cls}:${dir}`;
total += byTimestamp[ts][key] || 0;
}
return total;
});
[Link]({
label: cls,
data,
borderColor: '#' + [Link]([Link]()*16777215).toString(16),
backgroundColor: 'rgba(0,0,0,0.1)'
});
});

// Build series for stacked bar (one bar-per timestamp, stacks by


direction)
const dirSeries = [];
[Link](dir => {
const data = [Link](ts => {
// sum counts of all classes for this direction
let total = 0;
[Link](cls => {
const key = `${cls}:${dir}`;
total += byTimestamp[ts][key] || 0;
});
return total;
});
[Link]({
label: dir,
data,
backgroundColor: '#' + [Link]([Link]()*16777215).toString(16)
});
});

return {
labels: [Link](ts => [Link](11,19)), // HH:MM:SS
classSeries,
dirSeries
};
};

const { labels, classSeries, dirSeries } = buildChartData();


return (
<div style={{ maxWidth: 1000, margin: '20px auto' }}>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<h2>Welcome, {user?.username}</h2>
<button onClick={logout}>Logout</button>
</div>

<div style={{ margin: '20px 0' }}>


<label>Mode:&nbsp;
<select value={mode} onChange={e => setMode([Link])}>
<option value="intersection4">4-way Intersection</option>
<option value="point2">Front/Back Points</option>
</select>
</label>
&nbsp;&nbsp;
<label>Start (ISO):&nbsp;
<input type="datetime-local"
onChange={e => setStart([Link])} />
</label>
&nbsp;&nbsp;
<label>End (ISO):&nbsp;
<input type="datetime-local"
onChange={e => setEnd([Link])} />
</label>
&nbsp;
<button onClick={fetchData}>Fetch</button>
</div>

{loading && <p>Loading data...</p>}

{!loading && [Link] > 0 && (


<>
<LineChart
labels={labels}
series={classSeries}
title="Per-Minute Vehicle Counts by Class"
/>
<div style={{ height: 20 }} />
<StackedBar
labels={labels}
series={dirSeries}
title="Directional Flow"
/>
</>
)}
</div>
);
}

 mode controlled by a <select>.


 start/end use <input type="datetime-local"> (it produces a string like “2025-05-
10T15:00”).
 fetchData calls /api/traffic/counts/?scenario=point2&start=...&end=...
 buildChartData pivots the results into [Link] datasets.
4.8 frontend/src/[Link]
jsx
CopyEdit
// frontend/src/[Link]

import React, { useContext } from 'react';


import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { AuthContext, AuthProvider } from './contexts/AuthContext';
import Login from './components/Login';
import Dashboard from './components/Dashboard';

function PrivateRoute({ children }) {


const { user } = useContext(AuthContext);
return user ? children : <Navigate to="/login" />;
}

export default function App() {


return (
<AuthProvider>
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/dashboard"
element={
<PrivateRoute>
<Dashboard />
</PrivateRoute>
}
/>
<Route path="*" element={<Navigate to="/dashboard" />} />
</Routes>
</BrowserRouter>
</AuthProvider>
);
}

 <AuthProvider> wraps everything, making user and login available.


 <PrivateRoute> redirects to /login if not authenticated.

4.9 frontend/src/[Link]
jsx
CopyEdit
// frontend/src/[Link]

import React from 'react';


import ReactDOM from 'react-dom/client';
import App from './App';
const root = [Link]([Link]('root'));
[Link](
<[Link]>
<App />
</[Link]>
);

5. How to Set Everything Up & Run


5.1 PostgreSQL ➔ Django

1. Install PostgreSQL (see earlier instructions).


2. Create DB & User:

sql
CopyEdit
CREATE DATABASE smart_traffic_db;
CREATE USER traffic_user WITH ENCRYPTED PASSWORD 'traffic_pass';
GRANT ALL PRIVILEGES ON DATABASE smart_traffic_db TO traffic_user;

3. Install Django dependencies:

bash
CopyEdit
cd smart_traffic/backend
python3 -m venv .venv
source .venv/bin/activate # (Windows: .venv\Scripts\Activate.ps1)
pip install -r [Link]

4. Run migrations:

bash
CopyEdit
python [Link] makemigrations traffic
python [Link] migrate

5. Create superuser:

bash
CopyEdit
python [Link] createsuperuser

5.2 Ingestion Pipeline (Local MP4s)

1. Install pipeline dependencies (can share same venv as Django or separate):

bash
CopyEdit
cd ../pipeline
python3 -m venv .venv
source .venv/bin/activate
pip install opencv-python ultralytics pyyaml psycopg2-binary

2. Place:
o [Link] (YOLOv8 weights)
o [Link] (class names YAML)
o config/[Link] (with scenarios)
o MP4 files into pipeline/videos/
3. Run:

bash
CopyEdit
python ingest_to_pg.py --mode intersection4

Or:

bash
CopyEdit
python ingest_to_pg.py --mode point2

o This will fill your traffic_vehiclecount table with per-minute counts.

5.3 Django DRF Server


bash
CopyEdit
cd ../backend
source .venv/bin/activate # same venv where Django is installed
python [Link] runserver

 Django Admin ([Link] lets you view Intersections,


VehicleClass, VehicleCount.
 API endpoints:
o Login (get JWT):

arduino
CopyEdit
POST [Link]
Body: { "username": "...", "password": "..." }

o Refresh token:

arduino
CopyEdit
POST [Link]
Body: { "refresh": "<refresh_token>" }

o Get counts (authenticated):


pgsql
CopyEdit
GET [Link]
scenario=intersection4&start=2025-05-10T15:00:00Z&end=2025-05-
10T16:00:00Z
Header: Authorization: Bearer <access_token>

5.4 React Frontend


bash
CopyEdit
cd ../frontend
npm install
npm start

 Opens at [Link]
 Login page → enter superuser credentials → redirects to /dashboard.
 In Dashboard:
1. Choose Mode (intersection4 or point2).
2. Pick Start & End via datetime selector.
3. Click Fetch → see two charts:
 LineChart: per-minute total counts by vehicle class.
 StackedBar: stacks counts by direction.
 The charts automatically adapt to whichever direction strings the API returns.

6. Summary
1. Pipeline (pipeline/ingest_to_pg.py) runs YOLOv8+ByteTrack, counts vehicles by
direction (4 zones or 2 points), and bulk-inserts per-minute counts (with scenario) into
PostgreSQL.
2. Django DRF (backend/) models reflect the same tables; serializers/viewsets expose
/api/traffic/counts/ with filtering on intersection, timestamp range, class,
direction, and scenario. JWT auth protects the endpoints.
3. React (frontend/) provides a clean login form, a “Dashboard” that:
o Lets users select mode, start, and end.
o Fetches the data and draws a LineChart (by vehicle class) and a StackedBar (by
direction).
o Maintains JWT in AuthContext, attaches it to all API calls.

Everything is integrated:

 MP4 files → TrafficPipeline → PostgreSQL → Django API → React UI.

You can now:


 Switch between intersection4 ↔ point2 by --mode in ingestion and by selecting mode in
the UI.
 Add more scenarios to [Link] (e.g. “Tjunction”)—no code changes needed.
 Secure and deploy each component (e.g. containerize, push to Azure).

This codebase fulfills your requirement for a fully modular, multi-mode traffic monitoring
pipeline with end-to-end integration. Enjoy building and iterating on it!

You might also like