主要内容

相机校准使用AprilTag标记

AprilTags被广泛用作视觉标记为应用对象检测、定位,目标相机标定[1]。AprilTags就像QR码,但设计少编码数据,因此可以解码速度这是有用的,例如,对于实时机器人应用程序。

使用AprilTags作为校准模式的优点包括更大的特征点检测,和一致的,可重复的检测。下面的例子使用了readAprilTag函数来检测和定位AprilTags在校准模式。的readAprilTag功能支持所有官方标金宝app记的家庭。示例还使用其他计算机视觉工具箱™函数执行端到端相机校正。默认的棋盘模式AprilTags取而代之的是网格的均匀分布。为校准使用棋盘模式的一个例子,请参考使用单摄像机校准器应用

这个例子展示了如何使用AprilTags校准相机以编程方式,并通过使用相机校准器的应用:

相机校准使用功能接口

第一步:生成校准模式

下载并准备标签图片

预生成的标签为所有支持的家庭可以从下载金宝app在这里使用一个web浏览器或通过运行下面的代码:

downloadURL =“https://github.com/AprilRobotics/apriltag-imgs/archive/master.zip”;dataFolder = fullfile (tempdir,“apriltag-imgs”,filesep);选择= weboptions (“超时”、正);zipFileName = fullfile (dataFolder,“apriltag-imgs-master.zip”);folderExists =存在(dataFolder,“dir”);%在一个临时目录中创建一个文件夹来保存下载文件。如果~ folderExists mkdir (dataFolder);disp (“下载apriltag-imgs-master。邮政编码(60.1 MB)……”)websave (zipFileName downloadURL选项);%提取下载的文件的内容。disp (“提取apriltag-imgs-master.zip……”)解压缩(zipFileName dataFolder);结束
下载apriltag-imgs-master。邮政编码(60.1 MB)…
提取apriltag-imgs-master.zip……

helperGenerateAprilTagPattern函数的例子可以用来生成一个校准目标使用标记图像标签的具体安排。图像中包含的模式calibPattern,它可以用来打印模式(从MATLAB)。这个例子使用了tag36h11家庭,它提供了一个合理的检测性能和健壮性假阳性检测之间的权衡。

%设置的属性校准模式。tagArrangement = (5、8);tagFamily =“tag36h11”;%使用AprilTags生成校准模式。tagImageFolder = fullfile (dataFolder,“apriltag-imgs-master”,tagFamily);imdsTags = imageDatastore (tagImageFolder);calibPattern = helperGenerateAprilTagPattern (imdsTags tagArrangement tagFamily);

使用readAprilTag函数在此模式结果与个人的角落位置检测标签组合在一起。的helperAprilTagToCheckerLocations函数可用于这种安排转换为一个列为主的安排,比如一个棋盘。

%阅读和本地化的标签校准模式。[tagIds, tagLocs] = readAprilTag (calibPattern tagFamily);%根据标签ID值。[~,sortIdx] = (tagIds)进行排序;tagLocs = tagLocs (:,:, sortIdx);%重塑标签角落位置M-by-2数组。tagLocs =重塑(排列(tagLocs [1、3、2]), [], 2);% AprilTag角落位置转换成棋盘角位置。checkerIdx = helperAprilTagToCheckerLocations (tagArrangement);imagePoints = tagLocs (checkerIdx (:):);%显示角落的位置。图;imshow (calibPattern);持有情节(imagePoints (: 1) imagePoints (:, 2),“ro - - - - - -”MarkerSize = 15)

准备图像校准

几点需要注意而准备校准图片:

  • 虽然模式是印在一篇论文在这个例子中,考虑印刷在表面持平,并且不受变形由于水分,等等。

  • 自校准过程平面假设模式,模式中的任何缺陷(如一个粗糙表面)可以降低标定的准确性。

  • 校准过程至少需要2的图像模式但使用10至20图像产生更精确的结果。

  • 捕捉各种模式,模式的图像填充的图像,从而覆盖整个视野。例如,最佳捕捉镜头失真,图像的边缘图像的框架模式。

  • 确保捕获的图像的模式是完全可见的因为图片与部分可见的模式将被拒绝。

  • 准备的更多信息的图像校准模式,明白了准备相机,捕捉图像

calibImages.png

