分享

Cxcore数据保存和运行时类型信息

 牛人的尾巴 2014-10-01


[]

文件存储]

CvFileStorage

文件存储结构

typedef struct CvFileStorage
{
    ...       // hidden fields
} CvFileStorage;

构造函数 CvFileStorage 是将磁盘上存储的文件关联起来的“黑匣子” 。在下列函数描述中利用CvFileStorage 作为输入,允许存储或载入各种格式数据组成的层次集合,这些数据由标量值(scalar ),或者CXCore 对象(例如 矩阵,序列,图表 ) 和用户自定义对象。

CXCore 能将数据读入或写入 XML (http://www./XML) or YAML (http://www.) 格式. 下面这个例子是利用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 /* not used */
#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;

/*所有已读存储在文件元素的关键字被存储在hash表中,这样可以加速查找操作 */
typedef struct CvStringHashNode
{
    unsigned hashval;
    CvString str;
    struct CvStringHashNode* next;
}
CvStringHashNode;

/* 文件存储器的基本元素是-标量或集合*/
typedef struct CvFileNode
{
    int tag;
    struct CvTypeInfo* info; /* 类型信息(只能用于用户自定义对象,对于其它对象它为0) */
    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; /* NULL-指向数组对(attribute_name,attribute_value) 的空指针 */
    struct CvAttrList* next; /* 指向下一个属性块的指针 */
}
CvAttrList;

/* 初始化构造函数CvAttrList */
inline CvAttrList cvAttrList( const char** attr=NULL, CvAttrList* next=NULL );

/* 返回值为属性值,找不到适合的属性则返回值为0(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 /* 慢变量:不使用x值与y值  */
            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 /* default value */ );
            int y = cvReadIntByName( fs, pt, "y", 0 /* default value */ );
#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; /*  (CvTypeInfo)的大小 sizeof(CvTypeInfo) */
    struct CvTypeInfo* prev; /* 在列表中已定义过的类型  */
    struct CvTypeInfo* next; /* 在列表中下一个已定义过的类型  */
    const char* type_name; /*定义类型名,并写入文件存储器 */

    /* methods */
    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提供一个简单的接口.对象被打开之后,文件存储器被关闭,所有的临时缓冲区被删除。因而,为了能打开一个动态结构,如序列,轮廓或图像,你应该为该函数传递一个有效的目标存储器。


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多