Open Source Computer Vision Library https://opencv.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

716 lines
19 KiB

// 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::