OpenCV C++提取轮廓所有子轮廓失败:仅获取到一个子轮廓
问题分析与修复方案
你的代码只提取到一个子轮廓,核心问题出在子轮廓的遍历逻辑错误,同时存在变量未初始化的问题,以下是具体问题和修复后的代码:
关键问题点
- 子轮廓遍历逻辑错误:你原代码的
j循环完全无效,且仅获取了大轮廓的第一个子轮廓(hierarchy2[i][2]),没有遍历所有兄弟子轮廓。OpenCV的RETR_TREE模式下,hierarchy数组的每个元素格式为[Next, Previous, First Child, Parent],要遍历所有子轮廓需要从第一个子轮廓开始,通过Next(索引0)依次获取兄弟子轮廓。 - 变量未初始化:
rect_count未赋值就直接使用,会导致计数结果不可控。 - 绘制逻辑重复覆盖:原代码无论有多少子轮廓,只会绘制最后一次赋值的那个,所以最终只显示一个。
修复后的代码
findContours(midImage2, contours2, hierarchy2, RETR_TREE, CHAIN_APPROX_SIMPLE); for (int i = 0; i < contours2.size(); i++) { double areaSize = contourArea(contours2[i]); int rect_count = 0; // 初始化子轮廓计数 Point2f innerRectcornerPoints[4], largeRectCornerPoints[4]; RotatedRect innerRect, largeRect; if (areaSize > 3000) { // 绘制大轮廓的最小外接矩形 largeRect = minAreaRect(contours2[i]); largeRect.points(largeRectCornerPoints); for (int j = 0; j < 4; j++) { line(frame, largeRectCornerPoints[j], largeRectCornerPoints[(j + 1) % 4], Scalar(255, 255, 0), 3, 8); } putText(frame, "largeRect", largeRectCornerPoints[1], 2, 1, Scalar(255, 255, 0)); // 遍历当前大轮廓的所有子轮廓 int childIdx = hierarchy2[i][2]; // 获取第一个子轮廓的索引 while (childIdx != -1) { // 绘制子轮廓的最小外接矩形 innerRect = minAreaRect(contours2[childIdx]); innerRect.points(innerRectcornerPoints); for (int j = 0; j < 4; j++) { line(frame, innerRectcornerPoints[j], innerRectcornerPoints[(j + 1) % 4], Scalar(0, 255, 255), 3, 8); } // 给每个子矩形添加编号,方便区分 putText(frame, "innerRect" + to_string(rect_count + 1), innerRectcornerPoints[2], 2, 1, Scalar(0, 255, 255)); rect_count++; childIdx = hierarchy2[childIdx][0]; // 获取下一个兄弟子轮廓的索引 } } }
修复说明
- 初始化
rect_count,避免未定义行为。 - 通过
childIdx从大轮廓的第一个子轮廓开始,循环遍历所有兄弟子轮廓,直到childIdx == -1(无更多子轮廓)。 - 每个子轮廓单独绘制,不会被覆盖,还通过编号区分不同子矩形。
内容的提问来源于stack exchange,提问作者leo
相关产品推荐
相关产品推荐

