【计算机视觉】 相机姿态估计之标记检测-ArUco标记检测1

  • Post author:
  • Post category:其他

OpenCV  3.2.0-dev  http://docs.opencv.org/master/d9/d6d/tutorial_table_of_content_aruco.html

开篇 说明

aruco标记二进制基准标记可用于摄像机位姿估计。他们的主要好处是,他们的检测是强大的,快速和简单。

aruco模块包括这些类型的标记和检测工具使用姿势估计和相机校正。此外,ChArUco功能结合ArUco标记与传统棋方格,允许一个简单的和通用的角点检测。 模块还包括功能检测ChArUco角点,用于估计和相机校准。

 

姿态估计在许多计算机视觉应用中非常重要:机器人导航,增强现实等等。 该过程基于查找真实环境中的点与其2D图像投影之间的对应关系。 这通常是一个困难的步骤,因此通常使用合成或基准标记使其更容易。

最流行的方法之一是使用二元方形基准标记。 这些标记的主要好处是单个标记提供足够的对应(其四个角)以获得相机姿势。 此外,内部二进制编码使它们特别健壮,允许应用错误检测和校正技术的可能性。

aruco模块基于ArUco库 ,这是一个用于检测由RafaelMuñoz和Sergio Garrido开发的方形基准标记的流行库:

S. Garrido-Jurado,R.Muñoz-Salinas,FJ Madrid-Cuevas和MJMarín-Jiménez。 2014年。“在闭塞下自动生成和检测高度可靠的基准标记”。 模式识别。 47,6(2014年6月),2280-2292。 DOI = 10.1016 / j.patcog.2014.01.005

aruco功能包括在:#include <opencv2 / aruco.hpp>

标记和词典

ArUco标记是由宽黑色边框和内部二进制矩阵组成的合成方形标记,其确定其标识符(id)。 黑色边界便于其在图像中的快速检测,并且二进制编码允许其识别和错误检测和校正技术的应用。 标记大小决定了内部矩阵的大小。 例如,标记大小为4×4由16位组成。

ArUco标记的一些例子:

markers.jpg

                                                         标记图像的示例

必须注意的是,可以发现标记在环境中旋转,然而,检​​测过程需要能够确定其原始旋转,从而明确地识别每个角落。 这也是基于二进制编码完成的。

标记词典是在特定应用程序中考虑的一组标记。 它只是其每个标记的二进制编码列表。

字典的主要属性是字典大小和标记大小。

  • 字典大小是组成字典的标记的数量。
  • 标记大小是这些标记的大小(位数)。

aruco模块包括一些预定义的词典,涵盖一系列不同的词典大小和标记大小。

可以认为标记id是通过将二进制编码转换为十进制基数而获得的数字。 然而,这是不可能的,因为对于高标记尺寸,位数太高并且管理如此大量的数字是不实际的。 相反,标记id只是它所属的字典中的标记索引。 例如,字典中的前5个标记具有id:0,1,2,3和4。

有关字典的更多信息,请参阅“选择字典”部分。

标记创作

在检测之前,需要打印标记以便放置在环境中。 可以使用drawMarker()函数生成标记图像。

例如,让我们分析以下调用:

cv::Mat markerImage;
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::aruco::drawMarker(dictionary, 23, 200, markerImage, 1);

首先,通过选择aruco模块中的一个预定义词典来创建Dictionary对象。 具体地说,该字典由250个标记和6×6位的标记大小( DICT_6X6_250 )组成。

