天天看点

OpenCV4学习笔记(77)——ArUco模块之aruco标记板

失踪人口回归~~~上一次更新博客已经是十天前的事情,害(。・∀・)最近挺忙的,蛮多事情要做,同时还在学习新的东西,所以就把整理OpenCV笔记这件事暂且先放一放了。

言归正传,今天要整理的内容依然是有关于OpenCV的拓展模块ArUco,那就是aruco标记板的创建和标记检测,同时使用到增强型标记检测,最后利用检测出的标记对aruco标记板进行姿态估计。

在之前我们已经整理过什么是aruco标记了,那么aruco标记板又是何物???其实很简单,aruco标记板就是一系列来自相同字典的aruco标记的集合,我们可以将其打印在平面上以供检测使用。但是要注意的是,aruco标记板其实并不局限于二维平面,如果你乐意,完全可以打印在一张纸上然后折成立体的,例如XYZ坐标轴那种形状(墙角。。?)。

aruco标记板的优点呢很明显,就是精确度肯定会比单个aruco标记要更高,而且即使其中有部分标记未被检测出来,同样可以识别出这是一个标记板。总而言之,就是aruco标记板相对于单个aruco标记来说,其准确度、鲁棒性都会更好,然而使用便捷性显然会有下降,毕竟人家只是一小个标记你却足足一面板。。。当然了使用起来便捷性不足,同样也就限制了它的应用场景。

那么在OpenCV中,如何利用ArUco模块创建aruco标记板呢?首先,我们依然需要指定字典,也就是告诉程序说,那个谁,我要用这个字典里面的标记!!!

接着我们就可以使用

aruco::GridBoard::create()

来创建aruco标记板了,注意这里需要引入

GridBoard

这个子模块,直接用aruco来寻找的话是不可以的。

aruco::GridBoard::create()

的参数含义如下:

(1)参数markersX:在 X 轴方向上的标记数;

(2)参数markersY:在Y 轴方向上的标记数;

(3)参数markerLength:标记边长,单位通常为米;

(4)参数markerSaparation:标记间隔,单位通常为米;

(5)参数dictionary:生成标记的字典。

演示代码如下:

vector<vector<Point3f>>objPoints;
	auto dictionary = aruco::getPredefinedDictionary(DICT_6X6_250);
	auto board = aruco::GridBoard::create(5, 7, 0.04, 0.01, dictionary);
           

所以非常简单的,我们就创建好了一个aruco标记板,但是我们看不到它长啥样啊,所以为了一睹芳容,我们对它进行可视化,也就是

show()

出来,当然了你要是不想看可以不看它。我们使用创建的aruco标记板指针去调用

board->draw()

,其参数含义如下:

(1)参数outsize:输出图像的尺寸;

(2)参数img:输出的包含标记板的图像;

(3)参数marginSize:标记板的边框大小(不是每个标记!);

(4)参数borderBits:标记板中包含的每个标记的边框大小。

代码演示如下:

Mat boardImg;
	board->draw(Size(600, 800), boardImg, 10, 1);
	imshow("boardImg", boardImg);
           

我们来看一下创建出来的aruco标记板的芳容:

OpenCV4学习笔记(77)——ArUco模块之aruco标记板

好的,那接下来我们就要来对创建出的aruco标记板进行检测了,因为我没有打印出来,所以就直接拍照啦,如下图:

OpenCV4学习笔记(77)——ArUco模块之aruco标记板

接下来又是熟悉的一步:加载相机内参矩阵和畸变系数,这里我是已经标定好了的,所以直接输入值(话说一直想整理下相机标定的内容,然而,没啥空。。。)

cv::Mat cameraMatrix, distCoeffs;
	vector<double> camera = { 657.1548323619423, 0, 291.8582472145741,0, 647.384819351103, 391.254810476919,0, 0, 1 };
	cameraMatrix = Mat(camera);
	cameraMatrix = cameraMatrix.reshape(1, 3);
	vector<double> dist = { 0.1961793476399528, -1.38146317350581, -0.002301820186177369, -0.001054637905895881, 2.458286937422959 };
	distCoeffs = Mat(dist);
	distCoeffs = distCoeffs.reshape(1, 1);
           

接下来我们进行标记检测,这一步的检测和对于单个aruco标记检测所用代码是一样的,就不做介绍了

vector<vector<Point2f>>corners, rejectedCorners;
	vector<int>ids;
	auto parameters = aruco::DetectorParameters::create();
	aruco::detectMarkers(board_image, dictionary, corners, ids, parameters, rejectedCorners, cameraMatrix, distCoeffs);
           

接着我们进行增强型标记检测,这一步是针对于标记板而言的,可以将上面检测步骤中没有检出的aruco标记进行增强检测,提高检测的正确率。增强标记检测是对上一步中得到的候选标记角点,利用相机参数进行投影,并通过投影角点和候选角点的距离或者错误位比率来判断某候选角点是否为标记角点。

进行增强标记检测的API是

aruco::refineDetectedMarkers()

,其参数含义如下:

(1)参数image:检测到标记的图像;

(2)参数board:标记板;

(3)参数detectedCorners:已经检测到的标记角点,如果检测到新的标记角点则更新该参数;

(4)参数detecterIDs:已经检测到的标记的ID,如果检测到新的标记角点则更新该参数;

(5)参数rejectedCorners:候选角点,由

detectMarkers()

获得;如果检测到新的标记角点,则将该角点从候选角点中删除;

(6)和(7)参数:相机内外参数;

(8)参数 minRepDistance:候选角点和投影角点的最小距离,如果距离小于该值则可以认为该候选角点也是标记角点;

(9)参数errorCorrectionRate:与所用字典的纠错能力相同的允许错误位的比率。errorCorrectionRate = -1 表示忽略错误更正步骤;

通过这个API我们能够都aruco标记板进行二次增强检测,找到初步检测漏检的aruco标记,由于我们拍的图像还算完好,里面的标记都能够被检测出来,所以这个API的效果就不做演示了。

下面来看下对aruco标记板进行姿态估计的内容。

我们之前对aruco标记进行姿态估计时使用了一个API

estimatePose()

,那么这里要对aruco标记板进行姿态估计,也是一个很类似的API:

estimatePoseBoard()

,其参数含义与上面那个API是很相似的,只是多了一个输入参数

board

,并且返回值是检测到的aruco标记板的数量。代码演示如下:

//如果至少检测到一个标记,绘制标记、检测标记板并对标记板进行姿态估计
	Vec3d rvec, tvec;
	if (corners.size() > 0)
	{
		aruco::drawDetectedMarkers(board_image, corners, ids, Scalar(0, 255, 0));
		int boardNum = aruco::estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs, rvec, tvec);
		//如果至少检测到一个标记板
		if (boardNum > 0)
		{
			aruco::drawAxis(board_image, cameraMatrix, distCoeffs, rvec, tvec, 0.04);
		}
	}
	imshow("board", board_image);
           

下面看下对aruco标记板进行姿态估计的效果(注意这里检测出来的都是标记板内部的aruco标记):

OpenCV4学习笔记(77)——ArUco模块之aruco标记板

好的,那今天就整理了ArUco模块中对于aruco标记板的创建、检测、增强标记检测和姿态估计这些内容,本次笔记到此结束啦,下次有空再来~

PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!

继续阅读