Вопрос или проблема
Моя цель — откалибровать камеру с помощью изображений ArUco. Я использую OpenCV 4.11.0 и python3.8.8
Мне удалось воспроизвести результаты из учебника по шахматной доске (https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html). Однако я должен быть в состоянии сделать это с другими шаблонами (например, с изображениями ArUco).
Это тестовое изображение, которое я использую (фактически это скриншот, но это не должно иметь значения, верно?):
Вот мой код, который правильно обнаруживает этот 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)
Представленные в одном кадре, такие точки дают лишь минимальную информацию, так как они занимают слишком малую площадь и образуют лишь одну плоскость. Для успешной калибровки необходимо больше точек на каждом изображении, и желательно, чтобы они были расположены в трех измерениях (например, в шахматной доске это достигается добавлением третьего измерения, то есть глубины).
Применение
Для успешной калибровки с учетом вашего рабочего процесса следует предпринять такие шаги:
-
Расширение сетки: Убедитесь, что объектные точки образуют более подробную и объемную структуру. Если вы работаете с аркусо, это может достигаться использованием нескольких маркеров на одном изображении.
-
Множественные кадры: Используйте более одного изображения с разными ракурсами и положением маркеров. Это необходимо для более точной оценки искажений и свойств камеры.
-
Правильная идентификация маркеров:
- Убедитесь, что ArUco маркеры расшифровываются корректно. Используйте большее число маркеров и усложните вашу систему идентификации, если это возможно.
-
Проверка алгоритма:
- Проверьте корректность использования функций OpenCV. Функция
cv2.aruco.ArucoDetector
должна возвращать корректные идентификаторы и углы маркеров.
- Проверьте корректность использования функций OpenCV. Функция
Вот пример кода для исправления текущей программы с учетом недостающих аспектов:
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 различных изображений с различными углами и положением маркеров. Уделите внимание позиции и нахождению координат в трехмерном пространстве для точности результатов.