主要内容

使用AprilTag标记进行摄像机校准

AprilTags被广泛用作目标检测、定位应用的视觉标记,以及摄像机校准的目标[1]。AprilTags类似于QR码,但设计用于编码更少的数据,因此可以更快地解码,这对于实时机器人应用非常有用。

使用AprilTags作为校准模式的优点包括更好的特征点检测和一致的、可重复的检测Readapriltag.用于检测和定位校准模式中的AprilTags的函数Readapriltag.功能支持所有官方标金宝app签族。该示例还使用了额外的计算机视觉工具箱™功能来执行端到端摄像机校准。默认的棋盘格模式被间隔均匀的AprilTags网格所取代。有关使用棋盘图案进行校准的示例,请参阅使用单摄像机校准器应用程序

此示例演示如何以编程方式使用AprilTags和使用camera Calibrator应用程序校准相机:

基于功能接口的摄像机标定

步骤1:生成校准模式

下载并准备标签图像

所有受支持族的预生成标记都可以从金宝app在这里使用浏览器或运行以下代码:

下载网址='https://github.com/AprilRobotics/apriltag-imgs/archive/master.zip';dataFolder=fullfile(tempdir,“apriltag imgs”, filesep);选择= weboptions (“超时”,INF);zipfilename = [datafolder,'aprailtag-imgs-master.zip'];folderExists =存在(dataFolder,“dir”);%在临时目录中创建文件夹以保存下载的文件。如果~ folderExists mkdir (dataFolder);disp ('正在下载apriltag-imgs-master.zip(60.1MB)…')WebSave(Zipfilename,Drownolll,选项);%提取下载文件的内容。disp ('提取apriltag-imgs-master.zip ...')解压(zipFileName,dataFolder);结束

HelperGenerateAppriltPattern示例末尾的函数可用于使用特定标签排列的标签图像生成校准目标。模式图像包含在卡利布模式,可用于打印模式(来自MATLAB)。该示例使用tag36h11家庭,在检测性能和鲁棒性对假阳性检测之间提供合理的权衡。

%设置校准模式的属性。Tagarrangement = [5,8];tagfamily =“tag36h11”%使用APRILTAGS生成校准模式。tagImageFolder = [dataFolder“apriltag imgs master/”tagFamily];imdsTags = imageDatastore (tagImageFolder);calibPattern = helperGenerateAprilTagPattern(imdsTags, tagArrangement, tagFamily); / /生成一个

使用Readapriltag.此模式上的函数将检测到单个标记的角位置分组在一起。这个HelperapriltagtoCheckerlocations.功能可用于将这种布置转换为列主要布置,例如棋盘。

%读取并定位校准模式中的标签。[tagIds, tagLocs] = readAprilTag(calibPattern, tagFamily);%根据其ID值对标记进行排序。[〜,sortIdx] =排序(标记);taglocs = taglocs(:,sortidx);%将标签角位置重新塑造成M-by-2阵列。tagLocs=重塑(排列(tagLocs[1,3,2]),[],2);%将AprilTag角点位置转换为棋盘格角点位置。checkerIdx=HelperPriltAgToCheckerLocations(标记排列);imagePoints=标记位置(checkerIdx(:),:);%显示拐角位置。数字;imshow(Calibpattern);抓住绘图(图像点(:,1),图像点(:,2),“ro-”'Markersize',15)

为校准准备图像

准备校准图像时需要注意的几点:

  • 在该示例中,在纸上印刷图案,考虑在保持平坦的表面上打印它,并且由于湿度等而不受变形。

  • 由于校准程序假定图案是平面的,因此图案中的任何缺陷(例如,不均匀的表面)可以降低校准的准确性。

  • 校准程序需要至少2张图案图像,但使用10到20张图像会产生更准确的结果。

  • 捕获图案的各种图像,使图案填充大部分图像,从而覆盖整个视野。例如,要想最好地捕捉镜头的失真,就得在图像框的所有边缘都有图案的图像。

  • 确保图案在捕获的图像中完全可见,因为带有部分可见图案的图像将被拒绝。

  • 有关准备校准图案图像的更多信息,请参见准备相机并拍摄图像

步骤2:检测和本地化AprilTags

