Merge branch 'master' of https://github.com/liuruoze/EasyPR into linux_dev

Conflicts:
	src/test/accuracy_test.cpp
	src/util/general_test_prepare.cpp
1.3
Micooz 10 years ago
commit 374557fdaf

1
.gitignore vendored

@ -14,6 +14,7 @@ Thumbs.db
[Rr]elease/
[Rr]eleases/
experiment/
experi/
bak/
x64/
x86/

@ -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})
target_link_libraries(EasyPR ${OpenCV_LIBS})

@ -92,6 +92,7 @@
<ClCompile Include="src\test\accuracy_test.cpp" />
<ClCompile Include="src\train\ann_train.cpp" />
<ClCompile Include="src\train\svm_train.cpp" />
<ClCompile Include="src\util\CParser.cpp" />
<ClCompile Include="src\util\deface.cpp" />
<ClCompile Include="src\util\general_test_prepare.cpp" />
<ClCompile Include="src\util\generate_gdts.cpp" />
@ -109,6 +110,7 @@
<ClInclude Include="src\include\chars_identify.h" />
<ClInclude Include="src\include\chars_recognise.h" />
<ClInclude Include="src\include\chars_segment.h" />
<ClInclude Include="src\include\CParser.h" />
<ClInclude Include="src\include\features.h" />
<ClInclude Include="src\include\plate_detect.h" />
<ClInclude Include="src\include\plate_judge.h" />

@ -87,6 +87,9 @@
<ClCompile Include="src\util\general_test_prepare.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="src\util\CParser.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\include\chars_identify.h">
@ -119,5 +122,8 @@
<ClInclude Include="src\include\features.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="src\include\CParser.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

@ -77,7 +77,7 @@ int CPlateJudge::plateJudge(const vector<Mat>& inVec,
for (int j = 0; j < num; j++)
{
Mat inMat = inVec[j];
int response = -1;
plateJudge(inMat, response);

@ -89,6 +89,7 @@ bool CPlateLocate::verifySizes(RotatedRect mr)
Mat CPlateLocate::showResultMat(Mat src, Size rect_size, Point2f center, int index)
{
Mat img_crop;
getRectSubPix(src, rect_size, center, img_crop);
if(m_debug)
@ -278,8 +279,25 @@ int CPlateLocate::plateLocate(Mat src, vector<Mat>& resultVec)
//Create and rotate image
Mat rotmat = getRotationMatrix2D(minRect.center, angle, 1);
Mat img_rotated;
/*if(m_debug)
{
stringstream ss(stringstream::in | stringstream::out);
ss << "image/tmp/needRotate" << i << ".jpg";
imwrite(ss.str(), result);
}*/
warpAffine(src, img_rotated, rotmat, src.size(), CV_INTER_CUBIC);
/*if(m_debug)
{
stringstream ss(stringstream::in | stringstream::out);
ss << "image/tmp/img_rotated" << i << ".jpg";
imwrite(ss.str(), result);
}*/
//Mat resultMat(img_rotated, minRect);
Mat resultMat;
resultMat = showResultMat(img_rotated, rect_size, minRect.center, k++);

@ -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 <map>
#include <string>
#include <vector>
#include <sstream>
#include <stdexcept>
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<typename T> T as()
{
T r;
std::stringstream buf;
buf << _val;
buf >> r;
return r;
}
/*
* alias of as<std::string>()
* return std::string
*/
std::string val() const;
private:
std::string _val;
};
// class CParser
typedef std::vector<std::string> ArgList;
typedef std::map<std::string, CParseItem *> 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__

@ -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)
{
@ -71,8 +79,9 @@ int main()
case 4:
// TODO
break;
case 5:
general_test();
case 5:
//general_test();
generate_gdts();
break;
case 6:
// 开发团队;
@ -242,3 +251,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;
}
}

File diff suppressed because it is too large Load Diff

