سیستم شمارش ترافیک چیست؟ (مبتدی)
در این پروژه، یک دوربین ESP32-CAM (ارزان، WiFi، دوربین OV2640) تصویر تقاطع را capture میکند و به Raspberry Pi ارسال میکند. روی Raspberry Pi، OpenCV با الگوریتم MOG2 (Mixture of Gaussians Background Subtraction) پیکسلهای متحرک را شناسایی میکند.
وقتی یک ماشین از خط شمارش عبور میکند، شمارنده یک واحد افزایش مییابد. این سیستم میتواند به سیستمهای هوشمند مدیریت ترافیک UGV/AGV در محیطهای مسدود یا انبار متصل شود — مثلاً AGV را متوقف کند وقتی ترافیک سنگین است.
محصولی که میسازید
سیستم شمارش وسیله نقلیه با دوربین ESP32-CAM و OpenCV.
- هزینه: ESP32-CAM ≈ ۵ دلار + RPi
- دقت: ۸۵-۹۵% در نور روز
- لاگ: CSV با timestamp
کد ESP32-CAM — سرور MJPEG
#include "esp_camera.h"
#include <WiFi.h>
#include "esp_http_server.h"
const char* ssid = "YourWiFi";
const char* password = "YourPass";
// Camera config برای AI-Thinker ESP32-CAM:
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.pin_d0 = 5; config.pin_d1 = 18; config.pin_d2 = 19;
config.pin_d3 = 21; config.pin_d4 = 36; config.pin_d5 = 39;
config.pin_d6 = 34; config.pin_d7 = 35;
config.pin_xclk = 0; config.pin_pclk = 22;
config.pin_vsync = 25; config.pin_href = 23;
config.pin_sscb_sda = 26; config.pin_sscb_scl = 27;
config.pin_reset = -1; config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_VGA; // ۶۴۰×۴۸۰
config.jpeg_quality = 15;
config.fb_count = 2;
// سرور MJPEG ساده راهاندازی میشود
// روی http://[IP]:80/stream قابل دسترس
کد Python OpenCV — شمارش ماشین
import cv2
import numpy as np
import urllib.request
import datetime, csv
ESP32_URL = "http://192.168.1.105/stream"
COUNT_LINE_Y = 240 # نصف ارتفاع ۴۸۰ = خط شمارش
fgbg = cv2.createBackgroundSubtractorMOG2(history=100, varThreshold=50)
count = 0
prev_centers = []
log_file = open("traffic_log.csv","w",newline='')
writer = csv.writer(log_file)
writer.writerow(["time","count"])
cap = cv2.VideoCapture(ESP32_URL)
while True:
ret, frame = cap.read()
if not ret: continue
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
fgmask = fgbg.apply(gray)
# حذف نویز:
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_CLOSE, kernel)
# پیدا کردن Contourها:
contours, _ = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
if cv2.contourArea(cnt) > 1500:
x,y,w,h = cv2.boundingRect(cnt)
cy = y + h//2
if abs(cy - COUNT_LINE_Y) < 10:
count += 1
writer.writerow([datetime.datetime.now().isoformat(), count])
log_file.flush()
cv2.line(frame, (0,COUNT_LINE_Y), (640,COUNT_LINE_Y), (255,0,0), 2)
cv2.putText(frame, f"Count: {count}", (10,30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)
cv2.imshow("Traffic Counter", frame)
if cv2.waitKey(1) == ord('q'): break
cap.release()
چکلیست نصب و تنظیم
| بررسی | روش |
|---|---|
| ESP32-CAM روی WiFi وصل میشود؟ | Serial Monitor IP را نشان دهد |
| MJPEG Stream در مرورگر باز میشود؟ | http://[IP]/stream |
| MOG2 در شب/روشنایی کم کار میکند؟ | varThreshold را کم کنید |
| شمارش دوتایی (Double Counting) نمیکند؟ | Cooldown Timer اضافه کنید |