- Python 97.1%
- Jupyter Notebook 2.9%
Reconciliação de branches divergentes: - Local |
||
|---|---|---|
| .claude | ||
| legacy | ||
| weights | ||
| .gitignore | ||
| active_learning.py | ||
| avm2_render.py | ||
| avm_render.py | ||
| build_dataset.py | ||
| build_lane_dataset.py | ||
| calibrate_interactive.py | ||
| calibrate_visual.py | ||
| camera_classifier.py | ||
| CLAUDE.md | ||
| custom_loss.py | ||
| extract_cam_frames.py | ||
| fisheye.py | ||
| fsd_render.py | ||
| lane_classical.py | ||
| lane_model_infer.py | ||
| lane_pipeline.py | ||
| license_plate.py | ||
| main.py | ||
| make_quadrants_label.py | ||
| openpilot_render.py | ||
| panorama360.py | ||
| person_detector.py | ||
| README.md | ||
| tesla_render.py | ||
| train_camera_classifier.py | ||
| train_colab.ipynb | ||
| train_lane_model.py | ||
| vehicle_tracker.py | ||
| yolopv2_lib.py | ||
BYD 360 — cameras processing
Pipeline de processamento de vídeo dashcam BYD 360° (4 câmeras fisheye stitched) com YOLO. Detecta veículos, pessoas e placas em cada câmera, classifica dinamicamente qual câmera é cada quadrante (frente/trás/esq/dir), e renderiza em quatro estilos: openpilot first-person, AVM (Around View Monitor) surround top-down, Tesla FSD top-down via IPM, e legacy fsd.
Layout do vídeo de entrada
Vídeos 2x2 stitched (ex: 1920x1080 ou 2560x1920) com 4 cams fisheye:
+-------+-------+
| TL | TR | TL = câmera esquerda, TR = câmera traseira
+-------+-------+
| BL | BR | BL = câmera frontal, BR = câmera direita
+-------+-------+
(Confirmado para o dashcam BYD 360 usado neste projeto. Outros dashcams podem ter layout diferente — o camera_classifier detecta automaticamente.)
Estrutura
.
├── main.py # entrypoint CLI (offline / realtime, 5 estilos)
├── yolopv2_lib.py # YOLOPv2 inference batched + CUDA Graphs
├── person_detector.py # YOLOv8 wrapper (classe 0 COCO)
├── license_plate.py # YOLOv8 placas + EasyOCR opcional
├── camera_classifier.py # CameraClassifier YOLO26-cls (detecta layout)
├── fisheye.py # CROPS por quadrante (tira HUD/bumper/vignette)
│
├── avm_render.py # AVM v1 legado (warps empíricos)
├── avm2_render.py # AVM v2: stitch via calibration.json (8 pts)
├── tesla_render.py # Tesla-style top-down via IPM (homografia)
├── fsd_render.py # FSD legado (cars como icons)
├── openpilot_render.py # comma.ai openpilot first-person
│
├── lane_pipeline.py # poly fit + curvatura + offset (adapt Camera-based-ADAS)
├── vehicle_tracker.py # ByteTrack wrapper (IDs persistentes)
├── build_dataset.py # extrai dataset 4-classes dos vídeos
├── custom_loss.py # BonusPenaltyClassificationLoss
├── train_camera_classifier.py # treino com loss customizado
├── extract_cam_frames.py # extrai 1 frame por cam pra calibração
├── calibrate_interactive.py # GUI: arrasta 8 pontos pra calibrar AVM
├── calibrate_visual.py # render lado-a-lado de calibração IPM
├── make_quadrants_label.py # gera _quadrants_labeled.jpg pra confirmar layout
│
├── weights/ # pesos modelo (camera_classifier_v2.pt versionado;
│ # YOLOPv2/YOLOv8/license_plate ignorados — baixar separado)
├── assets/ # ego_car.png (silhueta top-down opcional)
├── legacy/ # _yolopv2_demo.py, _yolopv2_utils.py
├── graphify-out/ # mapa do projeto (graph.html, GRAPH_REPORT.md)
│
├── calibration.json # 8 pontos AVM por cam (gitignored, específico do veículo)
└── CLAUDE.md # contexto p assistentes de IA
Setup
Requer Python 3.11, GPU NVIDIA com driver compatível (testado em GTX 750 Ti com CUDA 12.1) — ou CPU only.
python3.11 -m venv venv
source venv/bin/activate
pip install --upgrade pip setuptools wheel
pip install --index-url https://download.pytorch.org/whl/cu121 torch==2.5.1 torchvision==0.20.1
pip install ultralytics opencv-contrib-python numpy supervision
# (opencv-contrib-python no lugar de opencv-python pq usamos
# cv2.createThinPlateSplineShapeTransformer no AVM2; supervision pra ByteTrack)
# Opcional p OCR de placas:
pip install easyocr
Pesos pré-treinados (baixar uma vez):
mkdir -p weights
# YOLOPv2 (vehicles + drivable area + lane lines, multi-task):
wget https://github.com/CAIC-AD/YOLOPv2/releases/download/V0.0.1/yolopv2.pt -O weights/yolopv2.pt
# YOLOv8n (person detector via ultralytics):
python -c "from ultralytics import YOLO; YOLO('yolov8n.pt')" && mv yolov8n.pt weights/
# YOLOv8 license plate (opcional):
# https://huggingface.co/keremberke/yolov8n-license-plate → weights/license_plate.pt
O classificador de câmeras (weights/camera_classifier_v2.pt, ~3MB) está versionado — pronto pra uso.
Como rodar
Visualização ao vivo
source venv/bin/activate
# openpilot first-person (front cam só) — modo padrão, leve
python main.py --device cuda --realtime --video videos/X.mp4
# AVM v2 surround top-down (4 cams stitched usando calibration.json)
python main.py --device cuda --realtime --style avm2 --video videos/X.mp4
# Tesla-style top-down via IPM (faixas projetadas em metros)
python main.py --device cuda --realtime --style tesla --video videos/X.mp4
# AVM legado
python main.py --device cuda --realtime --style avm --video videos/X.mp4
Gerar mp4
python main.py --style openpilot --save runs/demo.mp4 --max-frames 1000 --no-display
Desabilitar plate detector (libera VRAM em GPUs pequenas)
python main.py --device cuda --realtime --plate-weights /tmp/nonexistent.pt
Calibração AVM (8 pontos / 4 cams)
Pra rodar --style avm2 corretamente, gera um calibration.json específico do seu veículo:
# 1. Extrai um frame de cada câmera (lente completa, sem fisheye crop)
python extract_cam_frames.py --video Videos_training/X.mp4 --frame 500 --no-crop
# 2. Abre GUI interativa pra arrastar 8 pontos (2 por cam: TL + BR diagonal)
python calibrate_interactive.py
# Mouse: arrasta os pontos verdes (TL) e vermelhos (BR)
# 1/2/3/4 = selecionar cam ativa (vai pra frente)
# E = rotacionar imagem da cam ativa 90° CW
# T = toggle imagens (só borda)
# S = salvar calibration.json
# Q = sair
calibration.json é gitignored — cada veículo tem o seu.
Treino do classificador de câmeras
# 1. Coloca vídeos extras em Videos_training/
# 2. Extrai dataset rotulado (TL=esq, TR=tras, BL=frente, BR=dir)
python build_dataset.py
# Saída: dataset/{train,val}/{esq,tras,frente,dir}/*.jpg
# 3. Treina YOLO26n-cls com loss customizado (bonus por acerto + penalty por erro)
python train_camera_classifier.py --epochs 20 --device cuda --batch 32
# Resultado: runs/cls/byd-cameras/weights/best.pt
# Copiar para weights/camera_classifier.pt pra usar no main.py
Decisões importantes (rationale)
- YOLOPv2 vs YOLOv8 para veículos: YOLOPv2 entrega vehicles + drivable area + lane lines numa pass só, então é o
vehicle_modelno main. YOLOv8 entra só para pessoas e placas. - Crop fisheye antes da inferência: YOLOPv2 foi treinado em BDD100K (rectilinear). Sem crop, fisheye distorce demais e gera detecções fantasmas. Coeficientes em fisheye.py:CROPS tunados empiricamente.
- AVM2 usa lente CHEIA: pra stitching visual o quadrante uncropped (lente fisheye redonda completa) entra como
cam_rawno results dict. A máscara elíptica no renderer só pinta o conteúdo da lente, sem mostrar os cantos pretos. - CUDA Graphs no YOLOPv2: capturadas por batch-size (1 e 3). Reduz overhead PyTorch eager. Fallback eager se a captura falhar.
- Loss customizado para classificador de câmeras:
L = CE × penalty_when_wrong - bonus_amt × conf_correct × correct_mask. Injetado via callbackon_train_start. - Ordem de carregamento dos modelos: YOLOPv2/Person/Plate ANTES do classifier por causa de um bug do ultralytics 8.4.x + torch 2.5.1 que zera
torch.cuda.device_count()emmodel.predict(device='cpu'). - Lane curvature/offset via lane_pipeline: o openpilot_render computa raio de curvatura (m) + offset do centro (m) usando a
lane_linemask do YOLOPv2 warpada pro BEV (IPM 4 pts). Faz sliding window + poly fit 2ª ordem (técnica clássica do Camera-based-ADAS de ahmad12hamdan99) e exibe no HUD inferior. - ByteTrack para IDs persistentes: cada veículo detectado pela YOLOPv2 (front cam) recebe um tracker_id estável entre frames via supervision's ByteTrack. IDs aparecem como
#Nao lado de cada bbox no openpilot render. Mantém ID mesmo em oclusões curtas (até 30 frames perdidos).
Hardware testado
- Local GPU: GTX 750 Ti (2GB VRAM, compute 5.0) — funciona com torch 2.5.1+cu121. Limite VRAM: openpilot OK, AVM bem lento, plate detector causa OOM.
- Local CPU: AMD Ryzen 5 5500 — ~1.8 fps openpilot (sem plate), 0.22 fps com plate.
- Remoto: Ryzen 5 5600 (10 cores) + AMD RX 5700 (Vulkan via llama.cpp, ROCm experimental). Disponível para training CPU.
Estilos de renderização (--style)
| Estilo | Cams | Saída | Uso |
|---|---|---|---|
openpilot |
front | first-person com path ribbon + HUD | default, leve |
avm |
4 | surround com warps empíricos legado | legacy |
avm2 |
4 | surround via calibration.json (8 pts) | recomendado p 360° |
tesla |
4 | top-down via IPM (homografia) | experimental |
fsd |
front + sides | top-down legado com icons | legacy |
graphify
O mapa de conhecimento do projeto está em graphify-out/ (gitignored). Para gerar/atualizar:
# Pipeline completo (primeira vez)
/graphify
# Incremental (depois de mudanças)
/graphify --update
Outputs:
graphify-out/graph.html— mapa interativo navegávelgraphify-out/GRAPH_REPORT.md— god nodes, surprising connections, communities
Licença
YOLOPv2 modelo: MIT (CAIC-AD). Outros componentes: ver headers individuais.