您的位置:首页 > 其它

车牌识别系统

2017-08-21 18:18 176 查看
将车牌识别系统细分为三个部分:

1.车牌检测

2.字符分割

3.字符识别

1.车牌检测

为实现更稳定的检测性能,使用yolo来对车牌进行识别。具体的训练方法见darknet用自己的数据进行训练。数据由EasyPR提供的200多张和自己从网上爬的几百张组成,爬虫脚本和数据标注方法见自行准备深度学习训练数据。最终得到的效果不错,下面是一些测试结果:





2.字符分割

利用EasyPR开源的代码来实现字符分割,在源代码下修改如下:

1.src/core/plate_locate.cpp中注释掉int CPlateLocate::plateLocate(Mat src, vector &resultVec, int index)函数中的两行:

int CPlateLocate::plateLocate(Mat src, vector<Mat> &resultVec, int index) {
vector<CPlate> all_result_Plates;
plateColorLocate(src, all_result_Plates, index);
//plateSobelLocate(src, all_result_Plates, index);
//plateMserLocate(src, all_result_Plates, index);
for (size_t i = 0; i < all_result_Plates.size(); i++) {
CPlate plate = all_result_Plates[i];
resultVec.push_back(plate.getPlateMat());
}
return 0;
}


2.将test中全部删除,只保留chars.hpp和main.cpp

chars.hpp:

#ifndef EASYPR_CHARS_HPP
#define EASYPR_CHARS_HPP
namespace easypr {
namespace demo {
int test_chars_segment() {
cv::Mat src = cv::imread("resources/image/try_3.jpg");
std::vector<cv::Mat> resultVec;
CPlateLocate plate;
int result = plate.plateLocate(src, resultVec);
if(result==0)
{
size_t num = resultVec.size();
for(size_t j=0;j<num;j++)
{
std::vector<cv::Mat> resultVec2;
cv::Mat resultMat = resultVec[j];
CCharsSegment plate2;
int result2 = plate2.charsSegment(resultMat, resultVec2);
if(result2==0)
{
size_t num2=resultVec2.size();
for(size_t i=0;i<num2;i++)
{
cv::Mat resultMat2 = resultVec2[i];
cv::imshow("chars_segment", resultMat2);
cv::waitKey(0);
}
cv::destroyWindow("chars_segment");
}
}
}
return result;
}
}
}
#endif  // EASYPR_CHARS_HPP


main.cpp:

#include "easypr.h"
#include "chars.hpp"

namespace easypr {
namespace demo {
int testMain() {
assert(test_chars_segment() == 0);
return 0;
}
}  // namespace demo
}  // namespace easypr

int main(int argc, const char* argv[]) {
easypr::demo::testMain();
return 0;
}


这样处理后,终端在EasyPR根目录下输入

./demo


即可显示车牌分割后的字符

3.字符识别

依然使用darknet来进行字符识别。

不同于检测,这次使用darknet的classfier函数进行训练和识别,并考虑到分割出来的字符很小,使用了很浅的网络。

利用EasyPR提供的字符识别训练集(即resource/train/ann.7z)进行训练。将数据集解压后,每个文件夹中都有着对应的字符数据,对每个文件夹进行重命名处理。每个图像的命名格式采用(图片序号)_(标签).(图片格式)的格式进行命名。



重命名方法可以参考自行准备深度学习训练数据中的第2点。

重命名完成后,在darknet/data文件夹下新建char文件夹,并在char文件夹下新建image文件夹,将重命名完成的图片统一复制到image文件夹中,再使终端进入char路径(即darknet/data/char),输入

find `pwd`/image -name \*.jpg > train.list


会在char文件夹下自动生成train.list文件,其中包含每个图像的绝对路径。

在darknet/cfg文件夹下新建cifar.data(名字cifar可以自定义),并进行如下改写:

classes=65
train  = data/char/train.list
labels = data/char/labels.txt
backup = backup/
top=2


class 为识别类别数量,train为train.list路径,label为label文件路径。如果需要训练完后的评估,请参照train.list的方法生成val.list,然后再cifar中增加一行

valid=(your path)


然后在char文件夹下新建labels.txt:



每行一个类别标签。

标签的注意事项

1.不区分大小写

2.不能有包含关系,如ji和jin,不能出现这样的形式,可改为ji1和jin

最后,cfg文件夹下新建 cifar_small.cfg

[net]
batch=128
subdivisions=1
height=28
width=28
channels=3
max_crop=32
min_crop=32

hue=.1
saturation=.75
exposure=.75

learning_rate=0.01
policy=poly
power=4
max_batches = 5000000
momentum=0.9
decay=0.0005

[convolutional]
batch_normalize=1
filters=32
size=3
stride=1
pad=1
activation=leaky

[maxpool]
size=2
stride=2

[convolutional]
batch_normalize=1
filters=64
size=3
stride=1
pad=1
activation=leaky

[maxpool]
size=2
stride=2

[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky

[convolutional]
filters=65
size=1
stride=1
pad=1
activation=leaky

[avgpool]

[softmax]
groups=1

[cost]
type=sse


avgpool上面那个convolutional中的filter为自己的类别数。max_batches和学习率之类的自己按照自己的需要来调整。

万事俱备,开始训练:

终端进入darknet根目录,输入

./darknet classifier train cfg/cifar.data cfg/cifar_small.cfg


然后坐等结果吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: