Reputation: 27689
How to iterate through the contours if I only want first (root) level and second level in the hierarchy?
When iterating through contours
in the first code sample the desired contours are marked in the result image.. So far so good..
But in the second code sample I can't see how to iterate through first and second level via hierarchy
.. The root contour has id 124
but can't see the logic in how to find it's children..
In the bottom the output from hierarchy
array is posted
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]
Upvotes: 2
Views: 1634
Reputation: 19041
Just for posterity, let's define some symbolic names for the indices of the Vec4i
that represents the hierarchy data:
NEXT_SIBLING = 0
PREV_SIBLING = 1
CHILD_CONTOUR = 2
PARENT_CONTOUR = 3
Let's also recall that each of the 4 elements represents the index of the contours, and that -1
is used when there is no such object.
Let entry
be an Vec4i
representing a hierarchy entry. Then we can make following observations:
entry[PARENT_CONTOUR] == -1
→ This contour has no parent -- i.e. it's a top-level contour.entry[CHILD_CONTOUR] == -1
→ This contours has no children.entry[NEXT_SIBLING] == -1
→ There are no more contours at this level of hierarchy for this particular parent.At this point the strategy is simple.
Start with the first contour in the list (and verify that the assumption that it's a top-level contour holds). If this contour has a child contour, process that child contour and all its siblings. Repeat for all the siblings of the first contour.
#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]
Top-level contours without children are filled red. Top-level contours with children are filled blue. Second-level contours are filled green.
Upvotes: 3