当前位置:网站首页>(十二) findContours函数的hierarchy详解
(十二) findContours函数的hierarchy详解
2022-08-10 19:05:00 【恒友成】
欢迎访问个人网络日志知行空间
1.基本用法
获取对象的轮廓,一般最好先对图像进行灰度化再进行阈值处理,然后用来检测轮廓。
void cv::findContours(
InputOutputArray image,
OutputArrayOfArrays contours,
OutputArray hierarchy,
int mode,
int method,
Point offset = Point()
)
- image: 8位单通道图像
- contours: 检测到的轮廓,
vector<vector<cv::Point>> - hierarchy: 检测到的轮廓之间的嵌套和邻近关系,
vector<cv::Vec4i> - mode: 不同的轮廓检测算法,常用的有
RETR_EXTERNAL/RETR_LIST/RETR_CCOMP/RETR_TREE四种 - method: 轮廓逼近方法,见,可使用更少的点表示轮廓,减少内存占用。
- offset: 轮廓点应该偏移的量,当在
roi上提取轮廓后想还原到原图上时比较有用。
2.轮廓提取模式
第四个参数mode,可以选择不同的轮廓提取算法,常用的有RETR_EXTERNAL/RETR_LIST/RETR_CCOMP/RETR_TREE四种。下面分别进行介绍。在findContours函数中,其第3个参数hierarchy表示的轮廓之间的层级关系,对于不同mode的轮廓提取算法,其返回的值是不同的。如下图【来自于OpenCV Doc】:

图中不同的轮廓有层级嵌入关系,我们将外部的轮廓称为父,内部的轮廓称为子,hierarchy就是表示轮廓的父子和邻近关系的矩阵。上图中有0/1/2/3/4/5/2a/3a 8 个轮廓,其中0,1,2是最外侧的轮廓,可记为它们在层级0hierarchy-0。而2a是轮廓2的子轮廓,记为其在层级1hierarchy 1。同样轮廓3是轮廓2a的子轮廓,记为其在层级2hierarchy 2。同样轮廓3a是轮廓3的子轮廓,记为其在层级3hierarchy 3。4/5是3a的子轮廓,其构成层级4hierarchy 4。 属于每个层的轮廓都有其自己的信息,如它的子轮廓是什么,父轮廓是什么,OpenCV通过一个四个元素的数组来表示每个轮廓与其他轮廓的关系,这个四维数组中的值分别表示**[Next, Previous, First_Child, Parent], Next表示属于同一个层级hierarchy的下一个轮廓,以上图轮廓0为例,0,1,2属于同个层级hierarchy-0的轮廓,因此0的Next是1,1的Next是2。同一个层级中轮廓2已经是最后一个了,因此其Next是-1。同样对于上图的轮廓4,与其同属于层级4hierarchy-4的轮廓是5,因此4的Next=5,而5的Next=-1。Previous表示同一层级中之前的的那个轮廓**,如上图,1的Previous=0, 2的Previous=1,0的Previous=-1。First_Child表示当前轮廓的第一个子轮廓,如上图,0的First_Child=-1,2的First_Child=2a,3a的First_Child=4。Parent表示当前轮廓的父轮廓,如上图,4和5的父轮廓都是3a,3a的父轮廓是3,3的父轮廓是2a,2的Parent=-1。
findContours方法中的mode参数会返回不同的hierarchy信息,因为有些算法会找出轮廓间的嵌套和邻近关系,有些则只是把轮廓找出来而不会解析轮廓之间的信息。
2.1 RETR_LIST
RETR_LIST算法只会返回轮廓信息,而没有轮廓间的嵌套信息。因此,所有的轮廓都属于同个层级hierarchy没有父子关系, hierarchy返回值中只有Next和Previous,Parent和First_Child都为-1。四维数组的第3和第4个元素都是-1。如上图运行findContours后的输出:
findContours(image, contours, hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);
>>> hierarchy
[1, -1, -1, -1]
[2, 0, -1, -1]
[3, 1, -1, -1]
[4, 2, -1, -1]
[5, 3, -1, -1]
[6, 4, -1, -1]
[7, 5, -1, -1]
[-1, 6, -1, -1]
这里的0/1/2/3/4/5/6/7对应的是轮廓在contours中的下标。
2.2 RETR_EXTERNAL
RETR_EXTERNAL算法,只会返回最外侧的轮廓信息,所有的子轮廓都不会返回,如上图,使用RETR_EXTERNAL算法将只会返回hierarchy-0层级0的3个轮廓。当然hierarchy中也只有3个轮廓之间的邻近信息,Parent和First_Child依然都为-1。

