在本教程中,您将学习如何使用 OpenCV 和 Python 自动确定 ArUco 标记类型/字典。
到目前为止,在本系列中,我们已经学习了如何检测 ArUco 标记;然而,这取决于我们已经知道使用什么类型的 ArUco 字典来生成标记的事实。
这就提出了一个问题:如果您不知道用于生成标记的 ArUco 字典怎么办?如果不知道使用的 ArUco 字典,您将无法在图像/视频中检测到它们。
当这种情况发生时,您需要一种方法来自动确定图像中的 ArUco 标记类型——这正是我今天将向您展示的方法。
在本教程的第一部分,您将了解各种类型的 ArUco 标记和 AprilTag。
从那里,您将实现一个 Python 脚本,该脚本可以自动检测图像或视频流中是否存在任何类型的 ArUco 字典,从而允许您可靠地检测 ArUco 标记,即使您不知道使用什么 ArUco 字典生成他们!
在这个示例图像中,我们有四个 ArUco 标记,但我们不知道使用什么字典来生成它们,那么我们将如何实际检测它们?
当您在开发计算机视觉应用程序而您没有自己生成 ArUco 标记时,可能会出现这种情况。相反,这些标记可能是由其他人或组织生成的(或者您可能只需要一个通用算法来检测图像或视频流中的任何 ArUco 类型)。
当出现这种情况时,您需要能够自动推断出 ArUco 字典类型。
以下代码片段显示了分配给每种类型的标记字典的唯一变量标识符:
# 定义 OpenCV 支持的每个可能的 ArUco 标签的名称
ARUCO_DICT = {
"DICT_4X4_50": cv2.aruco.DICT_4X4_50,
"DICT_4X4_100": cv2.aruco.DICT_4X4_100,
"DICT_4X4_250": cv2.aruco.DICT_4X4_250,
"DICT_4X4_1000": cv2.aruco.DICT_4X4_1000,
"DICT_5X5_50": cv2.aruco.DICT_5X5_50,
"DICT_5X5_100": cv2.aruco.DICT_5X5_100,
"DICT_5X5_250": cv2.aruco.DICT_5X5_250,
"DICT_5X5_1000": cv2.aruco.DICT_5X5_1000,
"DICT_6X6_50": cv2.aruco.DICT_6X6_50,
"DICT_6X6_100": cv2.aruco.DICT_6X6_100,
"DICT_6X6_250": cv2.aruco.DICT_6X6_250,
"DICT_6X6_1000": cv2.aruco.DICT_6X6_1000,
"DICT_7X7_50": cv2.aruco.DICT_7X7_50,
"DICT_7X7_100": cv2.aruco.DICT_7X7_100,
"DICT_7X7_250": cv2.aruco.DICT_7X7_250,
"DICT_7X7_1000": cv2.aruco.DICT_7X7_1000,
"DICT_ARUCO_ORIGINAL": cv2.aruco.DICT_ARUCO_ORIGINAL,
"DICT_APRILTAG_16h5": cv2.aruco.DICT_APRILTAG_16h5,
"DICT_APRILTAG_25h9": cv2.aruco.DICT_APRILTAG_25h9,
"DICT_APRILTAG_36h10": cv2.aruco.DICT_APRILTAG_36h10,
"DICT_APRILTAG_36h11": cv2.aruco.DICT_APRILTAG_36h11
}
在本教程的其余部分,您将学习如何自动检查输入图像中是否存在任何这些 ArUco 类型。
我们今天使用一个 Python 脚本,guess_aruco_type.py
。该脚本将检查 images/ 目录中的示例,并且在事先不了解这些图像中的 ArUco 标签的情况下,将自动确定 ArUco 标签类型。
当您的任务是在图像/视频流中查找 ArUco 标签但不确定用于生成这些标签的 ArUco 字典时,这样的脚本非常有用。
自动AruCo/AprilTag类型识别实现的方法有点复杂,但我的感觉是,复杂只是在实践中起作用的启发式。
链接:https://pan.baidu.com/s/1DmjKL1tVbQX0YkDUzki2Jw
提取码:123a
# guess_aruco_type.py
# 用法
# python guess_aruco_type.py --image images/example_01.png
# 导入库
import argparse
import imutils
import cv2
# 构造参数解析器并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the input image containing ArUCo tag")
args = vars(ap.parse_args())
# 定义OpenCV支持的每个可能的ArUCo标签的名称
ARUCO_DICT = {"DICT_4X4_50": cv2.aruco.DICT_4X4_50, "DICT_4X4_100": cv2.aruco.DICT_4X4_100,
"DICT_4X4_250": cv2.aruco.DICT_4X4_250, "DICT_4X4_1000": cv2.aruco.DICT_4X4_1000,
"DICT_5X5_50": cv2.aruco.DICT_5X5_50, "DICT_5X5_100": cv2.aruco.DICT_5X5_100,
"DICT_5X5_250": cv2.aruco.DICT_5X5_250, "DICT_5X5_1000": cv2.aruco.DICT_5X5_1000,
"DICT_6X6_50": cv2.aruco.DICT_6X6_50, "DICT_6X6_100": cv2.aruco.DICT_6X6_100,
"DICT_6X6_250": cv2.aruco.DICT_6X6_250, "DICT_6X6_1000": cv2.aruco.DICT_6X6_1000,
"DICT_7X7_50": cv2.aruco.DICT_7X7_50, "DICT_7X7_100": cv2.aruco.DICT_7X7_100,
"DICT_7X7_250": cv2.aruco.DICT_7X7_250, "DICT_7X7_1000": cv2.aruco.DICT_7X7_1000,
"DICT_ARUCO_ORIGINAL": cv2.aruco.DICT_ARUCO_ORIGINAL,
"DICT_APRILTAG_16h5": cv2.aruco.DICT_APRILTAG_16h5,
"DICT_APRILTAG_25h9": cv2.aruco.DICT_APRILTAG_25h9,
"DICT_APRILTAG_36h10": cv2.aruco.DICT_APRILTAG_36h10,
"DICT_APRILTAG_36h11": cv2.aruco.DICT_APRILTAG_36h11}
# 从磁盘加载输入图像并调整其大小
print("[INFO] Loading image...")
image = cv2.imread(args["image"])
image = imutils.resize(image, width=800)
# 遍历 ArUCo 字典的类型
for (arucoName, arucoDictionary) in ARUCO_DICT.items():
# 加载 ArUCo 字典,获取 ArUCo 参数并尝试检测当前字典的标记
arucoDict = cv2.aruco.Dictionary_get(arucoDictionary)
arucoParams = cv2.aruco.DetectorParameters_create()
(corners, ids, rejected) = cv2.aruco.detectMarkers(image, arucoDict, parameters=arucoParams)
# 如果检测到至少一个 ArUCo 标记,则在终端中显示 ArUCo 标记及其类型名称
if len(corners) > 0:
print("[INFO] Detected {} markers for '{}'".format(len(corners), arucoName))
# 导入库
import argparse
import imutils
import cv2
# 构造参数解析器并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
help="path to input image containing ArUCo tag")
args = vars(ap.parse_args())
我们导入所需的命令行参数,然后解析我们的命令行参数。
这里只需要一个命令行参数,--image
,它是我们输入图像的路径。
解析命令行参数后,我们可以继续定义我们的 ARUCO_DICT
字典,它为 OpenCV 支持的每个 ArUco 字典提供名称和唯一变量标识符:
# 定义 OpenCV 支持的每个可能的 ArUco 标签的名称
ARUCO_DICT = {
"DICT_4X4_50": cv2.aruco.DICT_4X4_50,
"DICT_4X4_100": cv2.aruco.DICT_4X4_100,
"DICT_4X4_250": cv2.aruco.DICT_4X4_250,
"DICT_4X4_1000": cv2.aruco.DICT_4X4_1000,
"DICT_5X5_50": cv2.aruco.DICT_5X5_50,
"DICT_5X5_100": cv2.aruco.DICT_5X5_100,
"DICT_5X5_250": cv2.aruco.DICT_5X5_250,
"DICT_5X5_1000": cv2.aruco.DICT_5X5_1000,
"DICT_6X6_50": cv2.aruco.DICT_6X6_50,
"DICT_6X6_100": cv2.aruco.DICT_6X6_100,
"DICT_6X6_250": cv2.aruco.DICT_6X6_250,
"DICT_6X6_1000": cv2.aruco.DICT_6X6_1000,
"DICT_7X7_50": cv2.aruco.DICT_7X7_50,
"DICT_7X7_100": cv2.aruco.DICT_7X7_100,
"DICT_7X7_250": cv2.aruco.DICT_7X7_250,
"DICT_7X7_1000": cv2.aruco.DICT_7X7_1000,
"DICT_ARUCO_ORIGINAL": cv2.aruco.DICT_ARUCO_ORIGINAL,
"DICT_APRILTAG_16h5": cv2.aruco.DICT_APRILTAG_16h5,
"DICT_APRILTAG_25h9": cv2.aruco.DICT_APRILTAG_25h9,
"DICT_APRILTAG_36h10": cv2.aruco.DICT_APRILTAG_36h10,
"DICT_APRILTAG_36h11": cv2.aruco.DICT_APRILTAG_36h11
}
我们将彻底遍历这个字典,为每个条目加载 ArUco 检测器,然后将检测器应用于我们的输入图像。
如果我们命中了一个特定的标签类型,那么我们就知道ArUco标签存在于图像中。
说到这里,让我们现在实现这个逻辑:
# 从磁盘加载输入图像并调整其大小
print("[INFO] loading image...")
image = cv2.imread(args["image"])
image = imutils.resize(image, width=600)
# 遍历 ArUco 字典的类型
for (arucoName, arucoDict) in ARUCO_DICT.items():
# 加载 ArUCo 字典,获取 ArUCo 参数,并尝试检测当前字典的标记
arucoDict = cv2.aruco.Dictionary_get(arucoDict)
arucoParams = cv2.aruco.DetectorParameters_create()
(corners, ids, rejected) = cv2.aruco.detectMarkers(
image, arucoDict, parameters=arucoParams)
# 如果检测到至少一个 ArUco 标记,则向我们的终端显示 ArUco 名称
if len(corners) > 0:
print("[INFO] detected {} markers for '{}'".format(
len(corners), arucoName))
从磁盘加载我们的输入 --image
并调整其大小。从那里我们循环遍历 OpenCV 支持的所有可能的 ArUco 词典。
对于每个 ArUco 词典,我们:
如果生成的corners
列表的长度大于零,我们知道当前的arucoDict已经被用来(潜在地)在我们的输入图像中生成ArUco标签。
在这种情况下,我们将在图像中找到的标记数量以及ArUco字典的名称记录到终端,以便在运行脚本后进行进一步的研究。
$ python guess_aruco_type.py --image images/example_01.png
[INFO] loading image...
[INFO] detected 2 markers for 'DICT_5X5_50'
[INFO] detected 5 markers for 'DICT_5X5_100'
[INFO] detected 5 markers for 'DICT_5X5_250'
[INFO] detected 5 markers for 'DICT_5X5_1000'
rUco 标记属于 5×5 类,ID 分别高达 50、100、250 或 1000。这些结果意味着:
$ python guess_aruco_type.py --image images/example_02.png
[INFO] loading image...
[INFO] detected 1 markers for 'DICT_4X4_50'
[INFO] detected 1 markers for 'DICT_4X4_100'
[INFO] detected 1 markers for 'DICT_4X4_250'
[INFO] detected 1 markers for 'DICT_4X4_1000'
[INFO] detected 4 markers for 'DICT_ARUCO_ORIGINAL'
在这里,您可以看到包含 Pantone颜色匹配卡的示例图像。OpenCV(错误地)认为这些标记可能属于4×4类,但如果放大示例图像,就会发现这不是真的,因为这些实际上是6×6标记,标记周围有一个额外的填充。
此外,由于对于 4×4 类仅检测到一个标记,并且由于图像中总共有四个标记,因此我们可以推断这些一定是 DICT_ARUCO_ORIGINAL。
我们将看最后一张图片,这张图片包含 AprilTags:
$ python guess_aruco_type.py --image images/example_03.png
[INFO] loading image...
[INFO] detected 3 markers for 'DICT_APRILTAG_36h11'
在这里,OpenCV 可以推断出我们肯定正在查看 AprilTags。
# detect_aruco_image_type.py
# 用法
# python detect_aruco_image_type.py --image images/example_01.png
# 导入库
import argparse
import imutils
import cv2
import sys
# 构造参数解析器并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the input image containing ArUCo tag")
args = vars(ap.parse_args())
# 定义OpenCV支持的每个可能的ArUCo标签的名称
ARUCO_DICT = {"DICT_4X4_50": cv2.aruco.DICT_4X4_50, "DICT_4X4_100": cv2.aruco.DICT_4X4_100,
"DICT_4X4_250": cv2.aruco.DICT_4X4_250, "DICT_4X4_1000": cv2.aruco.DICT_4X4_1000,
"DICT_5X5_50": cv2.aruco.DICT_5X5_50, "DICT_5X5_100": cv2.aruco.DICT_5X5_100,
"DICT_5X5_250": cv2.aruco.DICT_5X5_250, "DICT_5X5_1000": cv2.aruco.DICT_5X5_1000,
"DICT_6X6_50": cv2.aruco.DICT_6X6_50, "DICT_6X6_100": cv2.aruco.DICT_6X6_100,
"DICT_6X6_250": cv2.aruco.DICT_6X6_250, "DICT_6X6_1000": cv2.aruco.DICT_6X6_1000,
"DICT_7X7_50": cv2.aruco.DICT_7X7_50, "DICT_7X7_100": cv2.aruco.DICT_7X7_100,
"DICT_7X7_250": cv2.aruco.DICT_7X7_250, "DICT_7X7_1000": cv2.aruco.DICT_7X7_1000,
"DICT_ARUCO_ORIGINAL": cv2.aruco.DICT_ARUCO_ORIGINAL,
"DICT_APRILTAG_16h5": cv2.aruco.DICT_APRILTAG_16h5,
"DICT_APRILTAG_25h9": cv2.aruco.DICT_APRILTAG_25h9,
"DICT_APRILTAG_36h10": cv2.aruco.DICT_APRILTAG_36h10,
"DICT_APRILTAG_36h11": cv2.aruco.DICT_APRILTAG_36h11}
# 从磁盘加载输入图像并调整其大小
print("[INFO] Loading image...")
image = cv2.imread(args["image"])
image = imutils.resize(image, width=800)
# 循环ArUCo字典的类型
for (arucoName, arucoDictionary) in ARUCO_DICT.items():
# 加载 ArUCo 字典,获取 ArUCo 参数并尝试检测当前字典的标记
arucoDict = cv2.aruco.Dictionary_get(arucoDictionary)
arucoParams = cv2.aruco.DetectorParameters_create()
(corners, ids, rejected) = cv2.aruco.detectMarkers(image, arucoDict, parameters=arucoParams)
# 如果检测到至少一个 ArUCo 标记,则在终端中显示 ArUCo 标记及其类型名称
if len(corners) > 0:
print("[INFO] Detected {} markers for '{}'".format(len(corners), arucoName))
# 展平 ArUCo ID 列表
IDS = ids.flatten()
# 循环检测到的 ArUCo corners
for (markerCorner, markerID) in zip(corners, IDS):
# 提取始终按以下顺序返回的标记corners:
# TOP-LEFT, TOP-RIGHT, BOTTOM-RIGHT, BOTTOM-LEFT
corners = markerCorner.reshape((4, 2))
(topLeft, topRight, bottomRight, bottomLeft) = corners
# 将每个 (x, y) 坐标对转换为整数
topRight = (int(topRight[0]), int(topRight[1]))
bottomRight = (int(bottomRight[0]), int(bottomRight[1]))
bottomLeft = (int(bottomLeft[0]), int(bottomLeft[1]))
topLeft = (int(topLeft[0]), int(topLeft[1]))
# 绘制ArUCo检测的边界框
cv2.line(image, topLeft, topRight, (0, 255, 0), 2)
cv2.line(image, topRight, bottomRight, (0, 255, 0), 2)
cv2.line(image, bottomRight, bottomLeft, (0, 255, 0), 2)
cv2.line(image, bottomLeft, topLeft, (0, 255, 0), 2)
# 计算并绘制 ArUCo 标记的中心 (x, y) 坐标
cX = int((topLeft[0] + bottomRight[0]) / 2.0)
cY = int((topLeft[1] + bottomRight[1]) / 2.0)
cv2.circle(image, (cX, cY), 4, (0, 0, 255), -1)
# Get marker type name
markerType = "{} -> {}".format(markerID, arucoName)
# 获取标记类型名称
cv2.putText(image, str(markerType), (topLeft[0], topLeft[1] - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
(0, 255, 0), 2)
print("[INFO] ArUco marker ID: {}".format(markerID))
# 显示输出图像
cv2.imshow("Image", image)
cv2.waitKey(0)
在本教程中,您学习了如何自动确定 ArUco 标记类型,即使您不知道最初使用的是什么 ArUco 字典!
我们的方法有点小技巧,因为它要求我们彻底遍历所有可能的 ArUco 词典,然后尝试检测输入图像中的特定 ArUco 词典。
https://www.pyimagesearch.com/2020/12/28/determining-aruco-marker-type-with-opencv-and-python/