helperDetectAprilTagCorners函数用于从捕获的图像中检测和定位标签,并将它们以棋盘式的方式排列,作为校准过程中的关键点。

%创建imageDatastore对象以存储捕获的图像。imdsCalib=图像数据存储(“aprilTagCalibImages/”);%从图像中检测校准模式。[imagePoints,boardSize]=HelperDetectPriltAgcorner(imdsCalib,tagArrangement,tagFamily);

第3步:为校准模式生成世界要点

生成的AprilTag模式使得标记以棋盘形式出现,因此上面确定的对应图像坐标的世界坐标(在图像点)可以使用generatecheckerboardpoint函数。

这里,用标签的尺寸代替正方形的尺寸,板的尺寸是上一步得到的。测量标签一侧外黑色边缘之间的标签大小。

%为阵列生成世界点坐标。Tagsize = 16;%毫米worldPoints=generateCheckerboardPoints(boardSize,tagSize);

第4步:估计相机参数

使用图像和世界点对应关系,估计相机参数使用估计摄像机参数函数。

%确定图像的大小。I=读取图像(imdsCalib,1);图像大小=[大小(I,1),大小(I,2)];%估计相机参数。参数=估计的摄像机参数(图像点、世界点、,'图片尺寸', 图片尺寸);

可视化校准精度和外部摄像机参数。在捕获的图像中显示校准模式的平面。

%显示重投影错误。图ShowreProizherErrors(Params)

显示extrinsics。图2显示外部(参数)

检查使用估计的摄像机参数获得的检测到的图像点和重投影点的位置。

%读取校准图像。i = ReadImage(IMDScalib,10);%插入标记用于检测到的和repeteate。i = InsertMarker(i,imagepoints(::,10),“哦”“颜色”“g”“尺寸”, 5); I=插入标记(I,参数重新投影点(:,:,10),'X'“颜色”“r”“尺寸”5);%显示图像。图imshow(我)

使用其他校准模式

虽然此示例在校准模式中使用APRILTAGS标记,但也可以扩展到其他平面图案的相同工作流程。的估计摄像机参数用于获取相机参数需要:

  • 图像点:校准模式中的关键点,以从捕获图像获得的图像坐标表示。

  • 世界点:标定图中关键点对应的世界点坐标。

如果有办法获得这些关键点,校准工作流程的其余部分将保持不变。

将AprilTag校准模式支持集成到相机校准器应用程序中金宝app

为方便使用,上述工作流程也可以集成到摄像机校准器应用程序中。总体工作流程保持不变,步骤如下:

1.使用AprilTags添加图像。

2.导入APRILTAGS的自定义模式检测器类。探测器必须执行以下操作:

  • 检测和本地化AprilTags

  • 为校准模式生成世界点

3.估计相机参数。

使用AprilTags添加图像

打开相机校准器应用程序:

  • MATLAB TOOLSTRIP:在应用程序标签,在图像处理与计算机视觉部分,单击摄像机校准器偶像

  • matlab命令提示符:输入cameraCalibrator

校准标签,在文件部分,点击添加图像,然后选择从文件。您可以通过单击添加多个文件夹中的图像添加图像对于每个文件夹。我们将重复使用与相同的图像以上。您需要至少2张图像才能进行相机校准。添加图像后,将显示以下UI:

展开自定义模式面板,以查看更多选项。

导入自定义模式检测器类

上面的UI显示了一个模式选择的下拉列表。默认情况下,应用程序不包括AprilTags的模式检测器。你可以创建一个自定义模式检测器类,然后将它添加到列表中,以便在应用程序中使用。)。已经提供了一种自定义模式检测器类,用于APRILTAGSmycustomapriltagpatterndetectorm.此类包含检测器所需参数的UI代码,以及用于检测和处理自定义AprilTags校准模式的函数。

该示例使用configureUIComponents()函数来配置UI组件和initializepropertyvalues()初始化它。的helperDrawImageAxesLabels函数(包括在示例末尾)用于在“摄影机校准器应用程序”对话框中显示的校准图像中渲染原点、X轴和Y轴标签。

主要的校准功能有:

  • 侦听器()-从捕获的图像中检测和定位AprilTags,并对其进行排序,以用作校准过程中的关键点。此函数是使用helperDetectAprilTagCorners函数,在示例末尾给出。

  • generateWorldPoints()-计算AprilTag模式中相应图像坐标的世界坐标。此函数使用HelperGenerateAppriltPattern函数,在示例末尾给出。

