1、概述
目前HyperLRP是一个开源的、基于深度学习高性能中文车牌识别库,本文主要在其基础上进行改动,自己训练一个crnn车牌识别模型。
2、可识别的车牌类型
- 单行蓝牌
- 单行黄牌
- 新能源车牌
- 白色警用车牌
- 使馆/港澳车牌
- 教练车牌
3、可识别的车牌类型
此处我们有依旧采用HyperLPR的
- cascade.xml 车牌检测模型 - 目前效果最好的cascade检测模型
PlateDetection::PlateDetection(std::string filename_cascade) { cascade.load(filename_cascade); }; void PlateDetection::plateDetectionRough(cv::Mat InputImage, std::vector<PlateInfo> &plateInfos, int min_w, int max_w) { cv::Mat processImage; cv::cvtColor(InputImage, processImage, cv::COLOR_BGR2GRAY); std::vector<cv::Rect> platesRegions; cv::Size minSize(min_w, min_w / 4); cv::Size maxSize(max_w, max_w / 4); cascade.detectMultiScale(processImage, platesRegions, 1.1, 3, cv::CASCADE_SCALE_IMAGE, minSize, maxSize); for (auto plate : platesRegions) { //此处稍微调整了一下,放大车牌截图 int zeroadd_x = static_cast<int>(plate.width * 0.1); int zeroadd_y = static_cast<int>(plate.height * 0.4); int zeroadd_w = static_cast<int>(plate.width * 0.2); int zeroadd_h = static_cast<int>(plate.height * 0.8); plate.x -= zeroadd_x; plate.y -= zeroadd_y; plate.height += zeroadd_h; plate.width += zeroadd_w; cv::Mat plateImage = util::cropFromImage(InputImage, plate); PlateInfo plateInfo(plateImage, plate); plateInfos.push_back(plateInfo); } }
- crnn.onnx端到端的车牌识别模型
- 车牌识别模型训练可参考:crnn-pytorch: crnn字符识别
PlateRecognizer::PlateRecognizer(std::string filename_crnn)
{
net = cv::dnn::readNet(filename_crnn);
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
//net.setPreferableBackend(cv::dnn::DNN_BACKEND_INFERENCE_ENGINE);
net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
}
inline float PlateRecognizer::Sigmoid(float x, std::vector<float> line_num)
{
float sum = 0.f;
for (int i = 0; i < line_num.size(); i++)
sum += exp(line_num[i]);
return static_cast<float>(exp(x) / sum);
}
std::pair<std::string, float> PlateRecognizer::getPlateName(cv::Mat &plateImg)
{
cv::Mat srcImg = plateImg.clone();
if (plateImg.channels() == 3) {
cvtColor(plateImg, srcImg, CV_BGR2GRAY);
}
cv::Mat blob = cv::dnn::blobFromImage(srcImg, 0.007843, cv::Size(128, 32), 127.5, false, false, CV_32F);
net.setInput(blob);
cv::Mat res = net.forward();
std::string plate, temp_C = "-";
float confidence = 0.0;
int length = 0;
std::vector<float> temp;
for (int r = 0; r < res.size[0]; r++)
{
cv::Mat slice = cv::Mat(1, res.size[2], CV_32F, res.ptr<float>(r));
float *line = (float*)res.ptr<float>(r);
for (int i = 0; i < slice.size[1]; i++) {
temp.push_back(line[i]);
}
cv::Point p; double m;
cv::minMaxLoc(slice, 0, &m, 0, &p);
std::string c = p.x > 0 ? alphabet[p.x - 1] : "-";
if (c != "-")
{
if (temp_C != c) {
plate += alphabet[p.x - 1];
}
length++;
confidence += Sigmoid((float)m, temp);
}
temp_C = c;
temp.clear();
}
std::pair<std::string, float> plate_conf("none", 0.f);
if (length > 0){
plate_conf.first = plate;
plate_conf.second = confidence / length;
}
return plate_conf;
}
4、检测结果