Code Monkey home page Code Monkey logo

liuruoze / easypr Goto Github PK

View Code? Open in Web Editor NEW
6.3K 525.0 2.5K 190.46 MB

(CGCSTCD'2017) An easy, flexible, and accurate plate recognition project for Chinese licenses in unconstrained situations. CGCSTCD = China Graduate Contest on Smart-city Technology and Creative Design

License: Apache License 2.0

C++ 98.13% CMake 0.48% C 0.10% Shell 0.02% Python 1.28%
computer-vision machine-learning artificial-intelligence plate-recognition unconstrained-situation datasets artificial-neural-networks support-vector-machines supervised-learning chinese-characters opencv opencv3

easypr's Introduction

EasyPR

EasyPR是一个开源的中文车牌识别系统,其目标是成为一个简单、高效、准确的非限制场景(unconstrained situation)下的车牌识别库。

相比于其他的车牌识别系统,EasyPR有如下特点:

  • 它基于openCV这个开源库。这意味着你可以获取全部源代码,并且移植到opencv支持的所有平台。
  • 它能够识别中文。例如车牌为苏EUK722的图片,它可以准确地输出std:string类型的"苏EUK722"的结果。
  • 它的识别率较高。图片清晰情况下,车牌检测与字符识别可以达到80%以上的精度。

更新

本次更新版本是1.6正式版本,主要有以下几点更新:

  1. 修正了多项readme的文本提示。

  2. 增加了C#调用EasyPR的一个项目的链接,感谢 @zhang-can 同学。

注意

  1. 对于Opencv3.2或以上版本,如果碰到编译问题,例如“ANN_MLP”相关的错误,尝试将config.h中将#define CV_VERSION_THREE_ZERO改为#define CV_VERSION_THREE_TWO试试.

  2. linux系统推荐使用Opencv3.2以上版本。3.2以下的版本例如3.0和3.1在识别时可能会出现车牌识别结果为空的情况。稳妥起见,建议都升级到最新的3.2版本。Windows版本没有这个问题。

待做的工作

  • 完成一个CNN框架
  • 替换ANN为CNN
  • 增加新能源车的识别(待定)
  • 增加两行车牌的识别(待定)

跨平台

目前除了windows平台以外,还有以下其他平台的EasyPR版本。一些平台的版本可能会暂时落后于主平台。

现在有一个无需配置opencv的1.5版本的懒人版。仅仅支持vs2013,也只能在debug和x86下运行,其他情况的话还是得配置opencv。感谢范文捷同学的帮助。页面里的两个文件都要下载,下载后用7zip解压。

版本 开发者 版本 地址
C# zhang-can 1.5 zhang-can/EasyPR-DLL-CSharp
android goldriver 1.4 linuxxx/EasyPR_Android
linux Micooz 1.6 已跟EasyPR整合
ios zhoushiwei 1.3 zhoushiwei/EasyPR-iOS
mac zhoushiwei,Micooz 1.6 已跟EasyPR整合
java fan-wenjie 1.2 fan-wenjie/EasyPR-Java
懒人版 fan-wenjie 1.5 git/oschina

兼容性

当前EasyPR是基于opencv3.0版本开发的,3.0及以上的版本应该可以兼容,以前的版本可能会存在不兼容的现象。

例子

假设我们有如下的原始图片,需要识别出中间的车牌字符与颜色:

EasyPR 原始图片

经过EasyPR的第一步处理车牌检测(PlateDetect)以后,我们获得了原始图片中仅包含车牌的图块:

EasyPR 车牌

接着,我们对图块进行OCR过程,在EasyPR中,叫做字符识别(CharsRecognize)。我们得到了一个包含车牌颜色与字符的字符串:

“蓝牌:苏EUK722”

示例

EasyPR的调用非常简单,下面是一段示例代码:

	CPlateRecognize pr;
	pr.setResultShow(false);
	pr.setDetectType(PR_DETECT_CMSER);
     
	vector<CPlate> plateVec;
	Mat src = imread(filepath);
	int result = pr.plateRecognize(src, plateVec);

我们首先创建一个CPlateRecognize的对象pr,接着设置pr的属性。

	pr.setResultShow(false);

这句话设置EasyPR是否打开结果展示窗口,如下图。设置为true就是打开,否则就是关闭。在需要观看定位结果时,建议打开,快速运行时关闭。

EasyPR 输出窗口

	pr.setDetectType(PR_DETECT_CMSER);

这句话设置EasyPR采用的车牌定位算法。CMER代表文字定位方法,SOBEL和COLOR分别代表边缘和颜色定位方法。可以通过"|"符号结合。

	pr.setDetectType(PR_DETECT_COLOR | PR_DETECT_SOBEL);

除此之外,还可以有一些其他的属性值设置:

	pr.setLifemode(true);

这句话设置开启生活模式,这个属性在定位方法为SOBEL时可以发挥作用,能增大搜索范围,提高鲁棒性。

	pr.setMaxPlates(4);

这句话设置EasyPR最多查找多少个车牌。当一副图中有大于n个车牌时,EasyPR最终只会输出可能性最高的n个。

下面来看pr的方法。plateRecognize()这个方法有两个参数,第一个代表输入图像,第二个代表输出的车牌CPlate集合。

	vector<CPlate> plateVec;
	Mat src = imread(filepath);
	int result = pr.plateRecognize(src, plateVec);

当返回结果result为0时,代表识别成功,否则失败。

CPlate类包含了车牌的各种信息,其中重要的如下:

	CPlate plate = plateVec.at(i);
	Mat plateMat = plate.getPlateMat();
	RotatedRect rrect = plate.getPlatePos();
	string license = plate.getPlateStr();

plateMat代表车牌图像,rrect代表车牌的可旋转矩形位置,license代表车牌字符串,例如“蓝牌:苏EUK722”。

这里说下如何去阅读如下图的识别结果。

EasyPR DetectResults

第1行代表的是图片的文件名。

第2行代表GroundTruth车牌,用后缀(g)表示。第3行代表EasyPR检测车牌,用后缀(d)表示。两者形成一个配对,第4行代表两者的字符差距。

下面同上。本图片中有3个车牌,所有共有三个配对。最后的Recall等指标代表的是整幅图片的定位评价,考虑了三个配对的结果。

有时检测车牌的部分会用“无车牌”与“No string”替代。“无车牌”代表“定位不成功”,“No string”代表“定位成功但字符分割失败”。

版权

EasyPR的源代码与训练数据遵循Apache v2.0协议开源。

EasyPR的resources/image/general_test文件夹下的图片数据遵循GDSL协议(通用数据共享协议)进行开放。

请确保在使用前了解以上协议的内容。

目录结构

以下表格是本工程中所有目录的解释:

目录 解释
src 所有源文件
include 所有头文件
test 测试程序
model 机器学习的模型
resources/text 中文字符映射表
resources/train 训练数据与说明
resources/image 测试用的图片
resources/doc 相关文档
tmp 训练数据读取目录,需要自建

以下表格是resources/image目录中子目录的解释:

目录 解释
general_test GDTS(通用数据测试集)
native_test NDTS(本地数据测试集)
tmp Debug模式下EasyPR输出中间图片的目录,需要自建

以下表格是src目录中子目录的解释:

目录 解释
core 核心功能
preprocess SVM预处理
train 训练目录,存放模型训练的代码
util 辅助功能

以下表格是src目录下一些核心文件的解释与关系:

文件 解释
plate_locate 车牌定位
plate_judge 车牌判断
plate_detect 车牌检测,是车牌定位与车牌判断功能的组合
chars_segment 字符分割
chars_identify 字符鉴别
chars_recognise 字符识别,是字符分割与字符鉴别功能的组合
plate_recognize 车牌识别,是车牌检测与字符识别的共有子类
feature 特征提取回调函数
plate 车牌抽象
core_func.h 共有的一些函数

以下表格是test目录下文件的解释:

文件 解释
main.cpp 主命令行窗口
accuracy.hpp 批量测试
chars.hpp 字符识别相关
plate.hpp 车牌识别相关

以下表格是train目录下文件的解释:

文件 解释
ann_train.cpp 训练二值化字符
annCh_train.hpp 训练中文灰度字符
svm_train.hpp 训练车牌判断
create_data.hpp 生成合成数据

使用

请参考这里

获取帮助

详细的开发与教程请见介绍与开发教程

如果你在使用过程中遇到任何问题,请在这里告诉我们。

EasyPR讨论QQ群号是:一群:366392603,二群:583022188,三群:637614031,四群:548362608,加前请注明EasyPR学习讨论。

Contributors

  • liuruoze:1.0-1.2,1.5版作者

  • 海豚嘎嘎(车主之家):1.3版算法贡献者,提升了车牌定位与字符识别的准确率

  • Micooz:1.3-1.4版架构重构,linux与mac支持,opencv3.0支持,utf-8编码转换

  • jsxyhelu:deface版本一

  • zhoushiwei:deface版本二

  • ahccom:新的plateLocate函数

  • 阿水:1.3版整合,数据标注等工作

  • fan-wenjie:1.5版opencv整合版提供者

  • Free:1.6版数据提供者

鸣谢

taotao1233,邱锦山,唐大侠,jsxyhelu,如果有一天(zhoushiwei),学习奋斗,袁承志,圣城小石匠,goldriver,Micooz,梦里时光,Rain Wang,任薛纪,ahccom,星夜落尘,海豚嘎嘎(车主之家),刘超,Free大神,以及所有对EasyPR贡献数据的热心同学。

easypr's People

Contributors

fugangqiang avatar igrass avatar lbyfind avatar liuruoze avatar micooz avatar zhangxinnan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

easypr's Issues

训练生成的svm.xml应该怎么用?

根据文档
2015-07-08 11 33 27
生成的训练结果,我把他替换到了resources/model里面,然后再测试的时候提示出错,请问我是哪里有问题吗?

错误信息:
OpenCV Error: Sizes of input arguments do not match (The sample size is different from what has been used for training) in cvPreparePredictData, file /tmp/opencv20150611-92017-pixpdt/opencv-2.4.11/modules/ml/src/inner_functions.cpp, line 1114
libc++abi.dylib: terminating with uncaught exception of type cv::Exception: /tmp/opencv20150611-92017-pixpdt/opencv-2.4.11/modules/ml/src/inner_functions.cpp:1114: error: (-209) The sample size is different from what has been used for training in function cvPreparePredictData

error: invalid initialization of non-const reference of type ‘cv::Mat&’ from an rvalue of type ‘cv::Mat’

linux平台编译出现如下错误:

EasyPR/src/core/plate_locate.cpp: In member function ‘int easypr::CPlateLocate::plateLocate(cv::Mat, std::vector<cv::Mat>&, int)’:
EasyPR/src/core/plate_locate.cpp:1282:50: error: invalid initialization of non-const reference of type ‘cv::Mat&’ from an rvalue of type ‘cv::Mat’
             cv::Mat& roi = dst_blue(safeBoundRect);
                                                  ^
EasyPR/src/core/plate_locate.cpp:1336:43: error: invalid initialization of non-const reference of type ‘cv::Mat&’ from an rvalue of type ‘cv::Mat’
    cv::Mat& roi = dst_yellow(safeBoundRect);
                                           ^
CMakeFiles/EasyPR.dir/build.make:215: recipe for target 'CMakeFiles/EasyPR.dir/src/core/plate_locate.cpp.o' failed
make[2]: *** [CMakeFiles/EasyPR.dir/src/core/plate_locate.cpp.o] Error 1
CMakeFiles/Makefile2:60: recipe for target 'CMakeFiles/EasyPR.dir/all' failed
make[1]: *** [CMakeFiles/EasyPR.dir/all] Error 2
Makefile:76: recipe for target 'all' failed
make: *** [all] Error 2

无法识别代码里面的百度测试图片

EasyPR-Java-master\res\image\baidu_image 里面百度图片很多都无法识别,我是直接用test的代码测试的,我发现一个现象是无法识别的车牌很多都是车牌上面装了个金属框的,我大概调试了一下代码,发现定位代码部分是定位到车牌了,但是定位车牌的区域比实际车牌区域要大,导致后来的OCR字符识别失效了,作者能针对这个优化一下吗?

SVM重新训练

1.1版对SVM进行了重新训练,但从目前情况来看,SVM模型还有改进的空间。一些图片本来是车牌的,被现在的模型识别为非车牌,而一些非车牌的,会被识别为车牌。

这个原因可能在于SVM选取的特征只考虑到了直方图信息,而没有考虑颜色信息;也有数据不全的可能性。

建议改进方式为:1.强化SVM的特征;2.增加更多训练数据。

另外,关于关于Svm训练的数据尺寸可以考虑从目前的136_36改为128_32,Ratio 为 4。保留原始数据,方便回迁,可以测试改进后具体效果。

此改进建议放在 #31 之后进行。

支持视频识别

最近做了些实验,按照openalpr的实现为EasyPR的demo加入了视频识别的支持,作者是否考虑纳入这个功能?

字符识别改进(1)

字符识别改进过程请参考“SVM开发详解”。整个过程被分成若干任务。

第一个任务(难度:简单):
1.分割训练数据与测试数据。

运行报错

平台:OS X 10.10.4

OpenCV 版本:2.4.11

运行命令:./easypr_test recognize -p ../resources/image/plate_recognize.jpg --svm ../resources/model/svm.xml -ann ../resources/model/ann.xml

目录结构:以上命令路径没错

错误信息:OpenCV Error: Assertion failed (layer_sizes != 0) in predict, file /tmp/opencv20150611-92017-pixpdt/opencv-2.4.11/modules/ml/src/ann_mlp.cpp, line 1611
libc++abi.dylib: terminating with uncaught exception of type cv::Exception: /tmp/opencv20150611-92017-pixpdt/opencv-2.4.11/modules/ml/src/ann_mlp.cpp:1611: error: (-215) layer_sizes != 0 in function predict

关于最新版的一个错误

不知道有没有被提交过: 在做3.0移植的时候,偶然发现chars_recognise.h中的 CCharsRecognise::charsRecognise的两个参数的重载函数版本声明与实现不符合。
根据声明使用的是cv::String& 实现使用的是std::string&
估计是使用了using语法结果忘记大写了吧?

关于easypr/util.h中的getFiles函数

认为你们是用的写法在具体上似乎有些结构混乱

  • 额我的意思是,有一些看似很浪费的写法。

  • 而且对于 32位和64位的需要分别修改代码。

  • 我的建议是这样,不如使用微软推荐的写法:

    HANDLE fileHandle;
    WIN32_FIND_DATAA fileData; //这个就无需考虑 32还是64位了
    
  • 使用递归来获取子文件夹内部的文件比用循环来的好多了,尤其是代码的清晰度上,很容易进行重构。

  • 如果考虑效率,在一个短小的递归中只要代码足够清晰,编译器能够为你优化出不逊色于循环的执行码来,尤其是对 VC++ 这种怪兽级别的家伙。

    if(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    {
        if(strcmp(fileData.cFileName, ".") == 0 ||
           strcmp(fileData.cFileName, "..") == 0)
                continue;
        strcat(tempDirBuf, fileData.cFileName);
        getFile(tempDirBuf, files); // 递归调用,并且使用strcat来代替append让编译器有更好的优化选择。
        ...
    
  • 对于文件

    else
    {
        strcat(tempFileDirBuf, fileData.cFileName);
    files.pushback(tempFileBuf, files);
    }
    
  • 总体 do...while 使用

    do{
    
             ....// Something 
    }while(FindNextFile(fileHandle, &fileData) != 0) ;
    

这是我近来使用你们的项目时候的某些小建议,当然也可能是我考虑的太片面。

不能在linux平台上编译

  1. src/include/features.h 与 linux 系统中 features.h 加载顺序有问题
  2. 许多源码文件中包含linux中没有的头文件objbase.h, windows.h, io.h
  3. src/train/ann_train.cpp 中 GetTickCount 函数未声明
  4. src/util/util.cpp 也不能编译成功
  5. 源文件编码建议改为 utf-8 类型

svm_train bug

我在windows测试SVM train的时候遇到一个问题。
文件名是plate_344.jpg,但是sprintf之后save_to就不对了,我改成如下就过了:
sprintf(save_to, "%s/train/%s", images_folder, file_name.c_str());

PS: 目前divide必须手动添加目录/has/train, /has/test, /no/train/, /no/test;为啥不检验一下目录是否存在,然后自动添加呢?比如在UTIL里添加:

bool Util::testIfFolderExist(const string &folder) {

if defined(WIN32) || defined(_WIN32)

if (_access(folder.c_str(), 0) == 0)
    return true;
else {
    string command = "mkdir " + folder;
    system(command.c_str());
    return true;
}

elif defined(linux) || defined(linux) || defined(APPLE)

DIR *dp;
if ((dp = opendir(path)) == NULL) {
    string command = "mkdir -p " + folder;
    system(command.c_str());
    return true;
}
else
    return true;

endif

return false;

}

profle模块

开发一个profile类,可以监控EasyPR在识别车牌过程中各个模块(定位,svm判断,分割,识别字符)的时间消耗,以此定位程序中的性能瓶颈

v1.2 centos 编译出错

v1.2 centos 编译出错
环境:
2.6.32-504.1.3.el6.x86_64 #1 SMP Tue Nov 11 17:57:25 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
opencv-2.4.9

[root@v01lab EasyPR-1.2]# make
Scanning dependencies of target EasyPR
[ 5%] Building CXX object CMakeFiles/EasyPR.dir/src/main.cpp.o
In file included from /usr/local/include/opencv2/core/types_c.h:55,
from /usr/local/include/opencv2/core/core.hpp:49,
from /usr/local/include/opencv2/imgproc/imgproc.hpp:50,
from /home/pr/EasyPR-1.2/src/include/prep.h:5,
from /home/pr/EasyPR-1.2/src/include/plate_recognize.h:15,
from /home/pr/EasyPR-1.2/src/main.cpp:1:
/usr/include/assert.h:39:42: error: missing binary operator before token "("
/usr/include/assert.h:105:42: error: missing binary operator before token "("
In file included from /usr/local/include/opencv2/core/types_c.h:57,
from /usr/local/include/opencv2/core/core.hpp:49,
from /usr/local/include/opencv2/imgproc/imgproc.hpp:50,
from /home/pr/EasyPR-1.2/src/include/prep.h:5,
from /home/pr/EasyPR-1.2/src/include/plate_recognize.h:15,
from /home/pr/EasyPR-1.2/src/main.cpp:1:
/usr/include/string.h:37:42: error: missing binary operator before token "("
In file included from /usr/include/math.h:34,
from /usr/local/include/opencv2/core/types_c.h:94,
from /usr/local/include/opencv2/core/core.hpp:49,
from /usr/local/include/opencv2/imgproc/imgproc.hpp:50,
from /home/pr/EasyPR-1.2/src/include/prep.h:5,
from /home/pr/EasyPR-1.2/src/include/plate_recognize.h:15,
from /home/pr/EasyPR-1.2/src/main.cpp:1:
/usr/include/bits/huge_val.h:28:18: error: missing binary operator before token "("
/usr/include/bits/huge_val.h:30:20: error: missing binary operator before token "("
....

色彩定位光照处理要加强

比如黑E 苏E这种如果原点前两个汉字的地方,光照比较强,色彩判断就会因为字体白色范围比较大造成区域错误

Assertion failed Issues about cv::Mat

error1
您好,请问一下,目前使用1.3版将image/test.jpg进行3-1产生notlabel数据后,执行选项3-2 的”标签learndata” 会出现如上的Assertion failed信息,关于这个错误,是否会在1.3正式版修正,谢谢!!

用cmake编译时出现如下错误

/home/root/EasyPR-master/src/core/core_func.cpp: In function 'cv::Mat easypr::colorMatch(const cv::Mat&, cv::Mat&, easypr::Color, bool)':
/home/root/EasyPR-master/src/core/core_func.cpp:45:3: error: 'vector' was not declared in this scope
vector hsvSplit;
^

我的g++版本是4.9.1,还有很多错误,不好复制过来,似乎大意是找不到vector这个类,需要使用std::vector
求问如何解决?

源代码编码支持UTF8,easypr_test界面支持UTF8

车牌识别感觉就这个项目很靠谱,下载了一个到mac下试了一下。源代码注释都是乱码,easypr_test的输出都是乱码(连输出的车牌号都是乱码)。

不知道是我哪个地方设置不正确,还是真有问题。希望能改进一下,方便linux平台的开发和调试。

v1.2 centos 编译出错,刚下载的

环境:
2.6.32-504.1.3.el6.x86_64 #1 SMP Tue Nov 11 17:57:25 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
opencv-2.4.9

[root@v01lab EasyPR-1.2]# make
Scanning dependencies of target EasyPR
[ 4%] Building CXX object CMakeFiles/EasyPR.dir/src/main.cpp.o
[ 9%] Building CXX object CMakeFiles/EasyPR.dir/src/core/core_func.cpp.o
[ 13%] Building CXX object CMakeFiles/EasyPR.dir/src/core/chars_identify.cpp.o
[ 18%] Building CXX object CMakeFiles/EasyPR.dir/src/core/chars_recognise.cpp.o
/home/pr/EasyPR12/src/core/chars_recognise.cpp: In constructor ‘easypr::CCharsRecognise::CCharsRecognise()’:
/home/pr/EasyPR12/src/core/chars_recognise.cpp:9: error: ‘nullptr’ was not declared in this scope
/home/pr/EasyPR12/src/core/chars_recognise.cpp: In destructor ‘easypr::CCharsRecognise::~CCharsRecognise()’:
/home/pr/EasyPR12/src/core/chars_recognise.cpp:17: error: ‘nullptr’ was not declared in this scope
/home/pr/EasyPR12/src/core/chars_recognise.cpp:21: error: ‘nullptr’ was not declared in this scope
make[2]: *** [CMakeFiles/EasyPR.dir/src/core/chars_recognise.cpp.o] Error 1
make[1]: *** [CMakeFiles/EasyPR.dir/all] Error 2
make: *** [all] Error 2

EasyPR 车标识别

能够识别车子的类型,例如大众,宝马,奔驰,尼桑,丰田等。

如何自己训练 SVM 模型呢?

我看了开发教程,也看了程序,还是没搞清楚我该怎么自己训练 SVM 模型。 请楼主点拨一下好吗?谢谢!

linux编译出错

CMakeFiles/EasyPR.dir/src/util/generate_gdts.cpp.o: In function generate_gdts()': generate_gdts.cpp:(.text+0x17): undefined reference tocv::CascadeClassifier::CascadeClassifier()'
generate_gdts.cpp:(.text+0x190): undefined reference to cv::imread(std::string const&, int)' generate_gdts.cpp:(.text+0x330): undefined reference tocv::_InputArray::_InputArray(cv::Mat const&)'
generate_gdts.cpp:(.text+0x369): undefined reference to cv::imwrite(std::string const&, cv::_InputArray const&, std::vector<int, std::allocator<int> > const&)' generate_gdts.cpp:(.text+0x43b): undefined reference tocv::CascadeClassifier::~CascadeClassifier()'
generate_gdts.cpp:(.text+0x590): undefined reference to cv::CascadeClassifier::~CascadeClassifier()' CMakeFiles/EasyPR.dir/src/util/learn_prepare.cpp.o: In functionlabel_data()':
learn_prepare.cpp:(.text+0x21c): undefined reference to cv::imread(std::string const&, int)' learn_prepare.cpp:(.text+0x3b4): undefined reference tocv::_InputArray::_InputArray(cv::Mat const&)'
都是一些这种类似的问题

字符识别改进(2)

目前EasyPR对字符识别的准确率较差,需要改进字符识别。

第二个任务(难度:简单):
2.在训练数据上训练模型,在测试数据上测试,使用precise与recall和fscore来衡量准确率;

运行“测试-车牌检测”时,程序出错

我是用的Windows版本。
在测试(testMain();)中,最新版本的车牌检测的主要函数是int result = pd.plateDetect(src, resultVec);,可是这个函数会出错。老版本的函数是int result = pd.plateDetectDeep(src, resultVec);,不会出错。不知其他人遇到这个问题没。

mac 遇到错误 EasyPR/include/easypr/util.h:74:42: error: no type named 'initializer_list' in namespace 'std' static void print_str_lines(const std::initializer_list<const char*>& lines) {

cmake . 之后,运行make 时遇到了下面的错误:
$ make
[ 5%] Building CXX object CMakeFiles/easypr.dir/src/core/chars_segment.cpp.o
In file included from ~/EasyPR/src/core/chars_segment.cpp:2:
~/EasyPR/include/easypr/util.h:74:42: error: no type named 'initializer_list' in namespace 'std'
static void print_str_lines(const std::initializer_list<const char*>& lines) {
~~~~~^
~/EasyPR/include/easypr/util.h:74:58: error: expected ')'
static void print_str_lines(const std::initializer_list<const char*>& lines) {
^
~/EasyPR/include/easypr/util.h:74:30: note: to match this '('
static void print_str_lines(const std::initializer_list<const char*>& lines) {
^
~/EasyPR/include/easypr/util.h:75:22: error: use of undeclared identifier 'lines'; did you mean 'line'?
for (auto line : lines) {
^~~~~
line
/usr/local/include/opencv2/core/core.hpp:2613:19: note: 'line' declared here
CV_EXPORTS_W void line(CV_IN_OUT Mat& img, Point pt1, Point pt2, const Scalar& color,
^
In file included from ~/EasyPR/src/core/chars_segment.cpp:2:
~/EasyPR/include/easypr/util.h:75:20: error: invalid range expression of type
'void (cv::Mat &, cv::Point_, cv::Point_, const cv::Scalar_ &, int, int, int)'; no viable 'begin' function available
for (auto line : lines) {

不知道您在做mac os 移植的时候是怎样解决的。 我的Mac 版本是 10.10.2

谢谢!

求linux编译方法

因为不怎么懂C++,也没有windows的VC环境,求教如何在linux或者mac下编译

windows编译失败

1>core\debug\11_manifest.rc(1): error RC2135: file not found: Debug\11.exe.embed.manifest

一个小问题

我的使用环境是Windows7+VS2013+OpenCV2.4.10,编译没有出什么麻烦,不过在/bin/release下找到easypr_test.exe和libeasypr.lib后,双击运行easypr_test.exe没有出现什么问题,但是不管是哪条指令输入,都是输入错误,找不到文件或者总计图片0张,不知道是什么问题,还请各位大大给点建议。(为了保险,我把OpenCV的dll基本都放在了该程序目录下)

plate_locate.cpp 运行时错误

OpenCV Error: Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows) in Mat, file /tmp/opencv-pcqRHK/opencv-2.4.10.1/modules/core/src/matrix.cpp, line 323
libc++abi.dylib: terminating with uncaught exception of type cv::Exception: /tmp/opencv-pcqRHK/opencv-2.4.10.1/modules/core/src/matrix.cpp:323: error: (-215) 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows in function Mat

使用如下测试图片
test

极端情况下车牌识别

作者您好,我想问下源码中提供的extreme_test,目前我实验时结果都是“无车牌”,是暂时不能识别,还是我个人的问题?

车牌定位的改进建议

我在EasyPR原来的边缘检测定位之前加入了根据车牌颜色(蓝色和黄色)粗定位的功能,能较好筛选出作者文档内Q5的车牌区域。望采纳。代码段如下:
//! 定位车牌图像
//! src 原始图像
//! resultVec 一个Mat的向量,存储所有抓取到的图像
//! 成功返回0,否则返回-1
int CPlateLocate::plateLocate(Mat src, vector& resultVec)
{
Mat src_blur, src_gray;
Mat grad;

int scale = SOBEL_SCALE;
int delta = SOBEL_DELTA;
int ddepth = SOBEL_DDEPTH;

if( !src.data )
{ return -1; }

//高斯模糊。Size中的数字影响车牌定位的效果。
GaussianBlur( src, src_blur, Size(m_GaussianBlurSize, m_GaussianBlurSize), 
    0, 0, BORDER_DEFAULT );

if(m_debug)
{ 
    stringstream ss(stringstream::in | stringstream::out);
    ss << "image/tmp/debug_GaussianBlur" << ".jpg";
    imwrite(ss.str(), src_blur);
}

/// Convert it to gray
cvtColor( src_blur, src_gray, CV_RGB2GRAY );

if(m_debug)
{ 
    stringstream ss(stringstream::in | stringstream::out);
    ss << "image/tmp/debug_gray" << ".jpg";
    imwrite(ss.str(), src_gray);
}
// RGB颜色初定位
// http://wenku.baidu.com/view/2329e5d2360cba1aa811da65.html?re=view
// RGB -> HSV
//      蓝         黄         白         黑
//H     200~255     25~55       /           /
//S     0.4~1       0.4~1       0~0.1       /
//V     0.3~1       0.3~1       0.9~1       0~0.35
//cvCvtColor(src,dst,CV_BGR2HSV);
//其中,src为三通道的,dst也为三通道的,
//OPENCV 中 H、S、V、顺序分别为3*x+0  3*x+1   3*x+2
//opencv中的 H分量是 0~180, S分量是0~255, V分量是0~255
//但是HSV颜色空间却规定的是,H范围0~360,S范围0~1,V范围0~1
//所以你需要自己转换一下,H*2,S/255, V/255

// 默认蓝色车牌
cv::Mat tmp;
cv::cvtColor(src, tmp, CV_BGR2HSV);
vector<Mat> hsvSplit;
split(tmp, hsvSplit);
cv::Mat dst_blue(src.rows, src.cols, CV_8UC1);
cv::Mat dst_yellow(src.rows, src.cols, CV_8UC1);
for(int i = 0; i<tmp.rows; i++)
{
    for(int j = 0; j<tmp.cols; j++)
    {
        int nH = hsvSplit[0].at<uchar>(i, j)*2;
        float fS = hsvSplit[1].at<uchar>(i, j)/255.0;
        float fV = hsvSplit[2].at<uchar>(i, j)/255.0;
        if(nH>=200 && nH<=255 && fS>=0.4 && fS<=1 && fV>=0.3 && fV<=1) // 蓝色
            dst_blue.at<uchar>(i, j) = 255;
        else
            dst_blue.at<uchar>(i, j) = 0;
    }
}
Mat element_blue = getStructuringElement(MORPH_ELLIPSE, Size(10, 10));
morphologyEx(dst_blue, dst_blue, MORPH_CLOSE, element_blue);
//Find 轮廓 of possibles plates
cv::Mat con_blue = dst_blue.clone();
vector< vector< Point> > contours_blue;
findContours(con_blue,
    contours_blue, // a vector of contours
    CV_RETR_EXTERNAL, // 提取外部轮廓
    CV_CHAIN_APPROX_NONE); // all pixels of each contours
//Start to iterate to each contour founded
vector<vector<Point> >::iterator itb = contours_blue.begin();

//Remove patch that are no inside limits of aspect ratio and area.
int tb = 0;
vector<cv::Rect> rects_blue;
while(itb != contours_blue.end())
{
    //Create bounding rect of object
    RotatedRect mr = minAreaRect(Mat(*itb));

    //large the rect for more
    if(!verifySizes(mr))
    {
        cv::Mat& roi = dst_blue(mr.boundingRect());
        roi.setTo(0);
    }
    else
    {
        rects_blue.push_back(mr.boundingRect());
    }
    ++itb;
}
//////////////////////////////////////////////////////////////////////////
for(int i = 0; i<tmp.rows; i++)
{
    for(int j = 0; j<tmp.cols; j++)
    {
        int nH = hsvSplit[0].at<uchar>(i, j)*2;
        float fS = hsvSplit[1].at<uchar>(i, j)/255.0;
        float fV = hsvSplit[2].at<uchar>(i, j)/255.0;
        if(nH>=25 && nH<=55 && fS>=0.4 && fS<=1 && fV>=0.3 && fV<=1) // 黄色
            dst_yellow.at<uchar>(i, j) = 255;
        else
            dst_yellow.at<uchar>(i, j) = 0;
    }
}

Mat element_yellow = getStructuringElement(MORPH_ELLIPSE, Size(10, 10));
morphologyEx(dst_yellow, dst_yellow, MORPH_CLOSE, element_blue);
//Find 轮廓 of possibles plates
cv::Mat con_yellow = dst_yellow.clone();
vector< vector< Point> > contours_yellow;
findContours(con_yellow,
    contours_yellow, // a vector of contours
    CV_RETR_EXTERNAL, // 提取外部轮廓
    CV_CHAIN_APPROX_NONE); // all pixels of each contours
//Start to iterate to each contour founded
vector<vector<Point> >::iterator ity = contours_yellow.begin();

//Remove patch that are no inside limits of aspect ratio and area.
tb = 0;
vector<cv::Rect> rects_yellow;
while(ity != contours_yellow.end())
{
    //Create bounding rect of object
    RotatedRect mr = minAreaRect(Mat(*ity));

    //large the rect for more
    if(!verifySizes(mr))
    {
        cv::Mat& roi = dst_yellow(mr.boundingRect());
        roi.setTo(0);
    }
    else
    {
        dst_yellow.push_back(mr.boundingRect());
    }
    ++ity;
}

/// Generate grad_x and grad_y
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;

/// Gradient X
//Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x );

/// Gradient Y
//Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y );

/// Total Gradient (approximate)
addWeighted( abs_grad_x, SOBEL_X_WEIGHT, abs_grad_y, SOBEL_Y_WEIGHT, 0, grad );

//Laplacian( src_gray, grad_x, ddepth, 3, scale, delta, BORDER_DEFAULT );  
//convertScaleAbs( grad_x, grad ); 
cv::Mat out_blue;
cv::multiply(grad, dst_blue, out_blue);
cv::Mat out_yellow;
cv::multiply(grad, dst_yellow, out_yellow);
if(m_debug)
{ 
    stringstream ss(stringstream::in | stringstream::out);
    ss << "image/tmp/debug_Sobel_blue" << ".jpg";
    imwrite(ss.str(), out_blue);
    ss << "image/tmp/debug_Sobel_yellow" << ".jpg";
    imwrite(ss.str(), out_yellow);
}

Mat img_threshold_blue;
Mat img_threshold_yellow;
threshold(out_blue, img_threshold_blue, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
threshold(out_yellow, img_threshold_yellow, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
//threshold(grad, img_threshold, 75, 255, CV_THRESH_BINARY);

if(m_debug)
{ 
    stringstream ss(stringstream::in | stringstream::out);
    ss << "image/tmp/debug_threshold_blue" << ".jpg";
    imwrite(ss.str(), img_threshold_blue);
    ss << "image/tmp/debug_threshold_yellow" << ".jpg";
    imwrite(ss.str(), img_threshold_yellow);
}

Mat element = getStructuringElement(MORPH_RECT, Size(m_MorphSizeWidth, m_MorphSizeHeight) );
morphologyEx(img_threshold_blue, img_threshold_blue, MORPH_CLOSE, element);
morphologyEx(img_threshold_yellow, img_threshold_yellow, MORPH_CLOSE, element);

if(m_debug)
{ 
    stringstream ss(stringstream::in | stringstream::out);
    ss << "image/tmp/debug_morphology_blue" << ".jpg";
    imwrite(ss.str(), img_threshold_blue);
    ss << "image/tmp/debug_morphology_yellow" << ".jpg";
    imwrite(ss.str(), img_threshold_yellow);
}

//Find 轮廓 of possibles plates
contours_blue.clear();
findContours(img_threshold_blue,
    contours_blue, // a vector of contours
    CV_RETR_EXTERNAL, // 提取外部轮廓
    CV_CHAIN_APPROX_NONE); // all pixels of each contours
contours_yellow.clear();
findContours(img_threshold_yellow,
    contours_yellow, // a vector of contours
    CV_RETR_EXTERNAL, // 提取外部轮廓
    CV_CHAIN_APPROX_NONE); // all pixels of each contours

Mat result;
if(m_debug)
{ 
    //// Draw blue contours on a white image
    src.copyTo(result);
    drawContours(result, contours_blue,
        -1, // draw all contours
        Scalar(0,0,255), // in blue
        1); // with a thickness of 1
    drawContours(result, contours_yellow,
        -1, // draw all contours
        Scalar(0, 0, 255), // in blue
        1); // with a thickness of 1
    stringstream ss(stringstream::in | stringstream::out);
    ss << "image/tmp/debug_Contours" << ".jpg";
    imwrite(ss.str(), result);
}


//Start to iterate to each contour founded
itb = contours_blue.begin();

vector<RotatedRect> rects;
//Remove patch that are no inside limits of aspect ratio and area.
int t = 0;
while (itb != contours_blue.end())
{
    //Create bounding rect of object
    RotatedRect mr = minAreaRect(Mat(*itb));

    //large the rect for more
    if( !verifySizes(mr))
    {
        itb = contours_blue.erase(itb);
    }
    else
    {
        ++itb;
        rects.push_back(mr);
    }
}

ity = contours_yellow.begin();
while(ity != contours_yellow.end())
{
    //Create bounding rect of object
    RotatedRect mr = minAreaRect(Mat(*ity));

    //large the rect for more
    if(!verifySizes(mr))
    {
        ity = contours_yellow.erase(ity);
    }
    else
    {
        ++ity;
        rects.push_back(mr);
    }
}
int k = 1;
for(int i=0; i< rects.size(); i++)
{
    RotatedRect minRect = rects[i];
    if(verifySizes(minRect))
    {   
        // rotated rectangle drawing 
        // Get rotation matrix
        // 旋转这部分代码确实可以将某些倾斜的车牌调整正,
        // 但是它也会误将更多正的车牌搞成倾斜!所以综合考虑,还是不使用这段代码。
        // 2014-08-14,由于新到的一批图片中发现有很多车牌是倾斜的,因此决定再次尝试
        // 这段代码。
        if(m_debug)
        { 
            Point2f rect_points[4]; 
            minRect.points( rect_points );
            for( int j = 0; j < 4; j++ )
                line( result, rect_points[j], rect_points[(j+1)%4], Scalar(0,255,255), 1, 8 );
        }

        float r = (float)minRect.size.width / (float)minRect.size.height;
        float angle = minRect.angle;
        Size rect_size = minRect.size;
        if (r < 1)
        {
            angle = 90 + angle;
            swap(rect_size.width, rect_size.height);
        }
        //如果抓取的方块旋转超过m_angle角度,则不是车牌,放弃处理
        if (angle - m_angle < 0 && angle + m_angle > 0)
        {
            //Create and rotate image
            Mat rotmat = getRotationMatrix2D(minRect.center, angle, 1);
            Mat img_rotated;
            warpAffine(src, img_rotated, rotmat, src.size(), CV_INTER_CUBIC);

            Mat resultMat;
            resultMat = showResultMat(img_rotated, rect_size, minRect.center, k++);

            resultVec.push_back(resultMat);
        }
    }
}

if(m_debug)
{ 
    stringstream ss(stringstream::in | stringstream::out);
    ss << "image/tmp/debug_result" << ".jpg";
    imwrite(ss.str(), result);
}

return 0;

}

用四周的线信息进行二次精准定位

目前定位的车牌,有时候会由于soble或颜色的误差,导致车牌定位不正。或者定位的范围过小,没有覆盖全部的车牌,或者定位的范围过大,只有部分是车牌。如果在一次定位的基础上,再配合车牌四周本身的线信息进行二次定位,就会大幅度减少这种定位不正的现象,从而形成精准定位。

此改进建议放到字符识别完善以后进行。

高分辨率图片的识别

识别太高分辨率图片时会出现问题,将原图片按比例缩小成600X800左右可以正常识别。这个可以在识别前加一个对图片大小的归一化来实现吧

train报错-easypr_test.exe svm --train --has-plate=has/ --no-plate=no/ --divide --svm=mo del/svm.xml

Dividing data to be trained and tested...
has/京CX8888_0.jpg -> has//train/京CX8888_0.jpg
has/赣A82F36_12.jpg -> has//train/赣A82F36_12.jpg
has/京A88731_0.jpg -> has//train/京A88731_0.jpg
has/京A88731_2.jpg -> has//train/京A88731_2.jpg
has/京CX8888_1.jpg -> has//test/京CX8888_1.jpg
has/京H99999_0.jpg -> has//test/京H99999_0.jpg
no/赣A82F36_5.jpg -> no//train/赣A82F36_5.jpg
no/赣A82F36_0.jpg -> no//train/赣A82F36_0.jpg
no/京A88731_1.jpg -> no//train/京A88731_1.jpg
no/京H99999_4.jpg -> no//train/京H99999_4.jpg
no/赣A82F36_10.jpg -> no//train/赣A82F36_10.jpg
no/京H99999_3.jpg -> no//train/京H99999_3.jpg
no/赣A82F36_8.jpg -> no//train/赣A82F36_8.jpg
no/赣A82F36_6.jpg -> no//train/赣A82F36_6.jpg
no/京CX8888_2.jpg -> no//train/京CX8888_2.jpg
no/京H99999_2.jpg -> no//train/京H99999_2.jpg
no/京H99999_1.jpg -> no//train/京H99999_1.jpg
no/京H99999_5.jpg -> no//train/京H99999_5.jpg
no/京A88731_4.jpg -> no//train/京A88731_4.jpg
no/赣A82F36_11.jpg -> no//train/赣A82F36_11.jpg
no/赣A82F36_9.jpg -> no//train/赣A82F36_9.jpg
no/赣A82F36_13.jpg -> no//test/赣A82F36_13.jpg
no/赣A82F36_1.jpg -> no//test/赣A82F36_1.jpg
no/赣A82F36_3.jpg -> no//test/赣A82F36_3.jpg
no/赣A82F36_7.jpg -> no//test/赣A82F36_7.jpg
no/赣A82F36_2.jpg -> no//test/赣A82F36_2.jpg
no/赣A82F36_4.jpg -> no//test/赣A82F36_4.jpg
no/京A88731_3.jpg -> no//test/京A88731_3.jpg
Collecting train data...
Collecting train data in has//train
Collecting train data in no//train
Generating svm model file, please wait...
OpenCV Error: Bad argument (While cross-validation one or more of the classes ha
ve been fell out of the sample. Try to enlarge CvSVMParams::k_fold) in CvSVM::
do_train, file C:\builds\2_4_PackSlave-win32-vc12-shared\opencv\modules\ml\src\s
vm.cpp, line 1402
C:\builds\2_4_PackSlave-win32-vc12-shared\opencv\modules\ml\src\svm.cpp:1402: er
ror: (-5) While cross-validation one or more of the classes have been fell out o
f the sample. Try to enlarge CvSVMParams::k_fold in function CvSVM::do_train

OpenCV Error: Null pointer (Invalid pointer to file storage) in cvStartWriteStru
ct, file C:\builds\2_4_PackSlave-win32-vc12-shared\opencv\modules\core\src\persi
stence.cpp, line 2948

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.