步骤2:AprilTags检测和定位

helperDetectAprilTagCorners功能,包括最后的例子,用于检测和定位标记从棋盘的方式捕获的图像和安排他们用作校准过程的关键点。

%创建一个imageDatastore对象存储捕获的图像。imdsCalib = imageDatastore (“aprilTagCalibImages /”);%检测图像的校准模式。[imagePoints, boardSize] = helperDetectAprilTagCorners (imdsCalib、tagArrangement tagFamily);

第三步:生成世界点校准模式

生成AprilTag模式是这样的标签是一个棋盘时尚,所以世界坐标对应的图像坐标确定(在上方imagePoints)可以使用generateCheckerboardPoints函数。

这里,广场的大小是被标记的大小,和董事会的大小从上一步获得。测量标记大小之间的一侧的外黑边标记。

AprilTagSize.png

%为模式生成世界点坐标。tagSize = 16;%在毫米worldPoints = generateCheckerboardPoints (boardSize tagSize);

第四步:估计相机参数

与形象和世界通讯,估计摄像机参数使用estimateCameraParameters函数。

%确定图像的大小。I = readimage (imdsCalib, 1);图象尺寸大小=(我、1:2);%估计摄像机的参数。params = estimateCameraParameters (imagePoints worldPoints,图象尺寸=图象尺寸);

可视化的准确性校准和外在相机参数。显示,飞机在捕获的图像的校准模式。

%显示reprojection错误。图showReprojectionErrors (params)

%显示外在。图showExtrinsics (params)

检查发现像点的位置和reprojected点,获得使用估计摄像机的参数。

%读图像校准。I = readimage (imdsCalib 10);%的插入标记检测和reprojected点。我= insertMarker (imagePoints (:,:, 10),“o”颜色=“g”、大小= 5);我= insertMarker (params.ReprojectedPoints (:,:, 10),“x”颜色=“r”、大小= 5);%显示图像。图imshow(我)

使用其他校准模式

而这个例子使用AprilTags标记在校准模式,相同的工作流可以扩展到其他的平面模式。的estimateCameraParameters用于获得相机参数要求:

  • imagePoints:重点在校准模式在图像坐标从捕获的图像。

  • worldPoints:相应的世界点坐标的关键点校准模式。

提供有一种方法来获得这些关键点,其余的校准工作流程是相同的。

AprilTag校准模式支持整合到相机校准器应用金宝app

为了方便使用,上面还可以集成到工作流相机校准器应用。整个工作流是相同的步骤:

1。与AprilTags添加图片。

2。导入一个定制模式为AprilTags探测器类。探测器必须做到以下几点:

  • AprilTags检测和定位

  • 生成世界点校准模式

3所示。估计相机参数。

添加图片和AprilTags

打开相机校准器的应用:

  • MATLAB将来发布:应用程序选项卡,图像处理和计算机视觉部分,单击相机校准器图标。

  • MATLAB命令提示:输入使用单摄像机校准器应用

校准选项卡,文件部分中,点击添加图片,然后选择从文件。你可以从多个文件夹,点击添加图片添加图片为每个文件夹。我们将重用相同的图像以上。您将需要至少2相机校正的图像。一旦你添加图片,出现以下界面:

UI1.png

扩大定制模式面板上,看到更多的选择。

UI2.png

导入自定义模式检测器类

上面的UI显示了模式选择的下拉列表。默认情况下,应用程序不包括AprilTags模式检测器。您可以创建一个定制模式检测器类,然后将其添加到列表中使用的应用程序。关于如何创建一个定制模式的更多信息,点击信息图标()。一个定制模式检测器类AprilTags已经提供MyCustomAprilTagPatternDetector.m文件。这个类包含UI代码为探测器所需的参数和功能检测和处理自定义AprilTags校准模式。

这个例子使用了configureUIComponents ()配置UI组件和函数initializePropertyValues ()初始化它。的helperDrawImageAxesLabels功能,包括最后的例子,用于呈现原点,x轴和y轴标签在校准图像显示在相机校准器应用程序对话框。

校准的功能主要有:

  • detectPatternPoints ()——探测和定位AprilTags从他们捕获的图像和各种用于校准过程的关键点。使用这个函数实现helperDetectAprilTagCorners函数,给定的例子。

  • generateWorldPoints ()——计算世界坐标中对应的图像坐标AprilTag模式。使用这个函数实现helperGenerateAprilTagPattern函数,给定的例子。

