您的位置:首页 > 理论基础

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

2017-06-02 16:00 645 查看
检测ArUco板

来源OpenCV http://docs.opencv.org/master/db/da9/tutorial_aruco_board_detection.html

1 效果图




板与轴
这是另一个例子与板部分堵塞:




板与遮挡
因为它可以观察到,尽管一些标记没有被发现,板构成仍然可以估计的标记。

2 ArUco板

ArUco板是一组标记,就像一个标志,它提供了一个单一的姿势相机。

最受欢迎的板是一个标记在同一平面上,因为它可以很容易地印刷:

然而,板并不局限于这种安排,可以代表任何2 d或3 d布局。

板的区别和一组独立的标记,标记之间的相对位置板是已知的先验。这允许的所有标记可用于估计相机的姿势对整个板。

当你使用一组独立的标志,你可以估计每个单独标记的姿势,因为你不知道在环境中相对位置的标记。

使用板的主要好处是:

· 姿势估计更多功能。
只有一些标记进行姿态估计是必要的。 因此,构成可以计算出即使在遮挡或部分观点的存在。

· 以来获得的姿势通常是更准确的点对应(标记角落)。

aruco模块允许使用。 主要的类  
cv::aruco::Board 类定义板布局:

class  Board {
public:
std::vector<std::vector<cv::Point3f> > objPoints;
cv::Ptr<cv::aruco::Dictionary> dictionary;
std::vector<int> ids;
};


一个类型的对象 板 有三个参数:

· 的 objPoints结构的3 d板的角落位置参考系统,即它的布局。 对于每一个标记,它的四个角落都存储在标准的顺序,即按顺时针方向从左上角开始。

· 的 字典参数表示的标记字典属于板标记。

· 最后, id结构表明每个标记的标识符 objPoints对指定的 字典。


板检测

板检测类似于标准标志检测。唯一的区别是在姿态估计的步骤。
事实上,使用标志板,一个标准的标记检测应该做过评估板构成。
aruco模块提供了一个特定的函数, estimatePoseBoard()板,执行评估:

cv::Mat inputImage;
// camera parameters are read from somewhere
cv::Mat cameraMatrix, distCoeffs;
readCameraParameters(cameraMatrix, distCoeffs);
// assume we have a function to create the board object
cv::Ptr<cv::aruco::Board> board = cv::aruco::Board::create();
...
std::vector<int> markerIds;
std::vector<std::vector<cv::Point2f>> markerCorners;
cv::aruco::detectMarkers(inputImage, board.dictionary, markerCorners, markerIds);
// if at least one marker detected
if(markerIds.size() > 0) {
cv::Vec3d rvec, tvec;
int valid = cv::aruco::estimatePoseBoard(markerCorners, markerIds, board, cameraMatrix, distCoeffs, rvec, tvec);
}

estimatePoseBoard的参数是:

· markerCorners和 markerIds:检测到标记的结构 detectMarkers()函数。

· 板 : 板 对象定义了板布局及其id

· cameraMatrix和 distCoeffs:相机标定参数姿态估计的必要条件。

· rvec和 tvec预测:板的构成。如果非空,那么作为初始猜测。

· 函数返回的标记用于估计总数板构成。注意,并不是所有的提供的标记 markerCorners和 markerIds应该使用,因为只有中列出的标记的id吗 板:id结构被认为是。

的 drawAxis()函数可以用来检查获得的姿势。
例如:





Board with axis

And this is another example with the board partially occluded:



Board with occlusions


因为它可以观察到,尽管一些标记没有被发现,板构成仍然可以估计的标记。

网格板

创建 板 对象需要指定环境中的每个标记的角落位置。然而,在许多情况下,板将只是一组标记在同一个平面上,在网格布局,所以它可以很容易地印刷和使用。

幸运的是,aruco模块提供的基本功能来创建和打印这些类型的标记。

的 GridBoard类是一个专业类的继承 板 类代表板和所有的标记在同一个平面上,在网格布局,如以下图片:




图像与aruco板
具体的坐标系统在网格板放置在板平面,集中在左下角的板和Z指出,像下图(X:红Y:绿色,Z:蓝色):





板与轴
一个 GridBoard对象可以定义使用以下参数:

可以很容易地创建这个对象从这些参数使用  
cv::aruco::GridBoard::create()静态函数:

一个 GridBoard对象可以定义使用以下参数:

· 标记在X方向上。

· 标记在Y方向上。

· 长度的标记。

· 的长度标记分离。

· 字典的标记。

· 所有标记的id(X * Y标记)。

可以很容易地创建这个对象从这些参数使用 
cv::aruco::GridBoard::create()
 静态函数:

cv::aruco::GridBoard board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);

·

