Помощь в использовании cv2.calibrateCamera(…) для калибровки моей камеры

Вопрос или проблема

Моя цель — откалибровать камеру с помощью изображений ArUco. Я использую OpenCV 4.11.0 и python3.8.8

Мне удалось воспроизвести результаты из учебника по шахматной доске (https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html). Однако я должен быть в состоянии сделать это с другими шаблонами (например, с изображениями ArUco).

Это тестовое изображение, которое я использую (фактически это скриншот, но это не должно иметь значения, верно?):

test2.png

Вот мой код, который правильно обнаруживает этот ArUco, но не удается откалибровать изображение:

import cv2
import numpy as np
import matplotlib.pyplot as plt

# Загрузите изображение
image = cv2.imread('test2.png')

# Конвертируйте изображение в оттенки серого
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
aruco_dict = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_250)
parameters = cv2.aruco.DetectorParameters()

# Создайте детектор ArUco
detector = cv2.aruco.ArucoDetector(aruco_dict, parameters)
# Обнаружьте маркеры
corners, ids, rejected = detector.detectMarkers(gray)
# Выведите обнаруженные маркеры
print("Detected markers:", ids)
if ids is not None:
    cv2.aruco.drawDetectedMarkers(image, corners, ids)
    cv2.imshow('Detected Markers', image)
    cv2.waitKey(1000)
    cv2.destroyAllWindows()
    
objpoints = [] # координаты 3D в реальном пространстве
imgpoints = [] # координаты 2D в плоскости изображения.

objp = np.zeros((2*2,3), np.float32)
objp[:,:2] = np.mgrid[0:2,0:2].T.reshape(-1,2)

objpoints.append(objp)
imgpoints.append(np.reshape(corners[0],(4,1,2)))
    
# неудача происходит здесь
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

Ошибка, которую я получаю, такая:

OpenCV(4.11.0) D:\a\opencv-python\opencv-python\opencv\modules\calib3d\src\calibration.cpp:414: error: (-5:Bad argument) There should be less vars to optimize (having 15) than the number of residuals (8 = 2 per point) in function ‘cv::calibrateCameraInternal’

Основной вопрос:

Я полагаю, что ошибка возникает из-за того, что я неправильно понимаю ObjectPoints и ImagePoints. У меня есть 4 угла, и они находятся в ImagePoints, а в ObjectPoints просто векторы, отображающие все эти комбинации для z=0. Я перечислил их ниже. Видите, где я ошибаюсь?

Ниже приведено содержимое моих objpoints и imgpoints для справки:

objpoints
Out[255]: 
[array([[0., 0., 0.],
        [1., 0., 0.],
        [0., 1., 0.],
        [1., 1., 0.]], dtype=float32)]

imgpoints
Out[256]: 
[array([[[823., 435.]],
 
        [[853., 435.]],
 
        [[853., 466.]],
 
        [[823., 465.]]], dtype=float32)]

Спасибо!

Ответ или решение

Калибровка камеры с использованием библиотек OpenCV и Python является важным этапом для обеспечения точности компьютерного зрения. В данном случае речь идет об использовании кодов ArUco вместо стандартных шахматных досок для калибровки, что является возможным, но требует более тщательной настройки и понимания процесса.

Теория

При калибровке камеры целью является определение матрицы камеры и вектору искажений. Для этого, необходимо задать пары соответствующих точек: трехмерных (объектных) и двухмерных (изображенческих). Объектные точки — это известные координаты маркеров в реальном мире, тогда как изображенческие точки — это координаты этих же маркеров на снимке.

Для успешной калибровки необходимо собрать достаточное количество таких пар с разных изображений, поскольку каждая пара предоставляет лишь ограниченную информацию об оптике камеры. В типичном случае, когда используется шахматная доска, объектные точки располагаются в виде сетки. С ArUco маркерами процесс аналогичен, но требует уверенности в идентификации и расположении каждого маркера.

Пример

В вашем примере объектные точки представляют собой простой сеткой 2×2, что недостаточно для калибровки:

objp = np.zeros((2*2,3), np.float32)
objp[:,:2] = np.mgrid[0:2,0:2].T.reshape(-1,2)

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

Применение

Для успешной калибровки с учетом вашего рабочего процесса следует предпринять такие шаги:

  1. Расширение сетки: Убедитесь, что объектные точки образуют более подробную и объемную структуру. Если вы работаете с аркусо, это может достигаться использованием нескольких маркеров на одном изображении.

  2. Множественные кадры: Используйте более одного изображения с разными ракурсами и положением маркеров. Это необходимо для более точной оценки искажений и свойств камеры.

  3. Правильная идентификация маркеров:

    • Убедитесь, что ArUco маркеры расшифровываются корректно. Используйте большее число маркеров и усложните вашу систему идентификации, если это возможно.
  4. Проверка алгоритма:

    • Проверьте корректность использования функций OpenCV. Функция cv2.aruco.ArucoDetector должна возвращать корректные идентификаторы и углы маркеров.

Вот пример кода для исправления текущей программы с учетом недостающих аспектов:

import cv2
import numpy as np

# Инициализация детектора ArUco
aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_6X6_250)
parameters = cv2.aruco.DetectorParameters_create()

# Читает изображения и конвертирует в серый
image = cv2.imread('test2.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Детектирование маркеров
corners, ids, rejected = cv2.aruco.detectMarkers(gray, aruco_dict, parameters=parameters)

# Подготовка объектных точек
# Поскольку у вас только одна плоскость, добавьте больше маркеров и их идентификацию
objp = np.zeros((1*4, 3), np.float32)
objp[:,:2] = np.mgrid[0:2,0:2].T.reshape(-1, 2)

# Сделайте больше захватов изображений с маркерами и их детекцией
objpoints = [objp]
imgpoints = [np.reshape(corners[0], (4, 1, 2))]

# Калибровка камеры
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

# Валидация
if ret:
    print("Калибровка успешна")
    print("Матрица камеры:")
    print(mtx)
    print("Коэффициенты искажения:")
    print(dist)
else:
    print("Калибровка не удалась")

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

Оцените материал
Добавить комментарий

Капча загружается...