Skip to content

Repository files navigation

🚦 Intelligent Transportation System

Adaptive traffic-signal control driven by per-lane vehicle density.

Python OpenCV YOLOv8 Streamlit CI License: MIT

hero


Why?

Most Indian intersections still rely on fixed-timer traffic lights that allocate the same green-light duration regardless of actual traffic. The result is predictable: empty roads get the same time as jammed ones, queues stretch, fuel is burned, and tempers flare.

This project replaces the dumb timer with a simple idea:

Look at each lane, estimate how much traffic is waiting, and split the cycle time proportionally.

It started as a 2016 B.Tech capstone in Java/Swing. This is the modern Python rewrite — cleaner, faster, and actually runnable. The original code is preserved in legacy-java/ for posterity.

What you get

  • Two density estimators, behind a common interface:
    • Classical — OpenCV Canny + morphology → edge-pixel ratio as density proxy. Zero-config, fast, ~30 lines of code.
    • YOLOv8 — Ultralytics yolov8n counts cars, motorcycles, buses, and trucks. Downloads a ~6 MB checkpoint on first run.
  • A proportional signal allocator with configurable cycle time and per-lane min/max green bounds.
  • A Streamlit web UI for live demos (upload 4 lane photos, see annotated results + bar charts + green-time table).
  • A CLI (python -m its …) for batch use.
  • Unit tests + CI, so it keeps working.

Demo

Streamlit app

streamlit run app.py

Pick a mode in the sidebar, choose bundled samples or upload 4 lane images, hit Simulate:

Classical (edge density) YOLOv8 (vehicle detection)
classical yolo

CLI

$ python -m its --mode yolo sample_images/lane_1.jpg sample_images/lane_2.jpg \
                             sample_images/lane_3.jpg sample_images/lane_4.jpg

=== Intelligent Transportation System — mode=yolo ===

Lane      Vehicles   Density   Green (s)
----------------------------------------
lane_1          17     0.850          45
lane_2          13     0.650          34
lane_3           7     0.350          18
lane_4           9     0.450          23
----------------------------------------
Total                                120s  (cycle=120s)

The busiest lane (17 vehicles) gets 45 seconds of green; the emptiest (7 vehicles) gets 18 seconds. A fixed-timer controller would have given them 30 s each.

Quick start

git clone https://github.com/aniruddhgoteti/Intelligent-Transportation-System.git
cd Intelligent-Transportation-System

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

# Web UI
streamlit run app.py

# or CLI
python -m its --mode classical sample_images/lane_1.jpg sample_images/lane_2.jpg \
                                sample_images/lane_3.jpg sample_images/lane_4.jpg

Requires Python 3.10+. YOLOv8 weights (yolov8n.pt, ~6 MB) are fetched by Ultralytics on first use and cached locally.

How it works

┌───────────┐   ┌────────────────┐   ┌──────────────┐   ┌──────────────┐
│ Lane image│→→→│ Density module │→→→│   Density    │→→→│   Signal     │
│  (BGR np) │   │ classical/yolo │   │   ∈ [0, 1]   │   │  allocator   │
└───────────┘   └────────────────┘   └──────────────┘   └──────┬───────┘
                                                               ↓
                                                     green times (seconds)

Classical density (its/density/classical.py)

  1. Convert to grayscale and Gaussian-blur (σ ≈ 1.2).
  2. Canny edge detection with hysteresis thresholds 80 / 200.
  3. One iteration of morphological dilation to join fragmented edges.
  4. density = count_nonzero(edges) / edges.size → already normalized to [0, 1].

This faithfully captures the intent of the original B.Tech project's BgEdgeDetect + TrafficDensity pipeline (~2,000 lines of hand-rolled Java pixel math), now ~30 lines of OpenCV.

YOLO density (its/density/yolo.py)

  1. Lazy-load yolov8n.pt from Ultralytics (cached after first run).
  2. Keep only COCO vehicle classes: car, motorcycle, bus, truck.
  3. density = min(total_vehicles / SATURATION, 1.0) with SATURATION = 20 by default.

Signal allocator (its/signal.py)

Given a density vector d₁…dₙ and a cycle C, each lane gets gᵢ = round(C · dᵢ / Σd) seconds, then each gᵢ is clamped to [min_green, max_green] and the residual is redistributed in density-descending order so the total hits C exactly. Falls back to an equal split when every density is zero.

Project layout

.
├── app.py                    # Streamlit UI
├── its/
│   ├── __main__.py           # `python -m its`
│   ├── cli.py                # argparse entrypoint
│   ├── signal.py             # green-time allocator
│   └── density/
│       ├── classical.py      # OpenCV edge density
│       └── yolo.py           # YOLOv8 vehicle counter
├── tests/                    # pytest suite
├── sample_images/            # 4 curated lane photos (lane_1..4.jpg)
├── docs/screenshots/         # README imagery
├── legacy-java/              # original 2016 Swing implementation (archived)
├── BTECH Report.docx         # original report
├── pyproject.toml
├── requirements.txt
└── .github/workflows/ci.yml

Tech stack

Layer Library
Image I/O & classical CV OpenCV 4.8+, NumPy
Detection Ultralytics YOLOv8
UI Streamlit
Testing pytest
CI GitHub Actions

Running the tests

pytest -q

Twelve tests cover the classical density estimator (zero/noise/grayscale/bounds) and the signal allocator (equal split, proportional allocation, clamping, feasibility guards). YOLO is not exercised in CI to keep it fast.

Roadmap

  • Real-time video input (OpenCV VideoCapture + sliding-window detection)
  • Emergency-vehicle priority (siren detection → force green)
  • Pedestrian crossing integration
  • Multi-intersection coordination (green waves)
  • Edge deployment notes (Jetson Nano / Raspberry Pi 5)

Legacy

The original 2016 Java/Swing implementation is archived under legacy-java/. The full B.Tech report is at BTECH Report.docx.

License

MIT © Aniruddh Goteti.

Releases

Packages

Contributors

Languages