opencv学习笔记(三十四)内存和序列

来源:互联网 发布:中韩萨德问题 知乎 编辑:程序博客网 时间:2024/06/05 18:24

1、内存
OpenCV使用内存存储器(memory storage)来统一管理各种动态对象的内存。内存存储器在底层被实现为一个有许多相同大小的内存块组成的双向链表,通过这种结构,OpenCV可以从内存存储器中快速地分配内存或将内存返回给内存存储器。
OpenCV中基于内存存储器实现的函数,经常需要向内存存储器申请内存空间(特别是那些返回动态结果的函数)。
内存存储器可以通过以下四个函数访问:
①:CvMemStorage* cvCreateMemStorage(
int block_size=0
);
②:void cvReleaseMemStorage(
CvMemStorage** storage
);
③:void cvClearMemStorage(
CvMemStorage* storage
);
④:void* cvMemStorageAlloc(
CvMemStorage* storage,
size_t size
);
cvCreateMemStorage用于创建一个内存存储器。参数block_size对应内存存储器中每个内存块的大小。如果block_size为0,则表示内存块采用默认的大小,内存块默认的大小为64 KB。该函数返回一个新创建的内存存储器指针。
cvReleaseMemStorage函数通过storage获取有效的内存存储器的地址,然后释放该内存存储器的所有空间。该函数的用法和OpenCV中释放图像、释放矩阵或者释放其他结构的函数方法类似。
cvClearMemStorage函数则用于清空内存存储器。注意,该函数是仅有的一种释放内存存储器中分配的内存的方法。该函数和通常释放内存的函数区别是,它只是将释放的内存返还给内存存储器,而并不返还给系统。实际上通过cvClearMemStorage,我们可以很方便地重复使用内存存储器中内存空间。注意,删除任何动态对象(如CvSeq,CvSet等)并不会将内存返还到内存存储器(这些结构通过在内部创建一个内存存储器以达到内存重复利用的目的)。
就像malloc ( )可以从堆中分配空间一样,OpenCV中的cvMemStorageAlloc也可以从一个内存存储器中申请空间。只需要向cvMemStorageAlloc指定一个内存存储器和要申请的内存空间大小,然后返回分配内存的地址(返回值和malloc一样为void指针)。

2、序列
序列是内存存储器中可以存储的一种对象。序列是某种结构的链表。OpenCV中,序列可以存储多种不同的结构。你可以将序列想像为许多编程语言中都存在的容器类或者容器类模板(如C++中的vector)。序列在内存被实现为一个双端队列(deque)。因此序列可以实现快速的随机访问,以及快速删除顶端的元素,但是从中间删除元素则稍慢些。
序列中有一些重要的属性(参考例8_1)需要了解。首先,最常用到的是total成员,total存储序列中保存的数据的个数。其次是h_prev,h_next,v_prev,和v_ next,它们是CV_ TREE_ NODE_ FIELDS的一部分,指向其他的序列(分别为上下左右四个方向)。这4个指针不是用来访问序列中的元素,而是用来链接不同的序列。OpenCV中也有其他的结构包含CV_ TREE_ NODE_ FIELDS,我们可以使用包含CV_ TREE_ NODE_ FIELDS的结构构造出更复杂的结构,例如队列、树、图等。仅仅使用变量h_prev和h_next,可实现一个简单的链表。另外两个变量v_prev和v_next可以用于创建那些比较密切的复杂的拓扑结构。通过这四个变量,函数cvFindContours可以将图像中的复杂的轮廓构造为轮廓树。

2.1 创建序列cvCreateSeq()
CvSeq* cvCreateSeq(
int seq_flags,
int header_size,
int elem_size,
CvMemStorage* storage
);
功能:创建一序列
调用这个函数首先需要知道一些信息,这些信息用于控制创建的序列采用何种方式来组织数据。还需要序列的头大小(通常为sizeof(CvSeq))
参数:
seq_flags为序列的符号标志。如果序列不会被传递给任何使用特定序列的函数,那么将它设为0,否则从预定义的序列类型中选择一合适的类型。
Header_size为序列头部的大小;必须大于或等于sizeof(CvSeq)。如果制定了类型或它的扩展名,则此类型必须适合基类的头部大小。
Elem_size为元素的大小,以字节计。这个大小必须与序列类型(由seq_flags指定)相一致。
例如,对于一个点的序列,元素类型 CV_SEQ_ELTYPE_POINT应当被指定,参数elem_size必须等同于sizeof(CvPoint)。Storage为指向前面定义的内存存储器。

2.2 删除序列cvClearSeq()
void cvClearSeq(
CvSeq* seq
);
该函数可以清空序列中的所有元素。不过该函数不会将不再使用的内存返回到内存存储器中,也不会释放给系统。但是当重新向序列中添加元素时,可以重复使用这里面的内存块。如果你想回收序列中的内存块,必须使用CvClearMemStore来实现。

3、直接访问序列中的元素

cvGetSeqElem()
格式:char * cvGetSeqElem(seq,index)
用法:
1. 首先返回的是char类型的指针,当然也可以利用强制类型转换,转换为序列中实际存储的数据类型。
例如:for(int i = 0; itotal;++i)
{
CvPoint p = (CvPoint )cvGetSeqElem(seq,i);
printf(“(%d^d)\n”,p->x,p->y);
}
2.seq是需要检测的序列,而index顾名思义是元素在序列中的索引,即第几个元素。
cvSeqElemIdx()
格式:
int cvSeqElemIdx(
const CvSeq* seq,
const void* element,
CvSeqBlock** block=NULL
);
cvSeqElemIdx函数是一个相对耗时的操作,因此使用的时候需要慎重(所花的时候跟序列的大小成正比)。
功能:返回序列中元素的索引。

4、切片、复制和移动序列中的数据
复制cvCloneSeq()
CvSeq* cvCloneSeq(const CvSeq* seq,CvMemStorage* storage=NULL);
该函数是对cvSeqSlice()进行简单的包装。cvSeqSlice()函数可以为序列中的子序列生成一个新的序列(深度复制);也可以仅仅为子序列创建一个头,和原来序列共用元素空间。
复制cvSeqSlice()
CvSeq* cvSeqSlice(
const CvSeq* seq,
CvMemStorage* storage=NULL,
int copy_data=0
);
cvSeqSlice中有一个CvSlice类型的参数,对应一个切片。我们可以用
cvSlice(a,b)函数,或GV_WHOLE_SEQ宏来定义切片,其中a对应开始,b对应结尾。在创建子序列的时候,只有切片之间的元素才会被复制(b如果为CV_WHOLE_SEQ_END_INDEX则表示序列在a位置后面的所有元素)。参数copy_data表示是否进行深度复制,如果进行深度复制则要复制每个元素。
删除cvSeqRemove()
void cvSeqRemove(CvSeq* seq,int index)
功能:删除序列中的指定位置的元素
插入cvSeqInsert()
char* cvSeqInsert(CvSeq* seq,int before_index,void* element=NULL)
功能:在序列中的指定位置添加元素
详见
http://blog.csdn.net/wqvbjhc/article/details/5497017

0 0
原创粉丝点击