Детекция пешеходов и велосипедистов для автономных систем
Уязвимые участники дорожного движения — пешеходы, велосипедисты, самокатчики — главная причина смертей в ДТП с участием автономных систем. Detect failure здесь не просто метрика в отчёте: это человеческая жизнь. Отсюда требования на порядок строже, чем для обычного CV: recall > 98% при любых условиях, включая ночь, дождь, частичное перекрытие.
Проблемы специфичные для VRU (Vulnerable Road Users)
Велосипедист с байком — вытянутый объект нестандартной формы. Самокатчик в 30 метрах занимает 15×40 пикселей. Пешеход за припаркованным автомобилем виден наполовину. Ребёнок ростом 100 см в 20 метрах — bbox 20×30 пикселей.
import torch
from ultralytics import YOLO
import numpy as np
from typing import Optional
class VRUDetector:
def __init__(self, model_path: str, camera_params: dict):
# YOLOv8l или RT-DETR-L для VRU: нужна высокая чувствительность
self.model = YOLO(model_path)
self.focal_length = camera_params['focal_length']
self.sensor_height = camera_params['sensor_height']
self.image_height_px = camera_params['image_height']
# Жёсткие пороги для VRU
self.conf_threshold = 0.3 # ниже, чем обычно — лучше лишний FP
self.min_height_px = 20 # минимальный размер для обнаружения
# Классы VRU
self.vru_classes = {0: 'person', 1: 'bicycle', 3: 'motorcycle'}
def detect(self, frame: np.ndarray,
min_distance_m: float = 1.0,
max_distance_m: float = 80.0) -> list[dict]:
results = self.model(frame, conf=self.conf_threshold,
classes=list(self.vru_classes.keys()))
vru_detections = []
for box in results[0].boxes:
x1, y1, x2, y2 = map(int, box.xyxy[0])
h_px = y2 - y1
cls_id = int(box.cls)
if h_px < self.min_height_px:
continue # слишком маленький объект
# Оценка дистанции по высоте bbox
distance = self._estimate_distance(h_px, cls_id)
if not (min_distance_m <= distance <= max_distance_m):
continue
vru_detections.append({
'class': self.vru_classes[cls_id],
'confidence': float(box.conf),
'bbox': [x1, y1, x2, y2],
'distance_m': distance,
'height_px': h_px,
'priority': 'HIGH' if cls_id == 0 else 'MEDIUM'
})
return sorted(vru_detections, key=lambda x: x['distance_m'])
def _estimate_distance(self, height_px: int, cls_id: int) -> float:
"""Простая монокулярная оценка по пинхол-модели"""
real_heights = {0: 1.75, 1: 1.05, 3: 1.10} # метры
real_h = real_heights.get(cls_id, 1.5)
return (real_h * self.focal_length) / (height_px * self.sensor_height
/ self.image_height_px)
Ночная детекция: критический сценарий
По статистике, 76% смертельных наездов на пешеходов происходит в тёмное время суток. Стандартные RGB модели при освещённости < 3 lux теряют 30–40% recall.
Решения:
1. Тепловая камера (FLIR Lepton, Bosch BTC): тело человека при 37°C хорошо выделяется на фоне асфальта. Recall в полной темноте: 88–93%. Недостаток — нет текстуры, сложнее различить велосипед/самокат.
2. Near-IR камера (850nm): автомобильные фары с ИК компонентой освещают 60–80м. YOLOv8 дообученный на ИК-данных (FLIR ADAS dataset содержит IR-канал) держит recall 85–90% ночью.
3. Fusion RGB + тепло: лучший результат, но сложнее и дороже.
class NightVRUFusion:
"""Поздний fusion: объединяем детекции с RGB и тепловой камеры"""
def fuse(self, rgb_dets: list, thermal_dets: list,
iou_threshold: float = 0.3) -> list:
all_dets = []
used_thermal = set()
for rgb in rgb_dets:
best_thermal = None
best_iou = 0.0
for i, therm in enumerate(thermal_dets):
iou = self._compute_iou(rgb['bbox'], therm['bbox'])
if iou > best_iou and iou > iou_threshold:
best_iou = iou
best_thermal = i
if best_thermal is not None:
# Объединяем confidence
fused = rgb.copy()
fused['confidence'] = min(
1.0, rgb['confidence'] * 0.6 +
thermal_dets[best_thermal]['confidence'] * 0.7
)
fused['source'] = 'fusion'
used_thermal.add(best_thermal)
all_dets.append(fused)
else:
all_dets.append(rgb)
# Детекции только из тепловой (объекты без RGB-эквивалента)
for i, therm in enumerate(thermal_dets):
if i not in used_thermal and therm['confidence'] > 0.5:
all_dets.append(therm)
return all_dets
Метрики качества VRU-детектора
| Условие | Recall цель | Precision цель |
|---|---|---|
| День, хорошая видимость | > 98% | > 90% |
| Сумерки | > 95% | > 85% |
| Ночь (ИК-фары) | > 88% | > 78% |
| Дождь средний | > 92% | > 82% |
| Частичное перекрытие (< 40%) | > 94% | > 83% |
Оценка на стандартных бенчмарках: KITTI Pedestrian, CityPersons, EuroCity Persons (специализирован для сложных условий).
Кейс: промышленный автопогрузчик
Автономный погрузчик на складе 15 тыс. м². Задача: остановиться при появлении человека в радиусе 3 метров. Использовали YOLOv8n + TensorRT INT8 на Jetson Orin NX: latency 18ms. При recall 99.1% на тестовом наборе из 400 сценариев — 0 пропущенных людей. FAR: 2–3 ложных срабатывания в смену (рабочий инструмент похожей формы).
| Тип системы | Срок |
|---|---|
| Детектор для конкретного сценария | 4–7 недель |
| Полная VRU-система с ночной детекцией | 8–14 недель |
| Fusion RGB+тепло с сертификацией | 4–8 месяцев |







