轮廓的查找、表达、绘制、特性及匹配

虽然Canny之类的边缘检测算法可以根据像素间的差异检测出轮廓边界的像素,但是它并没有将轮廓作为一个整体。下一步是要将这些边缘像素组装成轮廓。

轮廓是构成任何一个形状的边界或外形线。直方图对比和模板匹配根据色彩及色彩的分布来进行匹配,以下包括:轮廓的查找、表达方式、组织方式、绘制、特性、匹配。

首先回忆下几个结构体:

首先是图像本身的结构体:typedef struct CvMat{int type; /* CvMat 标识 (CV_MAT_MAGIC_VAL), 元素类型和标记 */int step; /* 以字节为单位的行数据长度*/int* refcount; /* 数据引用计数 */union{uchar* ptr;short* s;int* i;float* fl;double* db;} data;union{int rows;int height;};union{int cols;int width;};这个结构体是最基础的矩阵,而图像本身就是一个复杂的矩阵,所以图像是对这个结构体的继承:typedef struct _IplImage{int nSize; /* IplImage大小 */int ID; /* 版本 (=0)*/int nChannels; /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */int alphaChannel; /* 被OpenCV忽略 */int depth; /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F 可支持 */char colorModel[4]; /* 被OpenCV忽略 */char channelSeq[4]; /* 同上 */int dataOrder; /* 0 – 交叉存取颜色通道, 1 – 分开的颜色通道.cvCreateImage只能创建交叉存取图像 */int origin; /* 0 – 顶—左结构,1 – 底—左结构 (Windows bitmaps 风格) */int align; /* 图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */int width; /* 图像宽像素数 */int height; /* 图像高像素数*/struct _IplROI *roi;/* 图像感兴趣区域. 当该值非空只对该区域进行处理 */struct _IplImage *maskROI; /* 在 OpenCV中必须置NULL */void *imageId; /* 同上*/struct _IplTileInfo *tileInfo; /*同上*/int imageSize; /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/char *imageData; /* 指向排列的图像数据 */int widthStep; /* 排列的图像行大小,以字节为单位 */int BorderMode[4]; /* 边际结束模式, 被OpenCV忽略 */int BorderConst[4]; /* 同上 */char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */}IplImage;值得注意的地方:首先是origin这个,当有些图像复制或者视频播放时候,由于原点坐标位置未定,很容造成图片倒置。这时就得用void cvFlip( const CvArr* src, CvArr* dst=NULL, int flip_mode=0)函数或者直接设定origin来改变坐标原点;widthstep就是CvMat的step;构造方法:IplImage* cvCreateImage( CvSize size, int depth, int channels );直方图结构:typedef struct CvHistogram{int type;CvArr* bins;float thresh[CV_MAX_DIM][2]; /* 对于标准直方图,bins的值有左边界+右边界=2 */float** thresh2; /* 对于非标准直方图 */CvMatND mat; /* embedded matrix header for array histograms */}CvHistogram;

因此,由于直方图的复杂性,得到一个图片的直方图的步骤就不是一个函数完成的:1,分割图片通道2,求出bins数量及范围3,CvHistogram* cvCreateHist( int dims, int* sizes, int type,float** ranges=NULL, int uniform=1 );创建直方图4,void cvCalcHist( IplImage** image, CvHistogram* hist,int accumulate=0, const CvArr* mask=NULL );计算直方图

下面开始轮廓的学习。

查找轮廓 首先是如何在图像中找到轮廓,可以利用OpenCV提供的方法cvFindContours()可以很方便的查找轮廓。

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

既然在查找之前,我们需要将彩色图像转换成灰度图像,然后再将灰度图像转换成二值图像。代码如下所示:

1 CvSeq *contours = 0;2 cvCvtColor(src,dst,CV_BGR2GRAY);//将源图像进行灰度化cvFindContours(dst,f_storage,&contours); //查找轮廓5 cvZero(dst);

轮廓的表达方式 使用上面的代码可以得到图像的默认轮廓,但是轮廓在电脑中是如何表达的呢?在OpenCv中提供了两类表达轮廓的方式:顶点的序列、Freeman链码。

首先介绍下内存存储器的概念,这是OpenCV在创建动态对象时存取内存的技术。

CvMemStorage* cvCreateMemStorage( int block_size=0 );//创建默认值大小的内存空间void cvReleaseMemStorage( CvMemStorage** storage );//释放内存空间void cvClearMemStorage( CvMemStorage* storage );//清空内存块,可以用于重复使用,将内存返还给存储器,而不是返回给系统void *cvMemStorageAlloc(CvMemStorage *storage,size_t size);//开辟内存空间

序列

序列是内存存储器中可以存储的一种对象。序列是某种结构的链表。序列在内存中被实现为一个双端队列,因此序列可以实习快速的随机访问,以及快速删除顶端的元素,但是从中间删除元素则稍慢些。

序列结构:CvSeq可动态增长元素序列(OpenCV_1.0已发生改变,详见cxtypes.h) Growable sequence of elements

你不勇敢,没人替你坚强。

轮廓的查找、表达、绘制、特性及匹配

相关文章:

你感兴趣的文章:

标签云: