OpenCV —— 轮廓
把检测出的边缘像素组装成轮廓 —— cvFindContours
OpenCV 使用内存存储器来统一管理各种动态对象的内存。内存存储器在底层被实现为一个有许多相同大小的内存块组成的双向链表
内存储器可以通过四个函数访问 : cvCreateMemStorage(创建一个内存存储器,0采用默认大小) cvReleaseMemStorage cvClearMemStorage(和通常释放内存的函数区别 —— 只是将释放的内存返还给内存存储器,而并不返还给系统 —— 可以重复使用内存存储器中的内存空间) cvMemStorageAlloc (从一个内存存储器中申请空间)
序列 —— 序列在内存中被实现为一个双端队列 CvSeq
创建序列 cvCreateSeq() —— 需要:序列头的大小 sizeof(CvSeq),以及序列要存储的元素的大小
删除序列 cvClearSeq —— 清空序列中的所有元素,但不会将不再使用的内存返回到内存储器中,也不会释放给系统,当重新向序列中添加元素时,可以重复使用里面的内存块
直接访问序列中的元素 cvGetSeqElem
检测一个元素是否在序列中 cvSeqElemIdx
深度复制一个序列,并创建一个完全独立的序列结构 cvCloneSeq (是对cvSeqSlice进行简单的包装 ,cvSeqSlice 函数可以为序列中的子序列生成一个新的序列(深度复制),也可以仅仅为子序列创建一个头,和原来序列共用元素空间)
cvSeqSort 可以对序列进行排序 —— 需要自定义比较函数
cvSeqSearch 搜查序列中的元素
cvSeqInvert 将序列进行逆序操作,不改变元素内容,重新组织
cvSeqPartition 根据用户设定的标准,将函数进行拆分
将队列作为栈使用 —— cvSeqPush cvSeqPushFront cvSeqPop cvSeqPopFront cvSeqPushMulti cvSeqPopMulti
序列的读取和写入 CvSeqWriter (由cvStartWriteSeq函数初始化,由cvEndWriteSeq关闭写状态)
—— 写状态被打开的时候可用 CV_WRITE_SEQ , 刚写入的元素对用户来说可能并不能访问,写操作只有在cvEndWriteSeq 函数后,才会真正被写入到序列中(可通过 cvFlushSeqWriter 函数来显式刷新写操作)
序列和数组之间的转换 —— cvCvtSeqToArray cvMakeSeqHeaderForArray
轮廓对应一系列的点,也就是图像中的一条曲线,OpenCV中用序列来存储轮廓信息,序列中的每一个元素是曲线中一点的位置
cvFindContours 从二值图像中寻找轮廓(处理的图像可以是从cvCanny函数得到的有边缘像素的图像,或者是从cvThreshold 及 cvAdaptiveThreshold 得到的图像,这时的边缘是正和负区域之间的边界)
OpenCV 允许得到的轮廓被聚合成一个轮廓树,从而把包含关系编码到树结构中
图像必须是8位单通道图像,并且应该给转换成二值图像 (运行时,这个图像会被直接涂改,记得备份)
CV_RETR_EXTERNAL 只检测出最外的轮廓
CV_RETR_LIST 检测出所有的轮廓并将它们保存在list中
CV_RETR_CCOMP 检测出所有的轮廓并将它们组织成双层结构,顶层边界是所有成分的外界边界,第二层边界是孔的边界
CV_RETR_TREE 检测出所有的轮廓并且重新建立网络的轮廓结构
使用序列表示轮廓
cvStartFindContours —— 每次返回一个轮廓,而不是像cvFindContours那样一次查找所有的轮廓然后统一返回
cvFindNextContour
cvSubstituteContour —— 用于替换scanner指向的轮廓
cvEndFindContour —— 结束轮廓查找,并将scanner设置为结束状态
绘制轮廓 —— cvDrawContours
#include <cv.h>
#include <highgui.h> IplImage *g_img=NULL;
IplImage *g_gray=NULL;
int g_thresh=;
CvMemStorage *g_storage=NULL; void on_trackbar(int)
{
if (g_storage==NULL)
{
g_gray=cvCreateImage(cvGetSize(g_img),,);
g_storage=cvCreateMemStorage();
}else
{
cvClearMemStorage(g_storage);
} CvSeq* contours=;
cvCvtColor(g_img,g_gray,CV_BGR2GRAY);
cvThreshold(g_gray,g_gray,g_thresh,,CV_THRESH_BINARY);
cvFindContours(g_gray,g_storage,&contours);
cvZero(g_gray); if(contours)
{
cvDrawContours(g_gray,contours,cvScalarAll(),cvScalarAll(),);
}
cvShowImage("contours",g_gray); } int main(int argc,char** argv)
{
g_img=cvLoadImage("wukong.jpg",CV_LOAD_IMAGE_COLOR);
cvNamedWindow("contours",);
cvCreateTrackbar("threshold","contours",&g_thresh,,on_trackbar); cvWaitKey();
cvDestroyWindow("contours");
return ;
}
#include "cv.h"
#include "highgui.h"
#include "stdio.h" #define CVX_RED CV_RGB(0xff, 0x00, 0x00)
#define CVX_GREEN CV_RGB(0x00, 0xff, 0x00)
#define CVX_BLUE CV_RGB(0x00, 0x00, 0xff) int main()
{
IplImage* img_8uc1 = NULL;
cvNamedWindow("img_contour", CV_WINDOW_AUTOSIZE); if (img_8uc1 = cvLoadImage("wukong.jpg", ))
//CV_LOAD_IMAGE_GRAYSCALE == 0 加载lena.jpg 灰度图
{
IplImage* img_edge = cvCreateImage(cvGetSize(img_8uc1), , );
IplImage* img_8uc3 = cvCreateImage(cvGetSize(img_8uc1), , ); cvThreshold(img_8uc1, img_edge, , , CV_THRESH_BINARY);
//对灰度图img_8uc1 像进行阈值操作得到二值图像 img_edge CvMemStorage* storage = cvCreateMemStorage();
//创建一个内存储存器 默认为 64K CvSeq* first_contour = NULL;
//创建一个动态序列指针,用其指向第一个存储轮廓单元地址 int NC = cvFindContours(
//cvFindContours从二值图像中检索轮廓,并返回检测到的轮廓的个数
img_edge,
storage, //存储轮廓元素的储存容器
&first_contour, //指向第一个输出轮廓
sizeof (CvContour),
CV_RETR_LIST //提取所有轮廓,并且放置在 list 中
); printf("Total Contours Detected: %d\n", NC); cvCvtColor(img_8uc1, img_8uc3, CV_GRAY2BGR);
//色彩空间转换,将img_8uc1 转换为BGR空间,img_8uc3 为转换后结果 int n = ;
//用于下面轮廓的记数
for (CvSeq* c=first_contour; c!=NULL; c = c->h_next)
{ //从第一个轮廓开始遍历,直到所有轮廓都遍历结束
cvDrawContours(
img_8uc3, //用于绘制轮廓的图像
c, //指向目前轮廓所在地址空间
CVX_RED, //外层轮廓颜色
CVX_BLUE, //内层轮廓颜色
, //等级为0,绘制单独的轮廓
, //轮廓线条粗细
//线段类型为(8邻接)连接线
); printf("Contour #%d\n", n);
//输出第 n 个轮廓 cvShowImage("img_contour", img_8uc3);
//显示目前已绘制的轮廓图像 printf("%d elements:\n", c->total);
//输出构成目前轮廓点的个数 for (int i=; i<c->total; i++)
{
CvPoint* p = CV_GET_SEQ_ELEM(CvPoint, c, i);
//查找轮廓序列中索引所指定的点,并返回指向该点的指针
printf(" (%d, %d)\n", p->x, p->y);
//输出该点坐标
} if (cvWaitKey() == )
//按下ESC 键退出循环
break;
n++;
}
printf("Finished all contours. Hit ESC to finish\n"); while (cvWaitKey() != ); cvReleaseImage(&img_edge);
cvReleaseImage(&img_8uc3);
}
cvDestroyWindow("img_contour");
cvReleaseImage(&img_8uc1);
return ;
}
深入分析轮廓
多边形逼近
cvApproxPoly 处理一个轮廓序列,函数的返回值对应第一个轮廓 (因为cvApproxPoly在返回结果的时候需要创建新的对象,因此需要指定一个内存储器以及头结构大小)
特性概括
长度 cvContourPerimeter 作用于一个轮廓并返回其长度
面积 cvContourArea 计算轮廓面积
边界框
cvBoundingRect —— 返回一个包围轮廓的CvRect
cvMinAreaRect2 —— 返回一个包围轮廓最小的长方形,这个长方形很可能是倾斜的
cvMinEnclosingCircle —— 简单计算完全包围已有轮廓的最小圆
cvFitEllipse2 —— 使用拟合函数返回一个与轮廓最相近似的椭圆
几何
cvMaxRect —— 根据输入的2个矩形计算,它们的最小外包矩形
cvBoxPoints —— 计算CvBox2D 结构表示矩形的4个顶点
cvPointSeqFromMat —— 从mat中初始化序列
cvPointPolygonTest —— 测试一个点是否在多边形的内部
轮廓的匹配
矩 —— 通过对轮廓上所有点进行积分运算而得到的一个粗略特征
cvContoursMoments —— CvMoments 结构体来保存计算的结果
Hu矩 —— 从中心矩中计算而来(为了能够获取代表图像某个特征的矩函数,这些矩函数对某些变化(缩放,旋转和镜像)具有不变性)
使用Hu矩进行匹配 —— cvMatchShapes
等级匹配
使用轮廓树进行匹配 —— 此处轮廓树是用来描述一个特定形状内各部分的等级关系
cvCreateContourTree
cvContourFromContourTree
cvMatchContourTrees
轮廓的凸包和凸缺陷
成对几何直方图 PGH —— 似乎是为了获得旋转不变性
OpenCV —— 轮廓的更多相关文章
- OpenCV 轮廓基本特征
http://blog.csdn.net/tiemaxiaosu/article/details/51360499 OpenCV 轮廓基本特征 2016-05-10 10:26 556人阅读 评论( ...
- OpenCV轮廓vectorvector
OpenCV轮廓vectorvector,vector,vector,vector https://blog.csdn.net/Ahuuua/article/details/80593388 轮廓 ...
- 【转载】openCV轮廓操作
声明:非原创,转载自互联网,有问题联系博主 1.轮廓的提取 从图片中将目标提取出来,常常用到的是提取目标的轮廓. OpenCV里提取目标轮廓的函数是findContours(), 它的输入图像是一幅二 ...
- OpenCV 轮廓检测
使用OpenCV可以对图像的轮廓进行检测.这是之前用过的代码,挺简单的,回顾一下.主要要进行以下2步操作: 1.cvThreshold():对图像进行二值化处理 2.cvFindContours(): ...
- OpenCV轮廓检测,计算物体旋转角度
效果还是有点问题的,希望大家共同探讨一下 // FindRotation-angle.cpp : 定义控制台应用程序的入口点. // // findContours.cpp : 定义控制台应用程序的入 ...
- Opencv轮廓计数(学习)
#include <iostream>#include <opencv2/opencv.hpp>#include <opencv2/xfeatures2d.hpp> ...
- opencv轮廓外接矩形
1.寻找轮廓 api void cv::findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray ...
- opencv——轮廓发现与轮廓(二值图像)分析
引言 二值图像分析最常见的一个主要方式就是轮廓发现与轮廓分析,其中轮廓发现的目的是为轮廓分析做准备,经过轮廓分析我们可以得到轮廓各种有用的属性信息. 这里顺带提下边缘检测,和轮廓提取的区别: 边缘检测 ...
- opencv轮廓处理函数详细
ApproxChains 用多边形曲线逼近 Freeman 链 CvSeq* cvApproxChains( CvSeq* src_seq, CvMemStorage* storage, int me ...
随机推荐
- 关于zxing生成二维码,在微信长按识别不了问题
在做校园学生到校情况签到系统时,我采用了zxing作为二维码生成工具.在测试的时候使用微信打开连接发现.我长按我的二维码之后,总是不会出现以下这种识别二维码的选项. 这就大大的降低了用户的体验,只能大 ...
- 洛谷1440 求m区间的最小值 单调队列
题目描述 一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值.若前面的数不足m项则从第1个数开始,若前面没有数则输出0. 输入格式: 第一行两个数n,m. 第 ...
- bzoj1604 牛的邻居 STL
Description 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l ...
- JDBC连接SQL Server遇到的问题
需要使用到微软的JDBC sql server的驱动类,去官网下载jar包 使用的URL模式:"jdbc:sqlserver:地址:端口//;databaseName=YourDatabas ...
- 学习优化《机器学习与优化》中文PDF+英文PDF
正在学习机器学习中的优化处理,感觉<机器学习与优化>写得还是比较通俗易懂的,第七章特征选择我需要,特征提取:相关系数,相关比,熵和互信息..更高级的应该是文本挖掘的特征提取,比如LDA提取 ...
- 从终端运行python程序
终端窗口运行.py程序 首先你要安装python,命令行输入 python 有python提示符 >>> 出现说明安装成功 程序第一行应该是 #! python3 #! python ...
- C++输入流
输出流基本概念 输出流定义在头文件中.大部分程序都会包含头文件,这个头文件又包含了输入流和输出流头文件.头文件还声明了标准控制台输出流cout. 使用输出流的最简单的方法是使用<<运算 ...
- ArcGIS api for javascript——动态创建图层列表
描述 本例循环地图服务里的所有图层并增加每个图层到一个带checkbox的列表,checkbox能设置图层的显示或隐藏.动态创建列表的优势是所有的图层都会包含在列表中,即使服务器管理员删除或增加了图层 ...
- 利用socket模拟http的混合表单上传(在一个请求中提交表单并上传多个文件)
在非常多企业级应用中,我们都没法直接通过开发语言sdk包封装的http工具来模拟http复合表单(multipart/form-data),特别是在跨语言跨平台的编程过程中.事实上实现方 ...
- CodeForces 550E Brackets in Implications(构造)
[题目链接]:click here~~ [题目大意]给定一个逻辑运算符号a->b:当前仅当a为1b为0值为0,其余为1,构造括号.改变运算优先级使得最后结果为0 [解题思路]: todo~~ / ...