/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of the copyright holders may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ #include "precomp.hpp" namespace cv { using std::pair; template struct sorted_vector { sorted_vector() {} void clear() { vec.clear(); } size_t size() const { return vec.size(); } _ValueTp& operator [](size_t idx) { return vec[idx]; } const _ValueTp& operator [](size_t idx) const { return vec[idx]; } void add(const _KeyTp& k, const _ValueTp& val) { pair<_KeyTp, _ValueTp> p(k, val); vec.push_back(p); size_t i = vec.size()-1; for( ; i > 0 && vec[i].first < vec[i-1].first; i-- ) std::swap(vec[i-1], vec[i]); CV_Assert( i == 0 || vec[i].first != vec[i-1].first ); } bool find(const _KeyTp& key, _ValueTp& value) const { size_t a = 0, b = vec.size(); while( b > a ) { size_t c = (a + b)/2; if( vec[c].first < key ) a = c+1; else b = c; } if( a < vec.size() && vec[a].first == key ) { value = vec[a].second; return true; } return false; } void get_keys(vector<_KeyTp>& keys) const { size_t i = 0, n = vec.size(); keys.resize(n); for( i = 0; i < n; i++ ) keys[i] = vec[i].first; } vector > vec; }; template inline const _ValueTp* findstr(const sorted_vector& vec, const char* key) { if( !key ) return 0; size_t a = 0, b = vec.vec.size(); while( b > a ) { size_t c = (a + b)/2; if( strcmp(vec.vec[c].first.c_str(), key) < 0 ) a = c+1; else b = c; } if( ( a < vec.vec.size() ) && ( strcmp(vec.vec[a].first.c_str(), key) == 0 )) return &vec.vec[a].second; return 0; } Param::Param() { type = 0; offset = 0; readonly = false; getter = 0; setter = 0; } Param::Param(int _type, bool _readonly, int _offset, Algorithm::Getter _getter, Algorithm::Setter _setter, const string& _help) { type = _type; readonly = _readonly; offset = _offset; getter = _getter; setter = _setter; help = _help; } struct CV_EXPORTS AlgorithmInfoData { sorted_vector params; string _name; }; static sorted_vector& alglist() { static sorted_vector alglist_var; return alglist_var; } void Algorithm::getList(vector& algorithms) { alglist().get_keys(algorithms); } Ptr Algorithm::_create(const string& name) { Algorithm::Constructor c = 0; if( !alglist().find(name, c) ) return Ptr(); return c(); } Algorithm::Algorithm() { } Algorithm::~Algorithm() { } string Algorithm::name() const { return info()->name(); } void Algorithm::set(const string& parameter, int value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::set(const string& parameter, double value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::set(const string& parameter, bool value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::set(const string& parameter, const string& value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::set(const string& parameter, const Mat& value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::set(const string& parameter, const vector& value) { info()->set(this, parameter.c_str(), ParamType >::type, &value); } void Algorithm::set(const string& parameter, const Ptr& value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::set(const char* parameter, int value) { info()->set(this, parameter, ParamType::type, &value); } void Algorithm::set(const char* parameter, double value) { info()->set(this, parameter, ParamType::type, &value); } void Algorithm::set(const char* parameter, bool value) { info()->set(this, parameter, ParamType::type, &value); } void Algorithm::set(const char* parameter, const string& value) { info()->set(this, parameter, ParamType::type, &value); } void Algorithm::set(const char* parameter, const Mat& value) { info()->set(this, parameter, ParamType::type, &value); } void Algorithm::set(const char* parameter, const vector& value) { info()->set(this, parameter, ParamType >::type, &value); } void Algorithm::set(const char* parameter, const Ptr& value) { info()->set(this, parameter, ParamType::type, &value); } void Algorithm::setInt(const string& parameter, int value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::setDouble(const string& parameter, double value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::setBool(const string& parameter, bool value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::setString(const string& parameter, const string& value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::setMat(const string& parameter, const Mat& value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::setMatVector(const string& parameter, const vector& value) { info()->set(this, parameter.c_str(), ParamType >::type, &value); } void Algorithm::setAlgorithm(const string& parameter, const Ptr& value) { info()->set(this, parameter.c_str(), ParamType::type, &value); } void Algorithm::setInt(const char* parameter, int value) { info()->set(this, parameter, ParamType::type, &value); } void Algorithm::setDouble(const char* parameter, double value) { info()->set(this, parameter, ParamType::type, &value); } void Algorithm::setBool(const char* parameter, bool value) { info()->set(this, parameter, ParamType::type, &value); } void Algorithm::setString(const char* parameter, const string& value) { info()->set(this, parameter, ParamType::type, &value); } void Algorithm::setMat(const char* parameter, const Mat& value) { info()->set(this, parameter, ParamType::type, &value); } void Algorithm::setMatVector(const char* parameter, const vector& value) { info()->set(this, parameter, ParamType >::type, &value); } void Algorithm::setAlgorithm(const char* parameter, const Ptr& value) { info()->set(this, parameter, ParamType::type, &value); } int Algorithm::getInt(const string& parameter) const { return get(parameter); } double Algorithm::getDouble(const string& parameter) const { return get(parameter); } bool Algorithm::getBool(const string& parameter) const { return get(parameter); } string Algorithm::getString(const string& parameter) const { return get(parameter); } Mat Algorithm::getMat(const string& parameter) const { return get(parameter); } vector Algorithm::getMatVector(const string& parameter) const { return get >(parameter); } Ptr Algorithm::getAlgorithm(const string& parameter) const { return get(parameter); } string Algorithm::paramHelp(const string& parameter) const { return info()->paramHelp(parameter.c_str()); } int Algorithm::paramType(const string& parameter) const { return info()->paramType(parameter.c_str()); } int Algorithm::paramType(const char* parameter) const { return info()->paramType(parameter); } void Algorithm::getParams(vector& names) const { info()->getParams(names); } void Algorithm::write(FileStorage& fs) const { info()->write(this, fs); } void Algorithm::read(const FileNode& fn) { info()->read(this, fn); } AlgorithmInfo::AlgorithmInfo(const string& _name, Algorithm::Constructor create) { data = new AlgorithmInfoData; data->_name = _name; if (!alglist().find(_name, create)) alglist().add(_name, create); } AlgorithmInfo::~AlgorithmInfo() { delete data; } void AlgorithmInfo::write(const Algorithm* algo, FileStorage& fs) const { size_t i = 0, nparams = data->params.vec.size(); cv::write(fs, "name", algo->name()); for( i = 0; i < nparams; i++ ) { const Param& p = data->params.vec[i].second; const string& pname = data->params.vec[i].first; if( p.type == Param::INT ) cv::write(fs, pname, algo->get(pname)); else if( p.type == Param::BOOLEAN ) cv::write(fs, pname, (int)algo->get(pname)); else if( p.type == Param::REAL ) cv::write(fs, pname, algo->get(pname)); else if( p.type == Param::STRING ) cv::write(fs, pname, algo->get(pname)); else if( p.type == Param::MAT ) cv::write(fs, pname, algo->get(pname)); else if( p.type == Param::MAT_VECTOR ) cv::write(fs, pname, algo->get >(pname)); else if( p.type == Param::ALGORITHM ) { WriteStructContext ws(fs, pname, CV_NODE_MAP); Ptr nestedAlgo = algo->get(pname); nestedAlgo->write(fs); } else CV_Error( CV_StsUnsupportedFormat, "unknown/unsupported parameter type"); } } void AlgorithmInfo::read(Algorithm* algo, const FileNode& fn) const { size_t i = 0, nparams = data->params.vec.size(); AlgorithmInfo* info = algo->info(); for( i = 0; i < nparams; i++ ) { const Param& p = data->params.vec[i].second; const string& pname = data->params.vec[i].first; const FileNode n = fn[pname]; if( n.empty() ) continue; if( p.type == Param::INT ) { int val = (int)n; info->set(algo, pname.c_str(), p.type, &val, true); } else if( p.type == Param::BOOLEAN ) { bool val = (int)n != 0; info->set(algo, pname.c_str(), p.type, &val, true); } else if( p.type == Param::REAL ) { double val = (double)n; info->set(algo, pname.c_str(), p.type, &val, true); } else if( p.type == Param::STRING ) { string val = (string)n; info->set(algo, pname.c_str(), p.type, &val, true); } else if( p.type == Param::MAT ) { Mat m; cv::read(n, m); info->set(algo, pname.c_str(), p.type, &m, true); } else if( p.type == Param::MAT_VECTOR ) { vector mv; cv::read(n, mv); info->set(algo, pname.c_str(), p.type, &mv, true); } else if( p.type == Param::ALGORITHM ) { Ptr nestedAlgo = Algorithm::_create((string)n["name"]); CV_Assert( !nestedAlgo.empty() ); nestedAlgo->read(n); info->set(algo, pname.c_str(), p.type, &nestedAlgo, true); } else CV_Error( CV_StsUnsupportedFormat, "unknown/unsupported parameter type"); } } string AlgorithmInfo::name() const { return data->_name; } union GetSetParam { int (Algorithm::*get_int)() const; bool (Algorithm::*get_bool)() const; double (Algorithm::*get_double)() const; string (Algorithm::*get_string)() const; Mat (Algorithm::*get_mat)() const; vector (Algorithm::*get_mat_vector)() const; Ptr (Algorithm::*get_algo)() const; void (Algorithm::*set_int)(int); void (Algorithm::*set_bool)(bool); void (Algorithm::*set_double)(double); void (Algorithm::*set_string)(const string&); void (Algorithm::*set_mat)(const Mat&); void (Algorithm::*set_mat_vector)(const vector&); void (Algorithm::*set_algo)(const Ptr&); }; static string getNameOfType(int argType); static string getNameOfType(int argType) { switch(argType) { case Param::INT: return "integer"; case Param::SHORT: return "short"; case Param::BOOLEAN: return "boolean"; case Param::REAL: return "double"; case Param::STRING: return "string"; case Param::MAT: return "cv::Mat"; case Param::MAT_VECTOR: return "std::vector"; case Param::ALGORITHM: return "algorithm"; default: CV_Error(CV_StsBadArg, "Wrong argument type"); } return ""; } static string getErrorMessageForWrongArgumentInSetter(string algoName, string paramName, int paramType, int argType); static string getErrorMessageForWrongArgumentInSetter(string algoName, string paramName, int paramType, int argType) { string message = string("Argument error: the setter") + " method was called for the parameter '" + paramName + "' of the algorithm '" + algoName +"', the parameter has " + getNameOfType(paramType) + " type, "; if (paramType == Param::INT || paramType == Param::BOOLEAN || paramType == Param::REAL) { message += "so it should be set by integer, boolean, or double value, "; } else if (paramType == Param::SHORT) { message += "so it should be set by integer value, "; } message += "but the setter was called with " + getNameOfType(argType) + " value"; return message; } static string getErrorMessageForWrongArgumentInGetter(string algoName, string paramName, int paramType, int argType); static string getErrorMessageForWrongArgumentInGetter(string algoName, string paramName, int paramType, int argType) { string message = string("Argument error: the getter") + " method was called for the parameter '" + paramName + "' of the algorithm '" + algoName +"', the parameter has " + getNameOfType(paramType) + " type, "; if (paramType == Param::BOOLEAN) { message += "so it should be get as integer, boolean, or double value, "; } else if (paramType == Param::INT) { message += "so it should be get as integer or double value, "; } else if (paramType == Param::SHORT) { message += "so it should be get as integer value, "; } message += "but the getter was called to get a " + getNameOfType(argType) + " value"; return message; } void AlgorithmInfo::set(Algorithm* algo, const char* parameter, int argType, const void* value, bool force) const { const Param* p = findstr(data->params, parameter); if( !p ) CV_Error_( CV_StsBadArg, ("No parameter '%s' is found", parameter ? parameter : "") ); if( !force && p->readonly ) CV_Error_( CV_StsError, ("Parameter '%s' is readonly", parameter)); GetSetParam f; f.set_int = p->setter; if( argType == Param::INT || argType == Param::BOOLEAN || argType == Param::REAL ) { if ( !( p->type == Param::INT || p->type == Param::REAL || p->type == Param::BOOLEAN || (p->type == Param::SHORT && argType == Param::INT)) ) { string message = getErrorMessageForWrongArgumentInSetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } if( p->type == Param::INT ) { int val = argType == Param::INT ? *(const int*)value : argType == Param::BOOLEAN ? (int)*(const bool*)value : saturate_cast(*(const double*)value); if( p->setter ) (algo->*f.set_int)(val); else *(int*)((uchar*)algo + p->offset) = val; } else if( p->type == Param::SHORT ) { int val = *(const int*)value; if( p->setter ) (algo->*f.set_int)(val); else *(short*)((uchar*)algo + p->offset) = (short)val; } else if( p->type == Param::BOOLEAN ) { bool val = argType == Param::INT ? *(const int*)value != 0 : argType == Param::BOOLEAN ? *(const bool*)value : *(const double*)value != 0; if( p->setter ) (algo->*f.set_bool)(val); else *(bool*)((uchar*)algo + p->offset) = val; } else { double val = argType == Param::INT ? (double)*(const int*)value : argType == Param::BOOLEAN ? (double)*(const bool*)value : *(const double*)value; if( p->setter ) (algo->*f.set_double)(val); else *(double*)((uchar*)algo + p->offset) = val; } } else if( argType == Param::STRING ) { if( p->type != Param::STRING ) { string message = getErrorMessageForWrongArgumentInSetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } const string& val = *(const string*)value; if( p->setter ) (algo->*f.set_string)(val); else *(string*)((uchar*)algo + p->offset) = val; } else if( argType == Param::MAT ) { if( p->type != Param::MAT ) { string message = getErrorMessageForWrongArgumentInSetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } const Mat& val = *(const Mat*)value; if( p->setter ) (algo->*f.set_mat)(val); else *(Mat*)((uchar*)algo + p->offset) = val; } else if( argType == Param::MAT_VECTOR ) { if( p->type != Param::MAT_VECTOR ) { string message = getErrorMessageForWrongArgumentInSetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } const vector& val = *(const vector*)value; if( p->setter ) (algo->*f.set_mat_vector)(val); else *(vector*)((uchar*)algo + p->offset) = val; } else if( argType == Param::ALGORITHM ) { if( p->type != Param::ALGORITHM ) { string message = getErrorMessageForWrongArgumentInSetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } const Ptr& val = *(const Ptr*)value; if( p->setter ) (algo->*f.set_algo)(val); else *(Ptr*)((uchar*)algo + p->offset) = val; } else CV_Error(CV_StsBadArg, "Unknown/unsupported parameter type"); } void AlgorithmInfo::get(const Algorithm* algo, const char* parameter, int argType, void* value) const { const Param* p = findstr(data->params, parameter); if( !p ) CV_Error_( CV_StsBadArg, ("No parameter '%s' is found", parameter ? parameter : "") ); GetSetParam f; f.get_int = p->getter; if( argType == Param::INT || argType == Param::BOOLEAN || argType == Param::REAL ) { if( p->type == Param::INT ) { if (!( argType == Param::INT || argType == Param::REAL )) { string message = getErrorMessageForWrongArgumentInGetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } int val = p->getter ? (algo->*f.get_int)() : *(int*)((uchar*)algo + p->offset); if( argType == Param::INT ) *(int*)value = val; else *(double*)value = val; } else if( p->type == Param::SHORT ) { if( argType != Param::INT ) { string message = getErrorMessageForWrongArgumentInGetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } int val = p->getter ? (algo->*f.get_int)() : *(short*)((uchar*)algo + p->offset); *(int*)value = val; } else if( p->type == Param::BOOLEAN ) { if (!( argType == Param::INT || argType == Param::BOOLEAN || argType == Param::REAL )) { string message = getErrorMessageForWrongArgumentInGetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } bool val = p->getter ? (algo->*f.get_bool)() : *(bool*)((uchar*)algo + p->offset); if( argType == Param::INT ) *(int*)value = (int)val; else if( argType == Param::BOOLEAN ) *(bool*)value = val; else *(double*)value = (int)val; } else { if( argType != Param::REAL ) { string message = getErrorMessageForWrongArgumentInGetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } double val = p->getter ? (algo->*f.get_double)() : *(double*)((uchar*)algo + p->offset); *(double*)value = val; } } else if( argType == Param::STRING ) { if( p->type != Param::STRING ) { string message = getErrorMessageForWrongArgumentInGetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } *(string*)value = p->getter ? (algo->*f.get_string)() : *(string*)((uchar*)algo + p->offset); } else if( argType == Param::MAT ) { if( p->type != Param::MAT ) { string message = getErrorMessageForWrongArgumentInGetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } *(Mat*)value = p->getter ? (algo->*f.get_mat)() : *(Mat*)((uchar*)algo + p->offset); } else if( argType == Param::MAT_VECTOR ) { if( p->type != Param::MAT_VECTOR ) { string message = getErrorMessageForWrongArgumentInGetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } *(vector*)value = p->getter ? (algo->*f.get_mat_vector)() : *(vector*)((uchar*)algo + p->offset); } else if( argType == Param::ALGORITHM ) { if( p->type != Param::ALGORITHM ) { string message = getErrorMessageForWrongArgumentInGetter(algo->name(), parameter, p->type, argType); CV_Error(CV_StsBadArg, message); } *(Ptr*)value = p->getter ? (algo->*f.get_algo)() : *(Ptr*)((uchar*)algo + p->offset); } else CV_Error(CV_StsBadArg, "Unknown/unsupported parameter type"); } int AlgorithmInfo::paramType(const char* parameter) const { const Param* p = findstr(data->params, parameter); if( !p ) CV_Error_( CV_StsBadArg, ("No parameter '%s' is found", parameter ? parameter : "") ); return p->type; } string AlgorithmInfo::paramHelp(const char* parameter) const { const Param* p = findstr(data->params, parameter); if( !p ) CV_Error_( CV_StsBadArg, ("No parameter '%s' is found", parameter ? parameter : "") ); return p->help; } void AlgorithmInfo::getParams(vector& names) const { data->params.get_keys(names); } void AlgorithmInfo::addParam_(Algorithm& algo, const char* parameter, int argType, void* value, bool readOnly, Algorithm::Getter getter, Algorithm::Setter setter, const string& help) { CV_Assert( argType == Param::INT || argType == Param::BOOLEAN || argType == Param::REAL || argType == Param::STRING || argType == Param::MAT || argType == Param::MAT_VECTOR || argType == Param::ALGORITHM || argType == Param::SHORT ); data->params.add(string(parameter), Param(argType, readOnly, (int)((size_t)value - (size_t)(void*)&algo), getter, setter, help)); } void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, int& value, bool readOnly, int (Algorithm::*getter)(), void (Algorithm::*setter)(int), const string& help) { addParam_(algo, parameter, ParamType::type, &value, readOnly, (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); } void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, short& value, bool readOnly, int (Algorithm::*getter)(), void (Algorithm::*setter)(int), const string& help) { addParam_(algo, parameter, ParamType::type, &value, readOnly, (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); } void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, bool& value, bool readOnly, int (Algorithm::*getter)(), void (Algorithm::*setter)(int), const string& help) { addParam_(algo, parameter, ParamType::type, &value, readOnly, (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); } void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, double& value, bool readOnly, double (Algorithm::*getter)(), void (Algorithm::*setter)(double), const string& help) { addParam_(algo, parameter, ParamType::type, &value, readOnly, (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); } void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, string& value, bool readOnly, string (Algorithm::*getter)(), void (Algorithm::*setter)(const string&), const string& help) { addParam_(algo, parameter, ParamType::type, &value, readOnly, (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); } void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, Mat& value, bool readOnly, Mat (Algorithm::*getter)(), void (Algorithm::*setter)(const Mat&), const string& help) { addParam_(algo, parameter, ParamType::type, &value, readOnly, (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); } void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, vector& value, bool readOnly, vector (Algorithm::*getter)(), void (Algorithm::*setter)(const vector&), const string& help) { addParam_(algo, parameter, ParamType >::type, &value, readOnly, (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); } void AlgorithmInfo::addParam(Algorithm& algo, const char* parameter, Ptr& value, bool readOnly, Ptr (Algorithm::*getter)(), void (Algorithm::*setter)(const Ptr&), const string& help) { addParam_(algo, parameter, ParamType::type, &value, readOnly, (Algorithm::Getter)getter, (Algorithm::Setter)setter, help); } } /* End of file. */