该程序可用于计算 ArUco 字典度量。
要计算考虑翻转标记的指标,请使用 -'r' 标志。
该程序可用于创建和编写自定义 ArUco 词典。
#include <opencv2/objdetect/aruco_detector.hpp> // 包含aruco marker检测相关功能的头文件
#include <iostream> // 包含输入输出流相关功能的头文件
using namespace cv; // 使用命名空间cv,这样我们就可以直接使用OpenCV的函数和类而不需要加cv::前缀
using namespace std; // 使用命名空间std,标准的C++库函数比如std::cout可以直接写成cout
// 下面是静态函数的定义,因为我们不需要实例化对象就可以直接用类名调用它们
//为了确保ArUco标记的独一无二,这个函数计算了一个标记的自身最小汉明距离(即标记的不同旋转形态之间的最小差异度量),这有助于保证即使在不同的旋转下,标记也能被准确地检测和识别。
static int _getSelfDistance(const Mat &marker) {
// 计算单个marker自身的汉明距离(marker之间的差异程度)
Mat bytes = aruco::Dictionary::getByteListFromBits(marker); // 将marker的位图转换为字节列表
double minHamming = (double)marker.total() + 1; // 初始化最小汉明距离为marker的总数+1
for(int r = 1; r < 4; r++) { // 对每个旋转的标记进行遍历(共有四种旋转,不包括未旋转)
// 创建两个临时的字节行,用于存储转换后的字节信息
cv::Mat tmp1(1, bytes.cols, CV_8UC1, Scalar::all(0));
cv::Mat tmp2(1, bytes.cols, CV_8UC1, Scalar::all(0));
uchar* rot0 = tmp1.ptr(); // 获取行tmp1的指针
uchar* rot1 = tmp2.ptr(); // 获取行tmp2的指针
for (int i = 0; i < bytes.cols; ++i) { // 将marker的字节旋转r*90度并拷贝到临时字节行中
rot0[i] = bytes.ptr()[i];
rot1[i] = bytes.ptr()[bytes.cols*r + i];
}
// 计算两个临时行的汉明距离
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING);
// 更新最小汉明距离
if (currentHamming < minHamming) minHamming = currentHamming;
}
// 对marker进行水平翻转和垂直翻转后的处理逻辑与上面类似,不再重复。
// 在marker的所有可能的变换后,返回最小的汉明距离
// 检查水平翻转后的情况
Mat b; // 定义一个矩阵用于存储翻转的结果
flip(marker, b, 0); // 对marker进行水平翻转
Mat flipBytes = aruco::Dictionary::getByteListFromBits(b); // 获取翻转后marker的字节列表
// 对翻转后的marker进行相似度检查,逻辑与上面类似
for(int r = 0; r < 4; r++) {
// ... 代码逻辑与上面类似 ...
cv::Mat tmp1(1, flipBytes.cols, CV_8UC1, Scalar::all(0));
cv::Mat tmp2(1, bytes.cols, CV_8UC1, Scalar::all(0));
uchar* rot0 = tmp1.ptr();
uchar* rot1 = tmp2.ptr();
for (int i = 0; i < bytes.cols; ++i) {
rot0[i] = flipBytes.ptr()[i];
rot1[i] = bytes.ptr()[bytes.cols*r + i];
}
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING);
if(currentHamming < minHamming) minHamming = currentHamming;
}
// 检查垂直翻转后的情况
flip(marker, b, 1); // 对marker进行垂直翻转
flipBytes = aruco::Dictionary::getByteListFromBits(b); // 获取翻转后marker的字节列表
// 对垂直翻转后的marker进行相似度检查,逻辑与上面类似
for(int r = 0; r < 4; r++) {
// ... 代码逻辑与上面类似 ...
cv::Mat tmp1(1, flipBytes.cols, CV_8UC1, Scalar::all(0));
cv::Mat tmp2(1, bytes.cols, CV_8UC1, Scalar::all(0));
uchar* rot0 = tmp1.ptr();
uchar* rot1 = tmp2.ptr();
for (int i = 0; i < bytes.cols; ++i) {
rot0[i] = flipBytes.ptr()[i];
rot1[i] = bytes.ptr()[bytes.cols*r + i];
}
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING);
if(currentHamming < minHamming) minHamming = currentHamming;
}
// 返回最小汉明距离的四舍五入结果
return cvRound(minHamming);
}
//计算给定字典中,某个ArUco标记与特定ID的其他标记之间在全部或部分旋转的情况下的最小汉明距离。这个函数可以用于评估字典中标记的独一无二性,以及是否可以准确识别翻转后的标记。
static inline int getFlipDistanceToId(const aruco::Dictionary& dict, InputArray bits, int id, bool allRotations = true) {
/