cvFindContours检索轮廓和内存分配回收问题

时间:2021-10-10 02:35:34

1、cvFindContours函数原型:

int cvFindContours
( CvArr* image,
CvMemStorage* storage,
CvSeq** first_contour,
int header_size = sizeof(CvContour),
int mode = CV_RETR_LIST,
int method = CV_CHAIN_APPROX_SIMPLE,
CvPoint offset = cvPoint(0,0) );

2、返回值:找到轮廓的个数

3、参数如下:
image
8比特单通道的源二值图像。非零像素作为1处理,0像素保存不变。

storage
返回轮廓的容器。

first_contour
输出参数,用于存储指向第一个外接轮廓。

header_size
header序列的尺寸.如果选择method = CV_CHAIN_CODE, 则header_size >= sizeof(CvChain);其他,则header_size >= sizeof(CvContour)。

mode
CV_RETR_EXTERNAL:只检索最外面的轮廓;
CV_RETR_LIST:检索所有的轮廓,并将其放入list中;
CV_RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
CV_RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次。

method
边缘近似方法(除了CV_RETR_RUNS使用内置的近似,其他模式均使用此设定的近似算法)。可取值如下:
CV_CHAIN_CODE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
CV_CHAIN_APPROX_NONE:将所有的连码点,转换成点。
CV_CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:使用the flavors of Teh-Chin chain近似算法的一种。
CV_LINK_RUNS:通过连接水平段的1,使用完全不同的边缘提取算法。使用CV_RETR_LIST检索模式能使用此方法。

offset
偏移量,用于移动所有轮廓点。当轮廓是从图像的ROI提取的,并且需要在整个图像中分析时,这个参数将很有用。

4、应用

CvPoint p1,p2;
CvMemStorage * storage = cvCreateMemStorage(0);
CvSeq * pcontour = 0;
int mode = CV_RETR_CCOMP;

cvFindContours(ImgBW, storage, &pcontour, sizeof(CvContour), mode, CV_CHAIN_APPROX_SIMPLE);
for (; pcontour != 0; pcontour = pcontour -> h_next)
{
CvRect r = ((CvContour *)pcontour)->rect;
p1.x=r.x;
p1.y=r.y;
p2.x=r.x+r.width;
p2.y=r.y+r.height;
holeColor=CV_RGB(0,0,255);
externalColor=CV_RGB(255,0,0);
cvDrawContours(pImg,pcontour,externalColor,holeColor,1,1,8);
cvDrawRect(pImg,p1,p2,CV_RGB(255,0,0),1,8,0);
}

这个例子遍历所有轮廓,利用cvDrawContours绘制轮廓点、并通过cvDrawRect绘制该轮廓的外接矩形。

在使用 cvFindContours之前要定义CvMemStorage 分配内存来存储轮廓点,其中cvCreateMemStorage(0) 参数0为默认值,分配64k内存空间。

注意CvMemStorage为动态结构,如果在回调函数中循环检测轮廓,内存占用会逐渐变大,使用cvClearSeq清空序列并不能解决内存增长的问题,必须使用cvClearMemStorage清空内存

没有使用cvClearMemStorage的情况storage中块的top地址会逐渐增大,如图:
cvFindContours检索轮廓和内存分配回收问题
使用cvClearMemStorage后storage中块的top地址和bottom地址相同,如图:
cvFindContours检索轮廓和内存分配回收问题