_detectInitialCandidates
是 OpenCV 的 ArUco 模块中一个非常关键的函数,它负责检测图像中的候选 ArUco 标记。该函数的主要目标是:
- 使用多个尺度(scale)对输入图像进行自适应阈值处理;
- 在每个尺度下提取轮廓并筛选出符合要求的四边形角点;
- 将这些候选标记及其对应的轮廓保存到输出参数中。
📌 函数签名
static void _detectInitialCandidates(const Mat &grey,vector<vector<Point2f> > &candidates,vector<vector<Point> > &contours,const DetectorParameters ¶ms)
参数说明:
参数名 | 类型 | 含义 |
---|---|---|
grey | const Mat & | 输入的灰度图像 |
candidates | vector<vector<Point2f> > & | 输出的候选标记角点(4个点组成的矩形) |
contours | vector<vector<Point> > & | 输出的与候选角点对应的完整轮廓信息 |
params | const DetectorParameters & | 检测器参数,控制检测过程的行为 |
🔍 功能详解
1️⃣ 设置自适应阈值窗口大小范围
CV_Assert(params.adaptiveThreshWinSizeMin >= 3 && params.adaptiveThreshWinSizeMax >= 3);
CV_Assert(params.adaptiveThreshWinSizeMax >= params.adaptiveThreshWinSizeMin);
CV_Assert(params.adaptiveThreshWinSizeStep > 0);
确保传入的参数合法:
- 自适应阈值窗口最小和最大尺寸 ≥ 3(OpenCV 要求)
- 步长必须大于 0
2️⃣ 计算要使用的窗口大小数量(即图像金字塔层数)
int nScales = (params.adaptiveThreshWinSizeMax - params.adaptiveThreshWinSizeMin) /params.adaptiveThreshWinSizeStep + 1;
根据设定的最小、最大窗口大小和步长,计算需要尝试多少种不同的窗口大小。
例如:min=20
, max=40
, step=5
→ nScales = 5
3️⃣ 为每种窗口大小准备容器
vector<vector<vector<Point2f> > > candidatesArrays((size_t) nScales);
vector<vector<vector<Point> > > contoursArrays((size_t) nScales);
candidatesArrays[i]
:第 i 个窗口大小下的所有候选标记角点集合。contoursArrays[i]
:对应的所有轮廓。
4️⃣ 多线程处理不同尺度(parallel_for_)
parallel_for_(Range(0, nScales), [&](const Range& range) {for (int i = begin; i < end; i++) {int currScale = params.adaptiveThreshWinSizeMin + i * params.adaptiveThreshWinSizeStep;Mat thresh;_threshold(grey, thresh, currScale, params.adaptiveThreshConstant);_findMarkerContours(thresh, candidatesArrays[i], contoursArrays[i],params.minMarkerPerimeterRate, params.maxMarkerPerimeterRate,params.polygonalApproxAccuracyRate, params.minCornerDistanceRate,params.minSideLengthCanonicalImg);}
});
对于每一个窗口大小:
- 调用
_threshold()
进行自适应阈值处理:- 用于将图像二值化,便于后续提取轮廓。
- 调用
_findMarkerContours()
提取轮廓并筛选出可能的 ArUco 标记角点:- 筛选条件包括:周长范围、是否为凸四边形、角点距离等。
5️⃣ 合并所有尺度的结果
for(int i = 0; i < nScales; i++) {for(unsigned int j = 0; j < candidatesArrays[i].size(); j++) {candidates.push_back(candidatesArrays[i][j]);contours.push_back(contoursArrays[i][j]);}
}
将不同尺度下检测到的候选标记统一合并到最终输出变量 candidates
和 contours
中。
🧠 关键辅助函数说明
✅ _threshold()
static void _threshold(InputArray _in, OutputArray _out, int winSize, double constant)
- 使用
adaptiveThreshold()
对图像进行自适应二值化。 - 确保窗口大小为奇数。
- 采用
ADAPTIVE_THRESH_MEAN_C
方法,反向二值化 (THRESH_BINARY_INV
)。
✅ _findMarkerContours()
static void _findMarkerContours(const Mat &in,vector<vector<Point2f> > &candidates,vector<vector<Point> > &contoursOut,double minPerimeterRate,double maxPerimeterRate,double accuracyRate,double minCornerDistanceRate,int minSize)
这个函数负责从二值图像中提取轮廓,并筛选出可能是 ArUco 标记的四边形。
主要步骤:
-
查找所有轮廓
findContours(in, contours, RETR_LIST, CHAIN_APPROX_NONE);
-
逐个轮廓筛选
- 周长在指定范围内;
- 多边形逼近后为凸四边形;
- 四个角点之间最小距离满足要求;
- 如果启用 ArUco3 功能,则额外判断最小边长。
-
将符合条件的轮廓加入输出
- 角点存入
candidates
- 完整轮廓存入
contoursOut
- 角点存入
📈 总结流程图
_detectInitialCandidates()
│
├─ 设置参数检查
│
├─ 计算使用多少种窗口大小(nScales)
│
├─ 并行遍历每个窗口大小:
│ ├─ 图像二值化(_threshold)
│ └─ 提取并筛选候选标记(_findMarkerContours)
│ ├─ 查找轮廓
│ ├─ 筛选轮廓(凸四边形、周长、角点距离等)
│ └─ 添加进临时容器
│
└─ 合并所有窗口大小下的结果到输出
🧰 参数影响分析(DetectorParameters)
参数名 | 作用 |
---|---|
adaptiveThreshWinSizeMin | 最小阈值窗口大小,决定最小可检测标记大小 |
adaptiveThreshWinSizeMax | 最大阈值窗口大小,决定最大可检测标记大小 |
adaptiveThreshWinSizeStep | 窗口大小递增步长 |
minMarkerPerimeterRate | 最小周长比例(相对于图像宽度/高度) |
maxMarkerPerimeterRate | 最大周长比例 |
polygonalApproxAccuracyRate | 多边形逼近精度比例 |
minCornerDistanceRate | 角点间最小距离比例 |
minSideLengthCanonicalImg | ArUco3 功能中最小边长限制 |
📝 示例说明
假设你有如下代码调用:
Mat grey = ...; // 输入灰度图
vector<vector<Point2f>> candidates;
vector<vector<Point>> contours;
DetectorParameters params = DetectorParameters::create();
_detectInitialCandidates(grey, candidates, contours, params);
这段代码会:
- 使用多个窗口大小对图像进行自适应阈值;
- 提取轮廓并筛选出潜在的 ArUco 标记;
- 返回所有候选标记的四个角点坐标及其原始轮廓。
✅ 总结
特性 | 描述 |
---|---|
功能 | 检测图像中所有可能的 ArUco 标记候选区域 |
输入 | 灰度图像、检测参数 |
输出 | 候选角点列表、对应轮廓列表 |
关键技术 | 自适应阈值、轮廓检测、多边形逼近、几何筛选 |
性能优化 | 使用 parallel_for_ 实现多线程加速 |
后续处理 | 通常交给 _reorderCandidatesCorners() 排序角点顺序 |