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

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
Автор
Редакция

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

Мошенничество с картами Shein — как распознать
Кибербезопасность

Мошенничество с картами Shein — как распознать

CSV в PostgreSQL: импорт и экспорт
Базы данных

CSV в PostgreSQL: импорт и экспорт

Перенос паролей в Apple Passwords на Mac
Инструкции

Перенос паролей в Apple Passwords на Mac

Установка MS SQL Server на Ubuntu 20.04
Databases

Установка MS SQL Server на Ubuntu 20.04

Экономия трафика при раздаче интернета
Сетевые советы

Экономия трафика при раздаче интернета

Сделать Windows 10 похожей на Windows 7, XP, 8
Windows

Сделать Windows 10 похожей на Windows 7, XP, 8