如果我只希望层次结构中的第一级(根)和第二级,如何遍历轮廓?
当遍历第一个代码样本中的contours
时,在结果图像中标记了所需的轮廓。
但是在第二个代码示例中,我看不到如何通过hierarchy
遍历第一级和第二级。根轮廓的ID为124
,但看不到如何找到其子级的逻辑。
在底部发布了hierarchy
数组的输出
源图像
码
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(boxes, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
cv::Scalar color = cv::Scalar(0, 255, 0);
int thickness = 2;
cv::Mat test;
cv::cvtColor(boxes, test, cv::COLOR_GRAY2BGR);
// filter contours
for(int idx = 0; idx < contours.size(); idx++){
cv::Rect rect = cv::boundingRect(contours[idx]);
if(rect.width >= horizontal && rect.height >= vertical){
std::cout << idx << std::endl;
cv::rectangle(test, rect, color, thickness);
}
}
结果图片
层次迭代
if(!hierarchy.empty()){
for(int idx = 0; idx >= 0; idx = hierarchy[idx][0]){
cv::Rect rect = cv::boundingRect(contours[idx]);
if(rect.width >= horizontal && rect.height >= vertical){
std::cout << idx << std::endl;
cv::drawContours(mask, contours, idx, cv::Scalar(255, 255, 255));
cv::rectangle(test, rect, color, thickness);
std::cout << "x: " << rect.x << " y: " << rect.y << " w: " << rect.width << " h: " << rect.height << std::endl;
std::cout << "\tnext: " << hierarchy[idx][1] << std::endl;
std::cout << "\tprev: " << hierarchy[idx][2] << std::endl;
std::cout << "\tnested: " << hierarchy[idx][3] << std::endl;
for(int idy = 0; idy >= 0; idy = hierarchy[idy][0]){
std::cout << "\t\tchild: " << hierarchy[idy] << std::endl;
}
}
}
}
输出
124
x: 0 y: 799 w: 2191 h: 827
next: 123
prev: 125
nested: -1
child: [1, -1, -1, -1]
child: [2, 0, -1, -1]
child: [3, 1, -1, -1]
child: [4, 2, -1, -1]
child: [5, 3, -1, -1]
child: [6, 4, -1, -1]
child: [7, 5, -1, -1]
child: [8, 6, -1, -1]
child: [9, 7, -1, -1]
child: [10, 8, -1, -1]
child: [11, 9, -1, -1]
child: [12, 10, -1, -1]
child: [13, 11, -1, -1]
child: [14, 12, -1, -1]
child: [15, 13, -1, -1]
child: [16, 14, -1, -1]
child: [17, 15, -1, -1]
child: [18, 16, -1, -1]
child: [19, 17, -1, -1]
child: [20, 18, -1, -1]
child: [21, 19, -1, -1]
child: [22, 20, -1, -1]
child: [23, 21, -1, -1]
child: [24, 22, -1, -1]
child: [25, 23, -1, -1]
child: [26, 24, -1, -1]
child: [27, 25, -1, -1]
child: [28, 26, -1, -1]
child: [29, 27, -1, -1]
child: [30, 28, -1, -1]
child: [31, 29, -1, -1]
child: [32, 30, -1, -1]
child: [33, 31, -1, -1]
child: [34, 32, -1, -1]
child: [35, 33, -1, -1]
child: [36, 34, -1, -1]
child: [37, 35, -1, -1]
child: [38, 36, -1, -1]
child: [39, 37, -1, -1]
child: [40, 38, -1, -1]
child: [41, 39, -1, -1]
child: [42, 40, -1, -1]
child: [43, 41, -1, -1]
child: [44, 42, -1, -1]
child: [45, 43, -1, -1]
child: [46, 44, -1, -1]
child: [47, 45, -1, -1]
child: [48, 46, -1, -1]
child: [49, 47, -1, -1]
child: [50, 48, -1, -1]
child: [51, 49, -1, -1]
child: [52, 50, -1, -1]
child: [53, 51, -1, -1]
child: [54, 52, -1, -1]
child: [55, 53, -1, -1]
child: [56, 54, -1, -1]
child: [57, 55, -1, -1]
child: [58, 56, -1, -1]
child: [59, 57, -1, -1]
child: [60, 58, -1, -1]
child: [61, 59, -1, -1]
child: [62, 60, -1, -1]
child: [63, 61, -1, -1]
child: [64, 62, -1, -1]
child: [65, 63, -1, -1]
child: [66, 64, -1, -1]
child: [67, 65, -1, -1]
child: [68, 66, -1, -1]
child: [69, 67, -1, -1]
child: [70, 68, -1, -1]
child: [71, 69, -1, -1]
child: [72, 70, -1, -1]
child: [73, 71, -1, -1]
child: [74, 72, -1, -1]
child: [75, 73, -1, -1]
child: [76, 74, -1, -1]
child: [77, 75, -1, -1]
child: [78, 76, -1, -1]
child: [79, 77, -1, -1]
child: [80, 78, -1, -1]
child: [81, 79, -1, -1]
child: [82, 80, -1, -1]
child: [83, 81, -1, -1]
child: [84, 82, -1, -1]
child: [85, 83, -1, -1]
child: [86, 84, -1, -1]
child: [87, 85, -1, -1]
child: [88, 86, -1, -1]
child: [89, 87, -1, -1]
child: [90, 88, -1, -1]
child: [91, 89, -1, -1]
child: [92, 90, -1, -1]
child: [93, 91, -1, -1]
child: [94, 92, -1, -1]
child: [95, 93, -1, -1]
child: [96, 94, -1, -1]
child: [97, 95, -1, -1]
child: [98, 96, -1, -1]
child: [99, 97, -1, -1]
child: [100, 98, -1, -1]
child: [101, 99, -1, -1]
child: [102, 100, -1, -1]
child: [103, 101, -1, -1]
child: [104, 102, -1, -1]
child: [105, 103, -1, -1]
child: [106, 104, -1, -1]
child: [107, 105, -1, -1]
child: [108, 106, -1, -1]
child: [109, 107, -1, -1]
child: [110, 108, -1, -1]
child: [111, 109, -1, -1]
child: [112, 110, -1, -1]
child: [113, 111, -1, -1]
child: [114, 112, -1, -1]
child: [115, 113, -1, -1]
child: [116, 114, -1, -1]
child: [117, 115, -1, -1]
child: [118, 116, -1, -1]
child: [119, 117, -1, -1]
child: [120, 118, -1, -1]
child: [121, 119, -1, -1]
child: [122, 120, -1, -1]
child: [123, 121, -1, -1]
child: [124, 122, -1, -1]
child: [213, 123, 125, -1]
child: [214, 124, -1, -1]
child: [215, 213, -1, -1]
child: [216, 214, -1, -1]
child: [217, 215, -1, -1]
child: [218, 216, -1, -1]
child: [219, 217, -1, -1]
child: [220, 218, -1, -1]
child: [221, 219, -1, -1]
child: [222, 220, -1, -1]
child: [223, 221, -1, -1]
child: [224, 222, -1, -1]
child: [225, 223, -1, -1]
child: [226, 224, -1, -1]
child: [227, 225, -1, -1]
child: [228, 226, -1, -1]
child: [229, 227, -1, -1]
child: [230, 228, -1, -1]
child: [231, 229, -1, -1]
child: [232, 230, -1, -1]
child: [233, 231, -1, -1]
child: [234, 232, -1, -1]
child: [235, 233, -1, -1]
child: [236, 234, -1, -1]
child: [237, 235, -1, -1]
child: [238, 236, -1, -1]
child: [239, 237, -1, -1]
child: [240, 238, -1, -1]
child: [241, 239, -1, -1]
child: [242, 240, -1, -1]
child: [243, 241, -1, -1]
child: [244, 242, -1, -1]
child: [245, 243, -1, -1]
child: [246, 244, -1, -1]
child: [247, 245, -1, -1]
child: [248, 246, -1, -1]
child: [249, 247, -1, -1]
child: [250, 248, -1, -1]
child: [251, 249, -1, -1]
child: [252, 250, -1, -1]
child: [253, 251, -1, -1]
child: [254, 252, -1, -1]
child: [255, 253, -1, -1]
child: [256, 254, -1, -1]
child: [257, 255, -1, -1]
child: [258, 256, -1, -1]
child: [259, 257, -1, -1]
child: [260, 258, -1, -1]
child: [261, 259, -1, -1]
child: [262, 260, -1, -1]
child: [263, 261, -1, -1]
child: [264, 262, -1, -1]
child: [265, 263, -1, -1]
child: [266, 264, -1, -1]
child: [267, 265, -1, -1]
child: [268, 266, -1, -1]
child: [269, 267, -1, -1]
child: [270, 268, -1, -1]
child: [271, 269, -1, -1]
child: [272, 270, -1, -1]
child: [273, 271, -1, -1]
child: [274, 272, -1, -1]
child: [275, 273, -1, -1]
child: [276, 274, -1, -1]
child: [277, 275, -1, -1]
child: [278, 276, -1, -1]
child: [279, 277, -1, -1]
child: [280, 278, -1, -1]
child: [281, 279, -1, -1]
child: [282, 280, -1, -1]
child: [283, 281, -1, -1]
child: [-1, 282, -1, -1]
最佳答案
只是为了后代,让我们为表示层次结构数据的Vec4i
的索引定义一些符号名称:
NEXT_SIBLING = 0
PREV_SIBLING = 1
CHILD_CONTOUR = 2
PARENT_CONTOUR = 3
我们还要回想一下,这4个元素中的每一个都代表轮廓的索引,并且当没有这样的对象时使用
-1
。令
entry
为代表层次结构条目的Vec4i
。然后我们可以进行以下观察:entry[PARENT_CONTOUR] == -1
→此轮廓没有父级-即它是顶级轮廓。 entry[CHILD_CONTOUR] == -1
→该轮廓没有子级。 entry[NEXT_SIBLING] == -1
→此特定父级在此层次结构级别上没有其他轮廓。 在这一点上,策略很简单。
从列表中的第一个轮廓开始(并确认它是顶级轮廓的假设成立)。如果该轮廓具有子轮廓,则处理该子轮廓及其所有同级。对第一个轮廓的所有同级重复上述步骤。
样例代码
#include <opencv2/opencv.hpp>
#define NEXT_SIBLING 0
#define PREV_SIBLING 1
#define CHILD_CONTOUR 2
#define PARENT_CONTOUR 3
int main()
{
cv::Mat boxes(cv::imread("WqP29.png", cv::IMREAD_GRAYSCALE));
cv::Mat output;
cv::cvtColor(boxes, output, cv::COLOR_GRAY2BGR);
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(boxes, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
if (hierarchy.empty()) {
return -1;
}
// Iterate over top-level contours
for (int i(0); i >= 0; i = hierarchy[i][NEXT_SIBLING]) {
// This must be a top-level contour
CV_Assert(hierarchy[i][PARENT_CONTOUR] == -1);
if (hierarchy[i][CHILD_CONTOUR] == -1) {
// This contour has no children, draw it red for demonstration purposes
cv::drawContours(output, contours, i, cv::Scalar(0, 0, 255), -1);
continue;
}
std::cout << "Contour with children: #" << i
<< " r=" << cv::boundingRect(contours[i])
<< " h=" << hierarchy[i]
<< "\n";
// This contour has children, draw it blue for demonstration purposes
cv::drawContours(output, contours, i, cv::Scalar(255, 0, 0), -1);
// Iterate over all direct children
for (int j(hierarchy[i][CHILD_CONTOUR]); j >= 0; j = hierarchy[j][NEXT_SIBLING]) {
std::cout << " * Child contour: #" << j
<< " r=" << cv::boundingRect(contours[j])
<< " h=" << hierarchy[j]
<< "\n";
cv::drawContours(output, contours, j, cv::Scalar(0, 255, 0), -1);
}
}
cv::imwrite("WqP29_out.png", output);
return 0;
}
控制台输出
Contour with children: #124 r=[2190 x 827 from (1, 799)] h=[213, 123, 125, -1]
* Child contour: #125 r=[377 x 99 from (1808, 1521)] h=[127, -1, 126, 124]
* Child contour: #127 r=[377 x 98 from (1808, 1419)] h=[131, 125, 128, 124]
* Child contour: #131 r=[377 x 98 from (1808, 1317)] h=[133, 127, 132, 124]
* Child contour: #133 r=[377 x 98 from (1808, 1214)] h=[135, 131, 134, 124]
* Child contour: #135 r=[607 x 98 from (1197, 1214)] h=[137, 133, 136, 124]
* Child contour: #137 r=[943 x 98 from (250, 1214)] h=[144, 135, 138, 124]
* Child contour: #144 r=[243 x 99 from (3, 1214)] h=[146, 137, 145, 124]
* Child contour: #146 r=[377 x 98 from (1808, 1112)] h=[148, 144, 147, 124]
* Child contour: #148 r=[607 x 98 from (1197, 1112)] h=[150, 146, 149, 124]
* Child contour: #150 r=[943 x 98 from (250, 1112)] h=[156, 148, 151, 124]
* Child contour: #156 r=[243 x 98 from (3, 1112)] h=[158, 150, 157, 124]
* Child contour: #158 r=[377 x 99 from (1808, 1009)] h=[160, 156, 159, 124]
* Child contour: #160 r=[607 x 99 from (1197, 1009)] h=[162, 158, 161, 124]
* Child contour: #162 r=[943 x 99 from (250, 1009)] h=[171, 160, 163, 124]
* Child contour: #171 r=[243 x 99 from (3, 1009)] h=[173, 162, 172, 124]
* Child contour: #173 r=[377 x 98 from (1808, 907)] h=[174, 171, -1, 124]
* Child contour: #174 r=[607 x 98 from (1197, 907)] h=[175, 173, -1, 124]
* Child contour: #175 r=[943 x 98 from (250, 907)] h=[182, 174, 176, 124]
* Child contour: #182 r=[243 x 100 from (3, 907)] h=[183, 175, -1, 124]
* Child contour: #183 r=[377 x 98 from (1808, 805)] h=[187, 182, 184, 124]
* Child contour: #187 r=[607 x 98 from (1197, 805)] h=[199, 183, 188, 124]
* Child contour: #199 r=[943 x 98 from (250, 805)] h=[208, 187, 200, 124]
* Child contour: #208 r=[243 x 98 from (3, 805)] h=[-1, 199, 209, 124]
输出图像
没有子级的顶级轮廓以红色填充。带 child 的顶层轮廓以蓝色填充。第二级轮廓填充为绿色。
关于c++ - findContours和RETR_TREE遍历层次结构,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54948836/