一、概述
序列是内存存储器中可以存储的一种对象。序列是某种结构的链表。OpenCV中,序列可以存储多种不同的结构。你可以将序列想象为许多编程语言中都可以存在的容器类或者容器类模板(如C++中的vector)。序列在内存被实现为一个双端对列(deque)。因此序列可以实现快速的随机访问,以及快速删除顶端的元素,但是从中间删除元素则稍慢些。
二、结构体CvSeq定义
typedef struct CvSeqBlock
{
struct CvSeqBlock* prev; /* Previous sequence block. */
struct CvSeqBlock* next; /* Next sequence block. */
int start_index; /* Index of the first element in the block + */
/* sequence->first->start_index. */
int count; /* Number of elements in the block. */
schar* data; /* Pointer to the first element of the block. */
}
CvSeqBlock;
#define CV_TREE_NODE_FIELDS(node_type) \
int flags; /* Miscellaneous flags. */ \
int header_size; /* Size of sequence header. */ \
struct node_type* h_prev; /* Previous sequence. */ \
struct node_type* h_next; /* Next sequence. */ \
struct node_type* v_prev; /* 2nd previous sequence. */ \
struct node_type* v_next /* 2nd next sequence. */
#define CV_SEQUENCE_FIELDS() \
CV_TREE_NODE_FIELDS(CvSeq); \
int total; /* Total number of elements. */ \
int elem_size; /* Size of sequence element in bytes. */ \
schar* block_max; /* Maximal bound of the last block. */ \
schar* ptr; /* Current write pointer. */ \
int delta_elems; /* Grow seq this many at a time. */ \
CvMemStorage* storage; /* Where the seq is stored. */ \
CvSeqBlock* free_blocks; /* Free blocks list. */ \
CvSeqBlock* first; /* Pointer to the first sequence block. */
typedef struct CvSeq
{
CV_SEQUENCE_FIELDS()
}
CvSeq;
三、序列相关函数操作
1、创建序列
CvSeq* cvCreateSeq( int seq_flags, int header_size, int elem_size, CvMemStorage* storage );
seq_flags
序列的符号标志。如果序列不会被传递给任何使用特定序列的函数,那么将它设为 0, 否则从预定义的序列类型中选择一合适的类型。
header_size
序列头部的大小;必须大于或等于 sizeof(CvSeq). 如果制定了类型或它的扩展名,则此类型必须适合基类的头部大小。
elem_size
元素的大小,以字节计。这个大小必须与序列类型相一致。例如,对于一个点的序列,元素类型 CV_SEQ_ELTYPE_POINT 应当被指定, 参数elem_size 必须等同于 sizeof(CvPoint).
函数 cvCreateSeq 创建一序列并且返回指向该序列的指针。函数在存储块中分配序列的头部作为一个连续躯体,并且设置结构的 flags域, elem_size域, header_size域 和 storage域 的值为被传递过来的值,设置 delta_elems 为默认值(可通过函数 cvSetSeqBlockSize 重新对其赋值),清空其他的头 部域,包括前sizeof(CvSeq) 个字节的空间。
2、清空序列
void cvClearSeq( CvSeq* seq );
seq 序列
函数 cvClearSeq 删除序列中的所有元素。函数不会将内存返回到存储器中,当新的元素添加到序列中时,可重新使用该内存。函数时间复杂度为 O(1).
3、返回索引所指定的元素指针
char* cvGetSeqElem( const CvSeq* seq, int index );
#define CV_GET_SEQ_ELEM( TYPE, seq, index ) (TYPE*)cvGetSeqElem( (CvSeq*)(seq), (index) )
seq 序列
index 索引
函数 cvGetSeqElem 查找序列中索引所指定的元素,并返回指向该元素的指针。如果元素不存在,则返回 0。 函数支持负数,即: -1 代表 序列的最后一个元素, -2 代表最后第二个元素,等。如果序列只包含一个块,或者所需的元素在第一个块中,那么应当使用宏, CV_GET_SEQ_ELEM( elemType, seq, index )宏中的参数 elemType 是序列中元素的类型(如:CvPoint), 参数 seq 表示序列, 参数 index 代表所需元素的索引。 该宏首先核查所需的元素是否属于第一个块,如果是,则返回该元素,否则,该宏就调用主函数 GetSeqElem. 如果索引为负数的话,则总是调用函数 cvGetSeqElem。函数的时间复杂度为 O(1), 假设块的大小要比元素的数量要小。
4、创建序列的一份拷贝,是深度复制一个序列
CvSeq* cvCloneSeq( const CvSeq* seq, CvMemStorage* storage=NULL );
seq 序列
storage 存放新序列的 header部分和拷贝数据(如果需要)的目的存储块。如果为 NULL, 则函数使用包含输入序列的存储块 。
函数 cvCloneSeq 创建输入序列的一份完全拷贝。调用函数 cvCloneSeq (seq, storage) 等同于调用 cvSeqSlice(seq, CV_WHOLE_SEQ, storage, 1).
5、删除序列中的元素
void cvSeqRemove( CvSeq* seq, int index );
seq 序列
index 被珊元素的索引。
函数 cvSeqRemove 删除指定的索引元素。如果索引出了序列的范围,就报告发现错误。企图从空序列中删除元素,函数报告错误。函数通过移动序列中的元素来删除索引元素。
6、在序列中插入一数组
void cvSeqInsertSlice( CvSeq* seq, int before_index, const CvArr* from_arr );
seq 序列
slice 序列中被移动的那部分
from_arr 从中获取元素的数组
函数 cvSeqInsertSlice 在指定位置插入 来自数组from_arr中 所有元素。数组 from_arr 可以是一个 矩阵也可以是另外一个 序列。
7、将序列作为栈来使用
序列在内部其实对应一个双端队列,因此我们可以高效地从序列的任意一段(开头和结尾)访问序列。这样我们可以自然地将序列当作一个栈使用。具体有:
添加元素到序列的尾 char* cvSeqPush( CvSeq* seq, void* element=NULL );
在序列头部添加元素 char* cvSeqPushFront( CvSeq* seq, void* element=NULL );
删除序列尾部元素 void cvSeqPop( CvSeq* seq, void* element=NULL );
删除序列的头部元素 void cvSeqPopFront( CvSeq* seq, void* element=NULL );
添加多个元素到序列尾部或头部 void cvSeqPushMulti( CvSeq* seq, void* elements, int count, int in_front=0 );
删除多个序列头部或尾部的元素 void cvSeqPopMulti( CvSeq* seq, void* elements, int count, int in_front=0 );
在序列中添加元素 char* cvSeqInsert( CvSeq* seq, int before_index, void* element=NULL );
删除序列中的元素 void cvSeqRemove( CvSeq* seq, int index );