AprilTags широко используются в качестве визуальных маркеров для приложений в обнаружении объектов, локализации, и как цель для калибровки фотоаппарата [1]. AprilTags похожи на QR-коды, но спроектированы, чтобы закодировать меньше данных и могут поэтому декодироваться быстрее, который полезен, например, для приложений робототехники в реальном времени.
Этот пример использует readAprilTag
функция, чтобы обнаружить и локализовать AprilTags в калибровочном шаблоне. readAprilTag
функционируйте поддерживает все официальные семейства тегов. Пример также использует дополнительные функции Computer Vision Toolbox™, чтобы выполнить сквозную калибровку фотоаппарата. Шаблон шахматной доски по умолчанию заменяется сеткой равномерно расположенного с интервалами AprilTags. Для примера использования шаблона шахматной доски для калибровки обратитесь к Одному Приложению Camera Calibrator.
Преимущества использования AprilTags как калибровочный шаблон: больше устойчивого обнаружения характерной точки, сопоставимые и повторяемые обнаружения. Этот пример может также служить шаблоном для использования других пользовательских калибровочных скороговорок, таких как поле кругов вместо типичного шаблона шахматной доски.
Предсгенерированные теги для всех поддерживаемых семейств могут быть загружены отсюда с помощью веб-браузера или путем выполнения следующего кода:
downloadURL = 'https://github.com/AprilRobotics/apriltag-imgs/archive/master.zip'; dataFolder = fullfile(tempdir, 'apriltag-imgs', filesep); options = weboptions('Timeout', Inf); zipFileName = [dataFolder, 'apriltag-imgs-master.zip']; folderExists = exist(dataFolder, 'dir'); % Create a folder in a temporary directory to save the downloaded file if ~folderExists mkdir(dataFolder); disp('Downloading apriltag-imgs-master.zip (60.1 MB)...') websave(zipFileName, downloadURL, options); % Extract contents of the downloaded file disp('Extracting apriltag-imgs-master.zip...') unzip(zipFileName, dataFolder); end
Функция helperGenerateAprilTagPattern в конце конца экс-клена может использоваться, чтобы сгенерировать калибровочную цель использование изображений тега для определенного расположения тегов. Изображение шаблона содержится в calibPattern
, который может использоваться, чтобы распечатать шаблон (из MATLAB). Пример использует tag36h11 семейство, которое обеспечивает разумный компромисс между эффективностью обнаружения и робастностью к ложно-положительным обнаружениям.
% Set the properties of the calibration pattern. tagArrangement = [5,8]; tagFamily = 'tag36h11'; % Generate the calibration pattern using AprilTags. tagImageFolder = [dataFolder 'apriltag-imgs-master/' tagFamily]; imdsTags = imageDatastore(tagImageFolder); calibPattern = helperGenerateAprilTagPattern(imdsTags, tagArrangement, tagFamily);
Используя readAprilTag
функция на этом шаблоне результаты в обнаружениях с угловыми местоположениями отдельных тегов группировалась. Функция helperAprilTagToCheckerLocations может использоваться, чтобы преобразовать это расположение в упорядоченное по столбцам расположение, похожее на шахматную доску.
% Read and localize the tags in the calibration pattern. [tagIds, tagLocs] = readAprilTag(calibPattern, tagFamily); % Sort the tags based on their ID values. [~, sortIdx] = sort(tagIds); tagLocs = tagLocs(:,:,sortIdx); % Reshape the tag corner locations into an M-by-2 array. tagLocs = reshape(permute(tagLocs,[1,3,2]), [], 2); % Convert the AprilTag corner locations to checkerboard corner locations. checkerIdx = helperAprilTagToCheckerLocations(tagArrangement); imagePoints = tagLocs(checkerIdx(:),:); % Display corner locations. figure; imshow(calibPattern); hold on plot(imagePoints(:,1), imagePoints(:,2), 'ro-', 'MarkerSize',15)
Сгенерированный калибровочный шаблон должен быть распечатан на плоской поверхности и камере, которая должна быть калибрована, используется, чтобы получить изображения шаблона. Несколько моментов, которых необходимо отметить, при подготовке изображений к калибровке:
В то время как шаблон распечатан на бумаге в этом примере, рассмотрите печать его на поверхности, которая остается плоской, и не подвергается деформациям из-за влажности и т.д.
Поскольку калибровочная процедура принимает, что шаблон является плоским, любые недостатки в шаблоне (например, неровная поверхность) могут уменьшать точность калибровки.
Калибровочная процедура требует, чтобы по крайней мере 2 изображения шаблона, но использующий между 10 и 20 изображениями привели к более точным результатам.
Получите множество изображений шаблона, таким образом что трафаретные заливки большая часть изображения, таким образом покрыв целое поле зрения. Например, чтобы лучше всего получить искажение объектива, имейте изображения шаблона во всех ребрах фрейма изображения.
Убедитесь, что шаблон полностью отображается в полученных изображениях, поскольку изображения с частично видимыми шаблонами будут отклонены.
Для получения дополнительной информации о подготовке изображений калибровочного шаблона Подготовьте Шаблон, Камеру и Изображения.
Функция helperDetectAprilTagCorners, включенная в конце примера, используется, чтобы обнаружить и локализовать теги от полученных изображений и расположить их способом шахматной доски, который будет использоваться в качестве ключевых пунктов в калибровочной процедуре.
% Create an imageDatastore object to store the captured images. imdsCalib = imageDatastore("calibImages/"); % Detect the calibration pattern from the images. [imagePoints, boardSize] = helperDetectAprilTagCorners(imdsCalib, tagArrangement, tagFamily);
Сгенерированный шаблон AprilTag таков, что теги расположены способом шахматной доски, и таким образом, мировые координаты для соответствующих координат изображений, определенных выше (в imagePoints
) может быть получен с помощью generateCheckerboardPoints
функция.
Здесь, размер квадрата заменяется размером тега, и размер платы получен из предыдущего шага. Измерьте размер тега между внешними черными ребрами одной стороны тега.
% Generate world point coordinates for the pattern. tagSize = 16; % in millimeters worldPoints = generateCheckerboardPoints(boardSize, tagSize);
С изображением и мировыми соответствиями точки, оцените параметры камеры с помощью estimateCameraParameters
функция.
% Determine the size of the images. I = readimage(imdsCalib, 1); imageSize = [size(I,1), size(I,2)]; % Estimate the camera parameters. params = estimateCameraParameters(imagePoints, worldPoints, 'ImageSize', imageSize);
Визуализируйте точность калибровки и внешних параметров камеры, показывающих плоскости калибровочного шаблона в полученных изображениях.
% Display the reprojection errors.
figure
showReprojectionErrors(params)
% Display the extrinsics.
figure
showExtrinsics(params)
Смотрите местоположения обнаруженных точек изображений, и повторно спроектированные точки получили использование предполагаемых параметров камеры.
% Read a calibration image. I = readimage(imdsCalib, 10); % Insert markers for the detected and reprojected points. I = insertMarker(I, imagePoints(:,:,10), 'o', 'Color', 'g', 'Size', 5); I = insertMarker(I, params.ReprojectedPoints(:,:,10), 'x', 'Color', 'r', 'Size', 5); % Display the image. figure imshow(I)
В то время как этот пример использует маркеры AprilTags в калибровочном шаблоне, тот же рабочий процесс может быть расширен к другим плоским шаблонам также. estimateCameraParameters
используемый, чтобы получить параметры камеры требует:
imagePoints: Ключевые пункты в калибровочном шаблоне в координатах изображений получены из полученных изображений.
worldPoints: Соответствующие мировые координаты точки ключевых пунктов в калибровочном шаблоне.
Если существует способ получить эти ключевые пункты, остальная часть калибровочного рабочего процесса остается то же самое.
helperGenerateAprilTagPattern генерирует основанный на AprilTag калибровочный шаблон.
function calibPattern = helperGenerateAprilTagPattern(imdsTags, tagArragement, tagFamily) numTags = tagArragement(1)*tagArragement(2); tagIds = zeros(1,numTags); % Read the first image. I = readimage(imdsTags, 3); Igray = rgb2gray(I); % Scale up the thumbnail tag image. Ires = imresize(Igray, 15, 'nearest'); % Detect the tag ID and location (in image coordinates). [tagIds(1), tagLoc] = readAprilTag(Ires, tagFamily); % Pad image with white boundaries (ensures the tags replace the black % portions of the checkerboard). tagSize = round(max(tagLoc(:,2)) - min(tagLoc(:,2))); padSize = round(tagSize/2 - (size(Ires,2) - tagSize)/2); Ires = padarray(Ires, [padSize,padSize], 255); % Initialize tagImages array to hold the scaled tags. tagImages = zeros(size(Ires,1), size(Ires,2), numTags); tagImages(:,:,1) = Ires; for idx = 2:numTags I = readimage(imdsTags, idx + 2); Igray = rgb2gray(I); Ires = imresize(Igray, 15, 'nearest'); Ires = padarray(Ires, [padSize,padSize], 255); tagIds(idx) = readAprilTag(Ires, tagFamily); % Store the tag images. tagImages(:,:,idx) = Ires; end % Sort the tag images based on their IDs. [~, sortIdx] = sort(tagIds); tagImages = tagImages(:,:,sortIdx); % Reshape the tag images to ensure that they appear in column-major order % (montage function places image in row-major order). columnMajIdx = reshape(1:numTags, tagArragement)'; tagImages = tagImages(:,:,columnMajIdx(:)); % Create the pattern using 'montage'. imgData = montage(tagImages, 'Size', tagArragement); calibPattern = imgData.CData; end
helperDetectAprilTagCorners обнаруживает калибровочный шаблон AprilTag в изображениях.
function [imagePoints, boardSize, imagesUsed] = helperDetectAprilTagCorners(imdsCalib, tagArrangement, tagFamily) % Get the pattern size from tagArrangement. boardSize = tagArrangement*2 + 1; % Initialize number of images and tags. numImages = length(imdsCalib.Files); numTags = tagArrangement(1)*tagArrangement(2); % Initialize number of corners in AprilTag pattern. imagePoints = zeros(numTags*4,2,numImages); imagesUsed = zeros(1, numImages); % Get checkerboard corner indices from AprilTag corners. checkerIdx = helperAprilTagToCheckerLocations(tagArrangement); for idx = 1:numImages % Read and detect AprilTags in image. I = readimage(imdsCalib, idx); [tagIds, tagLocs] = readAprilTag(I, tagFamily); % Accept images if all tags are detected. if numel(tagIds) == numTags % Sort detected tags using ID values. [~, sortIdx] = sort(tagIds); tagLocs = tagLocs(:,:,sortIdx); % Reshape tag corner locations into a M-by-2 array. tagLocs = reshape(permute(tagLocs,[1,3,2]), [], 2); % Populate imagePoints using checkerboard corner indices. imagePoints(:,:,idx) = tagLocs(checkerIdx(:),:); imagesUsed(idx) = true; else imagePoints(:,:,idx) = []; end end end
helperAprilTagToCheckerLocations преобразует углы AprilTag в углы шахматной доски.
function checkerIdx = helperAprilTagToCheckerLocations(tagArrangement) numTagRows = tagArrangement(1); numTagCols = tagArrangement(2); numTags = numTagRows * numTagCols; % Row index offsets. rowIdxOffset = [0:numTagRows - 1; 0:numTagRows - 1]; % Row indices for first and second columns in board. col1Idx = repmat([4 1]', numTagRows, 1); col2Idx = repmat([3 2]', numTagRows, 1); col1Idx = col1Idx + rowIdxOffset(:)*4; col2Idx = col2Idx + rowIdxOffset(:)*4; % Column index offsets colIdxOffset = 0:4*numTagRows:numTags*4 - 1; % Implicit expansion to get all indices in order. checkerIdx = [col1Idx;col2Idx] + colIdxOffset; end
[1] Э. Олсон, "AprilTag: устойчивая и гибкая визуальная основанная на вере система", 2 011 Международных конференций IEEE по вопросам Робототехники и Автоматизации, Шанхая, 2011, стр 3400-3407, doi: 10.1109/ICRA.2011.5979561.