|
|
|
// This file is part of OpenCV project.
|
|
|
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
|
|
|
// of this distribution and at http://opencv.org/license.html
|
|
|
|
|
|
|
|
|
|
|
|
#include "precomp.hpp"
|
|
|
|
#include "persistence.hpp"
|
|
|
|
|
|
|
|
///////////////////////// new C++ interface for CvFileStorage ///////////////////////////
|
|
|
|
|
|
|
|
namespace cv
|
|
|
|
{
|
|
|
|
|
|
|
|
FileStorage::FileStorage()
|
|
|
|
{
|
|
|
|
state = UNDEFINED;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileStorage::FileStorage(const String& filename, int flags, const String& encoding)
|
|
|
|
{
|
|
|
|
state = UNDEFINED;
|
|
|
|
open( filename, flags, encoding );
|
|
|
|
}
|
|
|
|
|
|
|
|
FileStorage::FileStorage(CvFileStorage* _fs, bool owning)
|
|
|
|
{
|
|
|
|
if (owning) fs.reset(_fs);
|
|
|
|
else fs = Ptr<CvFileStorage>(Ptr<CvFileStorage>(), _fs);
|
|
|
|
|
|
|
|
state = _fs ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileStorage::~FileStorage()
|
|
|
|
{
|
|
|
|
while( structs.size() > 0 )
|
|
|
|
{
|
|
|
|
cvEndWriteStruct(fs);
|
|
|
|
structs.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FileStorage::open(const String& filename, int flags, const String& encoding)
|
|
|
|
{
|
|
|
|
CV_INSTRUMENT_REGION();
|
|
|
|
|
|
|
|
release();
|
|
|
|
fs.reset(cvOpenFileStorage( filename.c_str(), 0, flags,
|
|
|
|
!encoding.empty() ? encoding.c_str() : 0));
|
|
|
|
bool ok = isOpened();
|
|
|
|
state = ok ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FileStorage::isOpened() const
|
|
|
|
{
|
|
|
|
return fs && fs->is_opened;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStorage::release()
|
|
|
|
{
|
|
|
|
fs.release();
|
|
|
|
structs.clear();
|
|
|
|
state = UNDEFINED;
|
|
|
|
}
|
|
|
|
|
|
|
|
String FileStorage::releaseAndGetString()
|
|
|
|
{
|
|
|
|
String buf;
|
|
|
|
if( fs && fs->outbuf )
|
|
|
|
icvClose(fs, &buf);
|
|
|
|
|
|
|
|
release();
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNode FileStorage::root(int streamidx) const
|
|
|
|
{
|
|
|
|
return isOpened() ? FileNode(fs, cvGetRootFileNode(fs, streamidx)) : FileNode();
|
|
|
|
}
|
|
|
|
|
|
|
|
int FileStorage::getFormat() const
|
|
|
|
{
|
|
|
|
CV_Assert(!fs.empty());
|
|
|
|
return fs->fmt & FORMAT_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileStorage& operator << (FileStorage& fs, const String& str)
|
|
|
|
{
|
|
|
|
CV_TRACE_REGION_VERBOSE();
|
|
|
|
|
|
|
|
enum { NAME_EXPECTED = FileStorage::NAME_EXPECTED,
|
|
|
|
VALUE_EXPECTED = FileStorage::VALUE_EXPECTED,
|
|
|
|
INSIDE_MAP = FileStorage::INSIDE_MAP };
|
|
|
|
const char* _str = str.c_str();
|
|
|
|
if( !fs.isOpened() || !_str )
|
|
|
|
return fs;
|
|
|
|
if( *_str == '}' || *_str == ']' )
|
|
|
|
{
|
|
|
|
if( fs.structs.empty() )
|
|
|
|
CV_Error_( CV_StsError, ("Extra closing '%c'", *_str) );
|
|
|
|
if( (*_str == ']' ? '[' : '{') != fs.structs.back() )
|
|
|
|
CV_Error_( CV_StsError,
|
|
|
|
("The closing '%c' does not match the opening '%c'", *_str, fs.structs.back()));
|
|
|
|
fs.structs.pop_back();
|
|
|
|
fs.state = fs.structs.empty() || fs.structs.back() == '{' ?
|
|
|
|
INSIDE_MAP + NAME_EXPECTED : VALUE_EXPECTED;
|
|
|
|
cvEndWriteStruct( *fs );
|
|
|
|
fs.elname = String();
|
|
|
|
}
|
|
|
|
else if( fs.state == NAME_EXPECTED + INSIDE_MAP )
|
|
|
|
{
|
|
|
|
if (!cv_isalpha(*_str) && *_str != '_')
|
|
|
|
CV_Error_( CV_StsError, ("Incorrect element name %s", _str) );
|
|
|
|
fs.elname = str;
|
|
|
|
fs.state = VALUE_EXPECTED + INSIDE_MAP;
|
|
|
|
}
|
|
|
|
else if( (fs.state & 3) == VALUE_EXPECTED )
|
|
|
|
{
|
|
|
|
if( *_str == '{' || *_str == '[' )
|
|
|
|
{
|
|
|
|
fs.structs.push_back(*_str);
|
|
|
|
int flags = *_str++ == '{' ? CV_NODE_MAP : CV_NODE_SEQ;
|
|
|
|
fs.state = flags == CV_NODE_MAP ? INSIDE_MAP +
|
|
|
|
NAME_EXPECTED : VALUE_EXPECTED;
|
|
|
|
if( *_str == ':' )
|
|
|
|
{
|
|
|
|
flags |= CV_NODE_FLOW;
|
|
|
|
_str++;
|
|
|
|
}
|
|
|
|
cvStartWriteStruct( *fs, fs.elname.size() > 0 ? fs.elname.c_str() : 0,
|
|
|
|
flags, *_str ? _str : 0 );
|
|
|
|
fs.elname = String();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
write( fs, fs.elname, (_str[0] == '\\' && (_str[1] == '{' || _str[1] == '}' ||
|
|
|
|
_str[1] == '[' || _str[1] == ']')) ? String(_str+1) : str );
|
|
|
|
if( fs.state == INSIDE_MAP + VALUE_EXPECTED )
|
|
|
|
fs.state = INSIDE_MAP + NAME_EXPECTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
CV_Error( CV_StsError, "Invalid fs.state" );
|
|
|
|
return fs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FileStorage::writeRaw( const String& fmt, const uchar* vec, size_t len )
|
|
|
|
{
|
|
|
|
if( !isOpened() )
|
|
|
|
return;
|
|
|
|
CV_Assert(!fmt.empty());
|
|
|
|
size_t elemSize = ::icvCalcStructSize(fmt.c_str(), 0);
|
|
|
|
CV_Assert( len % elemSize == 0 );
|
|
|
|
cvWriteRawData( fs, vec, (int)(len/elemSize), fmt.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FileStorage::writeObj( const String& name, const void* obj )
|
|
|
|
{
|
|
|
|
if( !isOpened() )
|
|
|
|
return;
|
|
|
|
cvWrite( fs, name.size() > 0 ? name.c_str() : 0, obj );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FileStorage::write( const String& name, int val )
|
|
|
|
{
|
|
|
|
cvWriteInt(fs, name.c_str(), val);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStorage::write( const String& name, double val )
|
|
|
|
{
|
|
|
|
cvWriteReal(fs, name.c_str(), val);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStorage::write( const String& name, const String& val )
|
|
|
|
{
|
|
|
|
cvWriteString(fs, name.c_str(), val.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStorage::write( const String& name, InputArray val )
|
|
|
|
{
|
|
|
|
if(state & INSIDE_MAP)
|
|
|
|
*this << name;
|
|
|
|
*this << val.getMat();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStorage::writeComment( const String& comment, bool append )
|
|
|
|
{
|
|
|
|
cvWriteComment(fs, comment.c_str(), append ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStorage::startWriteStruct(const String& name, int flags, const String& typeName)
|
|
|
|
{
|
|
|
|
int struct_type = flags & FileNode::TYPE_MASK;
|
|
|
|
bool isflow = (flags & FileNode::FLOW) != 0;
|
|
|
|
CV_Assert(struct_type == FileNode::SEQ || struct_type == FileNode::MAP);
|
|
|
|
char strbegin_[] = { (struct_type == FileNode::SEQ ? '[' : '{'), (isflow ? ':' : '\0'), '\0' };
|
|
|
|
String strbegin = strbegin_;
|
|
|
|
if (!typeName.empty())
|
|
|
|
strbegin += typeName;
|
|
|
|
*this << name << strbegin;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileStorage::endWriteStruct()
|
|
|
|
{
|
|
|
|
if( structs.empty() )
|
|
|
|
CV_Error( CV_StsError, "Extra endWriteStruct()" );
|
|
|
|
char openparen = structs.back();
|
|
|
|
*this << (openparen == '[' ? "]" : "}");
|
|
|
|
}
|
|
|
|
|
|
|
|
String FileStorage::getDefaultObjectName(const String& _filename)
|
|
|
|
{
|
|
|
|
static const char* stubname = "unnamed";
|
|
|
|
const char* filename = _filename.c_str();
|
|
|
|
const char* ptr2 = filename + _filename.size();
|
|
|
|
const char* ptr = ptr2 - 1;
|
|
|
|
cv::AutoBuffer<char> name_buf(_filename.size()+1);
|
|
|
|
|
|
|
|
while( ptr >= filename && *ptr != '\\' && *ptr != '/' && *ptr != ':' )
|
|
|
|
{
|
|
|
|
if( *ptr == '.' && (!*ptr2 || strncmp(ptr2, ".gz", 3) == 0) )
|
|
|
|
ptr2 = ptr;
|
|
|
|
ptr--;
|
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
if( ptr == ptr2 )
|
|
|
|
CV_Error( CV_StsBadArg, "Invalid filename" );
|
|
|
|
|
|
|
|
char* name = name_buf.data();
|
|
|
|
|
|
|
|
// name must start with letter or '_'
|
|
|
|
if( !cv_isalpha(*ptr) && *ptr!= '_' ){
|
|
|
|
*name++ = '_';
|
|
|
|
}
|
|
|
|
|
|
|
|
while( ptr < ptr2 )
|
|
|
|
{
|
|
|
|
char c = *ptr++;
|
|
|
|
if( !cv_isalnum(c) && c != '-' && c != '_' )
|
|
|
|
c = '_';
|
|
|
|
*name++ = c;
|
|
|
|
}
|
|
|
|
*name = '\0';
|
|
|
|
name = name_buf.data();
|
|
|
|
if( strcmp( name, "_" ) == 0 )
|
|
|
|
strcpy( name, stubname );
|
|
|
|
return String(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNode FileStorage::operator[](const String& nodename) const
|
|
|
|
{
|
|
|
|
return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename.c_str()));
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNode FileStorage::operator[](const char* nodename) const
|
|
|
|
{
|
|
|
|
return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename));
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNode FileNode::operator[](const String& nodename) const
|
|
|
|
{
|
|
|
|
return FileNode(fs, cvGetFileNodeByName(fs, node, nodename.c_str()));
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNode FileNode::operator[](const char* nodename) const
|
|
|
|
{
|
|
|
|
return FileNode(fs, cvGetFileNodeByName(fs, node, nodename));
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNode FileNode::operator[](int i) const
|
|
|
|
{
|
|
|
|
return isSeq() ? FileNode(fs, (CvFileNode*)cvGetSeqElem(node->data.seq, i)) :
|
|
|
|
i == 0 ? *this : FileNode();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<String> FileNode::keys() const
|
|
|
|
{
|
|
|
|
CV_Assert(isMap());
|
|
|
|
|
|
|
|
std::vector<String> res;
|
|
|
|
res.reserve(size());
|
|
|
|
for (FileNodeIterator it = begin(); it != end(); ++it)
|
|
|
|
{
|
|
|
|
res.push_back((*it).name());
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
String FileNode::name() const
|
|
|
|
{
|
|
|
|
const char* str;
|
|
|
|
return !node || (str = cvGetFileNodeName(node)) == 0 ? String() : String(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
void* FileNode::readObj() const
|
|
|
|
{
|
|
|
|
if( !fs || !node )
|
|
|
|
return 0;
|
|
|
|
return cvRead( (CvFileStorage*)fs, (CvFileNode*)node );
|
|
|
|
}
|
|
|
|
|
|
|
|
static const FileNodeIterator::SeqReader emptyReader = {0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
|
|
|
|
|
FileNodeIterator::FileNodeIterator()
|
|
|
|
{
|
|
|
|
fs = 0;
|
|
|
|
container = 0;
|
|
|
|
reader = emptyReader;
|
|
|
|
remaining = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNodeIterator::FileNodeIterator(const CvFileStorage* _fs,
|
|
|
|
const CvFileNode* _node, size_t _ofs)
|
|
|
|
{
|
|
|
|
reader = emptyReader;
|
|
|
|
if( _fs && _node && CV_NODE_TYPE(_node->tag) != CV_NODE_NONE )
|
|
|
|
{
|
|
|
|
int node_type = _node->tag & FileNode::TYPE_MASK;
|
|
|
|
fs = _fs;
|
|
|
|
container = _node;
|
|
|
|
if( !(_node->tag & FileNode::USER) && (node_type == FileNode::SEQ || node_type == FileNode::MAP) )
|
|
|
|
{
|
|
|
|
cvStartReadSeq( _node->data.seq, (CvSeqReader*)&reader );
|
|
|
|
remaining = FileNode(_fs, _node).size();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
reader.ptr = (schar*)_node;
|
|
|
|
reader.seq = 0;
|
|
|
|
remaining = 1;
|
|
|
|
}
|
|
|
|
(*this) += (int)_ofs;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fs = 0;
|
|
|
|
container = 0;
|
|
|
|
remaining = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNodeIterator::FileNodeIterator(const FileNodeIterator& it)
|
|
|
|
{
|
|
|
|
fs = it.fs;
|
|
|
|
container = it.container;
|
|
|
|
reader = it.reader;
|
|
|
|
remaining = it.remaining;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNodeIterator& FileNodeIterator::operator=(const FileNodeIterator& it)
|
|
|
|
{
|
|
|
|
fs = it.fs;
|
|
|
|
container = it.container;
|
|
|
|
reader = it.reader;
|
|
|
|
remaining = it.remaining;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNodeIterator& FileNodeIterator::operator ++()
|
|
|
|
{
|
|
|
|
if( remaining > 0 )
|
|
|
|
{
|
|
|
|
if( reader.seq )
|
|
|
|
{
|
|
|
|
if( ((reader).ptr += (((CvSeq*)reader.seq)->elem_size)) >= (reader).block_max )
|
|
|
|
{
|
|
|
|
cvChangeSeqBlock( (CvSeqReader*)&(reader), 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
remaining--;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNodeIterator FileNodeIterator::operator ++(int)
|
|
|
|
{
|
|
|
|
FileNodeIterator it = *this;
|
|
|
|
++(*this);
|
|
|
|
return it;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNodeIterator& FileNodeIterator::operator --()
|
|
|
|
{
|
|
|
|
if( remaining < FileNode(fs, container).size() )
|
|
|
|
{
|
|
|
|
if( reader.seq )
|
|
|
|
{
|
|
|
|
if( ((reader).ptr -= (((CvSeq*)reader.seq)->elem_size)) < (reader).block_min )
|
|
|
|
{
|
|
|
|
cvChangeSeqBlock( (CvSeqReader*)&(reader), -1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
remaining++;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNodeIterator FileNodeIterator::operator --(int)
|
|
|
|
{
|
|
|
|
FileNodeIterator it = *this;
|
|
|
|
--(*this);
|
|
|
|
return it;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNodeIterator& FileNodeIterator::operator += (int ofs)
|
|
|
|
{
|
|
|
|
if( ofs == 0 )
|
|
|
|
return *this;
|
|
|
|
if( ofs > 0 )
|
|
|
|
ofs = std::min(ofs, (int)remaining);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t count = FileNode(fs, container).size();
|
|
|
|
ofs = (int)(remaining - std::min(remaining - ofs, count));
|
|
|
|
}
|
|
|
|
remaining -= ofs;
|
|
|
|
if( reader.seq )
|
|
|
|
cvSetSeqReaderPos( (CvSeqReader*)&reader, ofs, 1 );
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNodeIterator& FileNodeIterator::operator -= (int ofs)
|
|
|
|
{
|
|
|
|
return operator += (-ofs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FileNodeIterator& FileNodeIterator::readRaw(const String& fmt, uchar* vec, size_t len)
|
|
|
|
{
|
|
|
|
CV_Assert(!fmt.empty());
|
|
|
|
if( fs && container && remaining > 0 && len > 0)
|
|
|
|
{
|
|
|
|
if (reader.seq)
|
|
|
|
{
|
|
|
|
size_t step = ::icvCalcStructSize(fmt.c_str(), 0);
|
|
|
|
if (len % step && len != (size_t)INT_MAX) // TODO remove compatibility hack
|
|
|
|
{
|
|
|
|
CV_PARSE_ERROR("readRaw: total byte size not match elememt size");
|
|
|
|
}
|
|
|
|
size_t maxCount = len / step;
|
|
|
|
int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2] = {};
|
|
|
|
int fmt_pair_count = icvDecodeFormat(fmt.c_str(), fmt_pairs, CV_FS_MAX_FMT_PAIRS);
|
|
|
|
int vecElems = 0;
|
|
|
|
for (int k = 0; k < fmt_pair_count; k++)
|
|
|
|
{
|
|
|
|
vecElems += fmt_pairs[k*2];
|
|
|
|
}
|
|
|
|
CV_Assert(vecElems > 0);
|
|
|
|
size_t count = std::min((size_t)remaining, (size_t)maxCount * vecElems);
|
|
|
|
cvReadRawDataSlice(fs, (CvSeqReader*)&reader, (int)count, vec, fmt.c_str());
|
|
|
|
remaining -= count;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cvReadRawData( fs, container, vec, fmt.c_str() );
|
|
|
|
remaining = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void write( FileStorage& fs, const String& name, int value )
|
|
|
|
{ cvWriteInt( *fs, name.size() ? name.c_str() : 0, value ); }
|
|
|
|
|
|
|
|
void write( FileStorage& fs, const String& name, float value )
|
|
|
|
{ cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
|
|
|
|
|
|
|
|
void write( FileStorage& fs, const String& name, double value )
|
|
|
|
{ cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
|
|
|
|
|
|
|
|
void write( FileStorage& fs, const String& name, const String& value )
|
|
|
|
{ cvWriteString( *fs, name.size() ? name.c_str() : 0, value.c_str() ); }
|
|
|
|
|
|
|
|
void writeScalar(FileStorage& fs, int value )
|
|
|
|
{ cvWriteInt( *fs, 0, value ); }
|
|
|
|
|
|
|
|
void writeScalar(FileStorage& fs, float value )
|
|
|
|
{ cvWriteReal( *fs, 0, value ); }
|
|
|
|
|
|
|
|
void writeScalar(FileStorage& fs, double value )
|
|
|
|
{ cvWriteReal( *fs, 0, value ); }
|
|
|
|
|
|
|
|
void writeScalar(FileStorage& fs, const String& value )
|
|
|
|
{ cvWriteString( *fs, 0, value.c_str() ); }
|
|
|
|
|
|
|
|
|
|
|
|
void write( FileStorage& fs, const String& name, const Mat& value )
|
|
|
|
{
|
|
|
|
if( value.dims <= 2 )
|
|
|
|
{
|
|
|
|
CvMat mat = cvMat(value);
|
|
|
|
cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CvMatND mat = cvMatND(value);
|
|
|
|
cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: the 4 functions below need to be implemented more efficiently
|
|
|
|
void write( FileStorage& fs, const String& name, const SparseMat& value )
|
|
|
|
{
|
|
|
|
Ptr<CvSparseMat> mat(cvCreateSparseMat(value));
|
|
|
|
cvWrite( *fs, name.size() ? name.c_str() : 0, mat );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal::WriteStructContext::WriteStructContext(FileStorage& _fs,
|
|
|
|
const String& name, int flags, const String& typeName) : fs(&_fs)
|
|
|
|
{
|
|
|
|
cvStartWriteStruct(**fs, !name.empty() ? name.c_str() : 0, flags,
|
|
|
|
!typeName.empty() ? typeName.c_str() : 0);
|
|
|
|
fs->elname = String();
|
|
|
|
if ((flags & FileNode::TYPE_MASK) == FileNode::SEQ)
|
|
|
|
{
|
|
|
|
fs->state = FileStorage::VALUE_EXPECTED;
|
|
|
|
fs->structs.push_back('[');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fs->state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
|
|
|
|
fs->structs.push_back('{');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal::WriteStructContext::~WriteStructContext()
|
|
|
|
{
|
|
|
|
cvEndWriteStruct(**fs);
|
|
|
|
fs->structs.pop_back();
|
|
|
|
fs->state = fs->structs.empty() || fs->structs.back() == '{' ?
|
|
|
|
FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP :
|
|
|
|
FileStorage::VALUE_EXPECTED;
|
|
|
|
fs->elname = String();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void read( const FileNode& node, Mat& mat, const Mat& default_mat )
|
|
|
|
{
|
|
|
|
if( node.empty() )
|
|
|
|
{
|
|
|
|
default_mat.copyTo(mat);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
void* obj = cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node);
|
|
|
|
if(CV_IS_MAT_HDR_Z(obj))
|
|
|
|
{
|
|
|
|
cvarrToMat(obj).copyTo(mat);
|
|
|
|
cvReleaseMat((CvMat**)&obj);
|
|
|
|
}
|
|
|
|
else if(CV_IS_MATND_HDR(obj))
|
|
|
|
{
|
|
|
|
cvarrToMat(obj).copyTo(mat);
|
|
|
|
cvReleaseMatND((CvMatND**)&obj);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cvRelease(&obj);
|
|
|
|
CV_Error(CV_StsBadArg, "Unknown array type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void read( const FileNode& node, SparseMat& mat, const SparseMat& default_mat )
|
|
|
|
{
|
|
|
|
if( node.empty() )
|
|
|
|
{
|
|
|
|
default_mat.copyTo(mat);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Ptr<CvSparseMat> m((CvSparseMat*)cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node));
|
|
|
|
CV_Assert(CV_IS_SPARSE_MAT(m));
|
|
|
|
m->copyToSparseMat(mat);
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_EXPORTS void read(const FileNode& node, KeyPoint& value, const KeyPoint& default_value)
|
|
|
|
{
|
|
|
|
if( node.empty() )
|
|
|
|
{
|
|
|
|
value = default_value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
node >> value;
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_EXPORTS void read(const FileNode& node, DMatch& value, const DMatch& default_value)
|
|
|
|
{
|
|
|
|
if( node.empty() )
|
|
|
|
{
|
|
|
|
value = default_value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
node >> value;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CV__LEGACY_PERSISTENCE
|
|
|
|
void write( FileStorage& fs, const String& name, const std::vector<KeyPoint>& vec)
|
|
|
|
{
|
|
|
|
// from template implementation
|
|
|
|
cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ);
|
|
|
|
write(fs, vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
void read(const FileNode& node, std::vector<KeyPoint>& keypoints)
|
|
|
|
{
|
|
|
|
FileNode first_node = *(node.begin());
|
|
|
|
if (first_node.isSeq())
|
|
|
|
{
|
|
|
|
// modern scheme
|
|
|
|
#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED
|
|
|
|
FileNodeIterator it = node.begin();
|
|
|
|
size_t total = (size_t)it.remaining;
|
|
|
|
keypoints.resize(total);
|
|
|
|
for (size_t i = 0; i < total; ++i, ++it)
|
|
|
|
{
|
|
|
|
(*it) >> keypoints[i];
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
FileNodeIterator it = node.begin();
|
|
|
|
it >> keypoints;
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
keypoints.clear();
|
|
|
|
FileNodeIterator it = node.begin(), it_end = node.end();
|
|
|
|
for( ; it != it_end; )
|
|
|
|
{
|
|
|
|
KeyPoint kpt;
|
|
|
|
it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id;
|
|
|
|
keypoints.push_back(kpt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void write( FileStorage& fs, const String& name, const std::vector<DMatch>& vec)
|
|
|
|
{
|
|
|
|
// from template implementation
|
|
|
|
cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ);
|
|
|
|
write(fs, vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
void read(const FileNode& node, std::vector<DMatch>& matches)
|
|
|
|
{
|
|
|
|
FileNode first_node = *(node.begin());
|
|
|
|
if (first_node.isSeq())
|
|
|
|
{
|
|
|
|
// modern scheme
|
|
|
|
#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED
|
|
|
|
FileNodeIterator it = node.begin();
|
|
|
|
size_t total = (size_t)it.remaining;
|
|
|
|
matches.resize(total);
|
|
|
|
for (size_t i = 0; i < total; ++i, ++it)
|
|
|
|
{
|
|
|
|
(*it) >> matches[i];
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
FileNodeIterator it = node.begin();
|
|
|
|
it >> matches;
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
matches.clear();
|
|
|
|
FileNodeIterator it = node.begin(), it_end = node.end();
|
|
|
|
for( ; it != it_end; )
|
|
|
|
{
|
|
|
|
DMatch m;
|
|
|
|
it >> m.queryIdx >> m.trainIdx >> m.imgIdx >> m.distance;
|
|
|
|
matches.push_back(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int FileNode::type() const { return !node ? NONE : (node->tag & TYPE_MASK); }
|
|
|
|
bool FileNode::isNamed() const { return !node ? false : (node->tag & NAMED) != 0; }
|
|
|
|
|
|
|
|
size_t FileNode::size() const
|
|
|
|
{
|
|
|
|
int t = type();
|
|
|
|
return t == MAP ? (size_t)((CvSet*)node->data.map)->active_count :
|
|
|
|
t == SEQ ? (size_t)node->data.seq->total : (size_t)!isNone();
|
|
|
|
}
|
|
|
|
|
|
|
|
void read(const FileNode& node, int& value, int default_value)
|
|
|
|
{
|
|
|
|
value = !node.node ? default_value :
|
|
|
|
CV_NODE_IS_INT(node.node->tag) ? node.node->data.i : std::numeric_limits<int>::max();
|
|
|
|
}
|
|
|
|
|
|
|
|
void read(const FileNode& node, float& value, float default_value)
|
|
|
|
{
|
|
|
|
value = !node.node ? default_value :
|
|
|
|
CV_NODE_IS_INT(node.node->tag) ? (float)node.node->data.i :
|
|
|
|
CV_NODE_IS_REAL(node.node->tag) ? saturate_cast<float>(node.node->data.f) : std::numeric_limits<float>::max();
|
|
|
|
}
|
|
|
|
|
|
|
|
void read(const FileNode& node, double& value, double default_value)
|
|
|
|
{
|
|
|
|
value = !node.node ? default_value :
|
|
|
|
CV_NODE_IS_INT(node.node->tag) ? (double)node.node->data.i :
|
|
|
|
CV_NODE_IS_REAL(node.node->tag) ? node.node->data.f : std::numeric_limits<double>::max();
|
|
|
|
}
|
|
|
|
|
|
|
|
void read(const FileNode& node, String& value, const String& default_value)
|
|
|
|
{
|
|
|
|
value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? String(node.node->data.str.ptr) : String();
|
|
|
|
}
|
|
|
|
|
|
|
|
void read(const FileNode& node, std::string& value, const std::string& default_value)
|
|
|
|
{
|
|
|
|
value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? std::string(node.node->data.str.ptr) : default_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // cv::
|