@ -315,7 +315,6 @@ int test_plate_recognize()
{
cout << "test_plate_recognize" << endl;
//Mat src = imread("image/plate_locate.jpg");
Mat src = imread("image/test.jpg");
CPlateRecognize pr;

@ -0,0 +1,242 @@
#include <iostream>
#include <stdarg.h>
#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;
}
}

@ -11,74 +11,77 @@ using namespace easypr;
extern const string GENERAL_TEST_PATH;
// TODO 将下面的路径改成你的
const string your_data_path = "F:/data/easypr-data/tmp-3";
const string src_path = "F:/data/easypr-data/tmp-5";
// TODO 将下面的路径改成你的
const string dst_path = "F:/data/easypr-data/tmp-6";
int general_test()
{
////获取该路径下的所有文件
vector<string> files;
getFiles(your_data_path, files);
CPlateLocate lo;
CPlateJudge ju;
CPlateRecognize pr;
pr.LoadANN("model/ann.xml");
pr.LoadSVM("model/svm.xml");
pr.setLifemode(true);
int size = files.size();
//int size = 200;
if (0 == size)
{
cout << "No File Found!" << endl;
return 0;
}
cout << "Begin to prepare general_test!" << endl;
for (int i = 0; i < size; i++)
{
string filepath = files[i].c_str();
cout << "------------------" << endl;
// EasyPR开始判断车牌
Mat src = imread(filepath);
vector<string> plateVec;
int result = pr.plateRecognize(src, plateVec);
if (result == 0)
{
int num = plateVec.size();
if (num == 0)
{
cout << ""<< "无车牌" <<endl;
}
else
{
cout << plateVec[0] <<endl;
string colorplate = plateVec[0];
// 输出"蓝牌:苏E7KU22"中冒号后面的车牌
vector<string> spilt_plate;
SplitString(colorplate, spilt_plate, ":");
int size = spilt_plate.size();
if (size == 2)
{
stringstream ss(stringstream::in | stringstream::out);
ss << "F:/data/easypr-data/tmp-4" << "/" << spilt_plate[size-1] << ".jpg";
imwrite(ss.str(), src);
}
}
}
else
{
cout << "错误码:" << result << endl;
}
}
return 0;
}
////获取该路径下的所有文件
vector<string> files;
getFiles(src_path, files);
CPlateLocate lo;
CPlateJudge ju;
CPlateRecognize pr;
pr.LoadANN("model/ann.xml");
pr.LoadSVM("model/svm.xml");
pr.setLifemode(true);
int size = files.size();
//int size = 200;
if (0 == size)
{
cout << "No File Found!" << endl;
return 0;
}
cout << "Begin to prepare general_test!" << endl;
for (int i = 0; i < size; i++)
{
string filepath = files[i].c_str();
cout << "------------------" << endl;
// EasyPR开始判断车牌
Mat src = imread(filepath);
vector<string> plateVec;
int result = pr.plateRecognize(src, plateVec);
if (result == 0)
{
int num = plateVec.size();
if (num == 0)
{
cout << ""<< "无车牌" <<endl;
}
else
{
cout << plateVec[0] <<endl;
string colorplate = plateVec[0];
// 输出"蓝牌:苏E7KU22"中冒号后面的车牌
vector<string> spilt_plate;
SplitString(colorplate, spilt_plate, ":");
int size = spilt_plate.size();
if (size == 2)
{
stringstream ss(stringstream::in | stringstream::out);
ss << dst_path << "/" << spilt_plate[size-1] << ".jpg";
imwrite(ss.str(), src);
}
}
}
else
{
cout << "错误码:" << result << endl;
}
}
return 0;
}

@ -118,6 +118,6 @@ Mat imageProcess(Mat img)
Rect rect(width*0.01, height*0.01, width*0.99, height*0.99);
Mat dst = img(rect);
GaussianBlur( dst, dst, Size(1, 1), 0, 0, BORDER_DEFAULT );
//GaussianBlur( dst, dst, Size(1, 1), 0, 0, BORDER_DEFAULT );
return dst;
}
Loading…
Cancel
Save