源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标记的一些例子:
标记图像的示例
必须注意的是,可以发现标记在环境中旋转,然而,检测过程需要能够确定其原始旋转,从而明确地识别每个角落。 这也是基于二进制编码完成的。
标记词典是在特定应用程序中考虑的一组标记。 它只是其每个标记的二进制编码列表。
字典的主要属性是字典大小和标记大小。
- 字典大小是组成字典的标记的数量。
- 标记大小是这些标记的大小(位数)。
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是输出标记图像的大小。 在这种情况下,输出图像的大小为200x200像素。 请注意,此参数应足够大,以存储特定字典的位数。 因此,例如,对于6x6位的标记大小,您无法生成5x5像素的图像(并且不考虑标记边界)。 此外,为避免变形,此参数应与位数+边界大小成比例,或至少远高于标记大小(如示例中的200),因此变形无关紧要。
- 第四个参数是输出图像。
- 最后,最后一个参数是一个可选参数,用于指定标记黑色边框的宽度。 大小与位数成比例。 例如,值为2表示边框的宽度等于两个内部位的大小。 默认值为1。
生成的图像是:
生成的标记
完整的工作示例包含在模块示例文件夹内的create_marker.cpp
。
注意:现在,样本通过命令行通过OpenCV Commandline Parser获取输入。 对于此文件,示例参数将如下所示
"/Users/Sarthak/Dropbox/OpenCV_GSoC/marker.png" -d=10 -id=1
标记检测
给定一些ArUco标记可见的图像,检测过程必须返回检测到的标记列表。 每个检测标记包括:
- 图像中四个角的位置(按原始顺序)。
- 标记的id。
标记检测过程包括两个主要步骤:
- 检测候选标记。 在该步骤中,分析图像以找到作为标记的候选的正方形形状。 它首先进行自适应阈值处理以对标记进行分割,然后从阈值图像中提取轮廓,并丢弃那些非凸起或不接近正方形的轮廓。 还应用了一些额外的过滤(去除太小或太大的轮廓,去除彼此太近的轮廓等)。
- 在候选检测之后,有必要通过分析它们的内部编码来确定它们是否实际上是标记。 此步骤首先提取每个标记的标记位。 为此,首先,应用透视变换以获得其规范形式的标记。 然后,使用Otsu对规范图像进行阈值处理以分离白色和黑色位。 根据标记大小和边界大小将图像分成不同的单元格,并计算每个单元格上的黑色或白色像素的数量,以确定它是白色还是黑色位。 最后,分析比特以确定标记是否属于特定字典,并且在必要时采用纠错技术。
请考虑以下图像:
带标记的原始图像
这些是检测到的标记(绿色):
检测到标记的图像
这些是在识别步骤中被拒绝的标记候选者(粉红色):
拒绝候选人的形象
在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
)。 - 检测到的标记存储在
markerCorners
和markerIds
结构中:markerCorners
是检测到的标记的角点列表。 对于每个标记,其四个角以其原始顺序返回(从左上角开始顺时针)。 因此,第一个角是左上角,然后是右上角,右下角和左下角。markerIds
是markerIds
中每个检测到的标记的id列表。 请注意,返回的markerCorners
和markerIds
向量具有相同的大小。
- 第四个参数是
DetectionParameters
类型的对象。 此对象包括可在检测过程中自定义的所有参数。 这些参数将在下一节中详细说明。 - 最终参数
rejectedCandidates
是一个返回的标记候选列表,即已找到的那些方格,但它们不提供有效的编码。 每个候选者也由其四个角定义,其格式与markerCorners
参数相同。 此参数可以省略,仅用于调试目的和“refind”策略(请参阅refineDetectedMarkers()
)。
在detectMarkers()
检查您的标记是否已被正确检测之后,您可能想要做的下一件事。 幸运的是,aruco模块提供了一个在输入图像中绘制检测到的标记的功能,这个功能是drawDetectedMarkers()
。 例如:
cv::Mat outputImage
cv::aruco::drawDetectedMarkers(image, markerCorners, markerIds);
image
是输入/输出图像,其中将绘制标记(它通常与检测到标记的图像相同)。markerCorners
和markerIds
是detectMarkers()
函数提供的相同格式的检测到的标记的结构。
检测到标记的图像
请注意,此功能仅用于可视化,可以完全省略其使用。
通过这两个函数,我们可以创建一个基本的标记检测循环来检测来自我们相机的标记:
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校准教程中所述。 请注意,除非修改相机光学系统(例如更改其焦点),否则只需执行一次。
最后,校准后得到的是相机矩阵:具有焦距和相机中心坐标(又称内部参数)的3x3元素矩阵,以及失真系数: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()
函数返回的标记角的矢量。- 第二个参数是标记面的大小(以米为单位)或任何其他单位。 注意,估计姿势的平移向量将在同一单元中
cameraMatrix
和distCoeffs
是需要先验知道的相机校准参数。rvecs
和tvecs
分别是角落中每个标记的旋转和平移向量。
此功能假定的标记坐标系位于标记的中心,Z轴指向外,如下图所示。 轴颜色对应关系为X:红色,Y:绿色,Z:蓝色。
轴绘制的图像
aruco模块提供绘制轴的功能,如上图所示,因此可以检查姿势估计:
cv::aruco::drawAxis(image, cameraMatrix, distCoeffs, rvec, tvec, 0.1);
image
是输入/输出图像,其中将绘制轴(它通常与检测到标记的图像相同)。cameraMatrix
和distCoeffs
是相机校准参数。rvec
和tvec
是要绘制轴的姿势参数。- 最后一个参数是轴的长度,与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是具有6x6位和总共250个标记的预定义标记字典的示例。
从所有提供的词典中,建议选择适合您应用的较小词典。 例如,如果您需要200个6x6位标记,则最好使用DICT_6X6_250而不是DICT_6X6_1000。 字典越小,标记间距离越高。
- 自动字典生成:
可以自动生成字典以调整所需的标记和位数,从而优化标记间距离:
cv :: Ptr <cv :: aruco :: Dictionary> dictionary = cv :: aruco :: generateCustomDictionary(36,5);
这将生成由36个5x5位标记组成的自定义字典。 该过程可能需要几秒钟,具体取决于参数(较大的字典和较高的位数较慢)。
- 手动字典生成:
最后,可以手动配置字典,以便可以使用任何编码。 为此,需要手动分配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
对象。 此对象包括可在标记检测过程中自定义的所有选项。
在本节中,所有这些参数都被注释掉了。 参数可以根据它们涉及的过程进行分类:
阈值
标记检测过程的第一步骤之一是输入图像的自适应阈值处理。
例如,上面使用的样本图像的阈值图像是:
阈值图像
可以在以下参数中自定义此阈值:
int adaptiveThreshWinSizeMin
,int adaptiveThreshWinSizeMax
,int adaptiveThreshWinSizeStep
adaptiveThreshWinSizeMin
和adaptiveThreshWinSizeMax
参数表示为自适应阈值选择阈值窗口大小(以像素为单位)的间隔(请参阅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
这些参数确定标记的最小和最大尺寸,具体地说是标记的最大和最小标记周长。 它们未以绝对像素值指定,而是相对于输入图像的最大尺寸指定。
例如,尺寸为640x480且最小相对标记周长为0.05的图像将导致最小标记周长为640x0.05 = 32像素,因为640是图像的最大尺寸。 这同样适用于maxMarkerPerimeterRate
参数。
如果minMarkerPerimeterRate
太低,则会严重影响检测性能,因为将来会考虑更多轮廓。 对于maxMarkerPerimeterRate
参数,这种惩罚并不明显,因为通常存在比大轮廓更多的小轮廓。 minMarkerPerimeterRate
值为0且maxMarkerPerimeterRate
值为4(或更多)将等效于考虑图像中的所有轮廓,但出于性能原因,不建议这样做。
默认值:
{} minMarkerPerimeterRate```
- ```double polygonalApproxAccuracyRat
对每个候选者应用多边形近似,并且仅接受那些接近正方形的那些。 此值确定多边形近似可以产生的最大误差approxPolyDP()
有关详细信息,请参阅approxPolyDP()
函数)。
此参数与候选长度(以像素为单位)相关。 因此,如果候选者的周长为100像素且polygonApproxAccuracyRate的值为0.04,则最大误差为100x0.04 = 5.4像素。
在大多数情况下,默认值工作正常,但高失真图像可能需要更高的误差值。
默认值:0.05
double minCornerDistanceRate
同一标记中任意一对角之间的最小距离。 它相对于标记周长表示。 最小距离(以像素为单位)为Perimeter * minCornerDistanceRate。
默认值:0.05
double minMarkerDistanceRate
两个不同标记的任意一对角之间的最小距离。 它相对于两个标记的最小标记周长表示。 如果两个候选人太近,则忽略较小的候选人。
默认值:0.05
int minDistanceToBorder
到图像边框的任何标记角的最小距离(以像素为单位)。 如果遮挡很小,则可以正确地检测到图像边界部分遮挡的标记。 但是,如果其中一个角被遮挡,则返回的角通常被放置在图像边界附近的错误位置。
如果标记角的位置很重要,例如,如果要进行姿势估计,最好丢弃任何角落太靠近图像边界的标记。 在其他地方,没有必要。
默认值:3
比特提取
在候选检测之后,分析每个候选的比特以确定它们是否是标记。
在分析二进制代码本身之前,需要提取这些位。 为此,去除透视畸变并使用Otsu阈值对得到的图像进行阈值处理以分离黑色和白色像素。
这是删除标记的透视变形后获得的图像的示例:
透视删除
然后,将图像划分为具有与标记中的位数相同的单元格的网格。 在每个单元格上,计算黑色和白色像素的数量以确定分配给单元格的位(来自多数值):
标记细胞
有几个参数可以自定义此过程:
int markerBorderBits
此参数指示标记边框的宽度。 它与每个钻头的大小有关。 因此,值为2表示边框具有两个内部位的宽度。
此参数需要与您正在使用的标记的边框大小一致。 可以在标记绘图功能(如drawMarker()
配置边框大小。
默认值:1
double minOtsuStdDev
此值确定要执行Otsu阈值处理的像素值的最小标准偏差。 如果偏差很小,则可能意味着所有方形都是黑色(或白色),并且应用Otsu没有意义。 如果是这种情况,则所有位都设置为0(或1),具体取决于平均值是高于还是低于128。
默认值:5.0
int perpectiveRemovePixelPerCell
该参数确定在去除透视失真(包括边界)之后所获得的图像中的像素数(每个单元)。 这是上图中红色方块的大小。
例如,假设我们正在处理5x5位和1位边框大小的标记(请参阅markerBorderBits
)。 然后,每个维度的单元/比特的总数是5 + 2 * 1 = 7(边界必须被计数两次)。 细胞总数为7x7。
如果perpectiveRemovePixelPerCell
的值是10,则获得的图像的大小将是10 * 7 = 70-> 70x70像素。
此参数的较高值可以改善位提取过程(在某种程度上),但是它可能会影响性能。
默认值:4
double perspectiveRemoveIgnoredMarginPerCell
当提取每个单元的位时,计算黑色和白色像素的数量。 通常,不建议考虑所有单元像素。 相反,最好忽略单元格边缘的一些像素。
其原因在于,在去除透视畸变之后,细胞的颜色通常不是完全分离的,并且白色细胞可以侵入黑色细胞的一些像素(反之亦然)。 因此,最好忽略一些像素,以避免计算错误的像素。
例如,在下图中:
标记细胞边缘
只考虑绿色方块内的像素。 在右图中可以看出,得到的像素包含来自相邻单元的较低量的噪声。 perspectiveRemoveIgnoredMarginPerCell
参数指示红色和绿色方块之间的差异。
此参数与单元格的总大小有关。 例如,如果单元大小为40像素并且该参数的值为0.1,则在单元中忽略40 * 0.1 = 4像素的余量。 这意味着在每个单元格上分析的像素总量实际上是32x32,而不是40x40。
默认值: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 cornerRefinementMaxIterations
,double cornerRefinementMinAccuracy
这两个参数确定子像素细化过程的停止标准。它cornerRefinementMaxIterations
表示cornerRefinementMinAccuracy
停止进程前的最大迭代次数和最小错误值。
如果迭代次数太多,则会影响性能。另一方面,如果它太低,则会产生较差的子像素细化。
默认值:
cornerRefinementMaxIterations
:30,cornerRefinementMinAccuracy
:0.1
http://docs.opencv.org/master/d5/dae/tutorial_aruco_detection.html