drawMarker的参数是:

  • 第一个参数是先前创建的Dictionary对象。
  • 第二个参数是标记id,在这种情况下是字典DICT_6X6_250的标记23。 请注意,每个字典由不同数量的标记组成。 在这种情况下,有效ID从0到249.任何超出有效范围的特定id都将产生异常。
  • 第三个参数200是输出标记图像的大小。 在这种情况下,输出图像的大小为200×200像素。 请注意,此参数应足够大,以存储特定字典的位数。 因此,例如,对于6×6位的标记大小,您无法生成5×5像素的图像(并且不考虑标记边界)。 此外,为避免变形,此参数应与位数+边界大小成比例,或至少远高于标记大小(如示例中的200),因此变形无关紧要。
  • 第四个参数是输出图像。
  • 最后,最后一个参数是一个可选参数,用于指定标记黑色边框的宽度。 大小与位数成比例。 例如,值为2表示边框的宽度等于两个内部位的大小。 默认值为1。

生成的图像是:

marker23.jpg

                                      生成的标记

完整的工作示例包含在模块示例文件夹内的create_marker.cpp

注意:现在,样本通过命令行通过OpenCV Commandline Parser获取输入。 对于此文件,示例参数将如下所示

"/Users/Sarthak/Dropbox/OpenCV_GSoC/marker.png" -d=10 -id=1

标记检测

给定一些ArUco标记可见的图像,检测过程必须返回检测到的标记列表。 每个检测标记包括:

  • 图像中四个角的位置(按原始顺序)。
  • 标记的id。

标记检测过程包括两个主要步骤:

  1. 检测候选标记。 在该步骤中,分析图像以找到作为标记的候选的正方形形状。 它首先进行自适应阈值处理以对标记进行分割,然后从阈值图像中提取轮廓,并丢弃那些非凸起或不接近正方形的轮廓。 还应用了一些额外的过滤(去除太小或太大的轮廓,去除彼此太近的轮廓等)。
  2. 在候选检测之后,有必要通过分析它们的内部编码来确定它们是否实际上是标记。 此步骤首先提取每个标记的标记位。 为此,首先,应用透视变换以获得其规范形式的标记。 然后,使用Otsu对规范图像进行阈值处理以分离白色和黑色位。 根据标记大小和边界大小将图像分成不同的单元格,并计算每个单元格上的黑色或白色像素的数量,以确定它是白色还是黑色位。 最后,分析比特以确定标记是否属于特定字典,并且在必要时采用纠错技术。

请考虑以下图像:

singlemarkersoriginal.png

                                                                      带标记的原始图像

这些是检测到的标记(绿色):

singlemarkersdetection.png

检测到标记的图像

这些是在识别步骤中被拒绝的标记候选者(粉红色):

singlemarkersrejected.png

                                                                拒绝候选人的形象

在aruco模块中,检测在detectMarkers()函数中执行。 此功能在模块中是最重要的,因为所有其余功能都基于detectMarkers()返回的先前检测到的标记。

标记检测的一个例子:

cv::Mat inputImage;
...
std::vector<int> markerIds;
std::vector<std::vector<cv::Point2f>> markerCorners, rejectedCandidates;
cv::Ptr<cv::aruco::DetectorParameters> parameters;
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::aruco::detectMarkers(inputImage, dictionary, markerCorners, markerIds, parameters, rejectedCandidates);

 

detectMarkers的参数是:

  • 第一个参数是将要检测标记的图像。
  • 第二个参数是字典对象,在这种情况下是一个预定义的字典( DICT_6X6_250 )。
  • 检测到的标记存储在markerCornersmarkerIds结构中:
    • markerCorners是检测到的标记的角点列表。 对于每个标记,其四个角以其原始顺序返回(从左上角开始顺时针)。 因此,第一个角是左上角,然后是右上角,右下角和左下角。
    • markerIdsmarkerIds中每个检测到的标记的id列表。 请注意,返回的markerCornersmarkerIds向量具有相同的大小。
  • 第四个参数是DetectionParameters类型的对象。 此对象包括可在检测过程中自定义的所有参数。 这些参数将在下一节中详细说明。
  • 最终参数rejectedCandidates是一个返回的标记候选列表,即已找到的那些方格,但它们不提供有效的编码。 每个候选者也由其四个角定义,其格式与markerCorners参数相同。 此参数可以省略,仅用于调试目的和“refind”策略(请参阅refineDetectedMarkers() )。

