Разработка AI-системы распознавания дорожных знаков и разметки

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1Все 1566 услуг
Разработка AI-системы распознавания дорожных знаков и разметки
Средний
~1-2 недели
Часто задаваемые вопросы

Направления AI-разработки

Этапы разработки AI-решения

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1284
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1196
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    901
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1119
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    586
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    853

Распознавание дорожных знаков и разметки на основе 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 недель