findContours(image, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
[1, -1, -1, -1]
[2, 0, -1, -1]
[-1, 1, -1, -1]
2.3 RETR_CCOMP
RETR_CCOMP算法会找到图中所有的轮廓,但只会将轮廓组织成两层hierarchy=2。物体的外轮廓属于hierarchy-0,内轮廓属于hierarchy-1,如上图0/1/2/3/4/5都属于hierarchy-0,而2a/3a属于hierarchy-1。
findContours(image, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);
[1, -1, -1, -1]
[2, 0, -1, -1]
[4, 1, 3, -1]
[-1, -1, -1, 2]
[6, 2, 5, -1]
[-1, -1, -1, 4]
[7, 4, -1, -1]
[-1, 6, -1, -1]
值得注意的是对于轮廓2a和3a,其hierarchy分别是[-1, -1, -1, 2]和[-1, -1, -1, 4]。这是因为2a和3a虽然属于hierarchy-1,但中间还隔着轮廓3,因此2a和3a之间没有邻近关系。
再来看个例子,如下图:【来自于OpenCV Doc】

轮廓0是外轮廓,1和2分别是轮廓0所围成物体的内轮廓,4属于内轮廓,3属于外轮廓,6属于内轮廓,5属于外轮廓,7和8也都属于外轮廓。对于轮廓0其属于hierarchy-1,两个内轮廓1和2属于hierarchy-2。故对于轮廓0,其Next=3,同个层级hierarchy level的下一个,previous=-1,‵First-Child=1,故轮廓0的hierarchy=[3,-1, 1, -1]`。
轮廓1属于层级2,hierarchy-2,其同一层级的下一个(与1在同个父外轮廓中)轮廓是2,其他均为-1,因此轮廓1的hierarchy=[2, -1, -1, 0]。
轮廓2属于层级2,hierarchy-2,其前一个轮廓是同个父外轮廓下的1,其余为-1,因此轮廓2的hierarchy=[-1, 1, -1, 0]。
轮廓3在hierarchy-1中的Next=5,Previous=0,First-Child=4,Parent=-1。
>>> hierarchy
array([[[ 3, -1, 1, -1],
[ 2, -1, -1, 0],
[-1, 1, -1, 0],
[ 5, 0, 4, -1],
[-1, -1, -1, 3],
[ 7, 3, 6, -1],
[-1, -1, -1, 5],
[ 8, 5, -1, -1],
[-1, 7, -1, -1]]])
2.4 RETR_TREE
RETR_TREE算法提取所有的轮廓,并返回所有轮廓之间的嵌套关系。如上图,使用RETR_TREE得到的轮廓hierarchy之间的关系为:【来自于OpenCV Doc】括号中的绿色字表示轮廓所属的层级hierarchy。

以轮廓0为例,其属于hierarchy-0,‵Next=7, Previous=-1, First_Child=1, Parent=-1`。
>>> hierarchy
array([[[ 7, -1, 1, -1],
[-1, -1, 2, 0],
[-1, -1, 3, 1],
[-1, -1, 4, 2],
[-1, -1, 5, 3],
[ 6, -1, -1, 4],
[-1, 5, -1, 4],
[ 8, 0, -1, -1],
[-1, 7, -1, -1]]])

findContours(image, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);
[3, -1, 1, -1]
[2, -1, -1, 0]
[-1, 1, -1, 0]
[5, 0, 4, -1]
[-1, -1, -1, 3]
[6, 3, -1, -1]
[-1, 5, -1, -1]
3.测试代码
#include <opencv2/opencv.hpp>
#include <common.h>
using namespace std;
int main(int argc, char **argv)
{
cv::RNG rng(12345);
cout << "Usage: " << argv[0] << "\n";
cv::String img_dir = "/images/OpenCV/2findContours/hole-hierarchy.png";
cv::Mat image = cv::imread(img_dir, cv::IMREAD_GRAYSCALE);
vector<cv::Vec4i> hierarchy;
vector<vector<cv::Point> > contours;
findContours(image, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);
cv::cvtColor(image, image, cv::COLOR_GRAY2BGR);
std::cout << "Contours Size: " << contours.size() << std::endl;
for(size_t i=0; i<contours.size(); i++)
{
cv::Scalar clr = cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
cv::drawContours(image, contours, i, clr, 3);
}
for(auto &v : hierarchy)
{
std::cout << v << std::endl;
}
std::cout << image.channels() << std::endl;
cv::imwrite("contours.png", image);
cv::imshow("Img", image);
cv::waitKey(0);
return 0;
}s
参考资料
欢迎访问个人网络日志知行空间
边栏推荐
- 【SemiDrive源码分析】【MailBox核间通信】52 - DCF Notify 实现原理分析 及 代码实战
- 905. 区间选点(贪心)
- 这7个自动化办公模版 教你玩转表格数据自动化
- 【greenDao】Cannot access ‘org.greenrobot.greendao.AbstractDaoSession‘ which is a supertype of
- LeetCode·283.移除零·双指针
- FPGA:从0开始(安装开发环境)加破解
- 多种深度模型实现手写字母MNIST的识别(CNN,RNN,DNN,逻辑回归,CRNN,LSTM/Bi-LSTM,GRU/Bi-GRU)
- Solution for thread not gc-safe when Rider debugs ASP.NET Core
- 产品思维训练 | 新用户从注册到绑卡流失率很高是什么原因?
- 从 GAN 到 WGAN
猜你喜欢

越折腾越好用的 3 款开源 APP

弘玑Cyclone与风变科技达成战略合作:优势互补聚焦数字化人才培养

Redis persistence mechanism

【Knowledge Sharing】What is SEI in the field of audio and video development?

“2022零信任神兽方阵”启动调研,欢迎各单位填报信息

The servlet mapping path matching resolution

子域名收集&Google搜索引擎语法

FPGA:从0开始(安装开发环境)加破解

什么是企业知识库?有什么作用?如何搭建?

云渲染的应用正在扩大,越来越多的行业需要可视化服务
随机推荐
Today's bug, click on the bug that the Windows dynamic wallpaper disappears in the win10 taskbar, and no solution has been found yet.
什么是企业知识库?有什么作用?如何搭建?
We used 48h to co-create a web game: Dice Crush, to participate in international competitions
西安凯新(CAS:2408831-65-0)Biotin-PEG4-Acrylamide 特性
端口探测详解
【无标题】基于Huffman和LZ77的GZIP压缩
laya打包发布apk
2022 Hangdian Multi-School Seven Black Magic (Sign-in)
Hangdian Multi-School Seven 1003-Counting Stickmen (Combination Mathematics)
转铁蛋白修饰蛇床子素长循环脂质体/负载三七皂苷R1的PEG-PLGA纳米粒([email protected] NPs)
不止跑路,拯救误操作rm -rf /*的小伙儿
今日份bug,点击win10任务栏视窗动态壁纸消失的bug,暂未发现解决方法。
DefaultSelectStrategy NIOEventLoop执行策略
FEMRL: A Framework for Large-Scale Privacy-Preserving Linkage of Patients’ Electronic Health Rec论文总结
803. 区间合并(贪心)左端点、右端点排序均可
代理模式的使用总结
状态压缩dp蒙德里安的梦想
WCF and TCP message communication practice, c # 】 【 realize group chat function
FPGA:基础入门按键控制蜂鸣器
主动信息收集