From 62baca3efdd1a2904a8e9903465978de31f75bab Mon Sep 17 00:00:00 2001 From: Micooz Date: Fri, 6 Feb 2015 15:12:45 +0800 Subject: [PATCH] Add Feature: command line options bind. --- CMakeLists.txt | 7 +- EasyPR.vcxproj | 2 + EasyPR.vcxproj.filters | 6 + src/include/CParser.h | 127 +++++++++++++++++++++ src/main.cpp | 190 +++++++++++++++++++++++++++++++- src/util/CParser.cpp | 242 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 571 insertions(+), 3 deletions(-) create mode 100644 src/include/CParser.h create mode 100644 src/util/CParser.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ac98151..8acd793 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,9 @@ list(APPEND CMAKE_CXX_FLAGS "-std=c++0x") find_package(OpenCV REQUIRED) -aux_source_directory(./src SOURCE_FILES) +set(CMAKE_SOURCE_DIR ./src) + +include_directories(${CMAKE_SOURCE_DIR}/include/) set(SOURCE_FILES src/main.cpp @@ -28,7 +30,8 @@ set(SOURCE_FILES src/util/learn_prepare.cpp src/util/mc_data_prepare.cpp src/util/util.cpp + src/util/CParser.cpp ) add_executable(EasyPR ${SOURCE_FILES}) -target_link_libraries(EasyPR ${OpenCV_LIBS}) \ No newline at end of file +target_link_libraries(EasyPR ${OpenCV_LIBS}) diff --git a/EasyPR.vcxproj b/EasyPR.vcxproj index c273b91..01ddedc 100644 --- a/EasyPR.vcxproj +++ b/EasyPR.vcxproj @@ -92,6 +92,7 @@ + @@ -109,6 +110,7 @@ + diff --git a/EasyPR.vcxproj.filters b/EasyPR.vcxproj.filters index ebe558f..3a1f070 100644 --- a/EasyPR.vcxproj.filters +++ b/EasyPR.vcxproj.filters @@ -87,6 +87,9 @@ 源文件 + + 源文件 + @@ -119,5 +122,8 @@ 头文件 + + 头文件 + \ No newline at end of file diff --git a/src/include/CParser.h b/src/include/CParser.h new file mode 100644 index 0000000..62129dc --- /dev/null +++ b/src/include/CParser.h @@ -0,0 +1,127 @@ +////////////////////////////////////////////////////////////////////////// +// Name: CParser Header +// Date: 2015-02-05 +// Author: Micooz +// Copyright: Micooz +// Desciption: +// Defines OptionError, CParseItem, CParser +////////////////////////////////////////////////////////////////////////// +#ifndef __CPARSER_H__ +#define __CPARSER_H__ + +#include +#include +#include +#include +#include + +namespace easypr { + + // class OptionError + + class OptionError : public std::exception + { + public: + + explicit OptionError(const std::string &msg); + + const char *what() const throw(); + + ~OptionError() throw(); + + private: + std::string _msg; + }; + + // class CParseItem + + class CParseItem + { + public: + + explicit CParseItem(const std::string &val); + + /* + * dynamic type cast, support base data types including std::string + * return T + */ + template T as() + { + T r; + std::stringstream buf; + buf << _val; + buf >> r; + return r; + } + + /* + * alias of as() + * return std::string + */ + std::string val() const; + + private: + std::string _val; + }; + + // class CParser + + typedef std::vector ArgList; + typedef std::map ParseResult; + + class CParser + { + public: + + explicit CParser(int argc, char *argv[]); + + /* + * parse the cmd line + * return ParseResult* + */ + ParseResult *parse(); + + /* + * check whether a cretain option exist + * return bool + */ + bool has(const char *key); + + /* + * check whether a sequence of options exist + * example: has_or(3, "he", "or", "she"); + * return bool + */ + bool has_or(int n, ...); + + /* + * check whether a sequence of options exist + * example: has_and(3, "he", "and", "she"); + * return bool + */ + bool has_and(int n, ...); + + /* + * get the certain option's value + * return ParseItem* + */ + CParseItem *get(const std::string &key); + + /* + * output all ParseResult + */ + void dump(); + + /* + * release memory allocated in parse() + */ + ~CParser(); + + private: + ArgList _args; + ParseResult *_pr; + }; + +} + +#endif // __CPARSER_H__ diff --git a/src/main.cpp b/src/main.cpp index 805d25a..89c99ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,13 @@ #include "include/plate_recognize.h" #include "include/util.h" #include "include/features.h" +#include "include/CParser.h" using namespace easypr; int svmMain(); int acurayTestMain(); +void cmdMain(int argc, char *argv[]); namespace easypr { @@ -34,8 +36,14 @@ const string option[] = const int optionCount = 8; -int main() +int main(int argc, char *argv[]) { + if (argc > 1) { + //enable command line option + cmdMain(argc, argv); + return 0; + } + bool isExit = false; while (isExit != true) { @@ -242,3 +250,183 @@ int svmMain() // SVM ѵ //////////////////////////////////////////////////////////// + +// command line option support + +// the function declaration to be used, +// owing to the modules of the current EasyPR is separated, this is only temporary. + +int test_plate_locate(); +int test_plate_judge(); +int test_chars_segment(); +int test_chars_identify(); +int test_plate_detect(); +int test_chars_recognise(); +int test_plate_recognize(); + +void cmdMain(int argc, char *argv[]) +{ + const char *help[] = { + "EasyPR Usage: ", + "--help [ -h ] ʾ ", + "ģ ", + "--test_plate_locate [ -tpl ] ƶλ ", + "--test_plate_judge [ -tpj ] ж ", + "--test_plate_detect [ -tpd ] Ƽ ", + "--test_chars_segment [ -tcs ] ַָ ", + "--test_chars_identify [ -tci ] ַ ", + "--test_chars_recognize [ -tcr ] ַʶ ", + "--test_plate_recognize [ -tpr ] ʶ ", + "--test_all [ -ta ] ȫ ", + "--general_test [ -gt ] -general_test ", + "--native_test [ -nt ] -native_test ", + "SVMѵ", + "--svm_gen_learndata [ -sgl ] Learndata ", + "--svm_tag_learndata [ -stl ] ǩLearndata ", + "--svm_detect [ -sd ] Ƽ⣬-v-t ", + "--svm_divide [ -v ] ÷ָ ", + "--svm_train [ -t ] ѵ ", + "ANNѵδţ ", + "GDTS ", + "--gdts [ -gts ] GDTS ", + "--group Ŷ ", + "--thanks л ", + " ", + "Examples: ", + " $ ./EasyPR --test_plate_locate ", + "Will do the same as followings: ", + " $ ./EasyPR -tpl ", + " $ ./EasyPR -t -p -l ", + " $ ./EasyPR -ptl ", + " $ ./EasyPR -p -l -t ", + NULL + }; + + CParser parser(argc, argv); + + try { + + do { + if (parser.has_or(2, "help", "h") /* || argc < 2 */) { + int i = 0; + while (help[i]) { + cout << help[i++] << endl; + } + break; + } + + // tests + + if (parser.has_or(2, "test_plate_locate", "-tpl")) { + cout << (test_plate_locate() == 0 ? "passed" : "failed"); + break; + } + + if (parser.has_or(2, "test_plate_judge", "-tpj")) { + cout << (test_plate_judge() == 0 ? "passed" : "failed"); + break; + } + + if (parser.has_or(2, "test_plate_detect", "-tpd")) { + cout << (test_plate_detect() == 0 ? "passed" : "failed"); + break; + } + + if (parser.has_or(2, "test_chars_segment", "-tcs")) { + cout << (test_chars_segment() == 0 ? "passed" : "failed"); + break; + } + + if (parser.has_or(2, "test_chars_identify", "-tci")) { + cout << (test_chars_identify() == 0 ? "passed" : "failed"); + break; + } + + if (parser.has_or(2, "test_chars_recognize", "-tcr")) { + cout << (test_chars_recognise() == 0 ? "passed" : "failed"); + break; + } + + if (parser.has_or(2, "test_plate_recognize", "-tpr")) { + cout << (test_plate_recognize() == 0 ? "passed" : "failed"); + break; + } + + if (parser.has_or(2, "test_all", "-ta")) { + cout << "test_plate_locate " << (test_plate_locate() == 0 ? "passed" : "failed") << endl; + cout << "test_plate_judge " << (test_plate_judge() == 0 ? "passed" : "failed") << endl; + cout << "test_chars_segment " << (test_chars_segment() == 0 ? "passed" : "failed") << endl; + cout << "test_chars_identify " << (test_chars_identify() == 0 ? "passed" : "failed") << endl; + cout << "test_plate_detect " << (test_plate_detect() == 0 ? "passed" : "failed") << endl; + cout << "test_chars_recognize " << (test_chars_recognise() == 0 ? "passed" : "failed") << endl; + cout << "test_plate_recognize " << (test_plate_recognize() == 0 ? "passed" : "failed") << endl; + cout << "test_plate_locate " << (test_plate_locate() == 0 ? "passed" : "failed") << endl; + break; + } + + // batch testing + + if (parser.has_or(2, "general_test", "-gt")) { + acurayTest(GENERAL_TEST_PATH); + break; + } + + if (parser.has_or(2, "native_test", "-nt")) { + acurayTest(NATIVE_TEST_PATH); + break; + } + + // svm trains + + if (parser.has_or(2, "svm_gen_learndata", "-sgl")) { + getLearnData(); + break; + } + + if (parser.has_or(2, "svm_tag_learndata", "-stl")) { + label_data(); + break; + } + + if (parser.has_or(2, "svm_detect", "-sd")) { + svmTrain(parser.has_or(2, "v", "svm_divide"), parser.has_or(2, "t", "svm_train")); + break; + } + + // GDTS + + if (parser.has_or(2, "gdts", "gts")) { + general_test(); + break; + } + + // + + if (parser.has("group")) { + // Ŷ; + cout << endl; + cout << "EasyPRŶĿǰһ5ҵСڽEasyPR汾Ŀ" << endl; + cout << "ԱĿȤԸΪԴһǺܻӭļ롣" << endl; + cout << "ĿǰƸҪ˲ǣƶλͼʶѧϰվطţˡ" << endl; + cout << "Լ뷢ʼַ(easypr_dev@163.com)ڴļ룡" << endl; + cout << endl; + break; + } + + if (parser.has("thanks")) { + // л + cout << endl; + cout << "ĿڽУܵ˺ܶ˵İǶԱĿͻ׵" << endl; + cout << "(װ潨飬ţṩȵ,ʱ˳)" << endl; + cout << "taotao1233ƴjsxyheluһ(zhoushiwei)ѧϰܶԬ־ʥСʯgoldriverMicoozʱ⣬Rain Wang" << endl; + cout << "кܶͬѧԱĿҲ˹֧֣ڴҲһʾϵл⣡" << endl; + cout << endl; + break; + } + + } while(false); + + } catch (const std::exception &err) { + cout << err.what() << endl; + } +} diff --git a/src/util/CParser.cpp b/src/util/CParser.cpp new file mode 100644 index 0000000..700d984 --- /dev/null +++ b/src/util/CParser.cpp @@ -0,0 +1,242 @@ +#include +#include +#include "../include/CParser.h" + +using namespace easypr; +using namespace std; + +// class OptionError + +OptionError::OptionError(const string &msg) + : _msg(msg) +{ + +} + +const char * +OptionError::what() const throw() +{ + string msg; + msg.append("Command line parse error: ").append(_msg).push_back('.'); + return msg.c_str(); +} + +OptionError::~OptionError() throw() +{ + +} + + +// class CCParseItem + +CParseItem::CParseItem(const string &val) + : _val(val) +{ + +} + +CParseItem * +CParser::get(const string &key) +{ + if (_pr->count(key)) { + return (*_pr)[key]; + } + return NULL; +} + +string +CParseItem::val() const +{ + return _val; +} + + +// class CParser + +CParser::CParser(int argc, char *argv[]) + : _pr(NULL) +{ + _args.reserve(argc); + + for (int i = 0; i < argc; ++i) { + _args.push_back(argv[i]); + } + // to make it easier, parse automatically + this->parse(); +} + +ParseResult * +CParser::parse() +{ + if (_pr) { + return _pr; + } + + ArgList::iterator ibegin = _args.begin() + 1; // ignore the first cmd name + ArgList::iterator iend = _args.end(); + ArgList::iterator it = ibegin; + + _pr = new ParseResult; + + string block; + string previous(*ibegin); + + for ( ; it != iend; ++it) { + block.assign(*it); + + switch (block.size()) { + case 1: + if (block == "-") { + throw OptionError("single '-' is not allowed"); + } + break; + case 2: + if (block[0] == '-' ) { + if (block[1] == '-') { + throw OptionError("option '--' is incomplete"); + } else { + // single option + // etc: ./exec -s + (*_pr)[block.substr(1)] = NULL; + } + } + break; + default: // >=3 + if (block[0] == '-') { + if (block[1] == '-') { + // a long format option + // etc: ./exec --option + (*_pr)[block.substr(2)] = NULL; + } else { + // a conbination options + // etc: ./exec -ab[...] + string::iterator tbegin = block.begin() + 1; // ignore the first '-' + string::iterator tend = block.end(); + string::iterator t = tbegin; + + for (; t != tend; ++t) { + string key; + key.push_back(*t); + (*_pr)[key] = NULL; + } + } + } + break; + }// switch + + if (block[0] != '-' + && previous != block //not the first option + ) { + // it's the value of previous option. + // etc: ./exec -o [...] + // etc: ./exec -opq [...] + + if (previous[0] != '-') { + // previous is not an option, error occur + // etc: ./exec abc def + throw OptionError("'" + block + "' is not allowed here"); + } + + string key; + key.push_back(*(previous.end() - 1)); + + if (_pr->count(key)) { + (*_pr)[key] = new CParseItem(block); + } + } + + previous = block; + }// for + + return _pr; +} + +bool +CParser::has(const char *key) +{ + string skey(key); + + if (_pr && !skey.empty()) { + if (skey[0] == '-') { + //check conbination options, etc: CParser::has("-xyz") + for (size_t i = 1; i < skey.size(); ++i) { + string tkey; + tkey.push_back(skey[i]); + if (!_pr->count(tkey)) { + return false; + } + } + return true; + } else { + // check single option, etc: CParser::has("x") + return _pr->count(skey); + } + } + return false; +} + +bool +CParser::has_or(int n, ...) +{ + va_list keys; + va_start(keys, n); + while (n--) { + const char *key = va_arg(keys, const char *); + if (this->has(key)) { + return true; + } + } + va_end(keys); + return false; +} + +bool +CParser::has_and(int n, ...) +{ + va_list keys; + va_start(keys, n); + while (n--) { + const char *key = va_arg(keys, const char *); + if (!this->has(key)) { + return false; + } + } + va_end(keys); + return true; +} + +void +CParser::dump() +{ + if (_pr) { + ParseResult::iterator ibegin = _pr->begin(); + ParseResult::iterator iend = _pr->end(); + ParseResult::iterator it = ibegin; + for (; it != iend; ++it) { + cout << it->first; + if (it->second) { + cout << " = " << it->second->val() << endl; + } else { + cout << " set" << endl; + } + } + } +} + +CParser::~CParser() +{ + if (_pr) { + ParseResult::iterator ibegin = _pr->begin(); + ParseResult::iterator iend = _pr->end(); + ParseResult::iterator it = ibegin; + for (; it != iend; ++it) { + CParseItem *item = it->second; + if (item) { + delete item; + item = NULL; + } + } + delete _pr; + _pr = NULL; + } +}