如果我只希望层次结构中的第一级(根)和第二级,如何遍历轮廓?

当遍历第一个代码样本中的contours时,在结果图像中标记了所需的轮廓。

但是在第二个代码示例中,我看不到如何通过hierarchy遍历第一级和第二级。根轮廓的ID为124,但看不到如何找到其子级的逻辑。

在底部发布了hierarchy数组的输出

源图像

c++ - findContours和RETR_TREE遍历层次结构-LMLPHP


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);
    }
}

结果图片

c&#43;&#43; - findContours和RETR_TREE遍历层次结构-LMLPHP

层次迭代
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&#43;&#43; - findContours和RETR_TREE遍历层次结构-LMLPHP

    关于c++ - findContours和RETR_TREE遍历层次结构,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54948836/

    10-16 10:56