轮廓(查找和绘制轮廓、轮廓的表达与组织、轮廓的特性)

目录

    • 1、轮廓的定义
    • 2、如何在图像中找到轮廓
      • opencv自带的查找轮廓函数:findContours()
    • 3、轮廓的表达方式
      • 1.顶点的序列
      • 2.Freeman链码
    • 4、轮廓之间的组织方式
    • 5、轮廓的特点(这部分可以展开来详细探讨,这里不做过多解释)
    • 6、轮廓的匹配
    • 7、绘制轮廓drawContours()
    • 8、例子
      • 动态检测图形的轮廓
        • 步骤
        • 理解
        • 演示效果

1、轮廓的定义

轮廓是构成任何一个形状的边界或外形线。

2、如何在图像中找到轮廓

利用OpenCV提供的方法cvFindContours()可以很方便的查找轮廓。cvFindContours()方法从二值图像中寻找轮廓。
因此此方法处理的图像可以是从cvCanny()函数得到的有边缘像素的图像,或者从cvThreshold()及cvAdaptiveThreshold()得到的图像,这时的边缘是正和负区域之间的边界。

opencv自带的查找轮廓函数:findContours()

参数讲解:
参数
参数
参数:
参数

1】检测轮廓
//定义轮廓和层次结构
vector<vector<Point>> contours;			//每个轮廓存储为一个点向量
vector<Vec4i>hierarchy;			//	Vec4i
findContours(srcImage,contours,		//轮廓数组hierarchy,RETR_EXTERNAL,		//获取外轮廓CHAIN_APPROX_NONE			//获取每个轮廓中的每个像素);

3、轮廓的表达方式

1.顶点的序列

序列是内存存储器中可以存储的一种对象。序列是某种结构的链表。序列在内存中被实现为一个双端队列,因此序列可以实习快速的随机访问,以及快速删除顶端的元素,但是从中间删除元素则稍慢些。
用多个顶点(或各点间的线段)来表达轮廓。假设要表达一个从(0,0)到(2,2)的矩形,
(1)如果用点来表示,那么依次存储的可能是:(0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,1);
(2)如果用点间的线段来表达轮廓,那么依次存储的可能是:(0,0),(2,0),(2,2),(0,2)。

2.Freeman链码

Freeman链码需要一个起点,以及从起点出发的一系列位移。每个位移有8个方向,从0~7分别指向从正北开始的8个方向。假设要用Freeman链码表达从(0,0)到(2,2)的矩形,可能的表示方法是:起点(0,0),方向链2,2,4,4,6,6,0,0。

4、轮廓之间的组织方式

在查找到轮廓之后,不同轮廓是怎么组织的呢?根据不同的选择,它们可能是:(1)列表;(2)双层结构;(3)树型结构。
从纵向上来看,列表只有一层,双层结构有一或者两层,树型结构可能有一层或者多层。
如果要遍历所有的轮廓,可以使用递归的方式。

5、轮廓的特点(这部分可以展开来详细探讨,这里不做过多解释)

1.轮廓的多边形逼近
轮廓的多边形逼近指的是:使用多边形来近似表示一个轮廓。
多边形逼近的目的是为了减少轮廓的顶点数目。
多边形逼近的结果依然是一个轮廓,只是这个轮廓相对要粗旷一些。 可以使用方法cvApproxPoly()

2.轮廓的关键点
轮廓的关键点是:轮廓上包含曲线信息比较多的点。关键点是轮廓顶点的子集。
可以使用cvFindDominantPoints函数来获取轮廓上的关键点,该函数返回的结果一个包含 关键点在轮廓顶点中索引 的序列。再次强调:是索引,不是具体的点。如果要得到关键点的具体坐标,可以用索引到轮廓上去找。
3.轮廓的周长和面积
轮廓的周长可以用cvContourPerimeter或者cvArcLength函数来获取。
轮廓的面积可以用cvContourArea函数来获取。

4.轮廓的边界框
有三种常见的边界框:矩形、圆形、椭圆。
(1)矩形:在图像处理系统中提供了一种叫Rectangle的矩形,不过它只能表达边垂直或水平的特例;OpenCv中还有一种叫Box的矩形,它跟数学上的矩形一致,只要4个角是直角即可。
如果要获取轮廓的Rectangle,可以使用cvBoundingRect函数。
如果要获取轮廓的Box,可以使用cvMinAreaRect2函数。
(2)圆形
如果要获取轮廓的圆形边界框,可以使用cvMinEnclosingCircle函数。
(3)椭圆
如果要获取轮廓的椭圆边界框,可以使用cvFitEllipse2函数。
5.轮廓的矩
矩是通过对轮廓上所有点进行积分运算(或者认为是求和运算)而得到的一个粗略特征。
1空间矩
空间矩的实质为面积或者质量。可以通过一阶矩计算质心/重心。
公式
重心:重心
2中心矩
中心矩体现的是图像强度的最大和最小方向(中心矩可以构建图像的协方差矩阵),其只具有平移不变性,所以用中心矩做匹配效果不会很好。
中心
3归一化的中心矩
归一化后具有尺度不变性。
距
4Hu矩
12
6.轮廓的轮廓树
轮廓树用来描述某个特定轮廓的内部特征。注意:轮廓树跟轮廓是一一对应的关系;轮廓树不用于描述多个轮廓之间的层次关系。
轮廓树的创建过程:
从一个轮廓创建一个轮廓树是从底端(叶子节点)到顶端(根节点)的。首先搜索三角形突出或者凹陷的形状的周边(轮廓上的每一个点都不是完全和它的相邻点共线的)每个这样的三角形被一条线段代替,这条线段通过连接非相邻点的两点得到;因此实际上三角形或者被削平或者被填满。每个这样的替换都把轮廓的顶点减少,并且给轮廓树创建一个新节点。如果这样的一个三角形的两侧有原始边,那么她就是得到的轮廓树的叶子;如果一侧已是一个三角形,那么它就是那个三角形的父节点。这个过程的迭代最终把物体的外形简称一个四边形,这个四边形也被剖开;得到的两个三角形是根节点的两个子节点。
结果的二分树最终将原始轮廓的形状性比编码。每个节点被它所对应的三角形的信息所注释。
这样建立的轮廓树并不太鲁棒,因为轮廓上小的改变也可能会彻底改变结果的树,同时最初的三角形是任意选取的。为了得到较好的描述需要首先使用函数cvApproxPoly()之后将轮廓排列(运用循环移动)成最初的三角形不怎么收到旋转影响的状态。
可以用函数cvCreateContourTree来构造轮廓树。
7.轮廓的凸包和凸缺陷
这块内容会在后续详细探讨。
8.轮廓的成对几何直方图
成对几何直方图(pairwise geometrical histogram PGH)是链码编码直方图(chain code histogram CCH)的一个扩展或者延伸。CCH是一种直方图,用来统计一个轮廓的Freeman链码编码每一种走法的数字。这种直方图的一个优良性质为当物体旋转45度,那么新直方图是老直方图的循环平移。这样就可以不受旋转影响。
(1)轮廓保存的是一系列的顶点,轮廓是由一系列线段组成的多边形。对于看起来光滑的轮廓(例如圆),只是线段条数比较多,线段长度比较短而已。实际上,电脑中显示的任何曲线都由线段组成。
(2)每两条线段之间都有一定的关系,包括它们(或者它们的延长线)之间的夹角,两条线段的夹角范围是:(0,180)。
(3)每两条线段上的点之间还有距离关系,包括最短(小)距离、最远(大)距离,以及平均距离。最大距离我用了一个偷懒的计算方法,我把轮廓外界矩形的对角线长度看作了最大距离。
(4)成对几何直方图所用的统计数据包括了夹角和距离。

6、轮廓的匹配

1.Hu矩匹配
轮廓的Hu矩对包括缩放、旋转和镜像映射在内的变化具有不变性。cvMatchShapes函数可以很方便的实现对2个轮廓间的匹配。
2.轮廓树匹配
用树的形式比较两个轮廓。cvMatchContourTrees函数实现了轮廓树的对比。
3.成对几何直方图匹配
在得到轮廓的成对几何直方图之后,可以使用直方图对比的方法来进行匹配。

7、绘制轮廓drawContours()

轮廓的绘制比较简单,用上面提到的方法取得轮廓的所有点,然后把这些点连接成一个多边形即可。
使用函数drawContours(),更加方便。
1
2
使用例子:

//【2】绘制轮廓
//遍历所有顶层的轮廓,用不同的颜色绘制出来
int index = 0;
for (; index >= 0; index = hierarchy[index][0])
{Scalar color(rand() & 255,rand() & 255,rand() & 255);		//随机数drawContours(dstImage,		//outputImagecontours, 		//轮廓信息index, 			//当前轮廓的索引值color, 			//轮廓颜色FILLED, 		//绘制在轮廓内部8,				//8连通线型hierarchy);		//轮廓间的层次信息
}

8、例子

动态检测图形的轮廓

步骤

【1】读取原图,转为灰度图并高斯模糊
【2】canny检测图像边缘(滑动条控制阈值)
【3】对canny算子扫描后的图像进行查找轮廓
【4】绘制轮廓

理解

Canny之类的边缘检测算法可以根据像素间的差异检测出轮廓边界的像素,但是它并没有将轮廓作为一个整体。
对canny扫描后的图像查找轮廓是一种较好的选择。

#include <opencv2/opencv.hpp>
#include <iostream>
#include "windows.h"
#include <stdio.h>
#define WINDOW_NAME "【程序窗口】"			//为窗口标题定义的宏using namespace cv;
using namespace std;
//===========================动态检测图形的轮廓====================//=================全局变量声明=================
Mat g_srcImage;
Mat g_grayImage;
int g_nThresh = 80;
int g_nThresh_max = 255;
RNG g_rng(12345);
Mat g_cannyMat_output;
vector<vector<Point>> g_vContours;
vector<Vec4i> g_vHierarchy;//=============全局函数声明===============
void on_ThreshChange(int,void*);
int main()
{// Read image 读取图像SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN);		//字体为绿色//载入原图g_srcImage = imread("D:\\opencv_picture_test\\lena.jpg",1);//Mat srcImage = imread("D:\\opencv_picture_test\\形态学操作\\孔洞.png", 0);	//读取灰度图//转换成灰度并且模糊化降噪cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);blur(g_grayImage, g_grayImage, Size(3, 3));//创建窗口namedWindow("原始图窗口", WINDOW_AUTOSIZE);imshow("原始图窗口", g_srcImage);//创建滑动条并初始化createTrackbar("canny 阈值", "原始图窗口", &g_nThresh,g_nThresh_max, on_ThreshChange);on_ThreshChange(0,0);waitKey(0);return 0;
}
void on_ThreshChange(int, void*)
{//用Canny算子检测边缘Canny(g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh * 2, 3);//寻找轮廓.findContours(g_cannyMat_output, g_vContours, g_vHierarchy,RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//绘出轮廓Mat drawing = Mat::zeros(g_cannyMat_output.size(), CV_8UC3);for (int i = 0; i < g_vContours.size(); i++){Scalar color = Scalar(g_rng.uniform(0, 255),g_rng.uniform(0, 255), g_rng.uniform(0, 255));//任意值drawContours(drawing, g_vContours, i, color, 2, 8, g_vHierarchy,0, Point());}//显示效果图imshow("轮廓图",drawing);
}

演示效果

演示结果

参考链接:
主讲轮廓的特性;
轮廓的矩;
轮廓的矩;
以及《《OpenCV3编程入门》毛星云编著_电子工业出版社》。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/378633.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

01-基本配置与测试

一、开发环境 使用的是Anaconda 3&#xff0c;其中Python版本为3.6.3 首先&#xff0c;在Anaconda下的Scripts文件夹下打开命令框 使用pip install -U selenium安装selenium 打开Jupiter Notebook&#xff0c;输入from selenium import webdriver进行测试 不报错即安装成功 …

Opencv——查找并绘制凸包、凸包与轮廓的关系

定义 给定二维平面上的点集&#xff0c;凸包就是将最外层的点连接起来构成的凸多边型。 理解物体形状或轮廓的一 种比较有用的方法便是计算一个物体的凸包&#xff0c;然后计算其凸缺陷(convexity defects)。 检测凸包 opencv自带函数&#xff1a;convexHull() 参数解释&a…

java接口并发衡量_java 后端设计高并发接口总结

如何设置高并发接口一、并发队列的选择二、请求接口的合理设计三、高并发下的数据安全3.1 超发的原因3.2 悲观锁思路3.3 FIFO队列思路3.4 乐观锁思路一、并发队列的选择Java的并发包提供了三个常用的并发队列实现&#xff0c;分别是&#xff1a;ArrayBlockingQueue、Concurrent…

JAVA 取得当前目录的路径

在写java程序时不可避免要获取文件的路径...总结一下,遗漏的随时补上 1.可以在servlet的init方法里 String path getServletContext().getRealPath("/"); 这将获取web项目的全路径 例如 :E:/eclipseM9/workspace/tree/ tree是我web项目的根目录 2.你也可以随时在任意…

02.1-元素定位(find)

常用的一些方法 一、导包 from selenium import webdriver二、打开火狐&#xff08;空白页&#xff09; b webdriver.Firefox()三、跳转到指定的网站 b.get(https://www.baidu.com/)四、将浏览器页面最大化 b.maximize_window()五、通过F12可查看当前的贴吧为超链接形式 …

快速傅里叶变换(FFT)——按时间抽取DIT的基

目录【1】前言1、DIF计算量2、利用性质改善【2】公式推导1、N 到 2*N/2a、分解原序列b、分解后的DFT变换c、一系列化简操作之后d、蝶形信号流e、计算量总结2、N/2 到 2*N/4a、分解X2(k)序列b、蝶形信号流&#xff08;2列&#xff09;3、N/4 到 2*N/8a、蝶形信号流&#xff08;3…

快速傅里叶变换(FFT)——按频率抽取DIF的基

目录【1】回顾DIT【2】算法原理【3】运算特点【1】回顾DIT https://blog.csdn.net/qq_42604176/article/details/105559756 【2】算法原理 设序列点数&#xff1a;N2^M,M为正整数。将输入序列按照前一半、后一半分开。&#xff08;并非按照奇偶分&#xff09; 由于&#xf…

莫比乌斯函数---C++

【问题描述】 莫比乌斯函数&#xff0c;数论函数&#xff0c;由德国数学家和天文学家莫比乌斯(Mobius&#xff0c;1790-1868)提出。梅滕斯(Mertens)首先使用μ(n)作为莫比乌斯函数的记号。而据说&#xff0c;高斯(Gauss)比莫比乌斯早三十年就曾考虑过这个函数。莫比乌斯函数在数…

Opencv——findContours函数再探(由轮廓联想连通域)

目录关于调参的一些思考分析图像的一些角度面积、周长、矩形度、圆形度、宽长比例1&#xff1a;找出汽车轮毂圆孔&#xff08;从轮廓和连通域两个角度&#xff09;例2&#xff1a;找出芯片中间正方形物体例3&#xff1a;桌面上橘色物体总结关于调参的一些思考 合理的参数设置&…

modelsim 编译 xilinx库

1.为单个工程加入库 在某一个目录建立工程 然后 vlib unisim vcom -work unsim *.vhd 然后就加入了unisim库 如果是windows的话&#xff0c;工程文件mpf应该是记录了这个库的信息&#xff0c;所以重新打开这个工程时&#xff0c;依然有这个库 linux&#xff0c;不用gui界面…

php 载入css就可以显示,如何在进度条加载后显示页面

1.思路&#xff1a;加入很多图片&#xff0c;以延迟加载时间&#xff0c;实现加载完后显示图片。定义一个外层p&#xff0c;覆盖住图片&#xff0c;在内层p中引入加载时显示的图片&#xff0c;让内层p居中在页面上&#xff0c;利用setInterval定时器设置3秒后将外层p隐藏&#…

如何获取轮廓(连通域)的面积、周长、矩形度、圆形度、宽长比、周径比等形状描述符?

博主联系方式&#xff1a; QQ:1540984562 QQ交流群&#xff1a;892023501 群里会有往届的smarters和电赛选手&#xff0c;群里也会不时分享一些有用的资料&#xff0c;有问题可以在群里多问问。 目录前言1、轮廓面积获取函数2、轮廓周长获取函数3、轮廓圆形度计算4、矩形度计算…

01-基础部分

一、tensorflow和opencv测试 import tensorflow as tf import cv2hello tf.constant(hello tensorflow) session tf.Session() print(session.run(hello))print(hello opencv)运行效果如下&#xff1a; 二、基础部分 1、opencv基础 代码三部曲&#xff1a; 1、引入Open…

网络和通信 - Silverlight 中的 HTTP 通信和安全

Silverlight 支持几种使用 HTTP/HTTPS 的方案。虽然可以使用多种方式和技术执行 HTTP 调用&#xff0c;但是下表描述的是针对这些 HTTP 通信方案的建议方法 执行 HTTP 调用的选项 确定应由浏览器还是客户端来执行应用程序的 HTTP 处理后&#xff0c;应在创建任何 Web 请求之前指…

WT2605C高品质音频蓝牙语音芯片:外接功放实现双声道DAC输出的优势

在音频处理领域&#xff0c;双声道DAC输出能够提供更为清晰、逼真的音效&#xff0c;增强用户的听觉体验。针对这一需求&#xff0c;唯创知音的WT2605C高品质音频蓝牙语音芯片&#xff0c;通过外接功放实现双声道DAC输出&#xff0c;展现出独特的应用优势。 一、高品质音频处理…

角点检测(Harris角点检测法)

博主联系方式&#xff1a; QQ:1540984562 QQ交流群&#xff1a;892023501 群里会有往届的smarters和电赛选手&#xff0c;群里也会不时分享一些有用的资料&#xff0c;有问题可以在群里多问问。 目录原理讲解【1】为何选取角点作为特征&#xff1f;【2】角点的定义&#xff1a;…

02-图像的几何变换

一、图片缩放 imageInfo&#xff1a;图片宽、高、通道个数等 缩放&#xff1a; 等比例缩放&#xff1a;宽高比不变 任意比例缩放&#xff1a;图片拉伸、非拉伸 窗体大小 实现步骤&#xff1a; 1&#xff0c;完成图像的加载&#xff0c;拿到图像的数据信息 2&#xff0c;图片的宽…

微机原理——8086中断类型以及中断向量表、中断响应、中断返回

博主联系方式&#xff1a; QQ:1540984562 QQ交流群&#xff1a;892023501 群里会有往届的smarters和电赛选手&#xff0c;群里也会不时分享一些有用的资料&#xff0c;有问题可以在群里多问问。 目录先验知识回顾控制寄存器回顾1、8086中断类型1、外部可屏蔽中断2、外部不可屏蔽…

资料整理-工具篇

* 代码利器 Resharper 作为一个C#er&#xff0c;非常感谢有Resharper这样的代码利器。在VS系列的IDE中&#xff0c;使用Resharper后&#xff0c;你会发现&#xff0c;原来写代码也可以是一种享受&#xff01; 1. 首先&#xff0c;下载Resharper。下载地址&#xff1a;http://ww…

企业级php第三方支付平台,ThinkPHP新版企业级php第三方api第四方支付平台程序源码商业版 带接口文件等 某宝售价3000元...

本帖最后由 商业源码网 于 2017-12-21 11:23 编辑7 h$ . , C u0 R3 R y$ z! ] q( D D$ s( Y源码说明&#xff1a;) G: y; R# G0 0 g N. ; \0 w, A9 {5 # P今天黑锐给大家分享给好东西&#xff01;很不错的支付系统&#xff01;喜欢研究支付接口的朋友别错过&#xff01;ThinkP…