detectMarkers()检查您的标记是否已被正确检测之后,您可能想要做的下一件事。 幸运的是,aruco模块提供了一个在输入图像中绘制检测到的标记的功能,这个功能是drawDetectedMarkers() 。 例如:

cv::Mat outputImage
cv::aruco::drawDetectedMarkers(image, markerCorners, markerIds);
  • image是输入/输出图像,其中将绘制标记(它通常与检测到标记的图像相同)。
  • markerCornersmarkerIdsdetectMarkers()函数提供的相同格式的检测到的标记的结构。

singlemarkersdetection.png

                                                                      检测到标记的图像

请注意,此功能仅用于可视化,可以完全省略其使用。

通过这两个函数,我们可以创建一个基本的标记检测循环来检测来自我们相机的标记:

cv::VideoCapture inputVideo;
inputVideo.open(0);
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
while (inputVideo.grab()) {
    cv::Mat image, imageCopy;
    inputVideo.retrieve(image);
    image.copyTo(imageCopy);
    std::vector<int> ids;
    std::vector<std::vector<cv::Point2f> > corners;
    cv::aruco::detectMarkers(image, dictionary, corners, ids);
    // if at least one marker detected
    if (ids.size() > 0)
        cv::aruco::drawDetectedMarkers(imageCopy, corners, ids);
    cv::imshow("out", imageCopy);
    char key = (char) cv::waitKey(waitTime);
    if (key == 27)
        break;
}

请注意,某些可选参数已被省略,例如检测参数对象或被拒绝候选者的输出向量。

完整的工作示例包含在模块示例文件夹内的detect_markers.cpp

注意:现在,样本通过命令行通过OpenCV Commandline Parser获取输入。 对于此文件,示例参数将如下所示

-c="_path_/calib.txt" -d=10

姿势估计

在检测到标记后,您可能想要做的下一件事是从它们获取相机姿势。

要执行相机姿态估计,您需要知道相机的校准参数。 这是相机矩阵和失真系数。 如果您不知道如何校准相机,可以查看calibrateCamera()函数和OpenCV的校准教程。 您也可以使用aruco模块校准相机,如使用aruco校准教程中所述。 请注意,除非修改相机光学系统(例如更改其焦点),否则只需执行一次。

最后,校准后得到的是相机矩阵:具有焦距和相机中心坐标(又称内部参数)的3×3元素矩阵,以及失真系数:5个元素或更多元素的矢量模型相机产生的失真。

使用ArUco标记估计姿势时,您可以单独估计每个标记的姿势。 如果你想从一组标记估计一个姿势,你想要使用的是aruco Boards(参见ArUco Boards教程)。

相对于标记的相机姿势是从标记坐标系到相机坐标系的3d变换。 它由旋转和平移向量solvePnP()有关更多信息,请参阅solvePnP()函数)。

aruco模块提供估计所有检测到的标记的姿势的功能:

cv::Mat cameraMatrix, distCoeffs;
...
std::vector<cv::Vec3d> rvecs, tvecs;
cv::aruco::estimatePoseSingleMarkers(corners, 0.05, cameraMatrix, distCoeffs, rvecs, tvecs);
  • detectMarkers()参数是detectMarkers()函数返回的标记角的矢量。
  • 第二个参数是标记面的大小(以米为单位)或任何其他单位。 注意,估计姿势的平移向量将在同一单元中
  • cameraMatrixdistCoeffs是需要先验知道的相机校准参数。
  • rvecstvecs分别是角落中每个标记的旋转和平移向量。

此功能假定的标记坐标系位于标记的中心,Z轴指向外,如下图所示。 轴颜色对应关系为X:红色,Y:绿色,Z:蓝色。

singlemarkersaxis.png

                                                       轴绘制的图像

aruco模块提供绘制轴的功能,如上图所示,因此可以检查姿势估计:

cv::aruco::drawAxis(image, cameraMatrix, distCoeffs, rvec, tvec, 0.1);
  • image是输入/输出图像,其中将绘制轴(它通常与检测到标记的图像相同)。
  • cameraMatrixdistCoeffs是相机校准参数。
  • rvectvec是要绘制轴的姿势参数。
  • 最后一个参数是轴的长度,与tvec(通常是米)相同的单位

单个标记的姿势估计的基本完整示例:

cv::VideoCapture inputVideo;
inputVideo.open(0);
cv::Mat cameraMatrix, distCoeffs;
// camera parameters are read from somewhere
readCameraParameters(cameraMatrix, distCoeffs);
cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
while (inputVideo.grab()) {
    cv::Mat image, imageCopy;
    inputVideo.retrieve(image);
    image.copyTo(imageCopy);
    std::vector<int> ids;
    std::vector<std::vector<cv::Point2f>> corners;
    cv::aruco::detectMarkers(image, dictionary, corners, ids);
    // if at least one marker detected
    if (ids.size() > 0) {
        cv::aruco::drawDetectedMarkers(imageCopy, corners, ids);
        std::vector<cv::Mat> rvecs, tvecs;
        cv::aruco::estimatePoseSingleMarkers(corners, 0.05, cameraMatrix, distCoeffs, rvecs, tvecs);
        // draw axis for each marker
        for(int i=0; i<ids.size(); i++)
            cv::aruco::drawAxis(imageCopy, cameraMatrix, distCoeffs, rvecs[i], tvecs[i], 0.1);
    }
    cv::imshow("out", imageCopy);
    char key = (char) cv::waitKey(waitTime);
    if (key == 27)
        break;
}

视频示例:

https://www.youtube.com/watch?v=IsXWrcB_Hvs#action=share

完整的工作示例包含在模块示例文件夹内的detect_markers.cpp

注意:现在,样本通过命令行通过OpenCV Commandline Parser获取输入。 对于此文件,示例参数将如下所示

-c="_path_/calib.txt" -d=10

选择字典

aruco模块提供Dictionary类来表示标记字典。

除了标记大小和字典中标记的数量之外,还有另一个重要的字典参数,即标记间距离。 标记间距离是其标记之间的最小距离,并且它确定字典的错误检测和校正能力。

通常,较低的字典大小和较高的标记大小增加了标记间距离,反之亦然。 然而,由于需要从图像中提取的比特量较大,因此检测具有较大尺寸的标记更复杂。

例如,如果您的应用程序中只需要10个标记,最好使用仅由这10个标记组成的字典,而不是使用由1000个标记组成的一个字典。 原因是由10个标记组成的字典将具有更高的标记间距离,因此,它将更容易出错。

因此,aruco模块包括几种选择标记字典的方法,以便您可以提高系统的稳健性:

  • 预定义词典:

这是选择字典的最简单方法。 aruco模块包括一组具有各种标记大小和标记数量的预定义字典。 例如:


cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);

DICT_6X6_250是具有6×6位和总共250个标记的预定义标记字典的示例。

从所有提供的词典中,建议选择适合您应用的较小词典。 例如,如果您需要200个6×6位标记,则最好使用DICT_6X6_250而不是DICT_6X6_1000。 字典越小,标记间距离越高。

  • 自动字典生成:

可以自动生成字典以调整所需的标记和位数,从而优化标记间距离:

cv :: Ptr <cv :: aruco :: Dictionary> dictionary = cv :: aruco :: generateCustomDictionary(36,5);

这将生成由36个5×5位标记组成的自定义字典。 该过程可能需要几秒钟,具体取决于参数(较大的字典和较高的位数较慢)。

  • 手动字典生成:

最后,可以手动配置字典,以便可以使用任何编码。 为此,需要手动分配Dictionary对象参数。 必须注意的是,除非您有特殊原因要手动执行此操作,否则最好使用之前的备选方案之一。