通过单击导入模式检测器按钮下面自定义模式控制板。选择类文件mycustomapriltagpatterndetectorm..如果类中没有错误,那么您将看到以下视图:

对于本例,中的所有字段性质面板具有正确的值。但您可以自定义这些值以满足您的需要。请注意正方形表示世界单元中标签的宽度,并且也被认为等于图像中的每个标签之间的间隔。

点击好的数据浏览器窗格显示具有ID的图像列表,如下所示:

这些图像将包含检测到的图案。要查看图像,请从数据浏览器窗玻璃

估计相机参数

此时,摄像机校准过程与中给出的过程相同使用单摄像机校准器应用程序

使用默认校准设置,单击校准按钮校准tab.通过检查校准结果,直观显示校准的准确性重新注入错误窗格,然后可视化估计的外部相机参数相机中心显示相对于相机定位的图案的窗格。

金宝app支持函数和类

HelperGenerateAppriltPattern生成基于AprilTag的校准模式。

功能calbpattern = helperGenerateAprilTagPattern(imdsTags, tagarrmanagement, tagFamily) numTags = tagarrmanagement (1)* tagarrmanagement (2);numTags tagIds = 0 (1);%阅读第一张图片。I=读取图像(imdsTags,3);Igray=rgb2gray(I);%放大缩略图标记图像。Ires=调整大小(Igray,15,“最近的”);%检测标签ID和位置(在图像坐标中)。[tagIds(1),tagLoc]=readAprilTag(Ires,tagFamily);%带有白色边界的焊盘图像(确保标记替换黑色%部分的棋盘)。tagsize = round(max(tagloc(:,2)) -  min(tagloc(:,2)));PADSIZE =圆形(标签/ 2  - (尺寸(IRES,2) -  TAGSIZE)/ 2);IRES = PADARRAY(IRES,[PADSIZE,PADSIZE],255);%初始化tagImages数组以保存缩放的标记。tagImages = 0 (size(Ires,1), size(Ires,2), numTags);tagImages(:,: 1) =忿怒;idx=2:numTags I=readimage(imdsTags,idx+2);Igray=rgb2gray(I);Ires=imresize(Igray,15,“最近的”);Ires=padarray(Ires[padSize,padSize],255);TagID(idx)=readAprilTag(Ires,tagFamily);%存储标签图像。标记图像(:,:,idx)=Ires;结束%根据标签图像的ID对其进行排序。[~,sortIdx]=sort(tagid);tagImages=tagImages(:,:,sortIdx);%重塑标签图像以确保它们以列主要订单显示%(蒙太奇函数以行为主的顺序放置图像)。columnMajIdx = replaceall (1:numTags, tagarrangement)';tagImages = tagImages (:,:, columnMajIdx (:));使用“蒙太奇”创建图案。imgData=蒙太奇(标记图像,“尺寸”,tagArragement);calibPattern=imgData.CData;结束

helperDetectAprilTagCorners检测图像中的AprilTag校准模式。

功能[ImagePoints,BoardSize,Imageused] = HelperDetectapRiltagcorners(IMDScalib,Tagarrandement,Tagfamily)%从TagArrandement获取图案大小。boardSize=tagArrangement*2+1;%初始化图像和标记的数量。numimage=length(imdsCalib.Files);numTags=tagArrangement(1)*tagArrangement(2);%初始化APRIGRAG模式中的角数。图像点=零(numTags*4,2,numImages);imagesUsed=零(1,数字图像);从AprilTag角落获取checkerboard角落索引。checkerIdx=HelperPriltAgToCheckerLocations(标记排列);idx=1:numImages%读取并检测图像中的ApRIGLAGS。I = readimage(imdsCalib, idx);[tagIds, tagLocs] = readAprilTag(I, tagFamily);%如果检测到所有标记,则接受图像。如果numel(标记ID)=numTags%使用ID值对检测到的标记进行排序。[〜,sortIdx] =排序(标记);taglocs = taglocs(:,sortidx);%重塑标签角落位置到MY-2数组中。tagLocs=重塑(排列(tagLocs[1,3,2]),[],2);%使用棋盘角索引填充imagePoints。imagePoints(:,:,idx)=tagLocs(checkerIdx(:),:);imagesUsed(idx)=true;别的图像点(:,:,idx)=[];结束结束结束

