Live System · Jetson Nano · v1.0

Zone
Guard

Real-time person detection & zone intrusion alert system built on Jetson Nano. Draw any polygon zone on the live stream — get an alert the moment a person enters it. YOLOv5n · SAM polygon · Flask MJPEG.

30 FPS target
640 Resolution px
3s Alert cooldown
Zone vertices
CH-01 · 640×480 REC
ZONE A
PERSONS2
IN ZONE1 ⚠
ALERTS4
CLICK CANVAS TO DRAW ZONE · THEN PRESS SET POLYGON

System Architecture

Data Flow

HARDWARE
📷
NanoCamera
640×480 · 30fps
Jetson Nano CSI
CV MODEL
🧠
YOLOv5n
.engine (TensorRT)
class 0 = person
GEOMETRY
📐
Polygon Test
cv2.pointPolygon
Test(center_xy)
ALERT
🔔
Trigger
cooldown 3s
alert_count++
ENCODE
📹
MJPEG
cv2.imencode
.jpg → stream
FRONTEND
🌐
Flask + Canvas
<img> + canvas
overlay / POST zone

Workflow

How It Works

01
Camera Capture on Jetson Nano
nanocamera opens the CSI camera at 640×480 @ 30fps. Each frame is read in the gen_frames() generator loop, resized, and passed directly into YOLOv5 for inference. No intermediate buffering — latency stays minimal.
nanocamera · cv2.resize(frame, (640,480))
02
YOLOv5n Inference — Person Only
A custom .engine (TensorRT) file is loaded for maximum GPU utilization on Nano. model.classes = [0] restricts detections to person only. Output results.xyxy[0] gives bounding box corners + confidence per detection.
model(frame) → xyxy[0] → x1,y1,x2,y2, conf, cls
03
Draw Zone Polygon on Web UI
The browser renders a transparent <canvas> overlaid perfectly on the live <img> MJPEG feed. Each click adds a vertex to the polygon. Pressing Set Polygon POSTs the coordinate array to /set_polygon, which updates the server-side drawing_points list and sets polygon_defined = True.
canvas.addEventListener("click") → fetch POST /set_polygon
04
Point-in-Polygon Test per Detection
For every detected person, the bounding box center point (cx, cy) = ((x1+x2)//2, (y1+y2)//2) is tested against the polygon using cv2.pointPolygonTest(polygon_np, (cx,cy), False) >= 0. Returns positive if inside, negative if outside — O(n vertices) complexity.
cv2.pointPolygonTest → inside = True/False
05
Cooldown-Gated Alert Counter
When a person is detected inside the zone, the system checks time.time() - last_play_time > cooldown (3s) before triggering. This prevents alert flooding from a stationary person. alert_count is incremented and drawn live on the frame.
cooldown=3s · alert_count++ · cv2.putText overlay
06
MJPEG Streaming via Flask
Each annotated frame is JPEG-encoded with cv2.imencode('.jpg', frame) and yielded as a multipart/x-mixed-replace HTTP response. The browser's native <img> tag handles the stream — no WebSocket, no JS decode loop needed. Flask-CORS is enabled for cross-origin frontend access.
Response(gen_frames(), mimetype="multipart/x-mixed-replace; boundary=frame")

Capabilities

Key Features

🎯
TensorRT-Optimized Detection
YOLOv5n compiled to a .engine file via TensorRT. Full GPU acceleration on Jetson Nano's Maxwell architecture. Filters to class 0 (person) only — no wasted inference on other objects.
YOLOv5n TensorRT Class filtering
✏️
Interactive Zone Drawing
Draw any arbitrary polygon directly on the live feed by clicking the transparent canvas overlay. Works with 3+ vertices, any convex or concave shape. Zone is transmitted to the backend as a JSON coordinate array via POST /set_polygon.
Canvas API REST POST Arbitrary polygon
📐
OpenCV Point-in-Polygon
Uses cv2.pointPolygonTest to test each detected person's bounding box center against the defined polygon. Runs server-side per detection per frame. Handles concave polygons correctly.
cv2.pointPolygonTest BBox center
🔔
Cooldown-Gated Alerts
Alert counter increments only if cooldown (3s) has elapsed since last trigger. Prevents alert floods from a stationary person. alert_count is rendered directly onto each frame using cv2.putText.
Cooldown 3s alert_count Frame overlay
📹
Zero-JS MJPEG Stream
Flask yields annotated JPEG frames as a multipart/x-mixed-replace response. Standard browser <img> tag handles the stream natively — no WebSocket, no frontend decode loop, no dependencies.
MJPEG Flask No-JS stream
🔒
Thread-Safe State
Global state (drawing_points, polygon_defined, alert_count) is shared between the Flask request thread (/set_polygon) and the streaming generator. Flask-CORS handles cross-origin preflight.
Flask-CORS Global state Threading

Dependencies

Tech Stack

Jetson Nano
Edge GPU platform (Maxwell 128-core)
🧠
YOLOv5n
Nano YOLO · .engine (TensorRT)
🔥
PyTorch
Model loading · torch.hub
👁
OpenCV
Detection · polygon · encode
📷
NanoCamera
CSI camera wrapper for Jetson
🌐
Flask
MJPEG stream · REST API
🔗
Flask-CORS
Cross-origin frontend access
🧮
NumPy
Polygon array · int32 reshape