|
|
|
@ -1,9 +1,11 @@
|
|
|
|
|
//该代码主要用于车牌识别。它定义了一个名为PlateJudge的类,该类包含了一系列用于车牌识别的方法。
|
|
|
|
|
|
|
|
|
|
#include "easypr/core/plate_judge.h"
|
|
|
|
|
#include "easypr/config.h"
|
|
|
|
|
#include "easypr/core/core_func.h"
|
|
|
|
|
#include "easypr/core/params.h"
|
|
|
|
|
|
|
|
|
|
namespace easypr {
|
|
|
|
|
namespace easypr { //这部分代码实现了单例模式,确保PlateJudge类只有一个实例
|
|
|
|
|
|
|
|
|
|
PlateJudge* PlateJudge::instance_ = nullptr;
|
|
|
|
|
|
|
|
|
@ -14,7 +16,7 @@ namespace easypr {
|
|
|
|
|
return instance_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PlateJudge::PlateJudge() {
|
|
|
|
|
PlateJudge::PlateJudge() { //PlateJudge决定了使用哪种特征提取方法。
|
|
|
|
|
bool useLBP = false;
|
|
|
|
|
if (useLBP) {
|
|
|
|
|
LOAD_SVM_MODEL(svm_, kLBPSvmPath);
|
|
|
|
@ -26,7 +28,7 @@ namespace easypr {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PlateJudge::LoadModel(std::string path) {
|
|
|
|
|
void PlateJudge::LoadModel(std::string path) { //LoadModel函数用于加载SVM模型。
|
|
|
|
|
if (path != std::string(kDefaultSvmPath)) {
|
|
|
|
|
if (!svm_->empty())
|
|
|
|
|
svm_->clear();
|
|
|
|
@ -36,7 +38,7 @@ namespace easypr {
|
|
|
|
|
|
|
|
|
|
// set the score of plate
|
|
|
|
|
// 0 is plate, -1 is not.
|
|
|
|
|
int PlateJudge::plateSetScore(CPlate& plate) {
|
|
|
|
|
int PlateJudge::plateSetScore(CPlate& plate) { //plateSetScore函数用于设置车牌的评分。
|
|
|
|
|
Mat features;
|
|
|
|
|
extractFeature(plate.getPlateMat(), features);
|
|
|
|
|
float score = svm_->predict(features, noArray(), cv::ml::StatModel::Flags::RAW_OUTPUT);
|
|
|
|
@ -53,53 +55,60 @@ namespace easypr {
|
|
|
|
|
else return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int PlateJudge::plateJudge(const Mat& plateMat) {
|
|
|
|
|
int PlateJudge::plateJudge(const Mat& plateMat) { //plateJudge函数用于判断输入的图像是否为车牌。
|
|
|
|
|
CPlate plate;
|
|
|
|
|
plate.setPlateMat(plateMat);
|
|
|
|
|
return plateSetScore(plate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int PlateJudge::plateJudge(const std::vector<Mat> &inVec,
|
|
|
|
|
std::vector<Mat> &resultVec) {
|
|
|
|
|
int num = inVec.size();
|
|
|
|
|
for (int j = 0; j < num; j++) {
|
|
|
|
|
Mat inMat = inVec[j];
|
|
|
|
|
int PlateJudge::plateJudge(const std::vector<Mat> &inVec, //inVec是输入的图像向量,resultVec是输出的结果向量。
|
|
|
|
|
std::vector<Mat> &resultVec) { //对inVec中的每一张图像进行车牌判断。如果判断结果为车牌(即plateJudge(inMat)的返回值为0),则将该图像添加到resultVec中。
|
|
|
|
|
int num = inVec.size(); // 获取输入图像的数量
|
|
|
|
|
for (int j = 0; j < num; j++) { // 遍历每一张图像
|
|
|
|
|
Mat inMat = inVec[j]; // 获取当前图像
|
|
|
|
|
|
|
|
|
|
int response = -1;
|
|
|
|
|
response = plateJudge(inMat);
|
|
|
|
|
response = plateJudge(inMat); // 对当前图像进行车牌判断
|
|
|
|
|
|
|
|
|
|
if (response == 0) resultVec.push_back(inMat);
|
|
|
|
|
if (response == 0) resultVec.push_back(inMat); // 如果判断结果为车牌,将该图像添加到结果向量中
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
return 0; // 返回0,表示执行成功
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int PlateJudge::plateJudge(const std::vector<CPlate> &inVec,
|
|
|
|
|
std::vector<CPlate> &resultVec) {
|
|
|
|
|
int num = inVec.size();
|
|
|
|
|
for (int j = 0; j < num; j++) {
|
|
|
|
|
CPlate inPlate = inVec[j];
|
|
|
|
|
//属于PlateJudge类,用于判断输入的车牌向量中哪些是有效的车牌。这个方法的输入是一个CPlate对象的向量inVec,输出是一个有效车牌的CPlate对象的向量resultVec。
|
|
|
|
|
int PlateJudge::plateJudge(const std::vector<CPlate> &inVec,
|
|
|
|
|
std::vector<CPlate> &resultVec) { //接收两个参数:一个CPlate对象的向量inVec(输入的车牌向量)和一个CPlate对象的向量resultVec(输出的有效车牌向量)。
|
|
|
|
|
int num = inVec.size(); // 获取输入向量的大小
|
|
|
|
|
for (int j = 0; j < num; j++) { //遍历输入向量中的每一个元素
|
|
|
|
|
|
|
|
|
|
//获取当前的CPlate对象和它的车牌图像
|
|
|
|
|
CPlate inPlate = inVec[j];
|
|
|
|
|
Mat inMat = inPlate.getPlateMat();
|
|
|
|
|
|
|
|
|
|
//调用plateJudge方法判断当前的车牌图像是否有效,结果存储在response中
|
|
|
|
|
int response = -1;
|
|
|
|
|
response = plateJudge(inMat);
|
|
|
|
|
|
|
|
|
|
//如果当前的车牌图像有效(response等于0),则将当前的CPlate对象添加到结果向量中
|
|
|
|
|
if (response == 0)
|
|
|
|
|
resultVec.push_back(inPlate);
|
|
|
|
|
//如果当前的车牌图像无效,那么对车牌图像进行裁剪和调整大小
|
|
|
|
|
else {
|
|
|
|
|
int w = inMat.cols;
|
|
|
|
|
int h = inMat.rows;
|
|
|
|
|
Mat tmpmat = inMat(Rect_<double>(w * 0.05, h * 0.1, w * 0.9, h * 0.8));
|
|
|
|
|
Mat tmpDes = inMat.clone();
|
|
|
|
|
resize(tmpmat, tmpDes, Size(inMat.size()));
|
|
|
|
|
|
|
|
|
|
//再次调用plateJudge方法判断调整后的车牌图像是否有效,如果有效则将当前的CPlate对象添加到结果向量中
|
|
|
|
|
response = plateJudge(tmpDes);
|
|
|
|
|
if (response == 0) resultVec.push_back(inPlate);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
return 0; //结束循环并返回0,表示方法执行成功
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// non-maximum suppression
|
|
|
|
|
void NMS(std::vector<CPlate> &inVec, std::vector<CPlate> &resultVec, double overlap) {
|
|
|
|
|
void NMS(std::vector<CPlate> &inVec, std::vector<CPlate> &resultVec, double overlap) { //NMS函数实现了非极大值抑制,用于消除重叠的车牌。
|
|
|
|
|
std::sort(inVec.begin(), inVec.end());
|
|
|
|
|
std::vector<CPlate>::iterator it = inVec.begin();
|
|
|
|
|
for (; it != inVec.end(); ++it) {
|
|
|
|
@ -123,7 +132,7 @@ namespace easypr {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// judge plate using nms
|
|
|
|
|
int PlateJudge::plateJudgeUsingNMS(const std::vector<CPlate> &inVec, std::vector<CPlate> &resultVec, int maxPlates) {
|
|
|
|
|
int PlateJudge::plateJudgeUsingNMS(const std::vector<CPlate> &inVec, std::vector<CPlate> &resultVec, int maxPlates) { //plateJudgeUsingNMS函数使用非极大值抑制进行车牌识别。
|
|
|
|
|
std::vector<CPlate> plateVec;
|
|
|
|
|
int num = inVec.size();
|
|
|
|
|
bool useCascadeJudge = true;
|
|
|
|
|