文件存储
CvFileStorage
文件存储结构
typedef struct CvFileStorage
{
... // hidden fields
} CvFileStorage;
构造函数 CvFileStorage 是将磁盘上存储的文件关联起来的“黑匣子” 。在下列函数描述中利用CvFileStorage 作为输入,允许存储或载入各种格式数据组成的层次集合,这些数据由标量值(scalar ),或者CXCore 对象(例如 矩阵,序列,图表 ) 和用户自定义对象。
CXCore 能将数据读入或写入 XML (http://www.w3c.org/XML) or YAML (http://www.yaml.org) 格式. 下面这个例子是利用CXCore函数将3×3单位浮点矩阵存入XML 和 YAML文档。
XML:
<?xml version="1.0">
<opencv_storage>
<A type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>f</dt>
<data>1. 0. 0. 0. 1. 0. 0. 0. 1.</data>
</A>
</opencv_storage>
YAML:
%YAML:1.0
A: !!opencv-matrix
rows: 3
cols: 3
dt: f
data: [ 1., 0., 0., 0., 1., 0., 0., 0., 1.]
从例子中可以看到, XML是用嵌套标签来表现层次,而 YAML用缩排来表现(类似于Python语言) 。
相同的 CXCore 函数也能够在这两种格式下读写数据,特殊的格式决定了文件的扩展名, .xml 是 XML 的扩展名, .yml 或 .yaml 是 YAML的扩展名。
CvFileNode
文件存储器节点
#define CV_NODE_NONE 0
#define CV_NODE_INT 1
#define CV_NODE_INTEGER CV_NODE_INT
#define CV_NODE_REAL 2
#define CV_NODE_FLOAT CV_NODE_REAL
#define CV_NODE_STR 3
#define CV_NODE_STRING CV_NODE_STR
#define CV_NODE_REF 4
#define CV_NODE_SEQ 5
#define CV_NODE_MAP 6
#define CV_NODE_TYPE_MASK 7
#define CV_NODE_USER 16
#define CV_NODE_EMPTY 32
#define CV_NODE_NAMED 64
#define CV_NODE_TYPE(tag) ((tag) & CV_NODE_TYPE_MASK)
#define CV_NODE_IS_INT(tag) (CV_NODE_TYPE(tag) == CV_NODE_INT)
#define CV_NODE_IS_REAL(tag) (CV_NODE_TYPE(tag) == CV_NODE_REAL)
#define CV_NODE_IS_STRING(tag) (CV_NODE_TYPE(tag) == CV_NODE_STRING)
#define CV_NODE_IS_SEQ(tag) (CV_NODE_TYPE(tag) == CV_NODE_SEQ)
#define CV_NODE_IS_MAP(tag) (CV_NODE_TYPE(tag) == CV_NODE_MAP)
#define CV_NODE_IS_COLLECTION(tag) (CV_NODE_TYPE(tag) >= CV_NODE_SEQ)
#define CV_NODE_IS_FLOW(tag) (((tag) & CV_NODE_FLOW) != 0)
#define CV_NODE_IS_EMPTY(tag) (((tag) & CV_NODE_EMPTY) != 0)
#define CV_NODE_IS_USER(tag) (((tag) & CV_NODE_USER) != 0)
#define CV_NODE_HAS_NAME(tag) (((tag) & CV_NODE_NAMED) != 0)
#define CV_NODE_SEQ_SIMPLE 256
#define CV_NODE_SEQ_IS_SIMPLE(seq) (((seq)->flags & CV_NODE_SEQ_SIMPLE) != 0)
typedef struct CvString
{
int len;
char* ptr;
}
CvString;
typedef struct CvStringHashNode
{
unsigned hashval;
CvString str;
struct CvStringHashNode* next;
}
CvStringHashNode;
typedef struct CvFileNode
{
int tag;
struct CvTypeInfo* info;
union
{
double f;
int i;
CvString str;
CvSeq* seq;
struct CvMap* map;
} data;
}
CvFileNode;
这个构造函数只是用于重新找到文件存储器上的数据(例如,从文件中下载数据)。当数据已经写入文件时,按顺序写入,只用最小的缓冲完成,此时没有数据存放在文件存储器。
相反,当从文件中读数据时,所有文件在内存中像树一样被解析和描绘。树的每一个节点被CvFileNode表现出来。文件节点N的类型能够通过CV_NODE_TYPE(N->tag) 被重新找到。一些节点(叶结点)作为变量:字符串文本,整数,浮点数。其它的文件节点是集合文件节点,有两个类型集合:序列和图表 (我们这里使用 YAML 符号,无论用哪种方法,对于XML符号流也是同样有效)。序列(不要与CvSeq混淆)是由有序的非指定文件节点(注:没有关键字)构成的,图表是由无序的指定文件节点(注:有关键字)构成的。因而 ,序列的数据是通过索引(cvGetSepElem)来存取,图形的数据是通过名字(cvGetFileNodeByName)来存取下表描述不同类型的节点:
Type |
CV_NODE_TYPE(node->tag) |
Value |
Integer |
CV_NODE_INT |
node->data.i |
Floating-point |
CV_NODE_REAL |
node->data.f |
Text string |
CV_NODE_STR |
node->data.str.ptr |
Sequence |
CV_NODE_SEQ |
node->data.seq |
Map |
CV_NODE_MAP |
node->data.map* |
这里不需要直接存取图表内容(顺便说一下CvMap 是一个隐藏的构造函数)。图形中的数据可以用cvGetFileNodeByName函数得到,函数返回指向图表文件节点的指针。
一个用户对象是一个标准的类型实例,例如CvMat, CvSeq等,或者任何一个已注册的类型使用cvRegisterTypeInfo。这样的对象最初在文件中表现为一种层级关系,(像表现XML 和 YAM示例文件一样) 。在文件存储器打开并分析之后。当用户调用cvRead或cvReadByName函数时 那么对象将请求被解析 (按照原来的存储方式)。
CvAttrList
属性列表
typedef struct CvAttrList
{
const char** attr;
struct CvAttrList* next;
}
CvAttrList;
inline CvAttrList cvAttrList( const char** attr=NULL, CvAttrList* next=NULL );
const char* cvAttrValue( const CvAttrList* attr, const char* attr_name );
在当前版本的属性列表用来传递额外的参数,在使用cvWrite写入自定义数据对象时。除了对象类型说明(type_id 属性)以外,它不支持 XML 在标签内的属性(注:例如<A name="test"></A>不支持)。
OpenFileStorage
打开文件存储器读/写数据。
CvFileStorage* cvOpenFileStorage( const char* filename, CvMemStorage* memstorage, int flags );
filename
内存中的相关文件的文件名。
memstorage
内存中通常存储临时数据和动态结构,例如 CvSeq 和 CvGraph。如果memstorage 为空,将建立和使用一个暂存器。
flags
读/写选择器。
CV_STORAGE_READ - 内存处于读状态。
CV_STORAGE_WRITE - 内存处于写状态。
函数cvOpenFileStorage打开文件存储器读写数据,之后建立文件或继续使用现有的文件。文件扩展名决定读文件的类型: .xml 是 XML的扩展名, .yml 或 .yaml 是 YAML的扩展名。该函数的返回指针指向CvFileStorage结构。
ReleaseFileStorage
释放文件存储单元
void cvReleaseFileStorage( CvFileStorage** fs );
fs
双指针指向被关闭的文件存储器。
函数cvReleaseFileStorage 关闭一个相关的文件存储器并释放所有的临时内存。只有在内存的I/O操作完成后才能关闭文件存储器。
写数据
StartWriteStruct
向文件存储器中写数据
void cvStartWriteStruct( CvFileStorage* fs, const char* name,
int struct_flags, const char* type_name=NULL,
CvAttrList attributes=cvAttrList());
fs
初始化文件存储器。
name
被写入的数据结构的名称。在存储器被读取时可以通过名称访问数据结构。
struct_flags
有下列两个值:
CV_NODE_SEQ - 被写入的数据结构为序列结构。这样的数据没有名称。
CV_NODE_MAP - 被写入的数据结构为图表结构。这样的数据含有名称。
这两个标志符必须被指定一个
CV_NODE_FLOW - 这个可选择标识符只能作用于YAML流。被写入的数据结构被看做一个数据流(不是数据块),它更加紧凑,当结构或数组里的数据是标量时,推荐用这个标志。
type_name
可选参数 - 对象类型名称。如果是XML用打开标识符type_id 属性写入。如果是YAML 用冒号后面的数据结构名写入,:: 基本上它是伴随用户对象出现的。当读存储器时,编码类型名通常决定对象类型(见Cvtypeinfo和cvfindtypeinfo)。
attributes
这个参数当前版本没有使用。
函数 cvStartWriteStruct 开始写复合的数据结构(数据集合)包括序列或图表, 在结构体中所有的字段(可以是标量和新的结构)被写入后, 需要调用 cvEndWriteStruct . 该函数能够合并一些对象或写入一些用户对象(参考 CvTypeInfo )。
EndWriteStruct
结束数据结构的写操作
void cvEndWriteStruct( CvFileStorage* fs );
fs
初始化文件存储器。
函数cvEndWriteStruct 结束普通的写数据操作。
WriteInt
写入一个整型值
void cvWriteInt( CvFileStorage* fs, const char* name, int value );
fs
初始的文件存储器。
name
写入值的名称。如果母结构是一个序列,把name的值置为NULL。
value
写入的整型值。
函数 cvWriteInt 将一个单独的整型值(有符号的或无符号的)写入文件存储器。
WriteReal
写入一个浮点数
void cvWriteReal( CvFileStorage* fs, const char* name, double value );
fs
文件存储器。
name
写入值的名称。如果父结构是一个序列,则name的值应为NULL。
value
写入的浮点数。
函数 cvWriteReal 将一个单精度浮点数(有符号的或无符号的)写入文件存储器。一些特殊的值以特殊的编码表示:
NaN 表示不是数字
+.Inf 表示正无穷
-.Inf 表示负无穷
下面的实例展示怎样使用底层写函数存储自定义数据结构。
void write_termcriteria( CvFileStorage* fs, const char* struct_name,
CvTermCriteria* termcrit )
{
cvStartWriteStruct( fs, struct_name, CV_NODE_MAP, NULL, cvAttrList(0,0));
cvWriteComment( fs, "termination criteria", 1 );
if( termcrit->type & CV_TERMCRIT_ITER )
cvWriteInteger( fs, "max_iterations", termcrit->max_iter );
if( termcrit->type & CV_TERMCRIT_EPS )
cvWriteReal( fs, "accuracy", termcrit->epsilon );
cvEndWriteStruct( fs );
}
WriteString
写入文本字符串
void cvWriteString( CvFileStorage* fs, const char* name,
const char* str, int quote=0 );
fs
文件存储器。
name
写入字符串的名称。如果父结构是一个序列,name的值应为NULL。
str
写入的文本字符串。
quote
如果不为0,不管是否需要引号,字符串都将被写入引号。如果标识符为0。只有在需要的情况下写入引号(例如字符串的首位是数字或者空格时候就需要两边加上引号)。
函数 cvWriteString将文本字符串写入文件存储器。
WriteComment
写入注释
void cvWriteComment( CvFileStorage* fs, const char* comment, int eol_comment );
fs
文件存储器。
comment
写入的注释,注释可以是单行的或者多行的。
eol_comment
如果不为0,函数将注释加到当前行的后面。如果为0,并且是多行注释或者当前行放不下,那么注释将从新的一行开始。
函数 cvWriteComment将注释写入文件存储器。读内存时注释将被跳过,它只能被用于调试和查看描述。
StartNextStream
打开下一个数据流
void cvStartNextStream( CvFileStorage* fs );
fs
初始化文件存储器。
函数 cvStartNextStream 从文件存储器中打开下一个数据流。 YAML 和 XML 都支持多数据流。这对连接多个文件和恢复写入的程序很有用。
Write
写入用户对象
void cvWrite( CvFileStorage* fs, const char* name,
const void* ptr, CvAttrList attributes=cvAttrList() );
fs
文件存储器。
name
写入对象的名称。如果父结构是一个序列,name的值为NULL。
ptr
定义指针指向对象。
attributes
定义对象的属性,每种类型都有特别的指定(见讨论)。
函数 cvWrite将对象写入文件存储器。首先,使用cvTypeOf 查找恰当的类型信息。其次写入指定的方法类型信息。
属性被用于定制写入程序。下面的属性支持标准类型 (所有的*dt 属性在cvWriteRawData中都有相同的格式):
CvSeq
· header_dt -序列首位用户区的描述,它紧跟在CvSeq或CvChain(如果是自由序列)或CvContour(如果是轮廓或点序列)之后。
· dt - 序列元素的描述。
· recursive - 如果属性被引用并且不等于“0”或“false",则所有的序列树(轮廓)都被存储(注:递归存储)。:
CvGraph
· header_dt - 图表头用户区的描述,它紧跟在 CvGraph之后。
· vertex_dt - 图表顶点用户区的描述。
· edge_dt - 图表边用户区的描述( 注意权重值总是被写入,所以不需要明确的说明)。
下面的代码的含义是建立YAML文件用来描述CvFileStorage :
#include "cxcore.h"
int main( int argc, char** argv )
{
CvMat* mat = cvCreateMat( 3, 3, CV_32F );
CvFileStorage* fs = cvOpenFileStorage( "example.yml", 0, CV_STORAGE_WRITE );
cvSetIdentity( mat );
cvWrite( fs, "A", mat, cvAttrList(0,0) );
cvReleaseFileStorage( &fs );
cvReleaseMat( &mat );
return 0;
}
WriteRawData
写入基本数据数组
void cvWriteRawData( CvFileStorage* fs, const void* src,
int len, const char* dt );
fs
文件存储器。
src
指针指向输入数组。
len
写入数组的长度。
dt
下面是每一个数组元素说明的格式: ([count]{'u'|'c'|'w'|'s'|'i'|'f'|'d'})..., 这些特性与C语言的类型相似:
· 'u' - 8位无符号数。
· 'c' - 8位符号数。
· 'w' - 16位无符号数。
· 's' - 16位符号数。
· 'i' - 32位符号数。
· 'f' - 单精度浮点数。
· 'd' - 双精度浮点数。
· 'r' - 指针。输入的带符号的低32位整数。 这个类型常被用来存储结构体之间的链接。
count 是可选的,是当前类型的计数器。 例如, dt='2if' 是指任意的一个数组元素的结构是:2个字节整形数,后面跟一个单精度浮点数。上面的说明与‘iif', '2i1f' 等相同。另外一个例子:dt='u'是指 一个由类型组成的数组, dt='2d'是指由两个双精度浮点数构成的数组。
函数 cvWriteRawData 将数组写入文件存储器,数组由单独的数值构成。这个函数也可以用循环调用 cvWriteInt 和 cvWriteReal 替换,但是一个单独的函数更加有效。需要说明的是,那是因为元素没有名字,把它们写入序列(无名字)比写入图表(有名字关联)速度会快。
WriteFileNode
将文件节点写入另一个文件存储器
void cvWriteFileNode( CvFileStorage* fs, const char* new_node_name,
const CvFileNode* node, int embed );
fs
文件存储器
new_file_node
在目的文件存储器中设置新的文件节点名。保持现有的文件节点名,使用cvGetFileNodeName(节点).
node
被写入的节点。
embed
如果被写入的节点是个集合并且embed不为0,不建立额外的层次结构。否则所有的节点元素被写入新建的文件节点上。不过需要确定一点的是,图表元素只被写入图表,序列元素只被写入序列
函数 cvWriteFileNode将一个文件节点的拷贝写入文件存储器可能应用范围是: 将几个文件存储器合而为一。在XML 和YAML 之间变换格式等。
读取数据
从文件存储器中得到数据有两种步骤:首先查找文件节点包括哪些被请求的数据;然后利用手动或者使用自定义read 方法取得数据。
GetRootFileNode
从文件存储器中得到一个高层节点
CvFileNode* cvGetRootFileNode( const CvFileStorage* fs, int stream_index=0 );
fs
初始化文件存储器。
stream_index
从零开始计数的基索引。参考 cvStartNextStream. 在通常情况下,文件中只有一个流,但是可以拥有多个。
函数 cvGetRootFileNode 返回一个高层文件节点。高层节点没有名称,它们和流相对应,接连存入文件存储器。如果超出索引范围,函数返回NULL指针,所以要得到所有高层节点需要反复调用函数stream_index=0,1,...,直到返回NULL指针。这个函数是在文件存储器中递归寻找的基础方法。
GetFileNodeByName
在图表或者文件存储器中查找节点
CvFileNode* cvGetFileNodeByName( const CvFileStorage* fs,
const CvFileNode* map,
const char* name );
fs
初始化文件存储器。
map
设置父图表。如果为NULL,函数在所有的高层节点(流)中检索,从第一个开始。
name
设置文件节点名。
函数 cvGetFileNodeByName 文件节点通过name 查找文件节点该节点在图表中被查找,或者如果指针为NULL,那么在内存中的高层文件节点中查找。在图表中或者在序列调用cvGetSeqElem中使用到这个函数,这样可能遍历整个文件存储器。为了加速确定某个关键字的多重查询(例如结构数组 ),可以在cvGetHashedKey 和cvGetFileNode之中用到一个。
GetHashedKey
返回一个指向已有名称的唯一指针
CvStringHashNode* cvGetHashedKey( CvFileStorage* fs, const char* name,
int len=-1, int create_missing=0 );
fs
初始化文件存储器。
name
设置文字节点名。
len
名称的长度(已知),如果值为-1 长度会被计算出来 。
create_missing
标识符说明,是否应该将一个缺省节点的值加入哈希表。
函数 cvGetHashedKey返回指向每一个特殊文件节点名的唯一指针。这个指针可以传递给cvGetFileNode函数。它比cvGetFileNodeByName快,因为比较指针相对比较字符串快些。
观察下面例子:用二维图来表示一个点集,例:
%YAML:1.0
points:
- { x: 10, y: 10 }
- { x: 20, y: 20 }
- { x: 30, y: 30 }
# ...
因而,它使用哈希指针“x”和“y"加速对点的解析。
例:从一个文件存储器中读取一组的结构
#include "cxcore.h"
int main( int argc, char** argv )
{
CvFileStorage* fs = cvOpenFileStorage( "points.yaml", 0, CV_STORAGE_READ );
CvStringHashNode* x_key = cvGetHashedKey( fs, "x", -1, 1 );
CvStringHashNode* y_key = cvGetHashedKey( fs, "y", -1, 1 );
CvFileNode* points = cvGetFileNodeByName( fs, 0, "points" );
if( CV_NODE_IS_SEQ(points->tag) )
{
CvSeq* seq = points->data.seq;
int i, total = seq->total;
CvSeqReader reader;
cvStartReadSeq( seq, &reader, 0 );
for( i = 0; i < total; i++ )
{
CvFileNode* pt = (CvFileNode*)reader.ptr;
#if 1
CvFileNode* xnode = cvGetFileNode( fs, pt, x_key, 0 );
CvFileNode* ynode = cvGetFileNode( fs, pt, y_key, 0 );
assert( xnode && CV_NODE_IS_INT(xnode->tag) &&
ynode && CV_NODE_IS_INT(ynode->tag));
int x = xnode->data.i; // or x = cvReadInt( xnode, 0 );
int y = ynode->data.i; // or y = cvReadInt( ynode, 0 );
#elif 1
CvFileNode* xnode = cvGetFileNodeByName( fs, pt, "x" );
CvFileNode* ynode = cvGetFileNodeByName( fs, pt, "y" );
assert( xnode && CV_NODE_IS_INT(xnode->tag) &&
ynode && CV_NODE_IS_INT(ynode->tag));
int x = xnode->data.i; // or x = cvReadInt( xnode, 0 );
int y = ynode->data.i; // or y = cvReadInt( ynode, 0 );
#else
int x = cvReadIntByName( fs, pt, "x", 0 );
int y = cvReadIntByName( fs, pt, "y", 0 );
#endif
CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
printf("%d: (%d, %d)\n", i, x, y );
}
}
cvReleaseFileStorage( &fs );
return 0;
}
请注意,无论使用那一种方法访问图表,都比使用序列慢,例如上面的例子,如果把数据作为整数对放在在单一数字序列中,效率会更高。
GetFileNode
在图表或者文件存储器中查找节点
CvFileNode* cvGetFileNode( CvFileStorage* fs, CvFileNode* map,
const CvStringHashNode* key, int create_missing=0 );
fs
初始化文件存储器。
map
设置母图表。如果为NULL,函数在所有的高层节点(流)中检索,如果图表与值都为 NULLs,函数返回到根节点-图表包含高层节点
key
指向节点名的特殊节点 , 从cvGetHashedKey中得到 。
create_missing
标识符说明,是否应该将一个缺省节点加入图表。
函数 cvGetFileNode 查找一个文件节点。函数能够插入一个新的节点,当它不在图表中时
GetFileNodeName
返回文件节点名
const char* cvGetFileNodeName( const CvFileNode* node );
node
初始化文件节点。
函数 cvGetFileNodeName 返回文件节点名或返回NULL(如果文件节点没有名称或者node为NULL 。
ReadInt
从文件节点中得到整形值
int cvReadInt( const CvFileNode* node, int default_value=0 );
node
初始化文件节点
default_value
如果node为NULL,返回一个值。
函数 cvReadInt 从文件节点中返回整数。如果文件节点为NULL, default_value 被返回 。另外如果文件节点有类型 CV_NODE_INT, 则 node->data.i 被返回 。如果文件节点有类型 CV_NODE_REAL, 则 node->data.f 被修改成整数后返回。其他的情况是则结果不确定。
ReadIntByName
查找文件节点返回它的值
int cvReadIntByName( const CvFileStorage* fs, const CvFileNode* map,
const char* name, int default_value=0 );
fs
初始化文件存储器。
map
设置父图表。如果为NULL,函数在所有的高层节点(流)中检索。
name
设置节点名。
default_value
如果文件节点为NULL,返回一个值。
函数 cvReadIntByName是 cvGetFileNodeByName 和 cvReadInt的简单重叠.
ReadReal
从文件节点中得到浮点形值
double cvReadReal( const CvFileNode* node, double default_value=0. );
node
初始化文件节点。
default_value
如果node为NULL,返回一个值。
函数cvReadReal 从文件节点中返回浮点形值。如果文件节点为NULL, default_value 被返回(这样就不用检查cvGetFileNode 返回的指针是否为空了) 。另外如果文件节点有类型 CV_NODE_REAL , 则node->data.f 被返回 。如果文件节点有类型 CV_NODE_INT , 则 node->data.i 被修改成浮点数后返回。另外一种情况是,结果不确定。 .
ReadRealByName
查找文件节点返回它的浮点形值
double cvReadRealByName( const CvFileStorage* fs, const CvFileNode* map,
const char* name, double default_value=0. );
fs
初始化文件存储器。
map
设置父图表。如果为NULL,函数在所有的高层节点(流)中检索。
name
设置节点名。
default_value
如果node为NULL,返回一个值。
函数 cvReadRealByName 是 cvGetFileNodeByName 和cvReadReal 的简单重叠。
ReadString
从文件节点中得到字符串文本
const char* cvReadString( const CvFileNode* node, const char* default_value=NULL );
node
初始化文件节点。
default_value
如果node为NULL,返回一个值。
函数cvReadString 从文件节点中返回字符串文本。如果文件节点为NULL, default_value 被返回。另外如果文件节点有类型CV_NODE_STR, 则data.str.ptr 被返回。另外一种情况是,结果不确定。
ReadStringByName
查找文件节点返回它的字符串文本
const char* cvReadStringByName( const CvFileStorage* fs, const CvFileNode* map,
const char* name, const char* default_value=NULL );
fs
初始化文件存储器。
map
设置母图表。如果为NULL,函数在所有的高层节点(流)中检索。
name
设置节点名。
default_value
如果文件节点为NULL,返回一个值。
函数 cvReadStringByName是 cvGetFileNodeByName 和cvReadString 的简单重叠。
Read
解释对象并返回指向它的指针
void* cvRead( CvFileStorage* fs, CvFileNode* node,
CvAttrList* attributes=NULL );
fs
初始化文件存储器。
node
设置对象根节点。
attributes
不被使用的参数.
函数 cvRead 解释用户对象 (在文件存储器子树中建立新的对象)并返回。对象被解释 ,必须按原有的支持读方法的类型 (参考 CvTypeInfo).用类型名决定对象,并在文件中被解释。如果对象是动态结构,它将在内存中创建传递给cvOpenFileStorage或者使NULL指针被建立在临时性内存中。当cvReleaseFileStorage 被调用时释放内存。 如果对象不是动态结构 ,将在堆中被建立,释放它的内存需要用专用函数或通用函数cvRelease。
ReadByName
查找对象并解释
void* cvReadByName( CvFileStorage* fs, const CvFileNode* map,
const char* name, CvAttrList* attributes=NULL );
fs
初始化文件存储器。
map
设置父节点。如果它为NULL,函数从高层节点中查找。
name
设置节点名称。
attributes
不被使用的参数.
函数 cvReadByName 是由cvGetFileNodeByName 和 cvRead叠合的。 .
ReadRawData
读重数
void cvReadRawData( const CvFileStorage* fs, const CvFileNode* src,
void* dst, const char* dt );
fs
初始化文件存储器。
src
设置文件节点(有序的)来读数。
dst
设置指向目的数组的指针。
dt
数组元素的说明。格式参考 cvWriteRawData。
函数 cvReadRawData从有序的文件节点中读取标量元素。
StartReadRawData
初始化文件节点读取器
void cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src,
CvSeqReader* reader );
fs
初始化文件存储器。
src
设置文件节点(序列)来读数。
reader
设置顺序读取指针。
函数 cvStartReadRawData 初始化序列读取器从文件节点中读取数据。初始化的首部通过传给cvReadRawDataSlice使用 。
ReadRawDataSlice
初始化文件节点序列
void cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader,
int count, void* dst, const char* dt );
fs
文件存储器。
reader
设置序列读取器 . 用 cvStartReadRawData.初始化。
count
被读取元素的数量。
dst
指向目的数组的指针。
dt
数组元素的说明。格式参考 cvWriteRawData。
函数 cvReadRawDataSlice 从文件节点读一个或多个元素,组成一个序列用于指定数组。读入元素的总数由其他数组的元素总和乘以每个数组元素数目。例如 如果 dt='2if', 函数将读是total*3数量的序列元素。对于任何数组,可以使用cvSetSeqReaderPos自由定位,跳过某些位置或者重复读取。
运行时类型信息和通用函数
CvTypeInfo
类型信息
typedef int (CV_CDECL *CvIsInstanceFunc)( const void* struct_ptr );
typedef void (CV_CDECL *CvReleaseFunc)( void** struct_dblptr );
typedef void* (CV_CDECL *CvReadFunc)( CvFileStorage* storage, CvFileNode* node );
typedef void (CV_CDECL *CvWriteFunc)( CvFileStorage* storage,
const char* name,
const void* struct_ptr,
CvAttrList attributes );
typedef void* (CV_CDECL *CvCloneFunc)( const void* struct_ptr );
typedef struct CvTypeInfo
{
int flags;
int header_size;
struct CvTypeInfo* prev;
struct CvTypeInfo* next;
const char* type_name;
CvIsInstanceFunc is_instance;
CvReleaseFunc release;
CvReadFunc read;
CvWriteFunc write;
CvCloneFunc clone;
}
CvTypeInfo;
结构 CvTypeInfo包含的信息包括标准的或用户自定义的类型。类型的实例可能有也可能没有包含指向相应的CvTypeInfo结构的指针。在已有的对象中查找类型的方法是使用cvTypeOf函数。在从文件存储器中读对象的时候已有的类型信息可以通过类型名使用cvFindType来查找。用户可以通过cvRegisterType定义一个新的类型,并将类型信息结构加到文件列表的开始端,它可以从标准类型中建立专门的类型,重载基本的方法。
RegisterType
定义新类型
void cvRegisterType( const CvTypeInfo* info );
info
类型信息结构。
函数 cvRegisterType 定义一个新类型,可以通过信息来描述它。这个函数在内存创建了一个copy,所以在用完以后,应该删除它。
UnregisterType
删除定义的类型
void cvUnregisterType( const char* type_name );
type_name
被删除的类型的名称。
函数 cvUnregisterType通过指定的名称删除已定义的类型。如果不知道类型名,可以用cvTypeOf或者连续扫描类型列表,从cvFirstType开始,然后调用 cvUnregisterType(info->type_name)。
FirstType
返回类型列表的首位。
CvTypeInfo* cvFirstType( void );
函数 cvFirstType 返回类型列表中的第一个类型。可以利用CvTypeInfo 的prev next来实现遍历。
FindType
通过类型名查找类型
CvTypeInfo* cvFindType( const char* type_name );
type_name
类型名
函数 cvFindType通过类型名查找指定的类型。如果找不到返回值为NULL。
TypeOf
返回对象的类型
CvTypeInfo* cvTypeOf( const void* struct_ptr );
struct_ptr
定义对象指针。
函数 cvTypeOf 查找指定对象的类型。它反复扫描类型列表,调用每一个类型信息结构中的函数和方法与对象做比较,直到它们中的一个的返回值不为0或者所有的类型都被访问。
Release
删除对象
void cvRelease( void** struct_ptr );
struct_ptr
定义指向对象的双指针。
函数 cvRelease 查找指定对象的类型,然后调用release。
Clone
克隆一个对象
void* cvClone( const void* struct_ptr );
struct_ptr
定义被克隆的对象
函数 cvClone 查找指定对象的类型,然后调用 clone。
Save
存储对象到文件中
void cvSave( const char* filename, const void* struct_ptr,
const char* name=NULL,
const char* comment=NULL,
CvAttrList attributes=cvAttrList());
filename
初始化文件名。
struct_ptr
指定要存储的对象。
name
可选择的对象名。如果为 NULL, 对象名将从filename中列出。
comment
可选注释。加在文件的开始处。
attributes
可选属性。传递给cvWrite。
函数 cvSave存储对象到文件。它给cvWrite提供一个简单的接口。
Load
从文件中打开对象。
void* cvLoad( const char* filename, CvMemStorage* memstorage=NULL,
const char* name=NULL, const char** real_name=NULL );
filename
初始化文件名
memstorage
动态结构的内存,例如CvSeq或CvGraph。不能作用于矩阵或图像。:
name
可选对象名。如果为 NULL,内存中的第一个高层对象被打开。
real_name
可选输出参数。它包括已打开的对象的名称 (如果 name=NULL时有效)。
函数 cvLoad 从文件中打开对象。它给cvRead提供一个简单的接口.对象被打开之后,文件存储器被关闭,所有的临时缓冲区被删除。因而,为了能打开一个动态结构,如序列,轮廓或图像,你应该为该函数传递一个有效的目标存储器。
Cxcore其它混合函数
Wikipedia,自由的百科全书
CheckArr
检查输入数组的每一个元素是否是合法值
int cvCheckArr( const CvArr* arr, int flags=0,
double min_val=0, double max_val=0);
#define cvCheckArray cvCheckArr
arr
待检查数组
flags
操作标志, 0 或者下面值的组合:
CV_CHECK_RANGE - 如果设置这个标志, 函数检查数组的每一个值是否在范围 [minVal,maxVal) 以内;否则,它只检查每一个元素是否是 NaN 或者 ±Inf。
CV_CHECK_QUIET - 设置这个标志后, 如果一个元素是非法值的或者越界时,函数不会产生错误。
min_val
有效值范围的闭下边界。只有当 CV_CHECK_RANGE 被设置的时候它才有作用。
max_val
有效值范围的开上边界。只有当 CV_CHECK_RANGE 被设置的时候它才有作用。
函数 cvCheckArr 检查每一个数组元素是否是 NaN 或者 ±Inf。如果 CV_CHECK_RANGE 被设定, 它将检查每一个元素是否大于等于 minVal 并且小于maxVal。如果检查成功函数返回非零值,例如,所有元素都是合法的并且在范围内,如果检查失败则返回 0 。在后一种情况下如果 CV_CHECK_QUIET 标志没有被设定,函数将报出运行错误。
KMeans2
按照给定的类别数目对样本集合进行聚类
void cvKMeans2( const CvArr* samples, int cluster_count,
CvArr* labels, CvTermCriteria termcrit );
samples
输入样本的浮点矩阵,每个样本一行。
cluster_count
所给定的聚类数目
labels
输出整数向量:每个样本对应的类别标识
termcrit
指定聚类的最大迭代次数和/或精度(两次迭代引起的聚类中心的移动距离)
函数 cvKMeans2 执行 k-means 算法 搜索 cluster_count 个类别的中心并对样本进行分类,输出 labels(i) 为样本 i 的类别标识。
例子. 用 k-means 对高斯分布的随机样本进行聚类
#include "cxcore.h"
#include "highgui.h"
int main( int argc, char** argv )
{
#define MAX_CLUSTERS 5
CvScalar color_tab[MAX_CLUSTERS];
IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 );
CvRNG rng = cvRNG(0xffffffff);
color_tab[0] = CV_RGB(255,0,0);
color_tab[1] = CV_RGB(0,255,0);
color_tab[2] = CV_RGB(100,100,255);
color_tab[3] = CV_RGB(255,0,255);
color_tab[4] = CV_RGB(255,255,0);
cvNamedWindow( "clusters", 1 );
for(;;)
{
int k, cluster_count = cvRandInt(&rng)%MAX_CLUSTERS + 1;
int i, sample_count = cvRandInt(&rng)00 + 1;
CvMat* points = cvCreateMat( sample_count, 1, CV_32FC2 );
CvMat* clusters = cvCreateMat( sample_count, 1, CV_32SC1 );
for( k = 0; k < cluster_count; k++ )
{
CvPoint center;
CvMat point_chunk;
center.x = cvRandInt(&rng)%img->width;
center.y = cvRandInt(&rng)%img->height;
cvGetRows( points, &point_chunk, k*sample_count/cluster_count,
k == cluster_count - 1 ? sample_count : (k+1)*sample_count/cluster_count );
cvRandArr( &rng, &point_chunk, CV_RAND_NORMAL,
cvScalar(center.x,center.y,0,0),
cvScalar(img->width/6, img->height/6,0,0) );
}
for( i = 0; i < sample_count/2; i++ )
{
CvPoint2D32f* pt1 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count;
CvPoint2D32f* pt2 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count;
CvPoint2D32f temp;
CV_SWAP( *pt1, *pt2, temp );
}
cvKMeans2( points, cluster_count, clusters,
cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0 ));
cvZero( img );
for( i = 0; i < sample_count; i++ )
{
CvPoint2D32f pt = ((CvPoint2D32f*)points->data.fl)[i];
int cluster_idx = clusters->data.i[i];
cvCircle( img, cvPointFrom32f(pt), 2, color_tab[cluster_idx], CV_FILLED );
}
cvReleaseMat( &points );
cvReleaseMat( &clusters );
cvShowImage( "clusters", img );
int key = cvWaitKey(0);
if( key == 27 ) // 'ESC'
break;
}
}
SeqPartition
拆分序列为等效的类
typedef int (CV_CDECL* CvCmpFunc)(const void* a, const void* b, void* userdata);
int cvSeqPartition( const CvSeq* seq, CvMemStorage* storage, CvSeq** labels,
CvCmpFunc is_equal, void* userdata );
seq
划分序列
storage
存储序列的等效类的存储器,如果为空, 函数用 seq->storage 存储输出标签。
labels
输出参数。指向序列指针的指针,这个序列存储以0为开始的输入序列元素的标签。
is_equal
比较函数指针。如果两个特殊元素是来自同一个类,那这个比较函数返回非零值,否则返回 0 。划分算法用比较函数的传递闭包得到等价类。
userdata
直接传递给 is_equal 函数的指针。
函数 cvSeqPartition 执行二次方程算法为拆分集合为一个或者更多的等效类。函数返回等效类的数目。
例子:拆分二维点集。
#include "cxcore.h"
#include "highgui.h"
#include <stdio.h>
CvSeq* point_seq = 0;
IplImage* canvas = 0;
CvScalar* colors = 0;
int pos = 10;
int is_equal( const void* _a, const void* _b, void* userdata )
{
CvPoint a = *(const CvPoint*)_a;
CvPoint b = *(const CvPoint*)_b;
double threshold = *(double*)userdata;
return (double)(a.x - b.x)*(a.x - b.x) + (double)(a.y - b.y)*(a.y - b.y) <= threshold;
}
void on_track( int pos )
{
CvSeq* labels = 0;
double threshold = pos*pos;
int i, class_count = cvSeqPartition( point_seq, 0, &labels, is_equal, &threshold );
printf("M classes\n", class_count );
cvZero( canvas );
for( i = 0; i < labels->total; i++ )
{
CvPoint pt = *(CvPoint*)cvGetSeqElem( point_seq, i );
CvScalar color = colors[*(int*)cvGetSeqElem( labels, i )];
cvCircle( canvas, pt, 1, color, -1 );
}
cvShowImage( "points", canvas );
}
int main( int argc, char** argv )
{
CvMemStorage* storage = cvCreateMemStorage(0);
point_seq = cvCreateSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage );
CvRNG rng = cvRNG(0xffffffff);
int width = 500, height = 500;
int i, count = 1000;
canvas = cvCreateImage( cvSize(width,height), 8, 3 );
colors = (CvScalar*)cvAlloc( count*sizeof(colors[0]) );
for( i = 0; i < count; i++ )
{
CvPoint pt;
int icolor;
pt.x = cvRandInt( &rng ) % width;
pt.y = cvRandInt( &rng ) % height;
cvSeqPush( point_seq, &pt );
icolor = cvRandInt( &rng ) | 0x00404040;
colors[i] = CV_RGB(icolor & 255, (icolor >> 8)&255, (icolor >> 16)&255);
}
cvNamedWindow( "points", 1 );
cvCreateTrackbar( "threshold", "points", &pos, 50, on_track );
on_track(pos);
cvWaitKey(0);
return 0;
}
错误处理
在 OpenCV 中错误处理和 IPL (Image Processing Library)很相似。如果调用函数出现错误将并不直接返回错误代码,而是用CV_ERROR 宏调用 cvError 函数报错,按次序地,用 cvSetErrStatus 函数设置错误状态,然后调用标准的或者用户自定义的错误处理器(它可以显示一个消息对话框,导出错误日志等等, 参考函数 cvRedirectError, cvNulDevReport, cvStdErrReport, cvGuiBoxReport)。每个程序的线程都有一个全局变量,它包含了错误状态(一个整数值)。这个状态可以被 cvGetErrStatus 函数检索到。
有三个错误处理模式(参考 cvSetErrMode 和 cvGetErrMode):
Leaf
错误处理器被调用以后程序被终止。这是缺省值。它在调试中是很有用的,当错误发生的时候立即产生错误信息。然而对于产生式系统,后面两种模式提供的更多控制能力可能会更有用。
Parent
错误处理器被调用以后程序不会被终止。栈被清空 (它用 C++ 异常处理机制完成写/输出--w/o)。当调用 CxCore 的函数 cvGetErrStatus 起作用以后用户可以检查错误代码。
Silent
和 Parent 模式相似, 但是没有错误处理器被调用。
事实上, Leaf 和 Parent 模式的语义被错误处理器执行,上面的描述对 cvNulDevReport, cvStdErrReport. cvGuiBoxReport 的行为有一些细微的差别,一些自定义的错误处理器可能语义上会有很大的不同。错误处理宏
报错,检查错误等的宏
#define __BEGIN__ {
#define __END__ goto exit; exit: ; }
#define EXIT goto exit
#define CV_FUNCNAME( Name ) \
static char cvFuncName[] = Name
#define CV_ERROR( Code, Msg ) \
{ \
cvError( (Code), cvFuncName, Msg, __FILE__, __LINE__ ); \
EXIT; \
}
#define CV_CHECK() \
{ \
if( cvGetErrStatus() < 0 ) \
CV_ERROR( CV_StsBackTrace, "Inner function failed." ); \
}
#define CV_CALL( Statement ) \
{ \
Statement; \
CV_CHECK(); \
}
#define CV_ASSERT( Condition ) \
{ \
if( !(Condition) ) \
CV_ERROR( CV_StsInternal, "Assertion: " #Condition " failed" ); \
}
#define OPENCV_ERROR(status,func_name,err_msg) ...
#define OPENCV_ERRCHK(func_name,err_msg) ...
#define OPENCV_ASSERT(condition,func_name,err_msg) ...
#define OPENCV_CALL(statement) ...
取代上面的讨论, 这里有典型的 CXCORE 函数和这些函数使用的样例。错误处理宏的使用
#include "cxcore.h"
#include <stdio.h>
void cvResizeDCT( CvMat* input_array, CvMat* output_array )
{
CvMat* temp_array = 0; // declare pointer that should be released anyway.
CV_FUNCNAME( "cvResizeDCT" ); // declare cvFuncName
__BEGIN__; // start processing. There may be some declarations just after this macro,
// but they couldn't be accessed from the epilogue.
if( !CV_IS_MAT(input_array) || !CV_IS_MAT(output_array) )
// use CV_ERROR() to raise an error
CV_ERROR( CV_StsBadArg, "input_array or output_array are not valid matrices" );
// some restrictions that are going to be removed later, may be checked with CV_ASSERT()
CV_ASSERT( input_array->rows == 1 && output_array->rows == 1 );
// use CV_CALL for safe function call
CV_CALL( temp_array = cvCreateMat( input_array->rows, MAX(input_array->cols,output_array->cols),
input_array->type ));
if( output_array->cols > input_array->cols )
CV_CALL( cvZero( temp_array ));
temp_array->cols = input_array->cols;
CV_CALL( cvDCT( input_array, temp_array, CV_DXT_FORWARD ));
temp_array->cols = output_array->cols;
CV_CALL( cvDCT( temp_array, output_array, CV_DXT_INVERSE ));
CV_CALL( cvScale( output_array, output_array, 1./sqrt((double)input_array->cols*output_array->cols), 0 ));
__END__; // finish processing. Epilogue follows after the macro.
// release temp_array. If temp_array has not been allocated before an error occured, cvReleaseMat
// takes care of it and does nothing in this case.
cvReleaseMat( &temp_array );
}
int main( int argc, char** argv )
{
CvMat* src = cvCreateMat( 1, 512, CV_32F );
#if 1
CvMat* dst = cvCreateMat( 1, 256, CV_32F );
#else
CvMat* dst = 0;
#endif
cvSet( src, cvRealScalar(1.), 0 );
#if 0
cvSetErrMode( CV_ErrModeSilent );
#endif
cvResizeDCT( src, dst ); // if some error occurs, the message box will popup, or a message will be
// written to log, or some user-defined processing will be done
if( cvGetErrStatus() < 0 )
printf("Some error occured" );
else
printf("Everything is OK" );
return 0;
}
GetErrStatus
返回当前错误状态
int cvGetErrStatus( void );
函数 cvGetErrStatus 返回当前错误状态 - 这个状态是被最近调用的 cvSetErrStatus 设置的。 注意, 在 Leaf 模式下错误一旦发生程序立即被终止 ,因此对于总是需要调用函数仍然获得控制的应用,可以调用 cvSetErrMode 函数将错误模式设置为 Parent 或 Silent 。
SetErrStatus
设置错误状态
void cvSetErrStatus( int status );
status
错误状态
函数 cvSetErrStatus 设置错误状态为指定的值。大多数情况下, 该函数 被用来重设错误状态(设置为 CV_StsOk) 以从错误中恢复。在其他情况下调用 cvError 或 CV_ERROR 更自然一些。
GetErrMode
返回当前错误模式
int cvGetErrMode( void );
函数 cvGetErrMode 返回当前错误模式 - 这个值是被最近一次 cvSetErrMode 函数调用所设定的。
SetErrMode
设置当前错误模式
#define CV_ErrModeLeaf 0
#define CV_ErrModeParent 1
#define CV_ErrModeSilent 2
int cvSetErrMode( int mode );
mode
错误模式
函数 cvSetErrMode 设置指定的错误模式。关于不同的错误模式的讨论参考本节开始.
Error
产生一个错误
int cvError( int status, const char* func_name,
const char* err_msg, const char* file_name, int line );
status
错误状态
func_name
产生错误的函数名
err_msg
关于错误的额外诊断信息
file_name
产生错误的文件名
line
产生错误的行号
函数 cvError 设置错误状态为指定的值(通过 cvSetErrStatus) ,如果错误模式不是 Silent, 调用错误处理器。
ErrorStr
返回错误状态编码的原文描述
const char* cvErrorStr( int status );
status
错误状态
函数 cvErrorStr 返回指定错误状态编码的原文描述。如果是未知的错误状态该函数返回空(NULL)指针。
RedirectError
设置一个新的错误处理器
typedef int (CV_CDECL *CvErrorCallback)( int status, const char* func_name,
const char* err_msg, const char* file_name, int line, void* userdata );
CvErrorCallback cvRedirectError( CvErrorCallback error_handler,
void* userdata=NULL, void** prev_userdata=NULL );
error_handler
新的错误处理器
userdata
传给错误处理器的任意透明指针
prev_userdata
指向前面分配给用户数据的指针的指针
函数 cvRedirectError 在标准错误处理器或者有确定借口的自定义错误处理器中选择一个新的错误处理器。错误处理器和 cvError 函数有相同的参数。如果错误处理器返回非零的值, 程序终止, 否则, 程序继续运行。错误处理器通过 cvGetErrMode 检查当前错误模式而作出决定。
cvNulDevReport cvStdErrReport cvGuiBoxReport
提供标准错误操作
int cvNulDevReport( int status, const char* func_name,
const char* err_msg, const char* file_name,
int line, void* userdata );
int cvStdErrReport( int status, const char* func_name,
const char* err_msg, const char* file_name,
int line, void* userdata );
int cvGuiBoxReport( int status, const char* func_name,
const char* err_msg, const char* file_name,
int line, void* userdata );
status
错误状态
func_name
产生错误的函数名
err_msg
关于错误的额外诊断信息
file_name
产生错误的文件名
line
产生错误的行号
userdata
指向用户数据的指针,被标准错误操作忽略。
函数 cvNullDevReport, cvStdErrReport, cvGuiBoxReport 提供标准错误操作。cvGuiBoxReport 是 Win32 系统缺省的错误处理器, cvStdErrReport - 其他系统. cvGuiBoxReport 弹出错误描述的消息框并提供几个选择。下面是一个消息框的例子,如果和例子中的错误描述相同,它和上面的例子代码可能是兼容的。
错误消息对话框
如果错误处理器是 cvStdErrReport, 上面的消息将被打印到标准错误输出,程序将要终止和继续依赖于当前错误模式。
错误消息打印到标准错误输出 (在 Leaf 模式)
OpenCV ERROR: Bad argument (input_array or output_array are not valid matrices)
in function cvResizeDCT, D:\User\VP\Projects\avl_proba\a.cpp(75)
Terminating the application...
系统函数
Alloc
分配内存缓冲区
void* cvAlloc( size_t size );
size
以字节为单位的缓冲区大小
函数 cvAlloc 分配字节缓冲区大小并返回分配的缓冲区的指针。如果错误处理函数产生了一个错误报告则返回一个空(NULL)指针。 缺省地 cvAlloc 调用 icvAlloc 而 icvAlloc 调用 malloc ,然而用 cvSetMemoryManager 调用用户自定义的内存分配和释放函数也是可能的。
Free
释放内存缓冲区
void cvFree( void** ptr );
buffer
指向被释放的缓冲区的双重指针
函数 cvFree 释放被 cvAlloc 分配的缓冲区。在退出的时候它清除缓冲区指针,这就是为什么要使用双重指针的原因 。 如果 *buffer 已经是空(NULL), 函数什么也不做。
GetTickCount
Returns number of tics
int64 cvGetTickCount( void );
函数 cvGetTickCount 返回从依赖于平台的事件(从启动开始 CPU 的ticks 数目, 从1970年开始的微秒数目等等)开始的 tics 的数目。该函数对于精确测量函数/用户代码的执行时间是很有用的。要转化 tics 的数目为时间单位,使用函数 cvGetTickFrequency 。
GetTickFrequency
返回每个微秒的 tics 的数目
double cvGetTickFrequency( void );
函数 cvGetTickFrequency 返回每个微秒的 tics 的数目。 因此, cvGetTickCount() 和 cvGetTickFrequency() 将给出从依赖于平台的事件开始的 tics 的数目 。
RegisterModule
Registers another module 注册另外的模块
typedef struct CvPluginFuncInfo
{
void** func_addr;
void* default_func_addr;
const char* func_names;
int search_modules;
int loaded_from;
}
CvPluginFuncInfo;
typedef struct CvModuleInfo
{
struct CvModuleInfo* next;
const char* name;
const char* version;
CvPluginFuncInfo* func_tab;
}
CvModuleInfo;
int cvRegisterModule( const CvModuleInfo* module_info );
module_info
模块信息
函数 cvRegisterModule 添加模块到已注册模块列表中。模块被注册后,用 cvGetModuleInfo 函数可以检索到它的信息。注册模块可以通过 CXCORE的支持利用优化插件 (IPP, MKL, ...)。 CXCORE , CV (computer vision), CVAUX (auxilary computer vision) 和 HIGHGUI (visualization & image/video acquisition) 自身就是模块的例子。通常注册后共享库就被载入。参考 cxcore/src/cxswitcher.cpp and cv/src/cvswitcher.cpp 获取细节信息, 怎样注册的参考 cxcore/src/cxswitcher.cpp , cxcore/src/_cxipp.h 显示了 IPP 和 MKL 是怎样连接到模块的。
GetModuleInfo
检索注册模块和插件的信息
void cvGetModuleInfo( const char* module_name,
const char** version,
const char** loaded_addon_plugins );
module_name
模块名, 或者 NULL ,则代表所有的模块
version
输出参数,模块的信息,包括版本信息
loaded_addon_plugins
优化插件的名字和版本列表,这里 CXCORE 可以被找到和载入
函数 cvGetModuleInfo 返回一个或者所有注册模块的信息。返回信息被存储到库当中,因此,用户不用释放或者修改返回的文本字符。
UseOptimized
在优化/不优化两个模式之间切换
int cvUseOptimized( int on_off );
on_off
优化(<>0) 或者 不优化 (0).
函数 cvUseOptimized 在两个模式之间切换,这里只有纯 C 才从 cxcore, OpenCV 等执行。如果可用 IPP 和 MKL 函数也可使用。 当 cvUseOptimized(0) 被调用, 所有的优化库都不被载入。该函数在调试模式下是很有用的, IPP&MKL 不工作, 在线跨速比较等。它返回载入的优化函数的数目。注意,缺省地优化插件是被载入的,因此在程序开始调用 cvUseOptimized(1) 是没有必要的(事实上, 它只会增加启动时间)
SetMemoryManager
分配自定义/缺省内存管理函数
typedef void* (CV_CDECL *CvAllocFunc)(size_t size, void* userdata);
typedef int (CV_CDECL *CvFreeFunc)(void* pptr, void* userdata);
void cvSetMemoryManager( CvAllocFunc alloc_func=NULL,
CvFreeFunc free_func=NULL,
void* userdata=NULL );
alloc_func
分配函数; 除了 userdata 可能用来确定上下文关系外,接口和 malloc 相似
free_func
释放函数; 接口和 free 相似
userdata
透明的传给自定义函数的用户数据
函数 cvSetMemoryManager 设置将被 cvAlloc,cvFree 和高级函数 (例如. cvCreateImage) 调用的用户自定义内存管理函数(代替 malloc 和 free)。 注意, 当用 cvAlloc 分配数据的时候该函数被调用。 当然, 为了避免无限递归调用, 它不允许从自定义分配/释放函数调用 cvAlloc 和 cvFree 。
如果 alloc_func 和 free_func 指针是 NULL, 恢复缺省的内存管理函数。
SetIPLAllocators
切换图像 IPL 函数的分配/释放
typedef IplImage* (CV_STDCALL* Cv_iplCreateImageHeader)
(int,int,int,char*,char*,int,int,int,int,int,
IplROI*,IplImage*,void*,IplTileInfo*);
typedef void (CV_STDCALL* Cv_iplAllocateImageData)(IplImage*,int,int);
typedef void (CV_STDCALL* Cv_iplDeallocate)(IplImage*,int);
typedef IplROI* (CV_STDCALL* Cv_iplCreateROI)(int,int,int,int,int);
typedef IplImage* (CV_STDCALL* Cv_iplCloneImage)(const IplImage*);
void cvSetIPLAllocators( Cv_iplCreateImageHeader create_header,
Cv_iplAllocateImageData allocate_data,
Cv_iplDeallocate deallocate,
Cv_iplCreateROI create_roi,
Cv_iplCloneImage clone_image );
#define CV_TURN_ON_IPL_COMPATIBILITY() \
cvSetIPLAllocators( iplCreateImageHeader, iplAllocateImage, \
iplDeallocate, iplCreateROI, iplCloneImage )
create_header
指向 iplCreateImageHeader 的指针
allocate_data
指向 iplAllocateImage 的指针
deallocate
指向 iplDeallocate 的指针
create_roi
指向 iplCreateROI 的指针
clone_image
指向 iplCloneImage 的指针
函数 cvSetIPLAllocators 使用 CXCORE 来进行图像 IPL 函数的 分配/释放 操作。 为了方便, 这里提供了环绕宏 CV_TURN_ON_IPL_COMPATIBILITY。 当 IPL 和 CXCORE/OpenCV 同时使用以及调用 iplCreateImageHeader 等情况该函数很有用。如果 IPL 仅仅是被调用来进行数据处理,该函数就必要了,因为所有的分配/释放都由 CXCORE 来完成, 或者所有的分配/释放都由 IPL 和一些 OpenCV 函数来处理数据。