HelperapriltagtoCheckerlocations.将AprilTag角点转换为棋盘格角点。

功能checkkeridx = helperAprilTagToCheckerLocations(tagArrangement) numTagRows = tagArrangement(1);numTagCols = tagArrangement (2);numTags = numTagRows * numTagCols;%行索引偏移量。rowIdxOffset = [0:numTagRows - 1;0: numTagRows - 1];%板中第一列和第二列的行索引。col1Idx=repmat([4 1]',numtagrowth,1);col2Idx=repmat([3 2]',numtagrowth,1);col1Idx=col1Idx+rowIdxOffset(:)*4;col2Idx=col2Idx+rowIdxOffset(:)*4;%列索引偏移colidxoffset = 0:4 * numtagrows:numtags * 4  -  1;%隐式展开以按顺序获取所有索引。checkerIdx=[col1Idx;col2Idx]+colIdxOffset;结束

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

功能[originLabel, xLabel, yLabel] = helperDrawImageAxesLabels(boardSize, imagePoints) numboards = boardSize(1)-1;numBoardCols = boardSize (2) 1;%重塑棋盘角到boardSize形状数组BoardCoordsx = REPAPE(图像点(:,1),[NUMBOADROWS,NUMBOARDCOL]);BoardCoordsy = Rehape(图像点(:,2),[Numboadtrows,NumboadyCols]);Boardcoords =猫(3,BoardCoordsx,BoardCoordsy);%原点标签(检查原点位置是否在图像内)如果〜Isnan(BoardCoordsx(1,1))P1 = BoardCoords(1,1,:);refpointidx = find(〜isnan(boardcoordsx(:,1)),2);p2 = boardcoords(refpointidx(2),1,:);refpointidx =查找(〜isnan(boardcoordsx(1,:)),2);p3 = boardcoords(1,refpointidx(2),:);[loc, theta] = getAxesLabelPosition(p1, p2, p3);originlabel.location = loc;originlabel.orientation =θ;别的originLabel =结构;结束%轴标签firstRowIdx=NumOardCols:-1:1;refPointIdx13=find(~isnan(boardCoordsX(1,firstRowIdx)),2;refPointIdx13=firstRowIdx(refPointIdx13(1));p1=boardCoords(1,refPointIdx13(1));p3=boardCoords(1,refPointIdx13(2));refPointIdx2=find(~isnan(boardCoordsX(boardCoordsX(1)),refPointIdx13(1)),2);p2=boardCoords(refPointIdx13(1));[loc,theta]=getAxesLabelPosition(p1,p2,p3);theta=180+theta;xLabel.Location=loc;xLabel.Orientation=theta;%y轴标签firstColIdx = numBoardRows: 1:1;refPointIdx12 =找到(~ isnan (boardCoordsX (firstColIdx 1), 2);refPointIdx12 = firstColIdx (refPointIdx12);p1 = boardCoords (refPointIdx12 (1), 1:);p2 = boardCoords (refPointIdx12 (2), 1:);refPointIdx3 = find(~isnan(boardCoordsX(refPointIdx12(1),:)), 2);refPointIdx3 p3 = boardCoords (refPointIdx12 (1), (2):);[loc, theta] = getAxesLabelPosition(p1, p2, p3);yLabel。位置= loc; yLabel.Orientation = theta;%--------------------------------------------------------------%p1+v% \%\v1%p1-----p2% |%v2|% |%p3功能[LOC,THETA] = GetaxesLabelposition(P1,P2,P3)V1 = P3  -  P1;theta = -atan2d(v1(2),v1(1));V2 = P2  -  P1;v = -v1  -  v2;d =斜面(v(1),v(2));Mindist = 40;如果d 结束loc=p1+v;结束%--------------------------------------------------------------结束

参考

[1] E.Olson,“AprilTag:一个健壮灵活的视觉基准系统,”2011年IEEE机器人与自动化国际会议,上海,2011,PP。3400-3407,DOI:10.1109 / ICRA.2011.5979561。