class Dictionary {
    public:
    Mat bytesList;
    int markerSize;
    int maxCorrectionBits; // maximum number of bits that can be corrected
    ...
}
{bytesList```}
 of each marker dimension (for instance, 5 for markers with 5x5 bits). Finally, ```maxCorrectionBits``` is
the maximum number of erroneous bits that can be corrected during the marker detection. If this value is too
high, it can lead to a high amount of false positives.
Each row in ```bytesList``` represents one of the dictionary markers. However, the markers are not stored in its
binary form, instead they are stored in a special format to simplificate their detection.
Fortunately, a marker can be easily transformed to this form using the static method ```Dictionary::getByteListFromBits()```.
For example:
``` c++
    cv::aruco::Dictionary dictionary;
    // markers of 6x6 bits
    dictionary.markerSize = 6;
    // maximum number of bit corrections
    dictionary.maxCorrectionBits = 3;
    // lets create a dictionary of 100 markers
    for(int i=0; i<100; i++)
    {
        // assume generateMarkerBits() generate a new marker in binary format, so that
        // markerBits is a 6x6 matrix of CV_8UC1 type, only containing 0s and 1s
        cv::Mat markerBits = generateMarkerBits();
        cv::Mat markerCompressed = cv::aruco::Dictionary::getByteListFromBits(markerBits);
        // add the marker as a new row
        dictionary.bytesList.push_back(markerCompressed);
    }

探测器参数

detectMarkers()函数的一个参数是DetectorParameters对象。 此对象包括可在标记检测过程中自定义的所有选项。

在本节中,所有这些参数都被注释掉了。 参数可以根据它们涉及的过程进行分类:

阈值

标记检测过程的第一步骤之一是输入图像的自适应阈值处理。

例如,上面使用的样本图像的阈值图像是:

singlemarkersthresh.png

阈值图像

可以在以下参数中自定义此阈值:

  • int adaptiveThreshWinSizeMinint adaptiveThreshWinSizeMaxint adaptiveThreshWinSizeStep

adaptiveThreshWinSizeMinadaptiveThreshWinSizeMax参数表示为自适应阈值选择阈值窗口大小(以像素为单位)的间隔(请参阅OpenCV)

{阈值()“`}

参数“`adaptiveThreshWinSizeStep“`表示窗口大小的增量

“`adaptiveThreshWinSizeMin“`到adaptiveThreshWinSizeMax“`。

例如,对于值“`adaptiveThreshWinSizeMin“` = 5和adaptiveThreshWinSizeMax“` = 21和

“`adaptiveThreshWinSizeStep“` = 4,将有5个阈值步骤,窗口大小为5,9,13,17和21。

在每个阈值图像上,将提取候选标记。

如果标记尺寸太大,窗口大小的低值可能会“破坏”标记边界

它不会被检测到,如下图所示:

![破碎的标记图像](images / singlemarkersbrokenthresh.png)

另一方面,如果标记太小,太高的值可以产生相同的效果,并且它也可以

降低性能。 此外,该过程将倾向于全球阈值,失去适应性益处。

最简单的情况是对“`adaptiveThreshWinSizeMin“`使用相同的值

“`adaptiveThreshWinSizeMax“`,它产生一个阈值步骤。 但是,通常使用a更好

窗口大小的值范围,尽管许多阈值处理步骤也会显着降低性能。

默认值:

“`adaptiveThreshWinSizeMin“`:3,“`adaptiveThreshWinSizeMax“`:23,“`adaptiveThreshWinSizeStep“`:10

– “`double adaptiveTConstan

此参数表示在阈值条件中添加的常量值(请参阅OpenCV

{阈值()“`}

默认值:7

####轮廓过滤

阈值处理后,检测轮廓。 但是,不是所有的轮廓

被认为是候选人。 它们在不同的步骤中被过滤掉,以便形成轮廓

不太可能被标记丢弃。 本节中的参数是自定义的

这个过滤过程。

必须指出的是,在大多数情况下,检测能力之间存在平衡问题

和表现。 所有考虑的轮廓将在以下阶段处理,通常具有

更高的计算成本。 因此,最好在此阶段丢弃错误的候选人,而不是在后期阶段。

另一方面,如果过滤条件太严格,可以丢弃真实的标记轮廓,

因此,没有检测到。

– “`double minMarkerPerimeterRate“`,“`double maxMarkerPerimeterRat

这些参数确定标记的最小和最大尺寸,具体地说是标记的最大和最小标记周长。 它们未以绝对像素值指定,而是相对于输入图像的最大尺寸指定。

例如,尺寸为640×480且最小相对标记周长为0.05的图像将导致最小标记周长为640×0.05 = 32像素,因为640是图像的最大尺寸。 这同样适用于maxMarkerPerimeterRate参数。

如果minMarkerPerimeterRate太低,则会严重影响检测性能,因为将来会考虑更多轮廓。 对于maxMarkerPerimeterRate参数,这种惩罚并不明显,因为通常存在比大轮廓更多的小轮廓。 minMarkerPerimeterRate值为0且maxMarkerPerimeterRate值为4(或更多)将等效于考虑图像中的所有轮廓,但出于性能原因,不建议这样做。

默认值:

{} minMarkerPerimeterRate“`

– “`double polygonalApproxAccuracyRat

对每个候选者应用多边形近似,并且仅接受那些接近正方形的那些。 此值确定多边形近似可以产生的最大误差approxPolyDP()有关详细信息,请参阅approxPolyDP()函数)。

此参数与候选长度(以像素为单位)相关。 因此,如果候选者的周长为100像素且polygonApproxAccuracyRate的值为0.04,则最大误差为100×0.04 = 5.4像素。

在大多数情况下,默认值工作正常,但高失真图像可能需要更高的误差值。

默认值:0.05

  • double minCornerDistanceRate

同一标记中任意一对角之间的最小距离。 它相对于标记周长表示。 最小距离(以像素为单位)为Perimeter * minCornerDistanceRate。

默认值:0.05

  • double minMarkerDistanceRate

两个不同标记的任意一对角之间的最小距离。 它相对于两个标记的最小标记周长表示。 如果两个候选人太近,则忽略较小的候选人。

默认值:0.05

  • int minDistanceToBorder

到图像边框的任何标记角的最小距离(以像素为单位)。 如果遮挡很小,则可以正确地检测到图像边界部分遮挡的标记。 但是,如果其中一个角被遮挡,则返回的角通常被放置在图像边界附近的错误位置。

如果标记角的位置很重要,例如,如果要进行姿势估计,最好丢弃任何角落太靠近图像边界的标记。 在其他地方,没有必要。

默认值:3

比特提取

在候选检测之后,分析每个候选的比特以确定它们是否是标记。

在分析二进制代码本身之前,需要提取这些位。 为此,去除透视畸变并使用Otsu阈值对得到的图像进行阈值处理以分离黑色和白色像素。

这是删除标记的透视变形后获得的图像的示例:

removeperspective.png

                            透视删除

然后,将图像划分为具有与标记中的位数相同的单元格的网格。 在每个单元格上,计算黑色和白色像素的数量以确定分配给单元格的位(来自多数值):

bitsextraction1.png

                                      标记细胞

有几个参数可以自定义此过程:

  • int markerBorderBits

此参数指示标记边框的宽度。 它与每个钻头的大小有关。 因此,值为2表示边框具有两个内部位的宽度。

此参数需要与您正在使用的标记的边框大小一致。 可以在标记绘图功能(如drawMarker()配置边框大小。

默认值:1

  • double minOtsuStdDev

此值确定要执行Otsu阈值处理的像素值的最小标准偏差。 如果偏差很小,则可能意味着所有方形都是黑色(或白色),并且应用Otsu没有意义。 如果是这种情况,则所有位都设置为0(或1),具体取决于平均值是高于还是低于128。

默认值:5.0

  • int perpectiveRemovePixelPerCell

该参数确定在去除透视失真(包括边界)之后所获得的图像中的像素数(每个单元)。 这是上图中红色方块的大小。

例如,假设我们正在处理5×5位和1位边框大小的标记(请参阅markerBorderBits )。 然后,每个维度的单元/比特的总数是5 + 2 * 1 = 7(边界必须被计数两次)。 细胞总数为7×7。

如果perpectiveRemovePixelPerCell的值是10,则获得的图像的大小将是10 * 7 = 70-> 70×70像素。

此参数的较高值可以改善位提取过程(在某种程度上),但是它可能会影响性能。

默认值:4

  • double perspectiveRemoveIgnoredMarginPerCell

当提取每个单元的位时,计算黑色和白色像素的数量。 通常,不建议考虑所有单元像素。 相反,最好忽略单元格边缘的一些像素。

其原因在于,在去除透视畸变之后,细胞的颜色通常不是完全分离的,并且白色细胞可以侵入黑色细胞的一些像素(反之亦然)。 因此,最好忽略一些像素,以避免计算错误的像素。

例如,在下图中:

bitsextraction2.png

                                                                                    标记细胞边缘

只考虑绿色方块内的像素。 在右图中可以看出,得到的像素包含来自相邻单元的较低量的噪声。 perspectiveRemoveIgnoredMarginPerCell参数指示红色和绿色方块之间的差异。

此参数与单元格的总大小有关。 例如,如果单元大小为40像素并且该参数的值为0.1,则在单元中忽略40 * 0.1 = 4像素的余量。 这意味着在每个单元格上分析的像素总量实际上是32×32,而不是40×40。

默认值:0.13

标记识别

在提取了比特之后,下一步是检查提取的代码是否属于标记字典,并且如果需要,可以执行纠错。

  • double maxErroneousBitsInBorderRate

标记边框的位应为黑色。 此参数指定边框中允许的错误位数,即边框中的最大白位数。 它表示相对于标记中的总位数。

默认值:0.35

  • double errorCorrectionRate

每个标记字典具有可以校正的理论最大位数( Dictionary.maxCorrectionBits )。 但是,可以通过errorCorrectionRate参数修改此值。

例如,如果可以校正的允许比特数(对于使用的字典)是6并且errorCorrectionRate的值是0.5,则可以校正的实际最大比特数是6 * 0.5 = 3比特。

此值有助于减少纠错功能,以避免误报。

默认值:0.6

角落细化

在检测并识别出标记之后,最后一步是在角落位置执行子像素细化(参见OpenCV cornerSubPix()cv::aruco::CornerRefineMethod

请注意,此步骤是可选的,只有在标记角的位置必须准确时才有意义,例如用于姿势估计。 这通常是一个耗时的步骤,默认情况下禁用。

  • int cornerRefinementMethod

此参数确定是否执行角落子像素处理。 如果不需要精确的角,可以禁用它。

默认值: CORNER_REFINE_NONE

  • int cornerRefinementWinSize

此参数确定子像素细化过程的窗口大小。

高值可以产生窗口区域中包括闭合图像角落的效果,使得标记角落在处理期间移动到不同的错误位置。 此外,它会影响性能。

默认值:5

  • int cornerRefinementMaxIterationsdouble cornerRefinementMinAccuracy

这两个参数确定子像素细化过程的停止标准。它cornerRefinementMaxIterations表示cornerRefinementMinAccuracy停止进程前的最大迭代次数和最小错误值。

如果迭代次数太多,则会影响性能。另一方面,如果它太低,则会产生较差的子像素细化。

默认值:

cornerRefinementMaxIterations:30,cornerRefinementMinAccuracy:0.1

 

http://docs.opencv.org/master/d5/dae/tutorial_aruco_detection.html