parent
fc49dbdee1
commit
5d3cd897f0
@ -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,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,25 +1,25 @@
|
||||
#ifndef EASYPR_TRAIN_ANNTRAIN_H_
|
||||
#define EASYPR_TRAIN_ANNTRAIN_H_
|
||||
|
||||
#include "easypr/train/train.h"
|
||||
|
||||
namespace easypr {
|
||||
|
||||
class AnnTrain : public ITrain {
|
||||
public:
|
||||
explicit AnnTrain(const char* chars_folder, const char* xml);
|
||||
|
||||
virtual void train();
|
||||
|
||||
virtual void test();
|
||||
|
||||
private:
|
||||
virtual cv::Ptr<cv::ml::TrainData> tdata();
|
||||
|
||||
cv::Ptr<cv::ml::ANN_MLP> ann_;
|
||||
const char* ann_xml_;
|
||||
const char* chars_folder_;
|
||||
};
|
||||
}
|
||||
|
||||
#ifndef EASYPR_TRAIN_ANNTRAIN_H_
|
||||
#define EASYPR_TRAIN_ANNTRAIN_H_
|
||||
|
||||
#include "easypr/train/train.h"
|
||||
|
||||
namespace easypr {
|
||||
|
||||
class AnnTrain : public ITrain {
|
||||
public:
|
||||
explicit AnnTrain(const char* chars_folder, const char* xml);
|
||||
|
||||
virtual void train();
|
||||
|
||||
virtual void test();
|
||||
|
||||
private:
|
||||
virtual cv::Ptr<cv::ml::TrainData> tdata();
|
||||
|
||||
cv::Ptr<cv::ml::ANN_MLP> ann_;
|
||||
const char* ann_xml_;
|
||||
const char* chars_folder_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // EASYPR_TRAIN_ANNTRAIN_H_
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,73 +1,80 @@
|
||||
// 这个文件定义了EasyPR里所有特征生成的函数
|
||||
// 所属命名空间为easypr
|
||||
// 这个部分中的特征由easypr的开发者修改
|
||||
|
||||
#include "easypr/core/feature.h"
|
||||
#include "easypr/core/core_func.h"
|
||||
|
||||
/*! \namespace easypr
|
||||
Namespace where all the C++ EasyPR functionality resides
|
||||
*/
|
||||
namespace easypr {
|
||||
|
||||
//! 获取垂直和水平的直方图图值
|
||||
Mat getTheFeatures(Mat in) {
|
||||
const int VERTICAL = 0;
|
||||
const int HORIZONTAL = 1;
|
||||
|
||||
// Histogram features
|
||||
Mat vhist = ProjectedHistogram(in, VERTICAL);
|
||||
Mat hhist = ProjectedHistogram(in, HORIZONTAL);
|
||||
|
||||
// Last 10 is the number of moments components
|
||||
int numCols = vhist.cols + hhist.cols;
|
||||
|
||||
Mat out = Mat::zeros(1, numCols, CV_32F);
|
||||
|
||||
// Asign values to feature,样本特征为水平、垂直直方图
|
||||
int j = 0;
|
||||
for (int i = 0; i < vhist.cols; i++) {
|
||||
out.at<float>(j) = vhist.at<float>(i);
|
||||
j++;
|
||||
}
|
||||
for (int i = 0; i < hhist.cols; i++) {
|
||||
out.at<float>(j) = hhist.at<float>(i);
|
||||
j++;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
//! EasyPR的getFeatures回调函数
|
||||
//! 本函数是获取垂直和水平的直方图图值
|
||||
void getHistogramFeatures(const Mat& image, Mat& features) {
|
||||
Mat grayImage;
|
||||
cvtColor(image, grayImage, CV_RGB2GRAY);
|
||||
|
||||
//grayImage = histeq(grayImage);
|
||||
|
||||
Mat img_threshold;
|
||||
threshold(grayImage, img_threshold, 0, 255,
|
||||
CV_THRESH_OTSU + CV_THRESH_BINARY);
|
||||
features = getTheFeatures(img_threshold);
|
||||
}
|
||||
|
||||
//! EasyPR的getFeatures回调函数
|
||||
//! 本函数是获取SITF特征子
|
||||
void getSIFTFeatures(const Mat& image, Mat& features) {
|
||||
//待完善
|
||||
}
|
||||
|
||||
//! EasyPR的getFeatures回调函数
|
||||
//! 本函数是获取HOG特征子
|
||||
void getHOGFeatures(const Mat& image, Mat& features) {
|
||||
//待完善
|
||||
}
|
||||
|
||||
//! EasyPR的getFeatures回调函数
|
||||
//! 本函数是获取HSV空间量化的直方图特征子
|
||||
void getHSVHistFeatures(const Mat& image, Mat& features) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
} /* \namespace easypr */
|
||||
// 这个文件定义了EasyPR里所有特征生成的函数
|
||||
// 所属命名空间为easypr
|
||||
// 这个部分中的特征由easypr的开发者修改
|
||||
|
||||
#include "easypr/core/feature.h"
|
||||
#include "easypr/core/core_func.h"
|
||||
|
||||
namespace easypr {
|
||||
|
||||
//! 获取垂直和水平的直方图图值
|
||||
|
||||
Mat getTheFeatures(Mat in) {
|
||||
const int VERTICAL = 0;
|
||||
const int HORIZONTAL = 1;
|
||||
|
||||
// Histogram features
|
||||
Mat vhist = ProjectedHistogram(in, VERTICAL);
|
||||
Mat hhist = ProjectedHistogram(in, HORIZONTAL);
|
||||
|
||||
// Last 10 is the number of moments components
|
||||
int numCols = vhist.cols + hhist.cols;
|
||||
|
||||
Mat out = Mat::zeros(1, numCols, CV_32F);
|
||||
|
||||
// Asign values to feature,样本特征为水平、垂直直方图
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < vhist.cols; i++) {
|
||||
out.at<float>(j) = vhist.at<float>(i);
|
||||
j++;
|
||||
}
|
||||
for (int i = 0; i < hhist.cols; i++) {
|
||||
out.at<float>(j) = hhist.at<float>(i);
|
||||
j++;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
//! EasyPR的getFeatures回调函数
|
||||
//! 本函数是获取垂直和水平的直方图图值
|
||||
|
||||
void getHistogramFeatures(const Mat& image, Mat& features) {
|
||||
Mat grayImage;
|
||||
cvtColor(image, grayImage, CV_RGB2GRAY);
|
||||
|
||||
//grayImage = histeq(grayImage);
|
||||
|
||||
Mat img_threshold;
|
||||
threshold(grayImage, img_threshold, 0, 255,
|
||||
CV_THRESH_OTSU + CV_THRESH_BINARY);
|
||||
features = getTheFeatures(img_threshold);
|
||||
}
|
||||
|
||||
//! EasyPR的getFeatures回调函数
|
||||
//! 本函数是获取SITF特征子
|
||||
|
||||
void getSIFTFeatures(const Mat& image, Mat& features) {
|
||||
|
||||
//待完善
|
||||
|
||||
}
|
||||
|
||||
//! EasyPR的getFeatures回调函数
|
||||
//! 本函数是获取HOG特征子
|
||||
|
||||
void getHOGFeatures(const Mat& image, Mat& features) {
|
||||
|
||||
//待完善
|
||||
|
||||
}
|
||||
|
||||
//! EasyPR的getFeatures回调函数
|
||||
//! 本函数是获取HSV空间量化的直方图特征子
|
||||
|
||||
void getHSVHistFeatures(const Mat& image, Mat& features) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,123 +1,123 @@
|
||||
#include "easypr/train/ann_train.h"
|
||||
#include "easypr/config.h"
|
||||
#include "easypr/core/chars_identify.h"
|
||||
#include "easypr/core/core_func.h"
|
||||
#include "easypr/util/util.h"
|
||||
|
||||
namespace easypr {
|
||||
|
||||
AnnTrain::AnnTrain(const char* chars_folder, const char* xml)
|
||||
: chars_folder_(chars_folder), ann_xml_(xml) {
|
||||
ann_ = cv::ml::ANN_MLP::create();
|
||||
}
|
||||
|
||||
void AnnTrain::train() {
|
||||
cv::Mat layers(1, 3, CV_32SC1);
|
||||
layers.at<int>(0) = 120; // the input layer
|
||||
layers.at<int>(1) = kNeurons; // the neurons
|
||||
layers.at<int>(2) = kCharsTotalNumber; // the output layer
|
||||
|
||||
ann_->setLayerSizes(layers);
|
||||
ann_->setActivationFunction(cv::ml::ANN_MLP::SIGMOID_SYM, 1, 1);
|
||||
ann_->setTrainMethod(cv::ml::ANN_MLP::TrainingMethods::BACKPROP);
|
||||
ann_->setBackpropWeightScale(0.1);
|
||||
ann_->setBackpropMomentumScale(0.1);
|
||||
|
||||
auto traindata = tdata();
|
||||
std::cout << "Training ANN model, please wait..." << std::endl;
|
||||
long start = utils::getTimestamp();
|
||||
ann_->train(traindata);
|
||||
long end = utils::getTimestamp();
|
||||
std::cout << "Training done. Time elapse: " << (end - start) << "ms"
|
||||
<< std::endl;
|
||||
|
||||
ann_->save(ann_xml_);
|
||||
std::cout << "Your ANN Model was saved to " << ann_xml_ << std::endl;
|
||||
}
|
||||
|
||||
void AnnTrain::test() {
|
||||
assert(chars_folder_);
|
||||
|
||||
for (int i = 0; i < kCharsTotalNumber; ++i) {
|
||||
auto char_key = kChars[i];
|
||||
char sub_folder[512] = {0};
|
||||
|
||||
sprintf(sub_folder, "%s/%s", chars_folder_, char_key);
|
||||
fprintf(stdout, ">> Testing characters %s in %s \n", char_key, sub_folder);
|
||||
|
||||
auto chars_files = utils::getFiles(sub_folder);
|
||||
int corrects = 0, sum = 0;
|
||||
std::vector<std::pair<std::string, std::string>> error_files;
|
||||
|
||||
for (auto file : chars_files) {
|
||||
auto img = cv::imread(file, 0); // a grayscale image
|
||||
std::pair<std::string, std::string> ch =
|
||||
CharsIdentify::instance()->identify(img);
|
||||
if (ch.first == char_key) {
|
||||
++corrects;
|
||||
} else {
|
||||
error_files.push_back(
|
||||
std::make_pair(utils::getFileName(file), ch.second));
|
||||
}
|
||||
++sum;
|
||||
}
|
||||
fprintf(stdout, ">> [sum: %d, correct: %d, rate: %.2f]\n", sum, corrects,
|
||||
(float)corrects / (sum == 0 ? 1 : sum));
|
||||
std::string error_string;
|
||||
auto end = error_files.end();
|
||||
if (error_files.size() >= 10) {
|
||||
end -= static_cast<size_t>(error_files.size() * (1 - 0.1));
|
||||
}
|
||||
for (auto k = error_files.begin(); k != end; ++k) {
|
||||
auto kv = *k;
|
||||
error_string.append(" ").append(kv.first).append(": ").append(
|
||||
kv.second);
|
||||
if (k != end - 1) {
|
||||
error_string.append(",\n");
|
||||
} else {
|
||||
error_string.append("\n ...");
|
||||
}
|
||||
}
|
||||
fprintf(stdout, ">> [\n%s\n ]\n", error_string.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
cv::Ptr<cv::ml::TrainData> AnnTrain::tdata() {
|
||||
assert(chars_folder_);
|
||||
|
||||
cv::Mat samples;
|
||||
std::vector<int> labels;
|
||||
|
||||
std::cout << "Collecting chars in " << chars_folder_ << std::endl;
|
||||
|
||||
for (int i = 0; i < kCharsTotalNumber; ++i) {
|
||||
auto char_key = kChars[i];
|
||||
char sub_folder[512] = {0};
|
||||
|
||||
sprintf(sub_folder, "%s/%s", chars_folder_, char_key);
|
||||
std::cout << " >> Featuring characters " << char_key << " in "
|
||||
<< sub_folder << std::endl;
|
||||
|
||||
auto chars_files = utils::getFiles(sub_folder);
|
||||
for (auto file : chars_files) {
|
||||
auto img = cv::imread(file, 0); // a grayscale image
|
||||
auto fps = features(img, kPredictSize);
|
||||
|
||||
samples.push_back(fps);
|
||||
labels.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat samples_;
|
||||
samples.convertTo(samples_, CV_32F);
|
||||
cv::Mat train_classes =
|
||||
cv::Mat::zeros((int)labels.size(), kCharsTotalNumber, CV_32F);
|
||||
|
||||
for (int i = 0; i < train_classes.rows; ++i) {
|
||||
train_classes.at<float>(i, labels[i]) = 1.f;
|
||||
}
|
||||
|
||||
return cv::ml::TrainData::create(samples_, cv::ml::SampleTypes::ROW_SAMPLE,
|
||||
train_classes);
|
||||
}
|
||||
}
|
||||
#include "easypr/train/ann_train.h"
|
||||
#include "easypr/config.h"
|
||||
#include "easypr/core/chars_identify.h"
|
||||
#include "easypr/core/core_func.h"
|
||||
#include "easypr/util/util.h"
|
||||
|
||||
namespace easypr {
|
||||
|
||||
AnnTrain::AnnTrain(const char* chars_folder, const char* xml)
|
||||
: chars_folder_(chars_folder), ann_xml_(xml) {
|
||||
ann_ = cv::ml::ANN_MLP::create();
|
||||
}
|
||||
|
||||
void AnnTrain::train() {
|
||||
cv::Mat layers(1, 3, CV_32SC1);
|
||||
layers.at<int>(0) = 120; // the input layer
|
||||
layers.at<int>(1) = kNeurons; // the neurons
|
||||
layers.at<int>(2) = kCharsTotalNumber; // the output layer
|
||||
|
||||
ann_->setLayerSizes(layers);
|
||||
ann_->setActivationFunction(cv::ml::ANN_MLP::SIGMOID_SYM, 1, 1);
|
||||
ann_->setTrainMethod(cv::ml::ANN_MLP::TrainingMethods::BACKPROP);
|
||||
ann_->setBackpropWeightScale(0.1);
|
||||
ann_->setBackpropMomentumScale(0.1);
|
||||
|
||||
auto traindata = tdata();
|
||||
std::cout << "Training ANN model, please wait..." << std::endl;
|
||||
long start = utils::getTimestamp();
|
||||
ann_->train(traindata);
|
||||
long end = utils::getTimestamp();
|
||||
std::cout << "Training done. Time elapse: " << (end - start) << "ms"
|
||||
<< std::endl;
|
||||
|
||||
ann_->save(ann_xml_);
|
||||
std::cout << "Your ANN Model was saved to " << ann_xml_ << std::endl;
|
||||
}
|
||||
|
||||
void AnnTrain::test() {
|
||||
assert(chars_folder_);
|
||||
|
||||
for (int i = 0; i < kCharsTotalNumber; ++i) {
|
||||
auto char_key = kChars[i];
|
||||
char sub_folder[512] = {0};
|
||||
|
||||
sprintf(sub_folder, "%s/%s", chars_folder_, char_key);
|
||||
fprintf(stdout, ">> Testing characters %s in %s \n", char_key, sub_folder);
|
||||
|
||||
auto chars_files = utils::getFiles(sub_folder);
|
||||
int corrects = 0, sum = 0;
|
||||
std::vector<std::pair<std::string, std::string>> error_files;
|
||||
|
||||
for (auto file : chars_files) {
|
||||
auto img = cv::imread(file, 0); // a grayscale image
|
||||
std::pair<std::string, std::string> ch =
|
||||
CharsIdentify::instance()->identify(img);
|
||||
if (ch.first == char_key) {
|
||||
++corrects;
|
||||
} else {
|
||||
error_files.push_back(
|
||||
std::make_pair(utils::getFileName(file), ch.second));
|
||||
}
|
||||
++sum;
|
||||
}
|
||||
fprintf(stdout, ">> [sum: %d, correct: %d, rate: %.2f]\n", sum, corrects,
|
||||
(float)corrects / (sum == 0 ? 1 : sum));
|
||||
std::string error_string;
|
||||
auto end = error_files.end();
|
||||
if (error_files.size() >= 10) {
|
||||
end -= static_cast<size_t>(error_files.size() * (1 - 0.1));
|
||||
}
|
||||
for (auto k = error_files.begin(); k != end; ++k) {
|
||||
auto kv = *k;
|
||||
error_string.append(" ").append(kv.first).append(": ").append(
|
||||
kv.second);
|
||||
if (k != end - 1) {
|
||||
error_string.append(",\n");
|
||||
} else {
|
||||
error_string.append("\n ...");
|
||||
}
|
||||
}
|
||||
fprintf(stdout, ">> [\n%s\n ]\n", error_string.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
cv::Ptr<cv::ml::TrainData> AnnTrain::tdata() {
|
||||
assert(chars_folder_);
|
||||
|
||||
cv::Mat samples;
|
||||
std::vector<int> labels;
|
||||
|
||||
std::cout << "Collecting chars in " << chars_folder_ << std::endl;
|
||||
|
||||
for (int i = 0; i < kCharsTotalNumber; ++i) {
|
||||
auto char_key = kChars[i];
|
||||
char sub_folder[512] = {0};
|
||||
|
||||
sprintf(sub_folder, "%s/%s", chars_folder_, char_key);
|
||||
std::cout << " >> Featuring characters " << char_key << " in "
|
||||
<< sub_folder << std::endl;
|
||||
|
||||
auto chars_files = utils::getFiles(sub_folder);
|
||||
for (auto file : chars_files) {
|
||||
auto img = cv::imread(file, 0); // a grayscale image
|
||||
auto fps = features(img, kPredictSize);
|
||||
|
||||
samples.push_back(fps);
|
||||
labels.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat samples_;
|
||||
samples.convertTo(samples_, CV_32F);
|
||||
cv::Mat train_classes =
|
||||
cv::Mat::zeros((int)labels.size(), kCharsTotalNumber, CV_32F);
|
||||
|
||||
for (int i = 0; i < train_classes.rows; ++i) {
|
||||
train_classes.at<float>(i, labels[i]) = 1.f;
|
||||
}
|
||||
|
||||
return cv::ml::TrainData::create(samples_, cv::ml::SampleTypes::ROW_SAMPLE,
|
||||
train_classes);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "easypr/train/train.h"
|
||||
|
||||
namespace easypr {
|
||||
|
||||
ITrain::ITrain() {}
|
||||
|
||||
ITrain::~ITrain() {}
|
||||
}
|
||||
#include "easypr/train/train.h"
|
||||
|
||||
namespace easypr {
|
||||
|
||||
ITrain::ITrain() {}
|
||||
|
||||
ITrain::~ITrain() {}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue