Гид по технологиям

AR с OpenCV и ArUco — наложение изображений в реальном времени

5 min read Компьютерное зрение Обновлено 28 Dec 2025
AR с OpenCV и ArUco — наложение изображений
AR с OpenCV и ArUco — наложение изображений

Ноутбук при слабом свете с кодом в тёмной теме

Введение

Дополненная реальность (AR) объединяет реальный мир с виртуальным контентом, накладывая цифровую информацию на изображение окружающей среды. Современные достижения в области компьютерного зрения и обработки изображений сделали разработку AR-приложений доступной даже для прототипов на одном ноутбуке.

OpenCV — популярная библиотека с открытым исходным кодом, которая предоставляет алгоритмы и инструменты для создания AR-опыта. В этом руководстве вы создадите простую AR-программу: выберёте изображение для наложения, обнаружите физический плейсхолдер (маркеры ArUco) и спроецируете на него контент.

Важно: для надёжного наложения в большинстве задач рекомендуется выполнить калибровку камеры (матрица камеры и коэффициенты искажения). В статье даются практические советы, где это необходимо.

Что потребуется

  • Python 3.7+ (или ваша предпочитаемая версия) в виртуальном окружении
  • Библиотеки: opencv-contrib-python, numpy
  • Веб-камера или любой источник видеопотока
  • Изображение для наложения и/или 3D-модель (опционально)

Подготовка окружения

Создайте виртуальное окружение, затем установите зависимости:

pip install opencv-contrib-python numpy

Важно: устанавливайте именно пакет opencv-contrib-python, а не opencv-python — только в contrib-версии доступен модуль cv2.aruco, который используется для обнаружения маркеров.

Импорт библиотек

Создайте новый файл Python и подключите библиотеки:

import numpy as np
import cv2

Эти библиотеки обеспечивают функции для обработки изображений, матричных операций и вычисления гомографии.

Выбор изображения наложения

Для наложения в AR обычно используют растровое изображение или заранее сгенерированный рендер 3D-сцены. Загрузите изображение так:

overlay_image = cv2.imread('your_overlay_image.jpg')

Вы можете также генерировать изображение динамически (рендер 3D) или загружать последовательности кадров.

Обнаружение маркеров ArUco

Маркер ArUco — это квадрат с уникальным внутренним шаблоном, удобный для детекции и определения ориентации. Ниже функция, которая ищет маркеры в кадре, переводит изображение в оттенки серого, получает нужный словарь маркеров и возвращает углы и идентификаторы найденных маркеров.

def findArucoMarkers(image, markerSize=6, totalMarkers=250):
    # Convert the image to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Get the Aruco dictionary based on the marker size and total markers
    dictionary_key = getattr(cv2.aruco, f'DICT_{markerSize}X{markerSize}_{totalMarkers}')

    aruco_dictionary = cv2.aruco.getPredefinedDictionary(dictionary_key)

    # Set the Aruco detector parameters (default parameters)
    aruco_params = cv2.aruco.DetectorParameters()

    # Detect Aruco markers in the grayscale image
    marker_corners, marker_ids, _ = cv2.aruco.detectMarkers(gray, aruco_dictionary, parameters=aruco_params)

    return marker_corners, marker_ids

Пояснение: marker_corners — список углов каждого найденного маркера (четыре точки), marker_ids — массив идентификаторов.

Проекция изображения на маркеры (гомография и наложение)

Чтобы наложить изображение на маркер, вычисляется гомография между координатами углов исходного изображения и углами маркера в кадре. Затем изображение искажается (warpPerspective) и комбинируется с исходным кадром через маску.

def superimposeImageOnMarkers(video_frame, aruco_markers, overlay_image, video_width, video_height):
    frame_height, frame_width = video_frame.shape[:2]

    if aruco_markers[0] is not None and len(aruco_markers[0]) != 0:
        for i, marker_corner in enumerate(aruco_markers[0]):
            marker_corners = marker_corner.reshape((4, 2)).astype(np.int32)

            # Draw a polygon around the marker corners
            cv2.polylines(video_frame, [marker_corners], True, (0, 255, 0), 2)

            # Add marker ID as text on the top-left corner of the marker
            if aruco_markers[1] is not None:
                cv2.putText(video_frame, str(int(aruco_markers[1][i])), tuple(marker_corners[0]),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)

            # Find the homography matrix to map the overlay image onto the marker
            src_pts = np.array([[0, 0], [video_width, 0], [video_width, video_height], [0, video_height]], dtype='float32')
            dst_pts = marker_corners.astype('float32')

            homography_matrix, _ = cv2.findHomography(src_pts, dst_pts)

            # Warp the overlay image to align with the marker using homography matrix
            warped_image = cv2.warpPerspective(overlay_image, homography_matrix, (frame_width, frame_height))

            # Create a mask to apply the warped image only on the marker area
            mask = np.zeros((frame_height, frame_width), dtype='uint8')
            cv2.fillConvexPoly(mask, marker_corners, 255, cv2.LINE_AA)

            masked_warped_image = cv2.bitwise_and(warped_image, warped_image, mask=mask)

            # Apply the inverse mask to the video frame
            masked_video_frame = cv2.bitwise_and(video_frame, video_frame, mask=cv2.bitwise_not(mask))

            # Combine the masked warped image and masked video frame
            video_frame = cv2.add(masked_warped_image, masked_video_frame)

    return video_frame

Важно: порядок точек в src_pts и dst_pts должен соответствовать друг другу (например, по часовой стрелке), иначе гомография даст неверный результат.