导入类通过单击定制模式检测器导入模式检测器按钮下定制模式面板。选择类文件MyCustomAprilTagPatternDetector.m。如果在课堂上没有错误,那么您将会看到以下观点:

1. png

在这个例子中,所有的字段属性面板有正确的值。但是你可以定制这些值来满足您的需要。请注意,广场的大小代表了世界的单位和标签的宽度也认为等于图像中每个标记之间的间距。

点击好吧数据浏览器窗格中显示一个图像id列表,如下所示:

这些图像将包含检测模式。查看图像,选择从数据浏览器窗格。

2. png

估计摄像机参数

在这一点上,摄像机标定过程中给出的一样使用单摄像机校准器应用

默认的校准设置,单击校准按钮校准选项卡。可视化的校准检查的准确性Reprojection错误窗格,然后想象外在相机参数的估计Camera-centric窗格中显示的模式定位的相机。

校准images.PNG

金宝app支持函数和类

helperGenerateAprilTagPattern生成一个基于AprilTag校准模式。

函数calibPattern = helperGenerateAprilTagPattern (imdsTags tagArragement tagFamily) numTags = tagArragement (1) * tagArragement (2);numTags tagIds = 0 (1);%读第一形象。I = readimage (imdsTags 3);Igray = im2gray(我);%扩大缩略图图像标记。Ires = imresize (Igray 15“最近的”);%检测标签ID和位置(在图像坐标)。[tagIds (1) tagLoc] = readAprilTag (Ires tagFamily);%垫形象与白色边界(确保标签替换黑色的%棋盘的一部分)。tagSize =圆(max (tagLoc (:, 2)) - min (tagLoc (:, 2)));padSize =圆(tagSize / 2 -(大小(Ires 2)——tagSize) / 2);Ires = padarray (Ires [padSize padSize], 255);%初始化tagImages数组来保存扩展标签。tagImages = 0(大小(Ires, 1),大小(Ires, 2), numTags);tagImages(:,: 1) =忿怒;idx = 2: numTags I = readimage (imdsTags, idx + 2);Igray = im2gray(我);Ires = imresize (Igray 15“最近的”);Ires = padarray (Ires [padSize padSize], 255);tagIds (idx) = readAprilTag (Ires tagFamily);%保存标记图像。tagImages (:,:, idx) =忿怒;结束%根据他们的id标记图像。[~,sortIdx] = (tagIds)进行排序;tagImages = tagImages (:,:, sortIdx);%重塑标记图像,以确保他们出现在列为主的秩序%(蒙太奇函数图像行顺序)的地方。columnMajIdx =重塑(1:numTags, tagArragement) ';tagImages = tagImages (:,:, columnMajIdx (:));%使用“蒙太奇”创建的模式。imgData =蒙太奇(tagImages、大小= tagArragement);calibPattern = imgData.CData;结束

helperDetectAprilTagCorners在图像检测AprilTag校准模式。

函数[imagePoints, boardSize imagesUsed] = helperDetectAprilTagCorners (imdsCalib、tagArrangement tagFamily)%从tagArrangement获取模式的大小。boardSize = tagArrangement * 2 + 1;%初始化的图像和标记。numImages =长度(imdsCalib.Files);* tagArrangement numTags = tagArrangement (1) (2);%初始化的角落AprilTag模式。imagePoints = 0 (numTags * 4 2 numImages);numImages imagesUsed = 0 (1);%从AprilTag角落获得棋盘角指数。checkerIdx = helperAprilTagToCheckerLocations (tagArrangement);idx = 1: numImages%阅读和检测AprilTags形象。我= readimage (imdsCalib idx);[tagIds, tagLocs] = readAprilTag(我tagFamily);如果检测到所有标签%接受图像。如果元素个数(tagIds) = = numTags%检测到标签使用ID值。[~,sortIdx] = (tagIds)进行排序;tagLocs = tagLocs (:,:, sortIdx);%重塑标签角落位置M-by-2数组。tagLocs =重塑(排列(tagLocs [1、3、2]), [], 2);%填充imagePoints使用棋盘角指数。imagePoints (:,:, idx) = tagLocs (checkerIdx (:):);imagesUsed (idx) = true;其他的imagePoints (:,:, idx) = [];结束结束结束

