findContours和RETR_TREE遍历层次结构

时间:2019-03-01 16:38:17

标签: c++ opencv

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

在第一个代码样本中遍历contours时,结果图像中会标记出所需的轮廓。.到目前为止,很好..

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

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

源图像

enter image description here

代码

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

结果图像

enter image description here

层次结构迭代

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]

1 个答案:

答案 0 :(得分:2)

为了后代,让我们为表示层次结构数据的Module 'CpuUsage':invalid option 'dynamic_color' 的索引定义一些符号名称:

  • Vec4i
  • NEXT_SIBLING = 0
  • PREV_SIBLING = 1
  • CHILD_CONTOUR = 2

让我们回想一下,这4个元素中的每个元素都代表轮廓的索引,并且在没有这样的对象时使用PARENT_CONTOUR = 3

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

输出图像

没有子级的顶级轮廓用红色填充。带孩子的顶层轮廓填充为蓝色。第二级轮廓填充为绿色。

Sample output