Розпізнавання дорожніх знаків та розмітки на основі AI
Автономні системи та ADAS вимагають надійного розпізнавання знаків та розмітки – у дощ, туман, вночі, при частковому перекритті, на дорогах з вицвілою розміткою. Завдання дворівневе: детекція знака/розмітки на кадрі та її класифікація. Обидва рівні мають укладатися у сумарні 30–50ms.
Розпізнавання дорожніх знаків
import cv2
import numpy as np
from ultralytics import YOLO
import torch
import torch.nn as nn
class TrafficSignRecognizer:
def __init__(self, detector_path: str, classifier_path: str,
class_names: list):
# Детектор: YOLO находит все знаки на кадре
self.detector = YOLO(detector_path)
# Классификатор: EfficientNet-B3 или MobileNetV3
self.classifier = torch.load(classifier_path)
self.classifier.eval()
self.class_names = class_names
# Предобработка для классификатора
from torchvision import transforms
self.transform = transforms.Compose([
transforms.ToPILImage(),
transforms.Resize((64, 64)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])
])
@torch.no_grad()
def recognize(self, frame: np.ndarray) -> list[dict]:
# Детекция: находим bboxes знаков
det_results = self.detector(frame, conf=0.45, classes=[])
signs = []
for box in det_results[0].boxes:
x1, y1, x2, y2 = map(int, box.xyxy[0])
# Небольшой padding для лучшей классификации
pad = 8
x1, y1 = max(0, x1-pad), max(0, y1-pad)
x2, y2 = min(frame.shape[1], x2+pad), min(frame.shape[0], y2+pad)
roi = frame[y1:y2, x1:x2]
if roi.size == 0:
continue
# Классификация ROI
tensor = self.transform(roi).unsqueeze(0)
logits = self.classifier(tensor)
probs = torch.softmax(logits, dim=-1)
top_prob, top_idx = probs.max(-1)
signs.append({
'class': self.class_names[top_idx.item()],
'confidence': float(top_prob),
'det_confidence': float(box.conf),
'bbox': [x1, y1, x2, y2]
})
return signs
Детекція дорожньої розмітки
class LaneMarkingDetector:
def __init__(self, model_name: str = 'clrnet'):
"""
CLRNet (Cross Layer Refinement Network) — лучшее соотношение
точности и скорости для lane detection в 2024.
CULane F1 = 0.806, TuSimple F1 = 0.971.
"""
if model_name == 'clrnet':
self.model = self._load_clrnet()
elif model_name == 'ufld':
# Ultra-Fast Lane Detection v2 — быстрее, чуть хуже
self.model = self._load_ufld()
def detect_markings(self, frame: np.ndarray) -> dict:
lanes = self.model(frame)
# Классификация типов разметки
markings = {
'solid_white': [],
'dashed_white': [],
'solid_yellow': [],
'double_yellow': [],
'stop_line': []
}
for lane in lanes:
marking_type = self._classify_marking(frame, lane)
markings[marking_type].append(lane)
return markings
def _classify_marking(self, frame: np.ndarray,
lane_points: list) -> str:
"""По цвету и прерывистости определяем тип разметки"""
# Сэмплируем цвет вдоль линии
colors = []
for x, y in lane_points[::5]:
if 0 <= int(y) < frame.shape[0] and 0 <= int(x) < frame.shape[1]:
colors.append(frame[int(y), int(x)])
if not colors:
return 'solid_white'
mean_color = np.mean(colors, axis=0)
# Жёлтый: высокий R и G, низкий B
if mean_color[2] > 150 and mean_color[1] > 120 and mean_color[0] < 100:
return 'solid_yellow'
return 'solid_white'
Складні умови: проблеми та рішення
| Умова | Проблема | Рішення |
|---|---|---|
| Ніч | Знаки видно тільки при світлі фар | Навчання на нічних даних (CURE-TSD) |
| Дощ | Блики, розмитість | Deblurring + augmentation з мокрими знаками |
| Сніг на знак | Часткове перекриття | Few-shot + масковані приклади в датасеті |
| Вицвіла розмітка | Низький контраст | CLAHE preprocessing + data augmentation |
| Декілька знаків поруч | Перекриття bbox | NMS з IoU 0.3, не 0.5 |
Датасети для навчання
- GTSRB (Німеччина): 43 класи, 50k+ зображень — класика для знаків
- Mapillary Traffic Sign Dataset: 100k зображень, 313 класів, реальні дороги
- CULane: 133k кадрів, складні умови для lane detection
- BDD100K: 100k відео, знаки + розмітка + погана погода
Для локалізованих знаків (РФ, BY, UA) завжди потрібна донавчання на місцевих стандартах ГОСТ. У стандартному GTSRB немає знаків радянських стандартів, цегли специфічної форми, тимчасових знаків на помаранчевому фоні.
Продуктивність
EfficientDet-D2 для детекції знаків: [email protected] = 0.87 на GTSRB, latency 22ms на RTX 3060. Для бортового застосування на Qualcomm Snapdragon Ride: квантизуємо в INT8 через QNN, latency 35ms - вкладаємося в ADAS-вимоги.
| Завдання | Термін |
|---|---|
| Детектор + класифікатор знаків (1 країна) | 4–7 тижнів |
| Lane marking detection | 3-5 тижнів |
| Комбінована система знаки + розмітка | 7–12 тижнів |