helperAprilTagToCheckerLocations转换AprilTag角落棋盘的角落。

函数checkerIdx = helperAprilTagToCheckerLocations (tagArrangement) numTagRows = tagArrangement (1);numTagCols = tagArrangement (2);numTags = numTagRows * numTagCols;%行索引偏移量。rowIdxOffset = [0: numTagRows - 1;0:numTagRows - 1];%行指数第一和第二列。col1Idx = repmat (1 [4]、numTagRows 1);col2Idx = repmat (2 [3], numTagRows, 1);col1Idx = col1Idx + rowIdxOffset (:) * 4;col2Idx = col2Idx + rowIdxOffset (:) * 4;%列索引偏移量colIdxOffset = 0:4 * numTagRows: numTags * 4 - 1;%的扩张获得所有指标。checkerIdx = [col1Idx; col2Idx] + colIdxOffset;结束

helperDrawImageAxesLabels呈现原点,x轴和y轴标签在校准图像显示在校准器应用。

函数[originLabel,包含,yLabel] = helperDrawImageAxesLabels (boardSize, imagePoints) numBoardRows = boardSize (1) 1;numBoardCols = boardSize (2) 1;%重塑棋盘角落boardSize形状的阵列boardCoordsX =重塑(imagePoints (: 1), [numBoardRows numBoardCols]);boardCoordsY =重塑(imagePoints (:, 2), [numBoardRows numBoardCols]);boardCoords =猫(3 boardCoordsX boardCoordsY);%原产地标签(检查是否在原点位置图片)如果~ isnan (boardCoordsX (1,1)) p1 = boardCoords (1 1:);refPointIdx =找到(~ isnan (boardCoordsX (: 1), 2);p2 = boardCoords (refPointIdx (2), 1:);refPointIdx =找到(~ isnan (boardCoordsX (1,:)), 2);p3 = boardCoords (1, refPointIdx (2):);(loc,θ)= getAxesLabelPosition (p1, p2, p3);originLabel。位置= loc;originLabel。取向=θ;其他的originLabel =结构;结束%轴标签firstRowIdx = numBoardCols: 1:1;refPointIdx13 =找到(~ isnan (boardCoordsX (firstRowIdx)), 2);refPointIdx13 = firstRowIdx (refPointIdx13);p1 = boardCoords (1, refPointIdx13 (1):);p3 = boardCoords (1, refPointIdx13 (2):);refPointIdx2 =找到(~ isnan (boardCoordsX (:, refPointIdx13 (1))), 2);p2 = boardCoords (refPointIdx2 (2), refPointIdx13 (1):);(loc,θ)= getAxesLabelPosition (p1, p2, p3);θ= 180 +θ;包含。Location = loc; xLabel.Orientation = theta;%轴标签firstColIdx = numBoardRows: 1:1;refPointIdx12 =找到(~ isnan (boardCoordsX (firstColIdx 1), 2);refPointIdx12 = firstColIdx (refPointIdx12);p1 = boardCoords (refPointIdx12 (1), 1:);p2 = boardCoords (refPointIdx12 (2), 1:);refPointIdx3 =找到(~ isnan (boardCoordsX (refPointIdx12 (1):)), 2);refPointIdx3 p3 = boardCoords (refPointIdx12 (1), (2):);(loc,θ)= getAxesLabelPosition (p1, p2, p3);yLabel。位置= loc; yLabel.Orientation = theta;% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -% p1 + v% \% \ v1% p1 - - - - - - p2% |% v2 |% |% p3函数(loc,θ)= getAxesLabelPosition (p1, p2, p3) v1 = p3 - p1;θ= -atan2d (v1 (2), (1));v2 = p2 - p1;v = v1 - v2;d =函数(v (1), (2));minDist = 40;如果d < minDist v = (v / d) * minDist;结束loc = p1 + v;结束% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -结束

参考

[1]e·奥尔森“AprilTag:健壮且灵活的视觉基准系统,”2011年IEEE机器人与自动化国际会议上,上海,2011年,页。3400 - 3407 . doi: 10.1109 / ICRA.2011.5979561。