Рендеринг AR-контента (основной цикл)

Этот код объединяет обнаружение маркеров и наложение. Он захватывает кадры с веб-камеры, находит маркеры и отображает результат в окне.

def processVideoFeed(overlay_image):
    # Set the dimensions of the video feed
    video_height = 480
    video_width = 640

    # Open the video capture
    video_capture = cv2.VideoCapture(0)

    # Load and resize the overlay image
    overlay_image = cv2.resize(overlay_image, (video_width, video_height))

    while video_capture.isOpened():
        # Read a frame from the video capture
        ret, video_frame = video_capture.read()

        if not ret:
            break

        # Find Aruco markers in the video frame
        aruco_markers = findArucoMarkers(video_frame, totalMarkers=100)

        # Superimpose the overlay image on the markers in the video frame
        video_frame = superimposeImageOnMarkers(video_frame, aruco_markers, overlay_image, video_width, video_height)

        # Display the video frame with overlay
        cv2.imshow('Camera Feed', video_frame)

        # Check for 'q' key press to exit the loop
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    video_capture.release()
    cv2.destroyAllWindows()

Запустите программу так:

# Start processing the video feed
processVideoFeed(overlay_image)

Если всё настроено правильно, в окне вы увидите видео с наложенным изображением на обнаруженные маркеры.

Практические советы и улучшения

  • Освещение: равномерное, без резких бликов и бликов на маркере, улучшает детекцию.
  • Размер маркеров: чем больше маркер на кадре, тем точнее позиционирование. Для мелких объектов используйте более высокое разрешение или приблизьте камеру.
  • Калибровка камеры: для точного позиционирования и компенсации искажений используйте параметры калибровки (cv2.calibrateCamera). Без калибровки при сильном искажении геометрия может «плавать».
  • Стабилизация: сглаживайте трансформации между кадрами (фильтрация матриц), чтобы уменьшить дрожание наложения.
  • Производительность: уменьшайте размер кадров или используйте оптимизированные реализации, если нужно работать в реальном времени на слабом железе.

Частые ошибки и способы их решения

  • Ничего не обнаруживается: проверьте, что используете opencv-contrib-python и выбран правильный словарь DICT_…
  • Некорректная ориентация изображения: не тот порядок точек в src_pts/dst_pts. Убедитесь, что порядок совпадает.
  • Наложение «прыгает»: используйте среднее скользящее или фильтр Калмана для сглаживания позы.
  • Искажения по краям: калибруйте камеру и применяйте коррекцию дисторсии перед детекцией маркеров.

Контрольный список для развёртывания (роль-based)

  • Разработчик
    • Установить opencv-contrib-python и numpy
    • Проверить доступность камеры
    • Написать модуль обнаружения и модуль наложения как отдельные функции
  • Тестировщик
    • Проверить обнаружение при различном освещении и расстоянии
    • Проверить работу с разными словарями ArUco и размерами маркеров
  • Дизайнер
    • Подготовить изображение/ри́зеры для наложения с подходящим соотношением сторон
    • Убедиться, что визуальный контент читаем при разных масштабах

Мини-методология разработки (быстрая)

  1. Подготовьте окружение и убедитесь, что камера работает.
  2. Реализуйте функцию обнаружения маркеров и протестируйте вывод marker_ids/marker_corners.
  3. Реализуйте вычисление гомографии и базовое наложение одного изображения.
  4. Добавьте маскирование и комбинирование слоёв.
  5. Оптимизируйте производительность и добавьте фильтрацию трансформаций.
  6. Проведите тесты при разных условиях освещения и расстояний.

Критерии приёмки

  • Система надёжно обнаруживает ArUco-маркеры при умеренном освещении.
  • Наложенное изображение корректно выравнивается по маркеру без видимых разрывов.
  • FPS и задержка соответствуют целевым требованиям проекта (например, плавный видеопоток для конкретного устройства).
  • Поведение детекции адекватно при небольших смещениях или поворотах маркера.

Короткий глоссарий (1 строка на термин)

  • Гомография — матрица, задающая проективное преобразование между двумя плоскостями.
  • ArUco — библиотека квадратных маркеров с уникальными ID для быстрого распознавания.
  • Маскирование — процесс выделения области изображения для локальной обработки.

Когда этот подход не подходит (ограничения)

  • При отсутствии явных маркеров (например, планшет без плейсхолдеров) нужно использовать детекцию объектов/фичей или SLAM.
  • Для высокоточных задач позиционирования в 3D лучше применять калиброванные системы и аппаратные сенсоры (VIO/SLAM + IMU).

Шаблон быстрой отладки

  1. Проверьте, что cv2.aruco импортируется без ошибок.
  2. Отобразите кадр и убедитесь, что маркеры видимы невооружённым глазом.
  3. Выведите marker_ids и координаты углов в консоль для одного кадра.
  4. Нарисуйте полилинии и убедитесь, что они совпадают с маркером.
  5. Подключите калибровочную матрицу, если геометрия искажается.

Пример маркера ArUco с уникальным шаблоном

Итог

Приведённый набор функций образует каркас простого AR-приложения на базе OpenCV и ArUco. Вы можете расширить его: добавить рендер 3D-моделей, улучшить сглаживание трансформаций, внедрить калибровку и использовать аппаратное ускорение. Начните с проверенного пайплайна: обнаружение → вычисление гомографии → наложение → отображение.

Важно: перед развёртыванием проверьте поведение при реальных сценариях использования и при необходимости добавьте фильтрацию/калибровку.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство