AprilRobotics/apriltag
GitHub: AprilRobotics/apriltag
一个用 C 语言编写的高性能视觉基准标签检测库,为机器人研究提供快速标签检测和三维位姿估计能力。
Stars: 2338 | Forks: 661
# AprilTag 3
AprilTag 是机器人研究中非常流行的一种视觉基准系统。此代码库包含最新版本的 AprilTag,即 AprilTag 3。它包含了一个速度更快(>2 倍)的检测器,提高了对小型标签的检测率,支持灵活的标签布局,并具备位姿估计功能。AprilTag 由一个小型且依赖极少的 C 库组成。
你可以在[这里](https://github.com/AprilRobotics/apriltag-imgs)找到预生成布局的标签图像。我们推荐使用 tagStandard41h12 布局。
# 目录
- [论文](#papers)
- [安装](#install)
- [用法](#usage)
- [选择标签家族](#choosing-a-tag-family)
- [检测器入门](#getting-started-with-the-detector)
- [Python](#python)
- [C](#c)
- [Matlab](#matlab)
- [Julia](#julia)
- [从 AprilTag 2 升级](#upgrading-from-aprilTag-2)
- [OpenCV 集成](#opencv-integration)
- [调整检测器参数](#tuning-the-detector-parameters)
- [提升速度。](#increasing-speed)
- [增加检测距离。](#increasing-detection-distance)
- [位姿估计。](#pose-estimation)
- [调试](#debugging)
- [灵活布局](#flexible-layouts)
- [支持](#support)
# 论文
AprilTag 是以下论文的主题。
[AprilTag:一个稳健且灵活的视觉基准系统](https://april.eecs.umich.edu/papers/details.php?name=olson2011tags)
[AprilTag 2:高效且稳健的基准检测](https://april.eecs.umich.edu/papers/details.php?name=wang2016iros)
[基准标签的灵活布局](https://april.eecs.umich.edu/papers/details.php?name=krogius2019iros)
# 安装
官方仅支持 Linux 操作系统,不过用户在 Windows 上安装也有成功的案例。
默认安装会将头文件放置在 /usr/local/include 中,将共享库放置在 /usr/local/lib 中。它还会将 pkg-config 脚本安装到 /usr/local/lib/pkgconfig 中,并且如果安装了 python3,还会安装一个 python 包装器。
```
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --target install
```
默认情况下将构建共享(\*.so)库。如果你需要静态(\*.a)库,请将 `BUILD_SHARED_LIBS` 设置为 `OFF`:
```
cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF
cmake --build build --target install
```
如果你安装了 Ninja(`sudo apt install ninja-build`),你可以使用:
```
cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Release
cmake --build build --target install
```
通过 ninja 构建脚本来生成和编译。它将比使用 cmake 默认的 Makefile 生成器快得多。
如果你只想在本地使用而不进行全局安装,则可以省略 `--target install`。
# 用法
## 选择标签家族
对于绝大多数应用来说,tagStandard41h12 家族将是正确的选择。你可以在 [apriltag-imgs 代码库](https://github.com/AprilRobotics/apriltag-imgs)中找到这些标签的图像。在你最喜欢的编辑器中放大这些图像并将它们打印出来。
关于何时选择其他标签家族的一些经验法则:
1. 如果你需要更多的标签,请使用 tagStandard52h13
2. 如果你需要最大化小型圆形物体上的空间利用率,请使用 tagCircle49h12(或 tagCircle21h7)。
3. 如果你想制作一个递归标签,请使用 tagCustom48h12。
4. 如果你需要 ArUco 支持,请使用原生的 ArUco 家族(例如 `tagAruco4x4_50`、`tagAruco5x5_100`、`tagAruco6x6_250`、`tagAruco7x7_1000` 等)。这些现在已经完全集成。
如果这些都不符合你的需求,请在[这里](https://github.com/AprilRobotics/apriltag-generation)生成你自己的自定义标签家族。
## 检测器入门
### Python
```
import cv2
import numpy as np
from apriltag import apriltag
imagepath = 'test.jpg'
image = cv2.imread(imagepath, cv2.IMREAD_GRAYSCALE)
detector = apriltag("tagStandard41h12")
detections = detector.detect(image)
```
或者,你可以使用由 [duckietown](https://github.com/duckietown/lib-dt-apriltags) 创建的 AprilTag python 绑定。
### C
```
image_u8_t* im = image_u8_create_from_pnm("test.pnm");
if (im == NULL) {
fprintf(stderr, "Failed to load pnm image.\n");
exit(1);
}
apriltag_detector_t *td = apriltag_detector_create();
apriltag_family_t *tf = tagStandard41h12_create();
apriltag_detector_add_family(td, tf);
zarray_t *detections = apriltag_detector_detect(td, im);
for (int i = 0; i < zarray_size(detections); i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
// Do stuff with detections here.
}
// Cleanup.
apriltag_detections_destroy(detections);
tagStandard41h12_destroy(tf);
apriltag_detector_destroy(td);
```
### Matlab
由第三方提供,见[此处](https://github.com/alddiaz/MATLAB_AprilTag3)。
### Julia
由第三方提供,见[此处](https://github.com/JuliaRobotics/AprilTags.jl)
## 从 AprilTag 2 升级
对于大多数用例来说,这应该是一个直接替换的过程。
* refine_decode、refine_pose 和 black_border 选项已被移除。
* 如果你生成了自己的家族,你将需要为这些家族重新生成 C 代码。不过,Java 代码不需要重新生成,因此这应该会快速且简单。
## OpenCV 集成
请注意,此库没有外部依赖项。大多数应用程序
至少需要一种获取图像的方法。
有关在 C++ 中结合 OpenCV 使用 AprilTag 的示例,请参见 example/opencv_demo.cc。
构建完代码库后,你可以使用以下命令运行示例 opencv 应用程序:
```
$ ./build/opencv_demo
```
cv::Mat 对象中的图像数据可以直接传递给 AprilTag,而无需创建
深拷贝。只需为 cv::Mat 数据缓冲区创建一个 image_u8_t 头即可:
```
cv::Mat img;
image_u8_t img_header = { .width = img.cols,
.height = img.rows,
.stride = img.cols,
.buf = img.data
};
```
## 调整检测器参数
### 提升速度。
增加 quad_decimate 参数将提升检测器的速度,但代价是检测距离变短。如果你有多余的 CPU 核心来处理此问题,则可以增加 nthreads。如果你的图像有少许噪点,增加 quad_sigma 参数可以提升速度。
### 增加检测距离。
首先选择一张示例图像,并在 debug=1 的情况下运行检测器以生成调试图像。这些图像展示了检测器在检测流水线中每个步骤的输出。
如果你的标签边界没有被检测为四边形,请降低 quad_decimate(如有必要可降至 1)。
如果标签边界已被检测到,则可以尝试更改 decode_sharpening。
## 位姿估计。
我们提供了一种计算标签位姿的方法如下(或者,使用 OpenCv 的 Pnp 求解器并配合 SOLVEPNP_IPPE_SQUARE)。你需要包含 apriltag_pose.h 头文件,然后按如下方式调用 estimate_tag_pose 函数:
```
// First create an apriltag_detection_info_t struct using your known parameters.
apriltag_detection_info_t info;
info.det = det;
info.tagsize = tagsize;
info.fx = fx;
info.fy = fy;
info.cx = cx;
info.cy = cy;
// Then call estimate_tag_pose.
apriltag_pose_t pose;
double err = estimate_tag_pose(&info, &pose);
// Do something with pose.
...
```
其参数如下:
* `det`:标签检测结构体(april_detection_t)。
* `tagsize`:以米为单位的标签大小。每种标签设计都有一个黑色边界和一个白色边界,但有些设计是白色边界在内侧,有些是黑色边界在内侧。因此,标签大小是从两个边界相交处开始测量的,示例请参见下图。
* `fx`、`fy`:相机的焦距(以像素为单位)。对于大多数相机,`fx` 和 `fy` 将相等或几乎相等。
* `cx`、`cy`:相机的焦点中心(以像素为单位)。对于大多数相机,这将大致与图像中心相同。
注意:标签大小不应从标签外侧测量。标签大小的定义是检测角点之间的距离,或者说是白色边界和黑色边界之间边缘的长度。下面的插图中,对于 48h12Custom 标签家族的一个标签,红色的 X 标出了检测角点,红色箭头标出了标签大小。

### 坐标系
该坐标系的原点位于相机中心。Z 轴从相机中心指向镜头外部。X 轴在相机拍摄的图像中指向右侧,Y 轴指向下方。标签的坐标系以标签的中心为中心。从观察者的角度来看,X 轴指向右侧,Y 轴指向下方,Z 轴指向标签内部。
# 实用工具函数
AprilTag 3 现在包含了用于深拷贝结构体的辅助函数,这对于多线程应用程序或你需要将检测结果存储到超出检测器生命周期时非常重要。
* `apriltag_detector_copy(td)`:创建检测器配置的克隆。
* `apriltag_detections_copy(detections)`:返回一个新的 `zarray_t`,其中包含所有 `apriltag_detection_t` 对象的深拷贝。
* `apriltag_detection_copy(src, dst)`:将单个检测结果深拷贝到现有的结构体中。
# 调试
你可以通过设置 `ASAN` 选项,为 Debug 构建启用 [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html) 来调试内存问题:
```
cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Debug -DASAN=ON
cmake --build build
```
大多数情况下,你可以像往常一样运行你的可执行文件并检查 sanitizer 的输出。如果你收到类似 `ASan runtime does not come first in initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.` 的消息,则必须像这样预加载对应的 `libasan.so.5`:
```
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.5 ./build/opencv_demo
```
# 灵活布局
除了 AprilTag 2 支持的经典布局外,AprilTag 3 还支持各种可能的标签布局。标签的数据位现在可以延伸到标签边界之外,并且还可以定义在标签边界内部有“孔洞”(没有数据位)的布局。在此代码库中,我们包含了:
* 两种新标准布局的家族。此布局在标签边界外部添加了一层数据位,提高了数据密度和可能的标签数量,代价是检测距离略有缩短。
* 两种圆形标签家族。
* 一种中间有孔洞的家族。例如,这可以用于无人机应用,通过将不同大小的标签彼此放置在内部,从而允许在很宽的距离范围内进行检测。
你可以使用我们的另一个代码库 [AprilTag-Generation](https://github.com/AprilRobotics/apriltag-generation) 来生成你自己的标签家族。
# 支持
如有任何问题,请在此 GitHub 上创建 issue,而不是发送私信。这样其他有相同问题的人就能找到你的答案。
标签:Bash脚本, C/C++, OpenCV, 事务性I/O, 位姿估计, 客户端加密, 机器人学, 视觉基准, 计算机视觉, 逆向工具