opencv 之 findcontours() 函数详解

2023-10-09 16:40

本文主要是介绍opencv 之 findcontours() 函数详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

OpenCV中通过使用findContours函数,简单几个的步骤就可以检测出物体的轮廓,很方便。这些准备继续探讨一下

findContours方法中各参数的含义及用法,比如要求只检测最外层轮廓该怎么办?contours里边的数据结构是怎样

的?hierarchy到底是什么鬼?Point()有什么用?


先从findContours函数原型看起:


[cpp]  view plain copy
print ?
  1. findContours( InputOutputArray image, OutputArrayOfArrays contours,  
  2.                               OutputArray hierarchy, int mode,  
  3.                               int method, Point offset=Point());  


第一个参数:image,单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边

                     缘检测算子处理过的二值图像;


第二个参数:contours,定义为vector<vector<Point>> contours”,是一个向量,并且是一个双重向量,向量

           内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。  

           有多少轮廓,向量contours就有多少元素。


第三个参数:hierarchy,定义为“vector<Vec4i> hierarchy”,先来看一下Vec4i的定义:

                           typedef    Vec<int, 4>   Vec4i;                                                                                                                                       

           Vec4i是Vec<int,4>的别名,定义了一个“向量内每一个元素包含了4个int型变量”的向量。

           所以从定义上看,hierarchy也是一个向量,向量内每个元素保存了一个包含4个int整型的数组。

           向量hiararchy内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同。

           hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第

        i个轮廓的一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个

        轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为

        默认值-1。


第四个参数:int型的mode,定义轮廓的检索模式:


           取值一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略


           取值二:CV_RETR_LIST   检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关

                  系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓

                  所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到


           取值三:CV_RETR_CCOMP  检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围

                  内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层


           取值四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内

                   层轮廓还可以继续包含内嵌轮廓。


第五个参数:int型的method,定义轮廓的近似方法:


           取值一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内


           取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours

                   向量内,拐点与拐点之间直线段上的信息点不予保留


           取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近

                   似算法


第六个参数:Point偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加

            上该偏移量并且Point还可以是负值



下边用效果图对比一下findContours函数中各参数取不同值时,向量contours和hierarchy的内容如何变化,有何

异同。


主体程序如下:

[cpp]  view plain copy
print ?
  1. #include "core/core.hpp"    
  2. #include "highgui/highgui.hpp"    
  3. #include "imgproc/imgproc.hpp"    
  4. #include "iostream"  
  5.   
  6. using namespace std;   
  7. using namespace cv;    
  8.   
  9. int main(int argc,char *argv[])    
  10. {  
  11.     Mat imageSource=imread(argv[1],0);  
  12.     imshow("Source Image",imageSource);  
  13.     Mat image;  
  14.     GaussianBlur(imageSource,image,Size(3,3),0);  
  15.     Canny(image,image,100,250);  
  16.     vector<vector<Point>> contours;  
  17.     vector<Vec4i> hierarchy;  
  18.     findContours(image,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());  
  19.     Mat imageContours=Mat::zeros(image.size(),CV_8UC1);  
  20.     Mat Contours=Mat::zeros(image.size(),CV_8UC1);  //绘制  
  21.     for(int i=0;i<contours.size();i++)  
  22.     {  
  23.         //contours[i]代表的是第i个轮廓,contours[i].size()代表的是第i个轮廓上所有的像素点数  
  24.         for(int j=0;j<contours[i].size();j++)   
  25.         {  
  26.             //绘制出contours向量内所有的像素点  
  27.             Point P=Point(contours[i][j].x,contours[i][j].y);  
  28.             Contours.at<uchar>(P)=255;  
  29.         }  
  30.   
  31.         //输出hierarchy向量内容  
  32.         char ch[256];  
  33.         sprintf(ch,"%d",i);  
  34.         string str=ch;  
  35.         cout<<"向量hierarchy的第" <<str<<" 个元素内容为:"<<endl<<hierarchy[i]<<endl<<endl;  
  36.   
  37.         //绘制轮廓  
  38.         drawContours(imageContours,contours,i,Scalar(255),1,8,hierarchy);  
  39.     }  
  40.     imshow("Contours Image",imageContours); //轮廓  
  41.     imshow("Point of Contours",Contours);   //向量contours内保存的所有轮廓点集  
  42.     waitKey(0);  
  43.     return 0;  
  44. }  