第一个和第二个参数标记的数量分别在X和Y方向。
第三个和第四个参数分别标记长度和标记分离。 他们可以在任何单位提供,记住,估计姿势这个委员会将以相同的单位(一般来说,使用米)。
最后,提供了标记的字典。

所以,这个委员会将由5 x7 = 35标记。 每个标记的id分配,默认情况下,按升序开始0,所以他们将0,1,2,… 34岁。 这可以很容易地定制的访问id向量通过 
board.ids
,就像在 
父类。


创建一个网格板后,我们可能需要打印它并使用它。 一个函数生成的形象 GridBoard中提供

了 
cv::aruco::GridBoard::draw().。例如:

cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
cv::Mat boardImage;
board->draw( cv::Size(600, 500), boardImage, 10, 1 );

第一个参数是输出图像的像素大小。 在这种情况下600 x500像素。 如果这不是规模成正比,它将以图像为中心。
boardImage
:输出图像。
第三个参数(可选)边缘的像素,所以所有的标记都触碰图像边界。 在这种情况下,保证金是10。
最后,标记边界的大小,类似 
drawMarker()
函数。
默认值是1。

输出图像将是这样的:



一个完整的工作示例创建包含在 
create_board.cpp
模块内的样本文件夹。

注意:样品现在通过命令行通过输入 OpenCV命令行解析器 
这个文件的示例参数
"_output path_/aboard.png" -w=5 -h=7 -l=100 -s=10 -d=10

最后,一个完整的板检测的例子:

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);
cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
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::Vec3d rvec, tvec;
int valid = estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs, rvec, tvec);
// if at least one board marker detected
if(valid > 0)
cv::aruco::drawAxis(imageCopy, cameraMatrix, distCoeffs, rvec, tvec, 0.1);
}
cv::imshow("out", imageCopy);
char key = (char) cv::waitKey(waitTime);
if (key == 27)
break;
}


一个完整的工作包含在示例 
detect_board.cpp
模块内的样本文件夹。

注意:样品现在通过命令行通过输入 OpenCV命令行解析器 
这个文件的示例参数

-c="_path_"/calib.txt"
"_path_/aboard.png" -w=5 -h=7 -l=100 -s=10 -d=10


完善标记检测

ArUco也可以用来提高标记的检测。 如果我们有检测到标记的一个子集,属于,我们可以使用这些标记和会布局信息,试图找到先前没有被检测到的标记。

这可以通过使用 
refineDetectedMarkers()
之后不应调用函数,该函数调用 
detectMarkers()


这个函数的主要参数是原始图像标记检测对象,检测到标记,检测到标记id和被拒绝的标志。

被拒绝的角落可以获得的 
detectMarkers()
函数,也称为标记的候选人。
这个候选人是方形的形状已经发现在原始图像,但是未能通过识别步骤(即内心编纂了太多错误),因此他们没有被认为是标记。

然而,这些候选人有时实际标记没有被正确地识别图像中由于高噪音,非常低的分辨率或其他相关问题影响到二进制代码提取。 的 
refineDetectedMarkers()
函数发现这些候选人之间的通讯和失踪的标记。
这个搜索是基于两个参数:
候选人和失踪的投影之间的距离标记。 获得这些预测,必须发现至少一个的标志。
使用相机的参数获得的预测(相机畸变系数矩阵和)如果他们提供。 如果不是,从当地获得的预测单应性和只允许平面板(即Z坐标的所有角落标志应该是一样的)。 的 
minRepDistance
参数 
refineDetectedMarkers()
确定候选人之间的最小欧氏距离角落和预测标记(默认值10)。
二进制编纂。 如果一个候选人超过最小距离条件下,分析了其内部位再来确定它是否实际上是将标记。 然而,在这种情况下,条件不是如此强大和允许的数量错误比特可以更高。 这是表示的 
errorCorrectionRate
3.0参数(默认值)。
如果提供了负值,内部位根本不分析,只有角落距离评估。

这是一个使用的例子 
refineDetectedMarkers()
功能:

cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
std::vector<int> markerIds;
std::vector<std::vector<cv::Point2f>> markerCorners, rejectedCandidates;
cv::aruco::detectMarkers(inputImage, dictionary, markerCorners, markerIds, cv::aruco::DetectorParameters(), rejectedCandidates);
cv::aruco::refineDetectedMarkersinputImage, board, markerCorners, markerIds, rejectedCandidates);
// After calling this function, if any new marker has been detected it will be removed from rejectedCandidates and included
// at the end of markerCorners and markerIds


它还必须指出,在某些情况下,如果检测到标记的数量在第一时间太低(例如只有1或2标记),失踪的预测标记可以是糟糕的质量,产生错误的通讯。

查看更详细的实现模块样品。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