|
|
#include "easypr.h"
|
|
|
#include "easypr/util/switch.hpp"
|
|
|
|
|
|
#include "accuracy.hpp"
|
|
|
#include "chars.hpp"
|
|
|
#include "plate.hpp"
|
|
|
|
|
|
namespace easypr {
|
|
|
|
|
|
namespace demo {
|
|
|
|
|
|
// interactions
|
|
|
|
|
|
int accuracyTestMain() {
|
|
|
bool isExit = false;
|
|
|
while (!isExit) {
|
|
|
std::cout << "////////////////////////////////////" << std::endl;
|
|
|
const char* options[] = {"BatchTest Option:", "1. general_test;",
|
|
|
"2. native_test;", "3. 返回;", NULL};
|
|
|
Utils::print_str_lines(options);
|
|
|
std::cout << "////////////////////////////////////" << std::endl;
|
|
|
std::cout << "请选择一项操作:";
|
|
|
|
|
|
int select = -1;
|
|
|
bool isRepeat = true;
|
|
|
while (isRepeat) {
|
|
|
std::cin >> select;
|
|
|
isRepeat = false;
|
|
|
switch (select) {
|
|
|
case 1:
|
|
|
accuracyTest("resources/image/general_test");
|
|
|
break;
|
|
|
case 2:
|
|
|
accuracyTest("resources/image/native_test");
|
|
|
break;
|
|
|
case 3:
|
|
|
isExit = true;
|
|
|
break;
|
|
|
default:
|
|
|
std::cout << "输入错误,请重新输入:";
|
|
|
isRepeat = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int testMain() {
|
|
|
bool isExit = false;
|
|
|
while (!isExit) {
|
|
|
std::cout << "////////////////////////////////////" << std::endl;
|
|
|
const char* options[] = {
|
|
|
"EasyPR Test:", "1. test plate_locate(车牌定位);" /* 车牌定位 */,
|
|
|
"2. test plate_judge(车牌判断);" /* 车牌判断 */,
|
|
|
"3. test plate_detect(车牌检测);" /* 车牌检测(包含车牌定位与车牌判断) */,
|
|
|
"4. test chars_segment(字符分隔);" /* 字符分隔 */,
|
|
|
"5. test chars_identify(字符鉴别);" /* 字符鉴别 */,
|
|
|
"6. test chars_recognise(字符识别);" /* 字符识别(包含字符分隔与字符鉴别) */,
|
|
|
"7. test plate_recognize(车牌识别);" /* 车牌识别 */,
|
|
|
"8. test all(测试全部);" /* 以上全部 */, "9. 返回;" /* 退出 */, NULL};
|
|
|
Utils::print_str_lines(options);
|
|
|
std::cout << "////////////////////////////////////" << std::endl;
|
|
|
std::cout << "请选择一项操作:";
|
|
|
|
|
|
int select = -1;
|
|
|
bool isRepeat = true;
|
|
|
while (isRepeat) {
|
|
|
std::cin >> select;
|
|
|
isRepeat = false;
|
|
|
switch (select) {
|
|
|
case 1:
|
|
|
assert(test_plate_locate() == 0);
|
|
|
break;
|
|
|
case 2:
|
|
|
assert(test_plate_judge() == 0);
|
|
|
break;
|
|
|
case 3:
|
|
|
assert(test_plate_detect() == 0);
|
|
|
break;
|
|
|
case 4:
|
|
|
assert(test_chars_segment() == 0);
|
|
|
break;
|
|
|
case 5:
|
|
|
assert(test_chars_identify() == 0);
|
|
|
break;
|
|
|
case 6:
|
|
|
assert(test_chars_recognise() == 0);
|
|
|
break;
|
|
|
case 7:
|
|
|
assert(test_plate_recognize() == 0);
|
|
|
break;
|
|
|
case 8:
|
|
|
assert(test_plate_locate() == 0);
|
|
|
assert(test_plate_judge() == 0);
|
|
|
assert(test_plate_detect() == 0);
|
|
|
|
|
|
assert(test_chars_segment() == 0);
|
|
|
assert(test_chars_identify() == 0);
|
|
|
assert(test_chars_recognise() == 0);
|
|
|
|
|
|
assert(test_plate_recognize() == 0);
|
|
|
break;
|
|
|
case 9:
|
|
|
isExit = true;
|
|
|
break;
|
|
|
default:
|
|
|
std::cout << "输入错误,请重新输入:";
|
|
|
isRepeat = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
} // namespace demo
|
|
|
|
|
|
} // namespace easypr
|
|
|
|
|
|
void command_line_handler(int argc, const char* argv[]) {
|
|
|
program_options::Generator options;
|
|
|
|
|
|
options.add_subroutine("svm", "svm operations").make_usage("Usage:");
|
|
|
{
|
|
|
/* ------------------------------------------
|
|
|
| SVM Training operations
|
|
|
| ------------------------------------------
|
|
|
|
|
|
|
| $ demo svm --plates=path/to/plates/ [--test] --svm=save/to/svm.xml
|
|
|
|
|
|
|
| ------------------------------------------
|
|
|
*/
|
|
|
options("h,help", "show help information");
|
|
|
options(",plates", "",
|
|
|
"a folder contains both forward data and inverse data in the "
|
|
|
"separated subfolders");
|
|
|
options(",svm", easypr::kDefaultSvmPath, "the svm model file");
|
|
|
options("t,test", "run tests in --plates");
|
|
|
}
|
|
|
|
|
|
options.add_subroutine("ann", "ann operation").make_usage("Usages:");
|
|
|
{
|
|
|
/* ------------------------------------------
|
|
|
| ANN_MLP Training operations
|
|
|
| ------------------------------------------
|
|
|
|
|
|
|
| $ demo ann --zh-chars=zhchars/ --en-chars=enchars/ --ann=save/to/ann.xml
|
|
|
|
|
|
|
| ------------------------------------------
|
|
|
*/
|
|
|
options("h,help", "show help information");
|
|
|
options(",chars", "",
|
|
|
"the folder contains character sub-folders, with each folder"
|
|
|
"named by label defined in include/easypr/config.h");
|
|
|
options(",ann", easypr::kDefaultAnnPath,
|
|
|
"the ann model file you want to save");
|
|
|
options("t,test", "run test in --chars");
|
|
|
}
|
|
|
|
|
|
options.add_subroutine("locate", "locate plates in an image")
|
|
|
.make_usage("Usage:");
|
|
|
{
|
|
|
/* ------------------------------------------
|
|
|
| Plate locating operations
|
|
|
| ------------------------------------------
|
|
|
|
|
|
|
| $ demo locate -f file
|
|
|
|
|
|
|
| ------------------------------------------
|
|
|
*/
|
|
|
options("h,help", "show help information");
|
|
|
options("f,file", "",
|
|
|
"the target picture which contains one or more plates");
|
|
|
}
|
|
|
|
|
|
options.add_subroutine(
|
|
|
"judge", "determine whether an image block is the license plate")
|
|
|
.make_usage("Usage:");
|
|
|
{
|
|
|
/* ------------------------------------------
|
|
|
| Plate judge operations
|
|
|
| ------------------------------------------
|
|
|
|
|
|
|
| $ demo judge -f file --svm resources/model/svm.xml
|
|
|
|
|
|
|
| ------------------------------------------
|
|
|
*/
|
|
|
options("h,help", "show help information");
|
|
|
options("f,file", "the target image block");
|
|
|
options(",svm", easypr::kDefaultSvmPath, "the svm model file");
|
|
|
}
|
|
|
|
|
|
options.add_subroutine("recognize", "plate recognition").make_usage("Usage:");
|
|
|
{
|
|
|
/* ------------------------------------------
|
|
|
| Plate recognize operations
|
|
|
| ------------------------------------------
|
|
|
|
|
|
|
| $ demo recognize -p file --svm resources/model/svm.xml
|
|
|
| --ann resources/model/ann.xml
|
|
|
| $ demo recognize -pb dir/ --svm resources/model/svm.xml
|
|
|
| --ann resources/model/ann.xml
|
|
|
|
|
|
|
| ------------------------------------------
|
|
|
*/
|
|
|
options("h,help", "show help information");
|
|
|
options("p,path", "", "where is the target picture or target folder");
|
|
|
options("b,batch", "do batch recognition, if set, --path means a folder");
|
|
|
options("c,color", "returns the plate color, blue or yellow");
|
|
|
options(",svm", easypr::kDefaultSvmPath, "the svm model file");
|
|
|
options(",ann", easypr::kDefaultAnnPath, "the ann model file");
|
|
|
}
|
|
|
|
|
|
auto parser = options.make_parser();
|
|
|
|
|
|
try {
|
|
|
parser->parse(argc, argv);
|
|
|
} catch (const std::exception& err) {
|
|
|
std::cout << err.what() << std::endl;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
auto subname = parser->get_subroutine_name();
|
|
|
|
|
|
program_options::select(subname)
|
|
|
.found("svm",
|
|
|
[&]() {
|
|
|
if (parser->has("help") || argc <= 2) {
|
|
|
std::cout << options("svm");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
easypr::SvmTrain svm(parser->get("plates")->c_str(),
|
|
|
parser->get("svm")->c_str());
|
|
|
|
|
|
if (parser->has("test")) {
|
|
|
svm.test();
|
|
|
} else {
|
|
|
svm.train();
|
|
|
}
|
|
|
})
|
|
|
.found("ann",
|
|
|
[&]() {
|
|
|
if (parser->has("help") || argc <= 2) {
|
|
|
std::cout << options("ann");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
assert(parser->has("chars"));
|
|
|
assert(parser->has("ann"));
|
|
|
|
|
|
easypr::AnnTrain ann(parser->get("chars")->c_str(),
|
|
|
parser->get("ann")->c_str());
|
|
|
|
|
|
if (parser->has("test")) {
|
|
|
ann.test();
|
|
|
} else {
|
|
|
ann.train();
|
|
|
}
|
|
|
})
|
|
|
.found("locate",
|
|
|
[&]() {
|
|
|
if (parser->has("help") || argc <= 2) {
|
|
|
std::cout << options("locate");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (parser->has("file")) {
|
|
|
easypr::api::plate_locate(parser->get("file")->val().c_str());
|
|
|
std::cout << "finished, results can be found in tmp/"
|
|
|
<< std::endl;
|
|
|
}
|
|
|
})
|
|
|
.found("judge",
|
|
|
[&]() {
|
|
|
if (parser->has("help") || argc <= 2) {
|
|
|
std::cout << options("judge");
|
|
|
std::cout << "Note that the input image's size should "
|
|
|
<< "be the same as the one you gived to svm train."
|
|
|
<< std::endl;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (parser->has("file")) {
|
|
|
assert(parser->has("file"));
|
|
|
assert(parser->has("svm"));
|
|
|
|
|
|
auto image = parser->get("file")->val();
|
|
|
auto svm = parser->get("svm")->val();
|
|
|
|
|
|
const char* true_or_false[2] = {"false", "true"};
|
|
|
|
|
|
std::cout << true_or_false[easypr::api::plate_judge(
|
|
|
image.c_str(), svm.c_str())]
|
|
|
<< std::endl;
|
|
|
}
|
|
|
})
|
|
|
.found("recognize",
|
|
|
[&]() {
|
|
|
if (parser->has("help") || argc <= 2) {
|
|
|
std::cout << options("recognize");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (parser->has("path")) {
|
|
|
if (parser->has("batch")) {
|
|
|
// batch testing
|
|
|
auto folder = parser->get("path")->val();
|
|
|
easypr::demo::accuracyTest(folder.c_str());
|
|
|
} else {
|
|
|
// single testing
|
|
|
auto image = parser->get("path")->val();
|
|
|
|
|
|
if (parser->has("color")) {
|
|
|
// return plate color
|
|
|
const char* colors[2] = {"blue", "yellow"};
|
|
|
std::cout
|
|
|
<< colors[easypr::api::get_plate_color(image.c_str())]
|
|
|
<< std::endl;
|
|
|
} else {
|
|
|
// return strings
|
|
|
auto svm = parser->get("svm")->val();
|
|
|
auto ann = parser->get("ann")->val();
|
|
|
|
|
|
auto results = easypr::api::plate_recognize(
|
|
|
image.c_str(), svm.c_str(), ann.c_str());
|
|
|
for (auto s : results) {
|
|
|
std::cout << s << std::endl;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
std::cout << "option 'file' cannot be empty." << std::endl;
|
|
|
}
|
|
|
})
|
|
|
.others([&]() {
|
|
|
// no case matched, print all commands.
|
|
|
std::cout << "There are several sub commands listed below, "
|
|
|
<< "choose one by typing:\n\n"
|
|
|
<< " " << easypr::utils::getFileName(argv[0])
|
|
|
<< " command [options]\n\n"
|
|
|
<< "The commands are:\n" << std::endl;
|
|
|
auto subs = options.get_subroutine_list();
|
|
|
for (auto sub : subs) {
|
|
|
fprintf(stdout, "%s %s\n", sub.first.c_str(), sub.second.c_str());
|
|
|
}
|
|
|
std::cout << std::endl;
|
|
|
});
|
|
|
}
|
|
|
|
|
|
int main(int argc, const char* argv[]) {
|
|
|
if (argc > 1) {
|
|
|
// handle command line execution.
|
|
|
command_line_handler(argc, argv);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
bool isExit = false;
|
|
|
while (!isExit) {
|
|
|
std::cout << "////////////////////////////////////" << std::endl;
|
|
|
const char* options[] = {"EasyPR Option:", "1. 测试;",
|
|
|
"2. 批量测试;", "3. SVM训练;",
|
|
|
"4. ANN训练;", "5. GDTS生成;",
|
|
|
"6. 开发团队;", "7. 感谢名单;",
|
|
|
"8. 退出;", NULL};
|
|
|
easypr::Utils::print_str_lines(options);
|
|
|
std::cout << "////////////////////////////////////" << std::endl;
|
|
|
std::cout << "请选择一项操作:";
|
|
|
|
|
|
int select = -1;
|
|
|
bool isRepeat = true;
|
|
|
while (isRepeat) {
|
|
|
std::cin >> select;
|
|
|
isRepeat = false;
|
|
|
switch (select) {
|
|
|
case 1:
|
|
|
easypr::demo::testMain();
|
|
|
break;
|
|
|
case 2:
|
|
|
easypr::demo::accuracyTestMain();
|
|
|
break;
|
|
|
case 3:
|
|
|
std::cout << "Run \"demo svm\" for more usage." << std::endl;
|
|
|
{
|
|
|
easypr::SvmTrain svm("tmp/svm", "tmp/svm.xml");
|
|
|
svm.train();
|
|
|
//easypr::svmTrain(true, false);
|
|
|
}
|
|
|
break;
|
|
|
case 4:
|
|
|
std::cout << "Run \"demo ann\" for more usage." << std::endl;
|
|
|
{
|
|
|
easypr::AnnTrain ann("tmp/ann", "tmp/ann.xml");
|
|
|
ann.train();
|
|
|
}
|
|
|
break;
|
|
|
case 5:
|
|
|
easypr::preprocess::generate_gdts();
|
|
|
break;
|
|
|
case 6: {
|
|
|
// 开发团队;
|
|
|
// 暂时不接受应聘信息,谢谢!
|
|
|
std::cout << std::endl;
|
|
|
const char* recruitment[] = {
|
|
|
"我们EasyPR团队目前有一个5人左右的小组在进行EasyPR后续版本的开发"
|
|
|
"工作。",
|
|
|
"人数已满,暂时不接受应聘信息,谢谢!",
|
|
|
//"如果你对本项目感兴趣,并且愿意为开源贡献一份力量,我们很欢迎你的"
|
|
|
//"加入。",
|
|
|
//"目前招聘的主要人才是:车牌定位,图像识别,深度学习,网站建设相关"
|
|
|
//"方面的牛人。",
|
|
|
//"如果你觉得自己符合条件,请发邮件到地址(easypr_dev@163.com)"
|
|
|
//",期待你的加入!",
|
|
|
NULL};
|
|
|
easypr::Utils::print_str_lines(recruitment);
|
|
|
std::cout << std::endl;
|
|
|
break;
|
|
|
}
|
|
|
case 7: {
|
|
|
// 感谢名单
|
|
|
std::cout << std::endl;
|
|
|
const char* thanks[] = {
|
|
|
"本项目在建设过程中,受到了很多人的帮助,其中以下是对本项目做出突"
|
|
|
"出贡献的",
|
|
|
"(贡献包括有益建议,代码调优,数据提供等等,排名按时间顺序):",
|
|
|
"taotao1233,邱锦山,唐大侠,jsxyhelu,如果有一天(zhoushiwei),",
|
|
|
"学习奋斗,袁承志,圣城小石匠,goldriver,Micooz,梦里时光,",
|
|
|
"Rain Wang,ahccoms,星夜落尘,海豚嘎嘎",
|
|
|
"还有很多的同学对本项目也给予了鼓励与支持,在此也一并表示真诚的谢"
|
|
|
"意!",
|
|
|
NULL};
|
|
|
easypr::Utils::print_str_lines(thanks);
|
|
|
std::cout << std::endl;
|
|
|
break;
|
|
|
}
|
|
|
case 8:
|
|
|
isExit = true;
|
|
|
break;
|
|
|
default:
|
|
|
std::cout << "输入错误,请重新输入:";
|
|
|
isRepeat = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
} |