程序中所用原始图像如下:




通过调整第四个参数mode——轮廓的检索模式、第五个参数method——轮廓的近似方式和不同的偏移量Point(),就可以得到以下效果。



一、mode取值“CV_RETR_EXTERNAL”,method取值“CV_CHAIN_APPROX_NONE”,即只检测最外层轮廓,并且保存轮廓上所有点:



轮廓:



只有最外层的轮廓被检测到,内层的轮廓被忽略


contours向量内所有点集:



保存了所有轮廓上的所有点,图像表现跟轮廓一致


hierarchy向量:



重温一下hierarchy向量————向量中每个元素的4个整形分别对应当前轮廓的后一个轮廓、前一个轮廓、父轮廓、内

嵌轮廓的索引编号。


本次参数配置下,hierarchy向量内有3个元素,分别对应于3个轮廓。以第2个轮廓(对应向量内第1个元素)为例,

内容为[2,0,-1,-1], “2”表示当前轮廓的后一个轮廓的编号为2,“0”表示当前轮廓的前一个轮廓编号为0,其后2

个“-1”表示为空,因为只有最外层轮廓这一个等级,所以不存在父轮廓和内嵌轮廓。




二、 mode取值“CV_RETR_LIST”,method取值“CV_CHAIN_APPROX_SIMPLE”,即检测所有轮廓,但各轮廓之间彼此独立,不建立等级关系,并且仅保存轮廓上拐点信息:



检测到的轮廓跟上文“一”中是一致的,不再显示。


contours向量内所有点集:



contours向量中所有的拐点信息得到了保留,但是拐点与拐点之间直线段的部分省略掉了。


hierarchy向量(截取一部分):




本次参数配置下,检测出了较多轮廓。第1、第2个整形值分别指向上一个和下一个轮廓编号,由于本次配置mode取

值“RETR_LIST”,各轮廓间各自独立,不建立等级关系,所以第3、第4个整形参数为空,设为值-1。



三、mode取值“CV_RETR_TREE”,method取值“CV_CHAIN_APPROX_NONE”,即检测所有轮廓,轮廓间建立外层、内层的等级关系,并且保存轮廓上所有点。



contours向量内所有点集:



所有内外层轮廓都被检测到,contours点集组成的图形跟轮廓表现一致。


hierarchy向量(截取一部分)


本次参数配置要求检测所有轮廓,每个轮廓都被划分等级,最外围、第一内围、第二内围等等,所以除第1个最后一

个轮廓外,其他轮廓都具有不为-1的第3、第4个整形参数,分别指向当前轮廓的父轮廓、内嵌轮廓索引编号。


四、Point()偏移量设置


使用三中的参数配置,设置偏移量Point为Point(45,30)。


此时轮廓图像为:



可以看到轮廓图像整体向右下角有一个偏转,偏转量就是设置的(45,30)。

这个偏移量的设置不能过大或过小(负方向上的过小),若图像上任一点加上该偏移量后超出图像边界,程序会内存

溢出报错。

findContours函数的各参数就探讨到此,其他参数配置的情况大同小异。值得关注一下的是绘制轮廓的函数

drawContours中最后一个参数是一个Point类型的offset,这个offset跟findContours函数中的offset含义一致,设置之

后所绘制的轮廓是原始轮廓上所有像素点加上该偏移量offset后的效果。


当所分析图像是另外一个图像的ROI的时候,这个offset偏移量就可以大显身手了。通过加减这个偏移量,就可以把

ROI图像的检测结果投影到原始图像对应位置上

这篇关于opencv 之 findcontours() 函数详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/174165

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

opencv 滚动条

参数介绍:createTrackbar( trackbarname , "hello" , &alpha_slider ,alpha_max ,  on_trackbar )  ;在标签中显示的文字(提示滑动条的用途) TrackbarName创建的滑动条要放置窗体的名字 “hello”滑动条的取值范围从 0 到 alpha_max (最小值只能为 zero).滑动后的值存放在

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor