Merge branch 'master' of https://github.com/micooz/EasyPR into micooz-master

v1.6alpha
liuruoze 9 years ago
commit 75e797e6c1

7
.gitignore vendored

@ -5,18 +5,17 @@ resources/image/tmp/
*.sdf
*.opensdf
*.exe
*.dll
*.ilk
*.lib
*.pdb
*.ilk
demo
tmp
experi
#ignore thumbnails created by windows
Thumbs.db
#Ignore files build by Visual Studio
*.obj
*.user
*.aps
*.pch
@ -27,8 +26,6 @@ Thumbs.db
*.tlb
*.tlh
*.bak
*.cache
*.log
[Bb]in
[Dd]ebug*/
*.sbr

@ -16,7 +16,7 @@ endif()
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/local/opt/opencv3")
# opencv3 package required
find_package(OpenCV 3.0.0 REQUIRED)
find_package(OpenCV 3.1.0 REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
# easypr library
@ -40,6 +40,7 @@ set(SOURCE_FILES
src/preprocess/mc_data.cpp
src/util/util.cpp
src/util/program_options.cpp
src/util/kv.cpp
)
add_library(easypr STATIC ${SOURCE_FILES})

@ -75,6 +75,7 @@ EasyPR的resources/image/general_test文件夹下的图片数据遵循[GDSL协
| src | 所有源文件
| include | 所有头文件
| test | 测试程序
| etc | 中文字符映射表
| resources/model | 机器学习的模型
| resources/train | 训练数据与说明
| resources/image | 测试用的图片
@ -123,148 +124,7 @@ EasyPR的resources/image/general_test文件夹下的图片数据遵循[GDSL协
### 使用
EasyPR的所有源代码可在Github上的[项目主页](https://github.com/liuruoze/EasyPR)直接打包下载得到。
由于Github在中国有时下载速度较慢可以使用oschina的镜像[地址](http://git.oschina.net/easypr/EasyPR)来下载。
如果你熟悉git版本控制工具可以使用下面的命令来从Github里克隆代码
$ git clone https://github.com/liuruoze/EasyPR
EasyPR支持当前主流的操作系统通常不需要对源代码进行更改就可以编译运行尽管如此不同平台上IDE的配置也是有很大差异的下面主要说明WindowsLinux以及Mac OS下的编译方法。
**Note**: 无论在哪个平台使用EasyPR首先都要安装对应平台版本的[opencv](http://opencv.org/),建议使用正式稳定版本。
#### Windows
Windows下的配置建议使用最新的**Visual Studio 2013**版本。目前opencv3.0已经不支持vs2010vs2012对C++ 11支持的不足会存在编译问题。
在之前版本的使用和交流过程中我们发现很多同学对Visual Studio开发环境不甚了解甚至没有做过C++项目对EasyPR环境的配置存在很大的障碍。为此在新版本中我们特意准备了傻瓜式自动配置脚本来方便大家使用EasyPR。
**方法一(推荐)**
1. 首先你需要安装最新版本的[Python](https://www.python.org/downloads/)。将Python的安装目录默认安装在C:\Python34添加到系统环境变量PATH中。
2. 双击 `configure.py` 运行脚本,根据提示填写相关信息。
3. 打开解决方案文件 `EasyPR.sln`,直接编译运行即可。
**方法二**
* 打开解决方案文件 `EasyPR.sln`
**Note**: 该解决方案会加载两个项目,一个是`EasyPR`用于编译src/下的源文件生成静态库`libeasypr.lib`;另一个是`Demo`用来编译test/下的main.cpp并链接libeasypr.lib生成可执行程序。
* 配置OpenCV
OpenCV for Windows通常会将使用VS编译好二进制文件放到`opencv\build\`目录下。
解决方案自动加载的两个项目配置不符合你的环境,请依次手动配置:
**demo**
| 配置项 | 值
|-------------|-----------
| `C/C++`-`附加包含目录` | **[opencv3的include目录]**;$(SolutionDir)include
| `链接器`-`附加库目录` | **[opencv3的lib目录]**
| `链接器`-`输入`-`附加依赖项` | **opencv_world300d.lib**;%(AdditionalDependencies)
*Note*Debug版本为**opencv_world300d.lib**Release版本为**opencv_world300.lib**
**libeasypr**
| 配置项 | 值
|-------------|-----------
| `C/C++`-`附加包含目录` | **[opencv3的include目录]**;$(SolutionDir)include
* 生成解决方案
默认情况下,生成的 `demo.exe` 会放在项目根目录下。
**Note**: 直接双击运行程序会出现找不到opencv动态库的情况这个时候有两个办法
* 在`opencv3\build\x86(x64)\vc(..)\bin`下找到缺失的dll放到执行目录下。
* 将上述bin目录添加到系统环境变量**PATH**中,然后重新运行程序。
**参考**windows平台下的opencv的手动配置可以参考这份[博客](http://my.phirobot.com/blog/2014-02-opencv_configuration_in_vs.html)。
#### Linux & Mac OS
EasyPR使用CMake在Linux及Mac OS下进行构建确保系统安装了最新版本的[CMake](http://cmake.org)。
为了避免系统中安装的老版本opencv对编译的影响需要在 `CMakeLists.txt` 中修改:
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/local/opt/opencv3")
路径指向opencv3的安装目录该目录下应该有OpenCV的CMake配置文件。
项目提供了一键编译shell在项目根目录下执行
```
$ ./build
```
即可。
-----
**Note**: *你可以直接利用 EasyPR/include 和编译生成的静态库来调用EasyPR提供的函数接口编写自己的程序。*
运行Demo
```
$ ./demo // 进入菜单交互界面
$ ./demo ? // 查看CLI帮助
```
### 命令行示例
可以向 `demo[.exe]` 传递命令行参数来完成你想要的工作目前Demo支持5个子命令。对于每个子命令的帮助信息可以传入 `-h` 参数来获取。
**车牌识别**
# 利用提供的SVM和ANN模型来识别一张图片里面的所有车牌
$ ./demo recognize -p resources/image/plate_recognize.jpg --svm resources/model/svm.xml --ann resources/model/ann.xml
# 或者更简单一些(注意模型路径)
$ ./demo recognize -p resources/image/plate_recognize.jpg
**SVM训练**
新版本的EasyPR大大简化了SVM训练
# 首先准备好车牌图片集合plates/
# 是车牌的放在plates/has/
# 不是车牌的放在plates/no/
# 车牌可从项目resources/train/svm.7z中解压得到。
$ ./demo svm --plates=path/to/your/plates --svm=save/to/svm.xml
# 该命令将70%的车牌作为训练数据另外30%的车牌作为测试数据,
# 这个只可在 include/easypr/config.h 修改。
# 将训练好的模型存放在 save/to/svm.xml。
假设你在easypr的主目录下面新建了一个tmp文件夹并且把svm.7z解压得到的svm文件夹移动到tmp文件夹下面
则可以执行 $ demo svm --plates=tmp/svm --svm=tmp/svm.xml生成得到的tmp文件夹下面的svm.xml就是训练好的模型
替换resources/model/svm.xml就可以达到替换新模型的目的替换前请先备份原始模型。
**ANN训练**
先准备好字符图片集合可从项目resources/train/ann.7z中解压得到。
每类字符都存放在以其名称命名的子文件夹中,命名规则请参考 `include/easypr/config.h`
一切准备就绪后,运行下面这条命令即可:
$ ./demo ann --chars=path/to/chars --ann=save/to/ann.xml
假设你在easypr的主目录下面新建了一个tmp文件夹并且把ann.7z解压得到的ann文件夹移动到tmp文件夹下面
则可以执行 $ demo ann --chars=tmp/ann --ann=tmp/ann.xml生成得到的tmp文件夹下面的svm.xml就是训练好的模型
替换resources/model/ann.xml就可以达到替换新模型的目的替换前请先备份原始模型。
请参考[这里](Usage.md)
### 获取帮助

@ -0,0 +1,157 @@
# 使用
### 获取源代码
可以访问我们的项目主页获取代码:
* [github](https://github.com/liuruoze/EasyPR)
* [oschina](https://git.oschina.net/easypr/EasyPR)
如果你熟悉git版本控制工具可以使用下面的命令从 Github 克隆代码:
$ git clone https://github.com/liuruoze/EasyPR
### 准备工作
1. 安装OpenCV
从 [OpenCV官方网站](http://opencv.org/) 获取对应平台的 `OpenCV3.1.0`
EasyPR支持当前主流的操作系统通常不需要对源代码进行更改就可以编译运行尽管如此不同平台上IDE的配置也是有很大差异的下面主要说明WindowsLinux以及Mac OS下的编译方法。
#### Windows
对于使用 Windows 的同学建议的IDE是Visual Studio如果使用的不是VS请自行配置也欢迎分享你的配置方案。
|环境 | 需求
|------|----------
| 操作系统 | 64位Windows7 sp1 / Windows 8 及以上
| Visual Studio | vs2013 / vs2015
| Python可选 | Python3.*
**Note**: 预编译的 **OpenCV3.1** 已经不支持较低版本的Visual Studio请选择vs2013及以上的版本。
**方法一(推荐)**
1. 确保将Python的安装目录添加到系统环境变量PATH中。
2. 执行 `python configure.py` ,根据提示填写相关信息。
3. 打开解决方案文件 `EasyPR.sln`,直接编译运行即可。
**方法二**
打开解决方案文件 `EasyPR.sln`,该解决方案会加载两个项目:
* `EasyPR`用于编译src/下的源文件生成静态库`libeasypr.lib`
* `Demo`用来编译test/下的main.cpp并链接libeasypr.lib生成可执行程序。
**配置OpenCV**
OpenCV for Windows 通常会将使用VS编译好二进制文件放到 `opencv\build\` 目录下。
解决方案自动加载的两个项目配置不符合你的环境,请依次手动配置:
**demo**
| 配置项 | 值
|-------------|-----------
| `C/C++`-`附加包含目录` | **[opencv的include目录]**;$(SolutionDir)include
| `链接器`-`附加库目录` | **[opencv的lib目录]**
| `链接器`-`输入`-`附加依赖项` | **opencv_world310d.lib**;%(AdditionalDependencies)
*Note*Debug版本为**opencv_world310d.lib**Release版本为**opencv_world310.lib**
**libeasypr**
| 配置项 | 值
|-------------|-----------
| `C/C++`-`附加包含目录` | **[opencv的include目录]**;$(SolutionDir)include
**编译**
默认情况下,生成的 `demo.exe` 会放在项目根目录下。
**Note**: 直接双击运行程序会出现找不到opencv动态库的情况这个时候有两个办法
* 在`opencv\build\x64\vc(..)\bin`下找到缺失的dll放到执行目录下。
* 将上述bin目录添加到系统环境变量**PATH**中,然后重新运行程序。
**参考**windows平台下的opencv的手动配置可以参考这份[博客](http://my.phirobot.com/blog/2014-02-opencv_configuration_in_vs.html)。
#### Linux & Mac OS
EasyPR使用CMake在Linux及Mac OS下进行构建确保系统安装了最新版本的[CMake](http://cmake.org)。
为了避免系统中安装的老版本opencv对编译的影响需要在 `CMakeLists.txt` 中修改:
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/local/opt/opencv3")
路径指向opencv3的安装目录该目录下应该有OpenCV的CMake配置文件。
项目提供了一键编译shell在项目根目录下执行
```
$ ./build
```
即可。
----
**Note**: *你可以直接利用 EasyPR/include 和编译生成的静态库来调用EasyPR提供的函数接口编写自己的程序。*
运行Demo
```
$ ./demo // 进入菜单交互界面
$ ./demo ? // 查看CLI帮助
```
### 命令行示例
可以向 `demo[.exe]` 传递命令行参数来完成你想要的工作目前Demo支持5个子命令。对于每个子命令的帮助信息可以传入 `-h` 参数来获取。
**车牌识别**
# 利用提供的SVM和ANN模型来识别一张图片里面的所有车牌
$ ./demo recognize -p resources/image/plate_recognize.jpg --svm resources/model/svm.xml --ann resources/model/ann.xml
# 或者更简单一些(注意模型路径)
$ ./demo recognize -p resources/image/plate_recognize.jpg
**SVM训练**
新版本的EasyPR大大简化了SVM训练
# 首先准备好车牌图片集合plates/
# 是车牌的放在plates/has/
# 不是车牌的放在plates/no/
# 车牌可从项目resources/train/svm.7z中解压得到。
$ ./demo svm --plates=path/to/your/plates --svm=save/to/svm.xml
# 该命令将70%的车牌作为训练数据另外30%的车牌作为测试数据,
# 这个只可在 include/easypr/config.h 修改。
# 将训练好的模型存放在 save/to/svm.xml。
假设你在easypr的主目录下面新建了一个tmp文件夹并且把svm.7z解压得到的svm文件夹移动到tmp文件夹下面
则可以执行 $ demo svm --plates=tmp/svm --svm=tmp/svm.xml生成得到的tmp文件夹下面的svm.xml就是训练好的模型
替换resources/model/svm.xml就可以达到替换新模型的目的替换前请先备份原始模型。
**ANN训练**
先准备好字符图片集合可从项目resources/train/ann.7z中解压得到。
每类字符都存放在以其名称命名的子文件夹中,命名规则请参考 `etc/province_mapping`
一切准备就绪后,运行下面这条命令即可:
$ ./demo ann --chars=path/to/chars --ann=save/to/ann.xml
假设你在easypr的主目录下面新建了一个tmp文件夹并且把ann.7z解压得到的ann文件夹移动到tmp文件夹下面
则可以执行 $ demo ann --chars=tmp/ann --ann=tmp/ann.xml生成得到的tmp文件夹下面的svm.xml就是训练好的模型
替换resources/model/ann.xml就可以达到替换新模型的目的替换前请先备份原始模型。

@ -1,11 +1,9 @@
#!/usr/bin/env bash
BUILD_PATH="_build/"
build_tmp="_build/"
if [ ! -e $BUILD_PATH ]; then
mkdir $BUILD_PATH
fi
mkdir ${build_tmp} 2>/dev/null
cd ${build_tmp}
cd _build/
cmake ../
make -j 4
cmake --clean-first ..
make -j 4 --makefile Makefile

@ -4,7 +4,7 @@
# EasyPR auto configure script
# --------------------------------------------------------------------
#
# This script configures OpenCV3.0 for Visual Studio
# This script configures OpenCV3.1 for Visual Studio
# on Windows.
#
# You are required to have Python3.* installed, and python.exe must
@ -34,7 +34,7 @@ kConfig = {
"build": "",
"include": "",
"library": "",
"link": ["opencv_world300"],
"link": ["opencv_world310"],
"bit": "",
"vs": ""
}
@ -112,15 +112,15 @@ def check_opencv_version():
file = os.path.join(kConfig["build"], kOpenCVConfig)
print(">> Checking ", file)
fp = open(file)
major_version = 0
opencv_version = 0
try:
fline = fp.readline()
match = re.search(r"OpenCV_VERSION (\d)\.(\d)\.(\d{,2})", fline)
if match is not None:
major_version = match.group(1)
opencv_version = match.group(1) + "." + match.group(2)
finally:
fp.close()
return major_version
return opencv_version
def cli():
@ -133,28 +133,22 @@ def cli():
else:
print("Invalid path")
if check_opencv_version() != "3":
print("requires opencv 3")
if check_opencv_version() != "3.1":
print("requires opencv 3.1")
exit()
while True:
xbit = input("Which library version you want to use? (x86 for 32bit, x64 for 64bit): ")
if xbit == "x86" or xbit == "x64":
kConfig["bit"] = xbit
break
else:
print("Please type x86 or x64")
kConfig["bit"] = "x64"
while True:
vc = input("Which Visual Studio you are using? (vs2012 or vs2013): ")
if vc == "vs2012":
kConfig["vs"] = "vc11"
break
elif vc == "vs2013":
vc = input("Which Visual Studio you are using? (vs2013 or vs2015): ")
if vc == "vs2013":
kConfig["vs"] = "vc12"
break
elif vc == "vs2015":
kConfig["vs"] = "vc14"
break
else:
print("Please type vs2012 or vs2013")
print("Please type vs2013 or vs2015")
kConfig["library"] = os.path.normpath("%s/%s/%s/lib/" % (kConfig["build"], kConfig["bit"], kConfig["vs"]))

@ -0,0 +1,6 @@
////////////////////////////////////
BatchTest Option:
1. general_test;
2. native_test;
3. 返回;
////////////////////////////////////

@ -0,0 +1,18 @@
make_a_choice 请选择一项操作
input_error 输入错误,请重新输入
original_plate 原牌
empty_plate 无车牌
diff 差距
char 字符
error_code 错误码
summaries 统计参数
sum_pictures 总图片数
unrecognized 未识出图片
locate_rate 定位率
diff_average 平均字符差距
full_match 完全匹配数
full_rate 完全匹配率
seconds 总时间
seconds_average 平均执行时间
sec 秒

@ -0,0 +1,3 @@
我们EasyPR团队目前有一个5人左右的小组在进行EasyPR后续版本的开发工作。
人数已满,暂时不接受应聘信息,谢谢!

@ -0,0 +1,11 @@
////////////////////////////////////
EasyPR Option:
1. 测试;
2. 批量测试;
3. SVM训练;
4. ANN训练;
5. GDTS生成;
6. 开发团队;
7. 感谢名单;
8. 退出;
////////////////////////////////////

@ -0,0 +1,31 @@
zh_cuan 川
zh_gan1 甘
zh_hei 黑
zh_jin 津
zh_liao 辽
zh_min 闽
zh_qiong 琼
zh_sx 晋
zh_xin 新
zh_yue 粤
zh_zhe 浙
zh_e 鄂
zh_gui 贵
zh_hu 沪
zh_jing 京
zh_lu 鲁
zh_ning 宁
zh_shan 陕
zh_wan 皖
zh_yu 豫
zh_yun 云
zh_gan 赣
zh_gui1 桂
zh_ji 冀
zh_jl 吉
zh_meng 蒙
zh_qing 青
zh_su 苏
zh_xiang 湘
zh_yu1 渝
zh_zang 藏

@ -0,0 +1,12 @@
////////////////////////////////////
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. 返回;
////////////////////////////////////

@ -0,0 +1,7 @@
本项目在建设过程中,受到了很多人的帮助,其中以下是对本项目做出突出贡献的
(贡献包括有益建议,代码调优,数据提供等等,排名按时间顺序)
taotao1233邱锦山唐大侠jsxyhelu如果有一天(zhoushiwei)
学习奋斗袁承志圣城小石匠goldriverMicooz梦里时光
Rain Wangahccoms星夜落尘海豚嘎嘎
还有很多的同学对本项目也给予了鼓励与支持,在此也一并表示真诚的谢意!

@ -1,69 +1,54 @@
#ifndef EASYPR_CONFIG_H_
#define EASYPR_CONFIG_H_
namespace easypr {
static const char* kDefaultSvmPath = "resources/model/svm.xml";
static const char* kDefaultAnnPath = "resources/model/ann.xml";
typedef enum {
kForward = 1, // correspond to "has plate"
kInverse = 0 // correspond to "no plate"
} SvmLabel;
static const float kSvmPercentage = 0.7f;
static const int kPredictSize = 10;
static const int kNeurons = 40;
static const char *kChars[] = {
"0", "1", "2",
"3", "4", "5",
"6", "7", "8",
"9",
/* 10 */
"A", "B", "C",
"D", "E", "F",
"G", "H", /* {"I", "I"} */
"J", "K", "L",
"M", "N", /* {"O", "O"} */
"P", "Q", "R",
"S", "T", "U",
"V", "W", "X",
"Y", "Z",
/* 24 */
"zh_cuan" , "zh_e" , "zh_gan" ,
"zh_gan1" , "zh_gui" , "zh_gui1" ,
"zh_hei" , "zh_hu" , "zh_ji" ,
"zh_jin" , "zh_jing" , "zh_jl" ,
"zh_liao" , "zh_lu" , "zh_meng" ,
"zh_min" , "zh_ning" , "zh_qing" ,
"zh_qiong", "zh_shan" , "zh_su" ,
"zh_sx" , "zh_wan" , "zh_xiang",
"zh_xin" , "zh_yu" , "zh_yu1" ,
"zh_yue" , "zh_yun" , "zh_zang" ,
"zh_zhe"
/* 31 */
};
static const std::map<std::string, std::string> kCharsMap = {
{"zh_cuan" , ""}, {"zh_e" , ""}, {"zh_gan" , ""},
{"zh_gan1" , ""}, {"zh_gui" , ""}, {"zh_gui1" , ""},
{"zh_hei" , ""}, {"zh_hu" , ""}, {"zh_ji" , ""},
{"zh_jin" , ""}, {"zh_jing" , ""}, {"zh_jl" , ""},
{"zh_liao" , ""}, {"zh_lu" , ""}, {"zh_meng" , ""},
{"zh_min" , ""}, {"zh_ning" , ""}, {"zh_qing" , ""},
{"zh_qiong", ""}, {"zh_shan" , ""}, {"zh_su" , ""},
{"zh_sx" , ""}, {"zh_wan" , ""}, {"zh_xiang", ""},
{"zh_xin" , ""}, {"zh_yu" , ""}, {"zh_yu1" , ""},
{"zh_yue" , ""}, {"zh_yun" , ""}, {"zh_zang" , ""},
{"zh_zhe" , ""}
/* 31 */
};
static const int kCharsTotalNumber = 65;
static bool kDebug = false;
}
#ifndef EASYPR_CONFIG_H_
#define EASYPR_CONFIG_H_
namespace easypr {
static const char* kDefaultSvmPath = "resources/model/svm.xml";
static const char* kDefaultAnnPath = "resources/model/ann.xml";
typedef enum {
kForward = 1, // correspond to "has plate"
kInverse = 0 // correspond to "no plate"
} SvmLabel;
static const float kSvmPercentage = 0.7f;
static const int kPredictSize = 10;
static const int kNeurons = 40;
static const char *kChars[] = {
"0", "1", "2",
"3", "4", "5",
"6", "7", "8",
"9",
/* 10 */
"A", "B", "C",
"D", "E", "F",
"G", "H", /* {"I", "I"} */
"J", "K", "L",
"M", "N", /* {"O", "O"} */
"P", "Q", "R",
"S", "T", "U",
"V", "W", "X",
"Y", "Z",
/* 24 */
"zh_cuan" , "zh_e" , "zh_gan" ,
"zh_gan1" , "zh_gui" , "zh_gui1" ,
"zh_hei" , "zh_hu" , "zh_ji" ,
"zh_jin" , "zh_jing" , "zh_jl" ,
"zh_liao" , "zh_lu" , "zh_meng" ,
"zh_min" , "zh_ning" , "zh_qing" ,
"zh_qiong", "zh_shan" , "zh_su" ,
"zh_sx" , "zh_wan" , "zh_xiang",
"zh_xin" , "zh_yu" , "zh_yu1" ,
"zh_yue" , "zh_yun" , "zh_zang" ,
"zh_zhe"
/* 31 */
};
static const int kCharsTotalNumber = 65;
static bool kDebug = false;
}
#endif // EASYPR_CONFIG_H_

@ -1,6 +1,8 @@
#ifndef EASYPR_CORE_CHARSIDENTIFY_H_
#define EASYPR_CORE_CHARSIDENTIFY_H_
#include "easypr/util/kv.h"
#include <memory>
#include <opencv2/opencv.hpp>
namespace easypr {
@ -16,6 +18,7 @@ class CharsIdentify {
static CharsIdentify* instance_;
cv::Ptr<cv::ml::ANN_MLP> ann_;
std::shared_ptr<Kv> kv_;
};
}

@ -14,6 +14,7 @@
#include "easypr/core/chars_segment.h"
#include "easypr/core/chars_identify.h"
#include "easypr/util/util.h"
namespace easypr {
@ -25,16 +26,21 @@ class CCharsRecognise {
int charsRecognise(cv::Mat plate, std::string& plateLicense);
//! 获得车牌颜色
//! 获得车牌颜色
inline std::string getPlateColor(cv::Mat input) const {
std::string color = "未知";
std::string color = "未知";
Color result = getPlateType(input, true);
if (BLUE == result) color = "蓝牌";
if (YELLOW == result) color = "黄牌";
if (BLUE == result) color = "蓝牌";
if (YELLOW == result) color = "黄牌";
#ifdef OS_WINDOWS
color = utils::utf8_to_gbk(color.c_str());
#endif
return color;
}
//! 设置变量
//! 设置变量
inline void setLiuDingSize(int param) {
m_charsSegment->setLiuDingSize(param);
}
@ -55,7 +61,8 @@ class CCharsRecognise {
}
private:
//!字符分割
//!字符分割
CCharsSegment* m_charsSegment;
};

@ -1,53 +1,47 @@
//////////////////////////////////////////////////////////////////////////
// Name: chars_segment Header
// Version: 1.0
// Date: 2014-09-19
// Author: liuruoze
// Copyright: liuruoze
// Reference: Mastering OpenCV with Practical Computer Vision Projects
// Reference: CSDN Bloger taotao1233
// Desciption:
// Defines CCharsSegment
//////////////////////////////////////////////////////////////////////////
#ifndef EASYPR_CORE_CHARSSEGMENT_H_
#define EASYPR_CORE_CHARSSEGMENT_H_
#include "easypr/core/core_func.h"
/*! \namespace easypr
Namespace where all the C++ EasyPR functionality resides
*/
namespace easypr {
class CCharsSegment {
public:
CCharsSegment();
//! 字符分割
//! 字符分割
int charsSegment(Mat input, std::vector<Mat>& resultVec);
//! 字符尺寸验证
//! 字符尺寸验证
bool verifyCharSizes(Mat r);
//! 字符预处理
//! 字符预处理
Mat preprocessChar(Mat in);
//! 根据特殊车牌来构造猜测中文字符的位置和大小
//! 根据特殊车牌来构造猜测中文字符的位置和大小
Rect GetChineseRect(const Rect rectSpe);
//! 找出指示城市的字符的Rect例如苏A7003X就是A的位置
//! 找出指示城市的字符的Rect例如苏A7003X就是A的位置
int GetSpecificRect(const std::vector<Rect>& vecRect);
//! 这个函数做两个事情
// 1.把特殊字符Rect左边的全部Rect去掉后面再重建中文字符的位置。
// 2.从特殊字符Rect开始依次选择6个Rect多余的舍去。
//! 这个函数做两个事情
// 1.把特殊字符Rect左边的全部Rect去掉后面再重建中文字符的位置。
// 2.从特殊字符Rect开始依次选择6个Rect多余的舍去。
int RebuildRect(const std::vector<Rect>& vecRect, std::vector<Rect>& outRect,
int specIndex);
//! 将Rect按位置从左到右进行排序
//! 将Rect按位置从左到右进行排序
int SortRect(const std::vector<Rect>& vecRect, std::vector<Rect>& out);
//! 设置变量
//! 设置变量
inline void setLiuDingSize(int param) { m_LiuDingSize = param; }
inline void setColorThreshold(int param) { m_ColorThreshold = param; }
@ -56,41 +50,51 @@ class CCharsSegment {
inline void setWhitePercent(float param) { m_WhitePercent = param; }
inline float getWhitePercent() const { return m_WhitePercent; }
//! 是否开启调试模式常量默认0代表关闭
//! 是否开启调试模式常量默认0代表关闭
static const int DEFAULT_DEBUG = 1;
//! preprocessChar所用常量
//! preprocessChar所用常量
static const int CHAR_SIZE = 20;
static const int HORIZONTAL = 1;
static const int VERTICAL = 0;
//! preprocessChar所用常量
//! preprocessChar所用常量
static const int DEFAULT_LIUDING_SIZE = 7;
static const int DEFAULT_MAT_WIDTH = 136;
static const int DEFAULT_COLORTHRESHOLD = 150;
//! 是否开启调试模式
//! 是否开启调试模式
inline void setDebug(int param) { m_debug = param; }
//! 获取调试模式状态
//! 获取调试模式状态
inline int getDebug() { return m_debug; }
private:
//!柳钉判断参数
//!柳钉判断参数
int m_LiuDingSize;
//!车牌大小参数
//!车牌大小参数
int m_theMatWidth;
//!车牌颜色判断参数
//!车牌颜色判断参数
int m_ColorThreshold;
float m_BluePercent;
float m_WhitePercent;
//! 是否开启调试模式0关闭非0开启
//! 是否开启调试模式0关闭非0开启
int m_debug;
};
} /* \namespace easypr */
}
#endif // EASYPR_CORE_CHARSSEGMENT_H_

@ -1,55 +1,61 @@
#ifndef EASYPR_CORE_COREFUNC_H_
#define EASYPR_CORE_COREFUNC_H_
#include <opencv2/opencv.hpp>
using namespace cv;
/*! \namespace easypr
Namespace where all the C++ EasyPR functionality resides
*/
namespace easypr {
enum Color { BLUE, YELLOW, WHITE, UNKNOWN };
enum LocateType { SOBEL, COLOR, OTHER };
//! 根据一幅图像与颜色模板获取对应的二值图
//! 输入RGB图像, 颜色模板(蓝色、黄色)
//! 输出灰度图只有0和255两个值255代表匹配0代表不匹配
Mat colorMatch(const Mat& src, Mat& match, const Color r,
const bool adaptive_minsv);
//! 判断一个车牌的颜色
//! 输入车牌mat与颜色模板
//! 返回true或fasle
bool plateColorJudge(const Mat& src, const Color r, const bool adaptive_minsv,
float& percent);
bool bFindLeftRightBound(Mat& bound_threshold, int& posLeft, int& posRight);
bool bFindLeftRightBound1(Mat& bound_threshold, int& posLeft, int& posRight);
bool bFindLeftRightBound2(Mat& bound_threshold, int& posLeft, int& posRight);
//去除车牌上方的钮钉
//计算每行元素的阶跃数如果小于X认为是柳丁将此行全部填0涂黑
// X的推荐值为可根据实际调整
bool clearLiuDing(Mat& img);
void clearLiuDingOnly(Mat& img);
void clearLiuDing(Mat mask, int& top, int& bottom);
//! 获得车牌颜色
Color getPlateType(const Mat& src, const bool adaptive_minsv);
//! 直方图均衡
Mat histeq(Mat in);
Mat features(Mat in, int sizeData);
Rect GetCenterRect(Mat& in);
Mat CutTheRect(Mat& in, Rect& rect);
int ThresholdOtsu(Mat mat);
//! 获取垂直和水平方向直方图
Mat ProjectedHistogram(Mat img, int t);
} /*! \namespace easypr*/
#ifndef EASYPR_CORE_COREFUNC_H_
#define EASYPR_CORE_COREFUNC_H_
#include <opencv2/opencv.hpp>
using namespace cv;
/*! \namespace easypr
Namespace where all the C++ EasyPR functionality resides
*/
namespace easypr {
enum Color { BLUE, YELLOW, WHITE, UNKNOWN };
enum LocateType { SOBEL, COLOR, OTHER };
//! 根据一幅图像与颜色模板获取对应的二值图
//! 输入RGB图像, 颜色模板(蓝色、黄色)
//! 输出灰度图只有0和255两个值255代表匹配0代表不匹配
Mat colorMatch(const Mat& src, Mat& match, const Color r,
const bool adaptive_minsv);
//! 判断一个车牌的颜色
//! 输入车牌mat与颜色模板
//! 返回true或fasle
bool plateColorJudge(const Mat& src, const Color r, const bool adaptive_minsv,
float& percent);
bool bFindLeftRightBound(Mat& bound_threshold, int& posLeft, int& posRight);
bool bFindLeftRightBound1(Mat& bound_threshold, int& posLeft, int& posRight);
bool bFindLeftRightBound2(Mat& bound_threshold, int& posLeft, int& posRight);
//去除车牌上方的钮钉
//计算每行元素的阶跃数如果小于X认为是柳丁将此行全部填0涂黑
// X的推荐值为可根据实际调整
bool clearLiuDing(Mat& img);
void clearLiuDingOnly(Mat& img);
void clearLiuDing(Mat mask, int& top, int& bottom);
//! 获得车牌颜色
Color getPlateType(const Mat& src, const bool adaptive_minsv);
//! 直方图均衡
Mat histeq(Mat in);
Mat features(Mat in, int sizeData);
Rect GetCenterRect(Mat& in);
Mat CutTheRect(Mat& in, Rect& rect);
int ThresholdOtsu(Mat mat);
//! 获取垂直和水平方向直方图
Mat ProjectedHistogram(Mat img, int t);
} /*! \namespace easypr*/
#endif // EASYPR_CORE_COREFUNC_H_

@ -1,30 +1,36 @@
#ifndef EASYPR_CORE_FEATURE_H_
#define EASYPR_CORE_FEATURE_H_
#include <opencv2/opencv.hpp>
namespace easypr {
//! 获得车牌的特征数
cv::Mat getTheFeatures(cv::Mat in);
//! EasyPR的getFeatures回调函数
//! 用于从车牌的image生成svm的训练特征features
typedef void (*svmCallback)(const cv::Mat& image, cv::Mat& features);
//! EasyPR的getFeatures回调函数
//! 本函数是获取垂直和水平的直方图图值
void getHistogramFeatures(const cv::Mat& image, cv::Mat& features);
//! 本函数是获取SIFT特征子
void getSIFTFeatures(const cv::Mat& image, cv::Mat& features);
//! 本函数是获取HOG特征子
void getHOGFeatures(const cv::Mat& image, cv::Mat& features);
//! 本函数是获取HSV空间量化的直方图特征子
void getHSVHistFeatures(const cv::Mat& image, cv::Mat& features);
} /*! \namespace easypr*/
#ifndef EASYPR_CORE_FEATURE_H_
#define EASYPR_CORE_FEATURE_H_
#include <opencv2/opencv.hpp>
namespace easypr {
//! 获得车牌的特征数
cv::Mat getTheFeatures(cv::Mat in);
//! EasyPR的getFeatures回调函数
//! 用于从车牌的image生成svm的训练特征features
typedef void (*svmCallback)(const cv::Mat& image, cv::Mat& features);
//! EasyPR的getFeatures回调函数
//! 本函数是获取垂直和水平的直方图图值
void getHistogramFeatures(const cv::Mat& image, cv::Mat& features);
//! 本函数是获取SIFT特征子
void getSIFTFeatures(const cv::Mat& image, cv::Mat& features);
//! 本函数是获取HOG特征子
void getHOGFeatures(const cv::Mat& image, cv::Mat& features);
//! 本函数是获取HSV空间量化的直方图特征子
void getHSVHistFeatures(const cv::Mat& image, cv::Mat& features);
} /*! \namespace easypr*/
#endif // EASYPR_CORE_FEATURE_H_

@ -1,56 +1,61 @@
//////////////////////////////////////////////////////////////////////////
// Name: plate Header
// Version: 1.0
// Date: 2015-03-12
// Author: liuruoze
// Copyright: liuruoze
// Desciption:
// An abstract class for car plate.
//////////////////////////////////////////////////////////////////////////
#ifndef EASYPR_CORE_PLATE_H_
#define EASYPR_CORE_PLATE_H_
#include "core_func.h"
/*! \namespace easypr
Namespace where all the C++ EasyPR functionality resides
*/
namespace easypr {
class CPlate {
public:
bool bColored;
//! 构造函数
CPlate();
//! 设置与读取变量
inline void setPlateMat(Mat param) { m_plateMat = param; }
inline Mat getPlateMat() const { return m_plateMat; }
inline void setPlatePos(RotatedRect param) { m_platePos = param; }
inline RotatedRect getPlatePos() const { return m_platePos; }
inline void setPlateStr(String param) { m_plateStr = param; }
inline String getPlateStr() const { return m_plateStr; }
inline void setPlateLocateType(LocateType param) { m_locateType = param; }
inline LocateType getPlateLocateType() const { return m_locateType; }
private:
//! 车牌的图块
Mat m_plateMat;
//! 车牌在原图的位置
RotatedRect m_platePos;
//! 车牌字符串
String m_plateStr;
//! 车牌定位的方法
LocateType m_locateType;
};
} /*! \namespace easypr*/
//////////////////////////////////////////////////////////////////////////
// Name: plate Header
// Version: 1.0
// Date: 2015-03-12
// Author: liuruoze
// Copyright: liuruoze
// Desciption:
// An abstract class for car plate.
//////////////////////////////////////////////////////////////////////////
#ifndef EASYPR_CORE_PLATE_H_
#define EASYPR_CORE_PLATE_H_
#include "core_func.h"
/*! \namespace easypr
Namespace where all the C++ EasyPR functionality resides
*/
namespace easypr {
class CPlate {
public:
bool bColored;
//! 构造函数
CPlate();
//! 设置与读取变量
inline void setPlateMat(Mat param) { m_plateMat = param; }
inline Mat getPlateMat() const { return m_plateMat; }
inline void setPlatePos(RotatedRect param) { m_platePos = param; }
inline RotatedRect getPlatePos() const { return m_platePos; }
inline void setPlateStr(String param) { m_plateStr = param; }
inline String getPlateStr() const { return m_plateStr; }
inline void setPlateLocateType(LocateType param) { m_locateType = param; }
inline LocateType getPlateLocateType() const { return m_locateType; }
private:
//! 车牌的图块
Mat m_plateMat;
//! 车牌在原图的位置
RotatedRect m_platePos;
//! 车牌字符串
String m_plateStr;
//! 车牌定位的方法
LocateType m_locateType;
};
} /*! \namespace easypr*/
#endif // EASYPR_CORE_PLATE_H_

@ -1,24 +1,9 @@
//////////////////////////////////////////////////////////////////////////
// Name: plate_detect Header
// Version: 1.2
// Date: 2014-09-28
// MDate: 2015-03-13
// Author: liuruoze
// Copyright: liuruoze
// Reference: Mastering OpenCV with Practical Computer Vision Projects
// Reference: CSDN Bloger taotao1233
// Desciption:
// Defines CPlateDetect
//////////////////////////////////////////////////////////////////////////
#ifndef EASYPR_CORE_PLATEDETECT_H_
#define EASYPR_CORE_PLATEDETECT_H_
#include "easypr/core/plate_locate.h"
#include "easypr/core/plate_judge.h"
/*! \namespace easypr
Namespace where all the C++ EasyPR functionality resides
*/
namespace easypr {
class CPlateDetect {
@ -27,29 +12,37 @@ class CPlateDetect {
~CPlateDetect();
//! 深度车牌检测使用颜色与二次Sobel法综合
int plateDetect(Mat src, std::vector<CPlate>& resultVec,
//! 深度车牌检测使用颜色与二次Sobel法综合
int plateDetect(Mat src, std::vector<CPlate> &resultVec,
bool showDetectArea = true, int index = 0);
//! 展示中间的结果
int showResult(const Mat& result);
//! 展示中间的结果
int showResult(const Mat &result);
//! 装载SVM模型
//! 装载SVM模型
void LoadSVM(std::string s);
//! 生活模式与工业模式切换
//! 生活模式与工业模式切换
inline void setPDLifemode(bool param) { m_plateLocate->setLifemode(param); }
//! 是否开启调试模式
//! 是否开启调试模式
inline void setPDDebug(bool param) { m_plateLocate->setDebug(param); }
//! 获取调试模式状态
//! 获取调试模式状态
inline bool getPDDebug() { return m_plateLocate->getDebug(); }
//! 设置与读取变量
//! 设置与读取变量
inline void setGaussianBlurSize(int param) {
m_plateLocate->setGaussianBlurSize(param);
}
inline int getGaussianBlurSize() const {
return m_plateLocate->getGaussianBlurSize();
}
@ -57,6 +50,7 @@ class CPlateDetect {
inline void setMorphSizeWidth(int param) {
m_plateLocate->setMorphSizeWidth(param);
}
inline int getMorphSizeWidth() const {
return m_plateLocate->getMorphSizeWidth();
}
@ -64,6 +58,7 @@ class CPlateDetect {
inline void setMorphSizeHeight(int param) {
m_plateLocate->setMorphSizeHeight(param);
}
inline int getMorphSizeHeight() const {
return m_plateLocate->getMorphSizeHeight();
}
@ -71,32 +66,40 @@ class CPlateDetect {
inline void setVerifyError(float param) {
m_plateLocate->setVerifyError(param);
}
inline float getVerifyError() const {
return m_plateLocate->getVerifyError();
}
inline void setVerifyAspect(float param) {
m_plateLocate->setVerifyAspect(param);
}
inline float getVerifyAspect() const {
return m_plateLocate->getVerifyAspect();
}
inline void setVerifyMin(int param) { m_plateLocate->setVerifyMin(param); }
inline void setVerifyMax(int param) { m_plateLocate->setVerifyMax(param); }
inline void setJudgeAngle(int param) { m_plateLocate->setJudgeAngle(param); }
inline void setMaxPlates(int param) { m_maxPlates = param; }
inline int getMaxPlates() const { return m_maxPlates; }
private:
//! 设置一幅图中最多有多少车牌
//! 设置一幅图中最多有多少车牌
int m_maxPlates;
//! 车牌定位
//! 车牌定位
CPlateLocate* m_plateLocate;
};
} /*! \namespace easypr*/
}
#endif // EASYPR_CORE_PLATEDETECT_H_

@ -11,14 +11,17 @@ class PlateJudge {
public:
static PlateJudge* instance();
//! 对多幅车牌进行SVM判断
int plateJudge(const std::vector<CPlate>&, std::vector<CPlate>&);
//! 对多幅车牌进行SVM判断
//! 车牌判断
int plateJudge(const std::vector<Mat>&, std::vector<Mat>&);
int plateJudge(const std::vector<CPlate> &, std::vector<CPlate> &);
//! 车牌判断(一副图像)
int plateJudge(const Mat& inMat, int& result);
//! 车牌判断
int plateJudge(const std::vector<Mat> &, std::vector<Mat> &);
//! 车牌判断(一副图像)
int plateJudge(const Mat &inMat, int &result);
private:
PlateJudge();

@ -26,66 +26,81 @@ class CPlateLocate {
public:
CPlateLocate();
//! Sobel第一次搜索
//! 不限制大小和形状获取的BoundRect进入下一步
//! Sobel第一次搜索
//! 不限制大小和形状获取的BoundRect进入下一步
int sobelFrtSearch(const Mat& src, std::vector<Rect_<float>>& outRects);
//! Sobel第二次搜索
//! 对大小和形状做限制,生成参考坐标
//! Sobel第二次搜索
//! 对大小和形状做限制,生成参考坐标
int sobelSecSearch(Mat& bound, Point2f refpoint,
std::vector<RotatedRect>& outRects);
int sobelSecSearchPart(Mat& bound, Point2f refpoint,
std::vector<RotatedRect>& outRects);
//! 抗扭斜处理
//! 抗扭斜处理
int deskew(const Mat& src, const Mat& src_b,
std::vector<RotatedRect>& inRects, std::vector<CPlate>& outPlates);
//! 是否偏斜
//! 输入二值化图像,输出判断结果
//! 是否偏斜
//! 输入二值化图像,输出判断结果
bool isdeflection(const Mat& in, const double angle, double& slope);
//! Sobel运算
//! 输入彩色图像,输出二值化图像
//! Sobel运算
//! 输入彩色图像,输出二值化图像
int sobelOper(const Mat& in, Mat& out, int blurSize, int morphW, int morphH);
//! 计算一个安全的Rect
//! 计算一个安全的Rect
bool calcSafeRect(const RotatedRect& roi_rect, const Mat& src,
Rect_<float>& safeBoundRect);
//! 旋转操作
//! 旋转操作
bool rotation(Mat& in, Mat& out, const Size rect_size, const Point2f center,
const double angle);
//! 扭变操作
//! 扭变操作
void affine(const Mat& in, Mat& out, const double slope);
//! 颜色定位法
//! 颜色定位法
int plateColorLocate(Mat src, std::vector<CPlate>& candPlates, int index = 0);
//! Sobel定位法
//! Sobel定位法
int plateSobelLocate(Mat src, std::vector<CPlate>& candPlates, int index = 0);
int sobelOperT(const Mat& in, Mat& out, int blurSize, int morphW, int morphH);
//! Color搜索
//! Color搜索
int colorSearch(const Mat& src, const Color r, Mat& out,
std::vector<RotatedRect>& outRects, int index = 0);
//! 未使用函数与代码
//! 开始------------
//! 结束------------
//! 未使用函数与代码
//! 未使用函数与代码
//! 开始------------
//! 结束------------
//! 未使用函数与代码
//! 车牌定位
//! 车牌定位
int plateLocate(Mat, std::vector<Mat>&, int = 0);
//! 车牌的尺寸验证
//! 车牌的尺寸验证
bool verifySizes(RotatedRect mr);
//! 生活模式与工业模式切换
//! 生活模式与工业模式切换
void setLifemode(bool param);
//! 设置与读取变量
//! 设置与读取变量
inline void setGaussianBlurSize(int param) { m_GaussianBlurSize = param; }
inline int getGaussianBlurSize() const { return m_GaussianBlurSize; }
@ -105,13 +120,16 @@ class CPlateLocate {
inline void setJudgeAngle(int param) { m_angle = param; }
//! 是否开启调试模式
//! 是否开启调试模式
inline void setDebug(bool param) { m_debug = param; }
//! 获取调试模式状态
//! 获取调试模式状态
inline bool getDebug() { return m_debug; }
//! PlateLocate所用常量
//! PlateLocate所用常量
static const int DEFAULT_GAUSSIANBLUR_SIZE = 5;
static const int SOBEL_SCALE = 1;
static const int SOBEL_DELTA = 0;
@ -121,39 +139,48 @@ class CPlateLocate {
static const int DEFAULT_MORPH_SIZE_WIDTH = 17; // 17
static const int DEFAULT_MORPH_SIZE_HEIGHT = 3; // 3
//! showResultMat所用常量
//! showResultMat所用常量
static const int WIDTH = 136;
static const int HEIGHT = 36;
static const int TYPE = CV_8UC3;
//! verifySize所用常量
//! verifySize所用常量
static const int DEFAULT_VERIFY_MIN = 1; // 3
static const int DEFAULT_VERIFY_MAX = 24; // 20
//! 角度判断所用常量
//! 角度判断所用常量
static const int DEFAULT_ANGLE = 60; // 30
//! 是否开启调试模式常量默认0代表关闭
//! 是否开启调试模式常量默认0代表关闭
static const int DEFAULT_DEBUG = 1;
protected:
//! 高斯模糊所用变量
//! 高斯模糊所用变量
int m_GaussianBlurSize;
//! 连接操作所用变量
//! 连接操作所用变量
int m_MorphSizeWidth;
int m_MorphSizeHeight;
//! verifySize所用变量
//! verifySize所用变量
float m_error;
float m_aspect;
int m_verifyMin;
int m_verifyMax;
//! 角度判断所用变量
//! 角度判断所用变量
int m_angle;
//! 是否开启调试模式0关闭非0开启
//! 是否开启调试模式0关闭非0开启
bool m_debug;
};

@ -24,13 +24,16 @@ class CPlateRecognize : public CPlateDetect, public CCharsRecognise {
public:
CPlateRecognize();
//! 车牌检测与字符识别
//! 车牌检测与字符识别
int plateRecognize(Mat src, std::vector<std::string> &licenseVec);
//! 生活模式与工业模式切换
//! 生活模式与工业模式切换
inline void setLifemode(bool param) { CPlateDetect::setPDLifemode(param); }
//! 是否开启调试模式
//! 是否开启调试模式
inline void setDebug(bool param) { CPlateDetect::setPDDebug(param); }
};

@ -1,21 +1,23 @@
// 生成GDTS的文件
// 在捐赠数据到GDTS数据集里请先用这里的方法对图像进行预处理
// EasyPR开源项目非常注重保护原始图片的版权
// 所有的捐赠数据通过GDSL协议进行约定保证使用人仅用于非商业性目的
#ifndef EASYPR_CORE_GDTS_H_
#define EASYPR_CORE_GDTS_H_
#include <opencv2/opencv.hpp>
namespace easypr {
namespace preprocess {
// EasyPR的图像预处理函数进行模糊化与裁剪化处理
cv::Mat imageProcess(cv::Mat src);
int generate_gdts();
}
}
// 生成GDTS的文件
// 在捐赠数据到GDTS数据集里请先用这里的方法对图像进行预处理
// EasyPR开源项目非常注重保护原始图片的版权
// 所有的捐赠数据通过GDSL协议进行约定保证使用人仅用于非商业性目的
#ifndef EASYPR_CORE_GDTS_H_
#define EASYPR_CORE_GDTS_H_
#include <opencv2/opencv.hpp>
namespace easypr {
namespace preprocess {
// EasyPR的图像预处理函数进行模糊化与裁剪化处理
cv::Mat imageProcess(cv::Mat src);
int generate_gdts();
}
}
#endif // EASYPR_CORE_GDTS_H_

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save