提交 94760a5f 编写于 作者: K Kirill Kornyakov

command line parser added. Leonid Beynenson is original contributor of the...

command line parser added. Leonid Beynenson is original contributor of the class. Class will be used in samples for convenient (and unified) work with command arguments.
上级 aa1fac4c
......@@ -4166,6 +4166,132 @@ protected:
};
#endif
/*!
Command Line Parser
The class is used for reading command arguments.
Supports the following syntax:
//-k 10 1 2 --x 0.001 --size 640 480 --inputFile lena.jpg
int k = parser.get<int>("--k | -k", -1);
vector<int> kValues=parser.getVec<int>("--k | -k");
double x = parser.get<double>("--x");
cv::Size size = parser.get<cv::Size>("--size");
string inputFile = parser.get<string>("--inputFile");
*/
class CommandLineParser
{
public:
//! the default constructor
CommandLineParser(int argc, const char* argv[]);
//! allows to check if parameter is given
bool has(const std::string& keys) const;
//! get parameter
template<typename _Tp>
_Tp get(const std::string& name)
{
return fromStringsVec<_Tp>(getVec<std::string>(name));
}
//! get parameter with default value
template<typename _Tp>
_Tp get(const std::string& name, const _Tp& default_value)
{
if (!has(name))
return default_value;
return get<_Tp>(name);
}
//! get a vector of values for specified key
template<typename _Tp>
std::vector<_Tp> getVec(const std::string& keys);
protected:
std::map<std::string, std::vector<std::string> > data;
template<typename _Tp>
static _Tp fromStringSimple(const std::string& str)//the default conversion function
{
_Tp res;
std::stringstream s1(str);
s1 >> res;
return res;
}
template<typename _Tp>
static _Tp fromString(const std::string& str)
{
return fromStringSimple<_Tp>(str);
}
template<typename _Tp>
static _Tp fromStringNumber(const std::string& str)//the default conversion function for numbers
{
_Tp dummy_val=0; dummy_val+=1;
if (str.empty())
CV_Error(CV_StsParseError, "Empty string cannot be converted to a number");
const char* c_str=str.c_str();
if((!isdigit(c_str[0]))
&&
(
(c_str[0]!='-') || (strlen(c_str) <= 1) || ( !isdigit(c_str[1]) )
)
)
{
CV_Error(CV_StsParseError, "The string '"+ str +"' cannot be converted to a number");
}
return fromStringSimple<_Tp>(str);
}
template<typename _Tp>
static _Tp fromStringsVec(const std::vector<std::string>& vec_str)
{
if (vec_str.empty())
CV_Error(CV_StsParseError, "Cannot convert from an empty vector");
return fromString<_Tp>(vec_str[0]);
}
};
template<>
std::vector<std::string> CommandLineParser::getVec<std::string>(const std::string& keys);
template<typename _Tp>
std::vector<_Tp> CommandLineParser::getVec(const std::string& keys)
{
if (!has(keys))
return std::vector<_Tp>();
std::vector<std::string> v=getVec<std::string>(keys);
std::vector<_Tp> res;
for(size_t i=0; i < v.size(); i++)
{
_Tp val=fromString<_Tp>(v[i]);
res.push_back(val);
}
return res;
}
template<>
std::string CommandLineParser::fromString<std::string>(const std::string& str);
template<>
int CommandLineParser::fromString<int>(const std::string& str);
template<>
unsigned int CommandLineParser::fromString<unsigned int>(const std::string& str);
template<>
double CommandLineParser::fromString<double>(const std::string& str);
template<>
cv::Size CommandLineParser::fromStringsVec<cv::Size>(const std::vector<std::string>& str);
}
#endif // __cplusplus
......
#include "precomp.hpp"
using namespace std;
using namespace cv;
vector<string> split_string(const string& str, const string& delimiters)
{
vector<string> res;
string::size_type lastPos = str.find_first_not_of(delimiters, 0);
string::size_type pos = str.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos)
{
res.push_back(str.substr(lastPos, pos - lastPos));
lastPos = str.find_first_not_of(delimiters, pos);
pos = str.find_first_of(delimiters, lastPos);
}
return res;
}
void PreprocessArgs(int _argc, const char* _argv[], int& argc, char**& argv)
{
std::vector<std::string> buffer_vector;
std::string buffer_string;
std::string buffer2_string;
int find_symbol;
for (int i = 0; i < _argc; i++)
{
buffer_string = _argv[i];
find_symbol = buffer_string.find('=');
if (find_symbol == -1)
buffer_vector.push_back(buffer_string);
else if (find_symbol == 0 || find_symbol == (buffer_string.length() - 1))
{
buffer_string.erase(find_symbol, (find_symbol + 1));
buffer_vector.push_back(buffer_string);
}
else
{
buffer2_string = buffer_string;
buffer_string.erase(find_symbol);
buffer_vector.push_back(buffer_string);
buffer2_string.erase(0, find_symbol + 1);
buffer_vector.push_back(buffer2_string);
}
}
argc = buffer_vector.size();
argv = new char* [argc];
for (int i=0; i < argc; i++)
{
argv[i] = new char[buffer_vector[i].length() + 1];
memcpy(argv[i], buffer_vector[i].c_str(), buffer_vector[i].length() + 1);
}
}
CommandLineParser::CommandLineParser(int _argc, const char* _argv[])
{
std::string cur_name;
bool was_pushed=false;
int argc;
char** argv;
PreprocessArgs(_argc, _argv, argc, argv);
for(int i=1; i < argc; i++)
{
if(!argv[i])
break;
if( (argv[i][0]== '-') && (strlen(argv[i]) > 1) &&
((argv[i][1] < '0') || (argv[i][1] > '9')) )
{
if (!cur_name.empty() && !was_pushed)
{
data[cur_name].push_back("");
}
cur_name=argv[i];
was_pushed=false;
if (data.find(cur_name) != data.end())
{
string str_exception = "dublicating parameters for name='" + cur_name + "'";
CV_Error(CV_StsParseError, str_exception);
}
continue;
}
data[cur_name].push_back(argv[i]);
was_pushed=true;
}
if (!cur_name.empty() && !was_pushed)
data[cur_name].push_back("");
}
bool CommandLineParser::has(const std::string& keys) const
{
vector<string> names=split_string(keys, " |");
for(size_t j=0; j < names.size(); j++)
{
if (data.find(names[j])!=data.end())
return true;
}
return false;
}
template<>
std::vector<std::string> CommandLineParser::getVec<std::string>(const std::string& keys)
{
vector<string> names=split_string(keys, " |");
int found_index=-1;
for(size_t j=0; j < names.size(); j++)
{
const string& cur_name=names[j];
bool is_cur_found=has(cur_name);
if (is_cur_found && (found_index >= 0))
{
string str_exception = "dublicating parameters for "
"name='" + names[found_index] + "' and name='"+cur_name+"'";
CV_Error(CV_StsParseError, str_exception);
}
if (is_cur_found)
found_index=j;
}
if (found_index<0)
return vector<string>();
return data.find(names[found_index])->second;
}
template<>
std::string CommandLineParser::fromString<std::string>(const std::string& str)
{
return str;
}
template<>
int CommandLineParser::fromString<int>(const std::string& str)
{
return fromStringNumber<int>(str);
}
template<>
unsigned int CommandLineParser::fromString<unsigned int>(const std::string& str)
{
return fromStringNumber<unsigned int>(str);
}
template<>
double CommandLineParser::fromString<double>(const std::string& str)
{
return fromStringNumber<double>(str);
}
template<>
cv::Size CommandLineParser::fromStringsVec<cv::Size>(const std::vector<std::string>& vec_str)
{
if (vec_str.size() < 2)
CV_Error(CV_StsParseError, "Cannot convert vector of string to cv::Size : less than two strings");
cv::Size res;
res.width=fromString<int>(vec_str[0]);
res.height=fromString<int>(vec_str[1]);
return res;
}
#include <opencv2/core/core.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
......@@ -10,13 +11,13 @@ using namespace cv;
void help()
{
cout << "\nThis program demonstrates the cascade recognizer. Now you can use Haar or LBP features.\n"
cout << "\nThis program demonstrates the cascade classifier. Now you can use Haar or LBP features.\n"
"This classifier can recognize many ~rigid objects, it's most known use is for faces.\n"
"Usage:\n"
"./facedetect [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n"
" [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n"
" [--scale=<image scale greater or equal to 1, try 1.3 for example>\n"
" [filename|camera_index]\n\n"
" [--input=filename|camera_index]\n\n"
"see facedetect.cmd for one call:\n"
"./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye.xml\" --scale=1.3 \n"
"Hit any key to quit.\n"
......@@ -27,70 +28,42 @@ void detectAndDraw( Mat& img,
CascadeClassifier& cascade, CascadeClassifier& nestedCascade,
double scale);
String cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml";
String nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
int main( int argc, const char** argv )
{
CvCapture* capture = 0;
Mat frame, frameCopy, image;
const String scaleOpt = "--scale=";
size_t scaleOptLen = scaleOpt.length();
const String cascadeOpt = "--cascade=";
size_t cascadeOptLen = cascadeOpt.length();
const String nestedCascadeOpt = "--nested-cascade";
size_t nestedCascadeOptLen = nestedCascadeOpt.length();
String inputName;
help();
CascadeClassifier cascade, nestedCascade;
double scale = 1;
CommandLineParser parser(argc, argv);
for( int i = 1; i < argc; i++ )
{
cout << "Processing " << i << " " << argv[i] << endl;
if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 )
{
cascadeName.assign( argv[i] + cascadeOptLen );
cout << " from which we have cascadeName= " << cascadeName << endl;
}
else if( nestedCascadeOpt.compare( 0, nestedCascadeOptLen, argv[i], nestedCascadeOptLen ) == 0 )
{
if( argv[i][nestedCascadeOpt.length()] == '=' )
nestedCascadeName.assign( argv[i] + nestedCascadeOpt.length() + 1 );
if( !nestedCascade.load( nestedCascadeName ) )
cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
}
else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 )
{
if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 )
scale = 1;
cout << " from which we read scale = " << scale << endl;
}
else if( argv[i][0] == '-' )
{
cerr << "WARNING: Unknown option %s" << argv[i] << endl;
}
else
inputName.assign( argv[i] );
}
string cascadeName = parser.get<string>("--cascade", "../../data/haarcascades/haarcascade_frontalface_alt.xml");
if (!cascadeName.empty())
cout << " from which we have cascadeName= " << cascadeName << endl;
string nestedCascadeName = parser.get<string>("--nested-cascade", "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml");
if (!nestedCascadeName.empty())
cout << " from which we have nestedCascadeName= " << nestedCascadeName << endl;
double scale = parser.get<double>("--scale", 1.0);
string inputName = parser.get<string>("--input", "0"); //read from camera by default
CvCapture* capture = 0;
Mat frame, frameCopy, image;
CascadeClassifier cascade, nestedCascade;
if( !cascade.load( cascadeName ) )
{
cerr << "ERROR: Could not load classifier cascade" << endl;
cerr << "Usage: facedetect [--cascade=<cascade_path>]\n"
" [--nested-cascade[=nested_cascade_path]]\n"
" [--scale[=<image scale>\n"
" [filename|camera_index]\n" << endl ;
return -1;
}
if( !nestedCascade.load( nestedCascadeName ) )
cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') )
{
capture = cvCaptureFromCAM( inputName.empty() ? 0 : inputName.c_str()[0] - '0' );
int c = inputName.empty() ? 0 : inputName.c_str()[0] - '0' ;
if(!capture) cout << "Capture from CAM " << c << " didn't work" << endl;
if( !capture) cout << "Capture from CAM " << c << " didn't work" << endl;
}
else if( inputName.size() )
{
......@@ -98,14 +71,9 @@ int main( int argc, const char** argv )
if( image.empty() )
{
capture = cvCaptureFromAVI( inputName.c_str() );
if(!capture) cout << "Capture from AVI didn't work" << endl;
if( !capture ) cout << "Capture from AVI didn't work" << endl;
}
}
else
{
image = imread( "lena.jpg", 1 );
if(image.empty()) cout << "Couldn't read lena.jpg" << endl;
}
cvNamedWindow( "result", 1 );
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册