数据存储OpenCV提供了一种机制来序列化(serialize)和去序列化(de-serialize)其各种数据类型,可以从磁盘中按YAML或XML格式读/写。
在第4章中,我们将专门介绍存储和调用常见的对象IplImages的函数(cvSaveImage()和cvLoadImage())。
此外,第4章将讨论读/写视频的特有函数:可以从文件或者摄影机中读取数据的函数cvGrabFrame()以及写操作函数cvCreateVideoWriter()和cvWriteFrame()。
本小节将侧重于一般对象的永久存储:读/写矩阵、OpenCV结构、配置与日志文件。
首先,我们从有效且简便的OpenCV矩阵的保存和读取功能函数开始。
函数是cvSave()和cvLoad()。
例3-15展示了如何保存和读取一个5×5的单位矩阵(对角线上是1,其余地方都是0)。
例3-15:存储和读取CvMat1.CvMat A= cvMat( 5, 5, CV_32F, the_matrix_data );2.3.cvSave( "my_matrix.xml", &A );4.. . .5.// to load it then in some other program use …6.CvMat* A1= (CvMat*) cvLoad( "my_matrix.xml" );CxCore参考手册中有整节内容都在讨论数据存储。
首先要知道,在OpenCV中,一般的数据存储要先创建一个CvFileStorage结构(如例3-16)所示,该结构将内存对象存储在一个树形结构中。
然后通过使用CV_STORAGE_READ参数的cvOpenFileStorage()从磁盘读取数据,创建填充该结构,也可以通过使用CV_STORAGE_WRITE的cvOpenFileStorage()创建并打开CvFileStorage写数据,而后使用适当的数据存储函数来填充它。
在磁盘上,数据的存储格式为XML或者YAML。
例3-16:CvFileStorage结构,数据通过CxCore数据存储函数访问1.typedef struct CvFileStorage2.{3.... // hidden fields4.} CvFileStorage;CvFileStorage树内部的数据是一个层次化的数据集合,包括标量、CxCore对象(矩阵、序列和图)以及用户定义的对象。
假如有一个配置文件或日志文件。
配置文件告诉我们视频有多少帧(10),画面大小(320×240)并且将应用一个3×3的色彩转换矩阵。
例3-17展示了如何从磁盘中调出cfg.xml文件。
例3-17:往磁盘上写一个配置文件cfg.xml1.CvFileStorage* fs= cvOpenFileStorage(2."cfg.xml",3.0,4.CV_STORAGE_WRITE5.);6.cvWriteInt( fs, "frame_count", 10 );7.cvStartWriteStruct( fs, "frame_size", CV_NODE_SEQ );8.cvWriteInt( fs, 0, 320 );9.cvWriteInt( fs, 0, 200 );10.cvEndWriteStruct(fs);11.cvWrite( fs, "color_cvt_matrix", cmatrix );12.cvReleaseFileStorage( &fs );请留意这个例子中的一些关键函数。
我们可以定义一个整型变量通过cvWritelnt()向结构中写数据。
我们也可以使用cvStartWriteStruct()来创建任意一个可以任选一个名称(如果无名称请输入0或NULL)的结构。
这个结构有两个未命名的整型变量,使用cvEndWriteStruct()结束编写结构。
如果有更多的结构体,我们用相似的方法来解决;这种结构可以进行任意深度的嵌套。
最后,我们使用cvWrite()编写处色彩转换矩阵。
将这个相对复杂的矩阵程序与例3-15中简单的cvSave()程序进行对比。
便会发现cvSave()是cvWrite()在只保存一个矩阵时的快捷方式。
当写完数据后,使用cvReleaseFileStorage()释放CvFileStorage句柄。
例3-18显示了XML格式的输出内容。
例3-18:磁盘中的cfg.xml文件1.<?xml version="1.0"?>2.<opencv_storage>3.<frame_count>10</frame_count>4.<frame_size>320 200</frame_size>5.<color_cvt_matrix type_id="opencv-matrix">6.<rows>3</rows><cols>3</cols>7.<dt>f</dt>8.<data>...</data></color_cvt_matrix>9.</opencv_storage>我们将会在例3-19中将这个配置文件读入。
例3-19:磁盘中的cfg.xml文件1.CvFileStorage* fs= cvOpenFileStorage(2."cfg.xml",3.0,4.CV_STORAGE_READ5.);6.7.int frame_count= cvReadIntByName(8.fs,9.0,10."frame_count",11. 5 /* default value */12.);13.14.CvSeq* s= cvGetFileNodeByName(fs,0,"frame_size")->data.seq;15.16.int frame_width= cvReadInt(17.(CvFileNode*)cvGetSeqElem(s,0)18.);19.20.int frame_height= cvReadInt(21.(CvFileNode*)cvGetSeqElem(s,1)22.);23.24.CvMat* color_cvt_matrix= (CvMat*) cvReadByName(25.fs,26.0,27."color_cvt_matrix"28.);29.30.cvReleaseFileStorage( &fs );在阅读时,我们像例3-19中那样用cvOpenFileStorage()打开XML配置文件。
然后用cvReadlntByName()来读取frame_count,如果有没有读到的数,则赋一个默认值。
在这个例子中默认的值是5。
然后使用cvGetFileNodeByName()得到结构体frame_size。
在这里我们用cvReadlnt()读两个无名称的整型数据。
随后使用cvReadByName()读出我们已经定义的色彩转换矩阵。
将本例与例3-15中的cvLoad()进行对比。
如果我们只有一个矩阵要读取,那么可以使用cvLoad(),但是如果矩阵是内嵌在一个较大的结构中,必须使用cvRead()。
最后,释放CvFileStorage结构。
数据函数存储与CvFileStorage结构相关的表单列在表3-16中。
想了解更多细节,请查看CxCore手册。
表3-16:数据存储函数续表This line causes the error:> cvWrite(myFileStorage," X,Y,Reflectance", point3DSequence);It is too advanced syntax to be understood by OpenCV writing functions, namely, the tag name could not contain spaces or comma's.If you want to store each point as a structure,you may try the following:cvStartWriteStruct( myFileStorage, "point3DSequence", CV_NODE_SEQ ); for( i = 0; i < point3DSequence->total; i++ ){CvPoint3D32f* pt=(CvPoint3D32f*)cvGetSeqElem(point3DSequence,i); cvStartWriteStruct(myFileStorage, 0, CV_NODE_MAP+CV_NODE_FLOW); cvWriteReal( myFileStorage, "x", pt->x );cvWriteReal( myFileStorage, "y", pt->y );cvWriteReal( myFileStorage, "reflectance", pt->z ); cvEndWriteStruct( myFileStorage );}cvEndWriteStruct( myFileStorage );that will look nice, but a little bit bulky and then you willhave to read the elements manually from the filestorage.Or, if the all the data could be just written as a plain array:x0 y0 refl0 x1 y1 refl1 ...then just use:cvWrite( myFileStorage, "point3DSequence", point3DSequence );。