* new feature extracting method for gray Chinese mat

* new training process for Chinese gray images.
v1.6alpha
liuruoze 8 years ago
parent 1e604768db
commit a366a0b950

Binary file not shown.

Binary file not shown.

@ -9,10 +9,12 @@ error_code 错误码
summaries 统计参数
sum_pictures 总图片数
unrecognized 未定位车牌
locate_rate 定位
locate_rate 检出
diff_average 平均字符差距
full_match 完全匹配数
full_rate 完全匹配率
seconds 总时间
seconds 总时间
seconds_average 平均执行时间
sec 秒
sec 秒
detect_quality 定位
char_recongize 字符

@ -1,10 +1,10 @@
////////////////////////////////////
EasyPR Option:
1. 测试;
2. 批量测试;
2. 批量测试(推荐);
3. SVM训练;
4. ANN训练;
5. GDTS生成;
5. 中文字符训练;
6. 开发团队;
7. 感谢名单;
8. 退出;

@ -4,6 +4,7 @@
#include "easypr/core/plate_recognize.h"
#include "easypr/train/svm_train.h"
#include "easypr/train/ann_train.h"
#include "easypr/train/annCh_train.h"
#include "easypr/util/util.h"
#include "easypr/util/program_options.h"
#include "easypr/api.hpp"

@ -84,12 +84,27 @@ static const int kCharsTotalNumber = 65;
static bool kDebug = false;
static const int kGrayCharWidth = 20;
static const int kGrayCharHeight = 32;
// Disable the copy and assignment operator for this class.
#define DISABLE_ASSIGN_AND_COPY(className) \
private:\
className& operator=(const className&); \
className(const className&)
// Display the image.
#define SET_DEBUG(param) \
kDebug = param
// Display the image.
#define SHOW_IMAGE(imgName) \
if (kDebug) { \
imshow("imgName", imgName); \
waitKey(0); \
destroyWindow("imgName"); \
}
}
#endif // EASYPR_CONFIG_H_

@ -102,12 +102,6 @@ bool calcSafeRect(const RotatedRect& roi_rect, const Mat& src,
bool calcSafeRect(const RotatedRect &roi_rect, const int width, const int height,
Rect_<float> &safeBoundRect);
// shift an image
Mat translateImg(Mat img, int offsetx, int offsety);
// rotate an image
Mat rotateImg(Mat source, float angle);
// uniform resize all the image to same size for the next process
Mat uniformResize(const Mat &result, float& scale);

@ -12,6 +12,10 @@ cv::Mat getHistogram(cv::Mat in);
//! 用于从车牌的image生成svm的训练特征features
typedef void (*svmCallback)(const cv::Mat& image, cv::Mat& features);
//! EasyPR的getFeatures回调函数
//! convert from images to features used by gray char ann
typedef void (*annCallback)(const cv::Mat& image, cv::Mat& features);
//! EasyPR的getFeatures回调函数
//! 本函数是获取垂直和水平的直方图图值
void getHistogramFeatures(const cv::Mat& image, cv::Mat& features);
@ -41,6 +45,9 @@ cv::Mat charFeatures2(cv::Mat in, int sizeData);
//! LBP feature + Histom feature
void getLBPplusHistFeatures(const cv::Mat& image, cv::Mat& features);
//! grayChar feauter
void getGrayCharFeatures(const cv::Mat& grayChar, cv::Mat& features);
} /*! \namespace easypr*/
#endif // EASYPR_CORE_FEATURE_H_

@ -0,0 +1,38 @@
#ifndef EASYPR_TRAIN_ANNCHTRAIN_H_
#define EASYPR_TRAIN_ANNCHTRAIN_H_
#include "easypr/train/train.h"
#include "easypr/util/kv.h"
#include "easypr/core/feature.h"
#include <memory>
namespace easypr {
class AnnChTrain : public ITrain {
public:
explicit AnnChTrain(const char* chars_folder, const char* xml);
virtual void train();
virtual void test();
std::pair<std::string, std::string> identifyChinese(cv::Mat input);
cv::Mat AnnChTrain::generateGraySyntheticImage(const cv::Mat& image);
private:
virtual cv::Ptr<cv::ml::TrainData> tdata();
void AnnChTrain::trainVal(size_t number_for_count = 100);
cv::Ptr<cv::ml::ANN_MLP> ann_;
const char* ann_xml_;
const char* chars_folder_;
std::shared_ptr<Kv> kv_;
int type;
annCallback extractFeature;
};
}
#endif // EASYPR_TRAIN_ANNCHTRAIN_H_

@ -0,0 +1,27 @@
#ifndef EASYPR_CREATE_DATA_H_
#define EASYPR_CREATE_DATA_H_
#include "opencv2/opencv.hpp"
#include "easypr/config.h"
using namespace cv;
using namespace std;
/*! \namespace easypr
Namespace where all the C++ EasyPR functionality resides
*/
namespace easypr {
// shift an image
Mat translateImg(Mat img, int offsetx, int offsety);
// rotate an image
Mat rotateImg(Mat source, float angle);
// crop the image
Mat cropImg(Mat src, int x, int y, int shift);
Mat generateSyntheticImage(const Mat& image, int use_swap = 1);
} /*! \namespace easypr*/
#endif // EASYPR_CREATE_DATA_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

@ -27,13 +27,13 @@
<image>
<imageName>¾©PC5U22</imageName>
<taggedRectangles>
<taggedRectangle x="271" y="231" width="149" height="36" rotation="2">À¶ÅÆ:ÁÉAU3UZ2</taggedRectangle>
<taggedRectangle x="271" y="231" width="149" height="36" rotation="2">À¶ÅÆ:ËÕA88888</taggedRectangle>
</taggedRectangles>
</image>
<image>
<imageName>¼½FA3215</imageName>
<taggedRectangles>
<taggedRectangle x="99" y="689" width="128" height="39" rotation="-2">À¶ÅÆ:½úFA3215</taggedRectangle>
<taggedRectangle x="99" y="689" width="128" height="39" rotation="-2">À¶ÅÆ:³FA3215</taggedRectangle>
<taggedRectangle x="648" y="595" width="106" height="33" rotation="-1">À¶ÅÆ:ÏæAT1203</taggedRectangle>
<taggedRectangle x="970" y="600" width="121" height="30" rotation="0">À¶ÅÆ:ËÕA88888</taggedRectangle>
</taggedRectangles>
@ -137,7 +137,7 @@
<image>
<imageName>´¨AKQ291</imageName>
<taggedRectangles>
<taggedRectangle x="405" y="157" width="91" height="33" rotation="0">À¶ÅÆ:´¨AKQ291</taggedRectangle>
<taggedRectangle x="405" y="157" width="91" height="33" rotation="0">À¶ÅÆ:´¨AYQ291</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -228,7 +228,7 @@
<image>
<imageName>»¦AP0910</imageName>
<taggedRectangles>
<taggedRectangle x="798" y="610" width="123" height="35" rotation="0">»ÆÅÆ:»¦4PD91D</taggedRectangle>
<taggedRectangle x="798" y="610" width="123" height="35" rotation="0">»ÆÅÆ:»¦AP0910</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -272,13 +272,13 @@
<taggedRectangles>
<taggedRectangle x="687" y="526" width="139" height="43" rotation="4">À¶ÅÆ:½òAHP676</taggedRectangle>
<taggedRectangle x="824" y="174" width="55" height="18" rotation="0">À¶ÅÆ:ÄþGPF690</taggedRectangle>
<taggedRectangle x="1030" y="210" width="79" height="26" rotation="0">À¶ÅÆ:ËÕA88888</taggedRectangle>
<taggedRectangle x="1030" y="210" width="79" height="26" rotation="0">À¶ÅÆ:¶õ4GX178</taggedRectangle>
</taggedRectangles>
</image>
<image>
<imageName>½òDTG667</imageName>
<taggedRectangles>
<taggedRectangle x="668" y="703" width="176" height="47" rotation="6">À¶ÅÆ:¶õD1G667</taggedRectangle>
<taggedRectangle x="668" y="703" width="176" height="47" rotation="6">À¶ÅÆ:½òDTG667</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -314,7 +314,7 @@
<imageName>½òG68991</imageName>
<taggedRectangles>
<taggedRectangle x="977" y="411" width="152" height="36" rotation="4">À¶ÅÆ:½òG68991</taggedRectangle>
<taggedRectangle x="348" y="260" width="135" height="46" rotation="4">À¶ÅÆ:¶õM36N4</taggedRectangle>
<taggedRectangle x="348" y="260" width="135" height="46" rotation="4">À¶ÅÆ:ÃÉMRW36N</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -508,7 +508,7 @@
<image>
<imageName>ÕãG70000</imageName>
<taggedRectangles>
<taggedRectangle x="141" y="212" width="83" height="27" rotation="5">À¶ÅÆ:³G7001</taggedRectangle>
<taggedRectangle x="141" y="212" width="83" height="27" rotation="5">À¶ÅÆ:ËÕA88888</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -575,7 +575,7 @@
<imageName>ÏæA07G31</imageName>
<taggedRectangles>
<taggedRectangle x="96" y="885" width="191" height="61" rotation="0">À¶ÅÆ:¾©A11R55</taggedRectangle>
<taggedRectangle x="899" y="651" width="129" height="33" rotation="-2">À¶ÅÆ:ËÕA88888</taggedRectangle>
<taggedRectangle x="899" y="651" width="129" height="33" rotation="-2">À¶ÅÆ:ÃöL1C01Y</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -775,7 +775,7 @@
<image>
<imageName>ÍîA80375</imageName>
<taggedRectangles>
<taggedRectangle x="421" y="259" width="73" height="21" rotation="-1">»ÆÅÆ:ÍîA8037R</taggedRectangle>
<taggedRectangle x="421" y="259" width="73" height="21" rotation="-1">»ÆÅÆ:¼½A8037Q</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -952,7 +952,7 @@
<image>
<imageName>ÔÁA5DP12</imageName>
<taggedRectangles>
<taggedRectangle x="1120" y="747" width="185" height="70" rotation="0">À¶ÅÆ:ÔÁA5BP11</taggedRectangle>
<taggedRectangle x="1120" y="747" width="185" height="70" rotation="0">À¶ÅÆ:ÔÁA5DP11</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -1012,7 +1012,7 @@
<image>
<imageName>ÔÁAAA379</imageName>
<taggedRectangles>
<taggedRectangle x="359" y="329" width="206" height="56" rotation="4">À¶ÅÆ:ÔÁAAA39</taggedRectangle>
<taggedRectangle x="359" y="329" width="206" height="56" rotation="4">À¶ÅÆ:³AAA379</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -1024,7 +1024,7 @@
<image>
<imageName>ÔÁAAC044</imageName>
<taggedRectangles>
<taggedRectangle x="345" y="291" width="206" height="61" rotation="4">À¶ÅÆ:ÔÁAAC044</taggedRectangle>
<taggedRectangle x="345" y="291" width="206" height="61" rotation="4">À¶ÅÆ:¶õAAC044</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -1036,7 +1036,7 @@
<image>
<imageName>ÔÁAAF230</imageName>
<taggedRectangles>
<taggedRectangle x="290" y="274" width="218" height="61" rotation="3">À¶ÅÆ:ÔÁAAF2U0</taggedRectangle>
<taggedRectangle x="290" y="274" width="218" height="61" rotation="3">À¶ÅÆ:³AAF230</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -1187,7 +1187,7 @@
<image>
<imageName>ÔÁBP3T05</imageName>
<taggedRectangles>
<taggedRectangle x="163" y="348" width="78" height="23" rotation="0">À¶ÅÆ:ÔÁBP3T05</taggedRectangle>
<taggedRectangle x="163" y="348" width="78" height="23" rotation="0">À¶ÅÆ:ºÚBP3T05</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -1253,7 +1253,7 @@
<image>
<imageName>ÔÁSD050L</imageName>
<taggedRectangles>
<taggedRectangle x="1434" y="716" width="188" height="59" rotation="-1">À¶ÅÆ:ÔÁSD050L</taggedRectangle>
<taggedRectangle x="1434" y="716" width="188" height="59" rotation="-1">À¶ÅÆ:ÔÁS0050L</taggedRectangle>
</taggedRectangles>
</image>
<image>
@ -1325,13 +1325,13 @@
<image>
<imageName>ËÕA9YP07</imageName>
<taggedRectangles>
<taggedRectangle x="516" y="363" width="126" height="37" rotation="3">À¶ÅÆ:ºÚGQ9YP0</taggedRectangle>
<taggedRectangle x="516" y="363" width="126" height="37" rotation="3">À¶ÅÆ:ºÚ49YP07</taggedRectangle>
</taggedRectangles>
</image>
<image>
<imageName>ËÕAD6A99</imageName>
<taggedRectangles>
<taggedRectangle x="488" y="395" width="234" height="65" rotation="0">À¶ÅÆ:ËÕAD6A99</taggedRectangle>
<taggedRectangle x="488" y="395" width="234" height="65" rotation="0">À¶ÅÆ:¸ÊAC6A99</taggedRectangle>
</taggedRectangles>
</image>
<image>

@ -2533,3 +2533,48 @@ Recall:88.4615%, Precise:53.4871%, Fscore:66.6657%.
Recall:78.0573%, Precise:83.3587%, Fscore:80.6209%.
0-error:60.8%, 1-error:71.6%, Chinese-precise:74.4%
总时间:579秒, 平均执行时间:2.26172秒
2017-04-04 09:17:48
总图片数:256, Plates count:297, 未定位车牌:45, 定位率:84.8485%
Recall:78.713%, Precise:83.4918%, Fscore:81.032%.
0-error:59.127%, 1-error:69.8413%, Chinese-precise:72.2222%
总时间:557秒, 平均执行时间:2.17578秒
2017-04-04 09:29:05
总图片数:0, Plates count:0, 未定位车牌:0, 检出率:-1.#IND%
Recall:0%, Precise:0%, Fscore:0%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总时间:0秒, 平均执行时间:-1.#IND秒
2017-04-04 09:29:55
总图片数: 0, Plates count:0, 未定位车牌:0, 检出率:-1.#IND%
Recall:0%, Precise:0%, Fscore:0%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总时间: 0秒, 平均执行时间:-1.#IND秒
2017-04-04 09:30:41
总图片数:0, Plates count:0, 未定位车牌:0, 检出率:-1.#IND%
Recall:0%, Precise:0%, Fscore:0%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总时间: 0秒, 平均执行时间:-1.#IND秒
2017-04-04 09:31:39
总图片数:0, Plates count:0, 未定位车牌:0, 检出率:-1.#IND%
Recall:0%, Precise:0%, Fscore:0%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总共时间: 0秒, 平均执行时间:-1.#IND秒
2017-04-04 09:33:13
总图片数:0, Plates count:0, 未定位车牌:0, 检出率:-1.#IND%
Recall:0%, Precise:0%, Fscore:0%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总共时间: 0秒, 平均执行时间:-1.#IND秒
2017-04-04 09:33:44
总图片数:0, Plates count:0, 未定位车牌:0, 检出率:-1.#IND%
Recall:0%, Precise:0%, Fscore:0%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总共时间: 0秒, 平均执行时间:-1.#IND秒
2017-04-04 09:34:02
总图片数:0, Plates count:0, 未定位车牌:0, 检出率:-1.#IND%
Recall:0%, Precise:0%, Fscore:0%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总共时间: 0秒, 平均执行时间:-1.#IND秒
2017-04-04 09:43:26
总图片数:256, Plates count:297, 未定位车牌:12, 检出率:95.9596%
Recall:88.4994%, Precise:66.935%, Fscore:76.2213%.
0-error:59.6%, 1-error:70.4%, Chinese-precise:72.4%
总共时间: 552秒, 平均执行时间:2.15625秒

@ -2230,23 +2230,6 @@ Mat adaptive_image_from_points(const std::vector<Point>& points,
return result;
}
// shift an image
Mat translateImg(Mat img, int offsetx, int offsety){
Mat dst;
Mat trans_mat = (Mat_<double>(2, 3) << 1, 0, offsetx, 0, 1, offsety);
warpAffine(img, dst, trans_mat, img.size());
return dst;
}
// rotate an image
Mat rotateImg(Mat source, float angle){
Point2f src_center(source.cols / 2.0F, source.rows / 2.0F);
Mat rot_mat = getRotationMatrix2D(src_center, angle, 1.0);
Mat dst;
warpAffine(source, dst, rot_mat, source.size());
return dst;
}
// calc safe Rect
// if not exit, return false

@ -208,9 +208,6 @@ Mat charFeatures2(Mat in, int sizeData) {
int numCols = vhist.cols + hhist.cols + lowData.cols * lowData.cols;
Mat out = Mat::zeros(1, numCols, CV_32F);
// Asign values to
// feature,ANN的样本特征为水平、垂直直方图和低分辨率图像所组成的矢量
int j = 0;
for (int i = 0; i < vhist.cols; i++) {
@ -233,6 +230,42 @@ Mat charFeatures2(Mat in, int sizeData) {
return out;
}
void getGrayCharFeatures(const Mat& grayChar, Mat& features) {
SET_DEBUG(true);
// TODO: check channnels == 1
SHOW_IMAGE(grayChar);
// resize to uniform size, like 20x32
Mat char_mat;
char_mat.create(kGrayCharHeight, kGrayCharWidth, CV_32FC1);
resize(grayChar, char_mat, char_mat.size(), 0, 0, INTER_LINEAR);
SHOW_IMAGE(char_mat);
// convert to float
bool useConvert = false;
if (useConvert) {
Mat float_img;
float scale = 1.f / 255;
char_mat.convertTo(float_img, CV_32FC1, scale, 0);
SHOW_IMAGE(float_img);
}
// cut from mean, it can be optional
bool useMean = true;
if (useMean) {
char_mat -= mean(char_mat);
SHOW_IMAGE(char_mat);
}
// use lbp to get features, it can be changed to other
Mat lbpimage = libfacerec::olbp(char_mat);
SHOW_IMAGE(lbpimage);
Mat lbp_hist = libfacerec::spatial_histogram(lbpimage, 32, 4, 4);
// return back
features = lbp_hist;
}
void getLBPplusHistFeatures(const Mat& image, Mat& features) {
// TODO

@ -63,12 +63,12 @@ int CPlateRecognize::plateRecognize(const Mat& src, std::vector<CPlate> &plateVe
plateVecOut.push_back(item);
}
else {
/*std::string license = plateColor;
std::string license = plateColor;
item.setPlateStr(license);
plateVecOut.push_back(item);
if (0) {
std::cout << "resultCR:" << resultCR << std::endl;
}*/
}
}
}
if (getResultShow()) {

@ -0,0 +1,223 @@
#include <numeric>
#include <ctime>
#include "easypr/train/annCh_train.h"
#include "easypr/config.h"
#include "easypr/core/chars_identify.h"
#include "easypr/core/feature.h"
#include "easypr/core/core_func.h"
#include "easypr/util/util.h"
#include "easypr/train/create_data.h"
namespace easypr {
AnnChTrain::AnnChTrain(const char* chars_folder, const char* xml)
: chars_folder_(chars_folder), ann_xml_(xml) {
ann_ = cv::ml::ANN_MLP::create();
type = 1;
kv_ = std::shared_ptr<Kv>(new Kv);
kv_->load("etc/province_mapping");
extractFeature = getGrayCharFeatures;
}
void AnnChTrain::train() {
int classNumber = 0;
int input_number = 0;
int hidden_number = 0;
int output_number = 0;
classNumber = kChineseNumber;
input_number = kGrayCharHeight * kGrayCharWidth;
hidden_number = 64;
output_number = classNumber;
cv::Mat layers;
layers.create(1, 3, CV_32SC1);
layers.at<int>(0) = input_number;
layers.at<int>(1) = hidden_number;
layers.at<int>(2) = output_number;
ann_->setLayerSizes(layers);
ann_->setActivationFunction(cv::ml::ANN_MLP::SIGMOID_SYM, 1, 1);
ann_->setTrainMethod(cv::ml::ANN_MLP::TrainingMethods::RPROP);
ann_->setTermCriteria(cvTermCriteria(CV_TERMCRIT_ITER, 30000, 0.0001));
ann_->setBackpropWeightScale(0.05);
ann_->setBackpropMomentumScale(0.9);
// using raw data or raw + synthic data.
trainVal(350);
}
std::pair<std::string, std::string> AnnChTrain::identifyChinese(cv::Mat input) {
Mat feature;
extractFeature(input, feature);
float maxVal = -2;
int result = -1;
cv::Mat output(1, kChineseNumber, CV_32FC1);
ann_->predict(feature, output);
for (int j = 0; j < kChineseNumber; j++) {
float val = output.at<float>(j);
// std::cout << "j:" << j << "val:" << val << std::endl;
if (val > maxVal) {
maxVal = val;
result = j;
}
}
auto index = result + kCharsTotalNumber - kChineseNumber;
const char* key = kChars[index];
std::string s = key;
std::string province = kv_->get(s);
return std::make_pair(s, province);
}
void AnnChTrain::test() {
//TODO
}
cv::Mat AnnChTrain::generateGraySyntheticImage(const Mat& image) {
int rand_type = rand();
Mat result = image.clone();
if (rand_type % 2 == 0) {
int ran_x = rand() % 5 - 2;
int ran_y = rand() % 5 - 2;
result = translateImg(result, ran_x, ran_y);
}
else if (rand_type % 2 != 0) {
float angle = float(rand() % 15 - 7);
result = rotateImg(result, angle);
}
return result;
}
void AnnChTrain::trainVal(size_t number_for_count) {
assert(chars_folder_);
cv::Mat train_samples;
std::vector<cv::Mat> val_images;
std::vector<int> train_label, val_labels;
float percentage = 0.7f;
int classNumber = kChineseNumber;
for (int i = 0; i < classNumber; ++i) {
auto char_key = kChars[i + kCharsTotalNumber - classNumber];
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);
size_t char_size = chars_files.size();
fprintf(stdout, ">> Characters count: %d \n", char_size);
std::vector<cv::Mat> matVec;
matVec.reserve(number_for_count);
for (auto file : chars_files) {
auto img = cv::imread(file, IMREAD_GRAYSCALE); // a grayscale image
matVec.push_back(img);
}
// genrate the synthetic images
/*for (int t = 0; t < (int)number_for_count - (int)char_size; t++) {
int rand_range = char_size + t;
int ran_num = rand() % rand_range;
auto img = matVec.at(ran_num);
auto simg = generateGraySyntheticImage(img);
matVec.push_back(simg);
}*/
fprintf(stdout, ">> Characters count: %d \n", matVec.size());
// random sort the mat;
srand(unsigned(time(NULL)));
//random_shuffle(matVec.begin(), matVec.end());
size_t split_index = size_t(matVec.size() * percentage);
for (size_t i = 0; i < matVec.size(); ++i) {
Mat img = matVec.at(i);
Mat feature;
extractFeature(img, feature);
if (i <= split_index) {
train_samples.push_back(feature);
train_label.push_back(i);
}
else {
val_images.push_back(img);
val_labels.push_back(i);
}
}
}
// generate train data
train_samples.convertTo(train_samples, CV_32F);
cv::Mat train_classes = cv::Mat::zeros((int)train_label.size(), classNumber, CV_32F);
for (int i = 0; i < train_classes.rows; ++i)
train_classes.at<float>(i, train_label[i]) = 1.f;
auto train_data = cv::ml::TrainData::create(train_samples, cv::ml::SampleTypes::ROW_SAMPLE, train_classes);
// train the data, calculate the cost time
std::cout << "Training ANN chinese model, please wait..." << std::endl;
long start = utils::getTimestamp();
ann_->train(train_data);
long end = utils::getTimestamp();
ann_->save(ann_xml_);
std::cout << "Your ANN Model was saved to " << ann_xml_ << std::endl;
std::cout << "Training done. Time elapse: " << (end - start) / (1000 * 60) << "minute" << std::endl;
// test the accuracy_rate
int corrects_all = 0, sum_all = val_images.size();
for (size_t i = 0; i < val_images.size(); ++i) {
cv::Mat img = val_images.at(i);
int label = val_labels.at(i);
auto char_key = kChars[i + kCharsTotalNumber - classNumber];
std::pair<std::string, std::string> ch = identifyChinese(img);
if (ch.first == char_key)
corrects_all++;
}
float accuracy_rate = (float)corrects_all / (float)sum_all;
std::cout << "Accuracy_rate: " << accuracy_rate << std::endl;
}
cv::Ptr<cv::ml::TrainData> AnnChTrain::tdata() {
assert(chars_folder_);
cv::Mat samples;
std::vector<int> labels;
std::cout << "Collecting chars in " << chars_folder_ << std::endl;
int classNumber = 0;
if (type == 0) classNumber = kCharsTotalNumber;
if (type == 1) classNumber = kChineseNumber;
for (int i = 0; i < classNumber; ++i) {
auto char_key = kChars[i + kCharsTotalNumber - classNumber];
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 = charFeatures2(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(), classNumber, 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,11 +1,13 @@
#include <numeric>
#include <ctime>
#include "easypr/train/ann_train.h"
#include "easypr/config.h"
#include "easypr/core/chars_identify.h"
#include "easypr/core/feature.h"
#include "easypr/core/core_func.h"
#include "easypr/train/create_data.h"
#include "easypr/util/util.h"
#include <numeric>
#include <ctime>
namespace easypr {

@ -0,0 +1,73 @@
#include "easypr/train/create_data.h"
namespace easypr {
// shift an image
Mat translateImg(Mat img, int offsetx, int offsety){
Mat dst;
Mat trans_mat = (Mat_<double>(2, 3) << 1, 0, offsetx, 0, 1, offsety);
warpAffine(img, dst, trans_mat, img.size(), 1, 0, Scalar(255));
return dst;
}
// rotate an image
Mat rotateImg(Mat source, float angle){
Point2f src_center(source.cols / 2.0F, source.rows / 2.0F);
Mat rot_mat = getRotationMatrix2D(src_center, angle, 1.0);
Mat dst;
warpAffine(source, dst, rot_mat, source.size(), 1, 0, Scalar(255));
return dst;
}
// crop the image
Mat cropImg(Mat src, int x, int y, int shift){
int width = kGrayCharWidth;
int height = kGrayCharHeight;
int crop_width = width - shift;
int crop_height = height - shift;
int x_shift = shift;
int y_shift = shift;
x = x < x_shift ? x : x_shift;
y = y < y_shift ? y : y_shift;
Rect rect = Rect(x, y, crop_width, crop_height);
Mat dst = src(rect);
resize(dst, dst, Size(width, height));
return dst;
}
Mat generateSyntheticImage(const Mat& image, int use_swap) {
int rd = rand();
Mat result = image.clone();
if (rd >> 0 & 1) {
int shift = 4;
int ran_x = rand() % shift;
int ran_y = rand() % shift;
result = cropImg(result, ran_x, ran_y, shift);
}
if (rd >> 1 & 1) {
}
if (rd >> 2 & 1) {
}
if (rd >> 3 & 1) {
int ran_x = rand() % 6 - 3;
int ran_y = rand() % 6 - 3;
result = translateImg(result, ran_x, ran_y);
}
if (rd >> 4 & 1) {
float angle = float(rand() % 20 - 10);
result = rotateImg(result, angle);
}
return result;
}
}

@ -34,11 +34,11 @@ void SvmTrain::train() {
fprintf(stdout, ">> Training SVM model, please wait...\n");
long start = utils::getTimestamp();
/*svm_->trainAuto(train_data, 10, SVM::getDefaultGrid(SVM::C),
svm_->trainAuto(train_data, 10, SVM::getDefaultGrid(SVM::C),
SVM::getDefaultGrid(SVM::GAMMA), SVM::getDefaultGrid(SVM::P),
SVM::getDefaultGrid(SVM::NU), SVM::getDefaultGrid(SVM::COEF),
SVM::getDefaultGrid(SVM::DEGREE), true);*/
svm_->train(train_data);
SVM::getDefaultGrid(SVM::DEGREE), true);
//svm_->train(train_data);
long end = utils::getTimestamp();
fprintf(stdout, ">> Training done. Time elapse: %ldms\n", end - start);

@ -404,7 +404,7 @@ namespace easypr {
cout << "------------------" << endl;
cout << endl;
cout << kv->get("summaries") << ":" << endl;
cout << kv->get("sum_pictures") << ":" << count_all << ", ";
cout << kv->get("sum_pictures") << ": " << count_all << ", ";
cout << "Plates count" << ":" << all_plate_count << ", ";
float count_detect = float(all_plate_count - count_nodetect);
@ -438,18 +438,20 @@ namespace easypr {
}
//cout << "Detect quality evalution result:" << endl;
cout << "Recall" << ":" << recall_2003_result * 100 << "%" << ", ";
cout << "Precise" << ":" << precise_2003_result * 100 << "%" << ", ";
cout << "Fscore" << ":" << fscore_2003_result * 100 << "%" << "." << endl;
cout << kv->get("detect_quality") << ": ";
cout << "Recall" << "," << recall_2003_result * 100 << "%" << "; ";
cout << "Precise" << "," << precise_2003_result * 100 << "%" << "; ";
cout << "Fscore" << "," << fscore_2003_result * 100 << "%" << ";" << endl;
cout << "0-error" << ":" << non_error_rate * 100 << "%, ";
cout << "1-error" << ":" << one_error_rate * 100 << "%, ";
cout << "Chinese-precise" << ":" << (1 - chinese_error_rate) * 100 << "% " << endl;
cout << kv->get("char_recongize") << ": ";
cout << "0-error" << "," << non_error_rate * 100 << "%; ";
cout << "1-error" << "," << one_error_rate * 100 << "%; ";
cout << "Chinese-precise" << "," << (1 - chinese_error_rate) * 100 << "% " << endl;
double seconds = difftime(end, begin);
double avgsec = seconds / double(count_all);
cout << kv->get("seconds") << ":" << seconds << kv->get("sec") << ", ";
cout << kv->get("seconds") << ": " << seconds << kv->get("sec") << ", ";
cout << kv->get("seconds_average") << ":" << avgsec << kv->get("sec") << endl;
// set the result.
@ -494,7 +496,8 @@ namespace easypr {
myfile << "0-error" << ":" << non_error_rate * 100 << "%, ";
myfile << "1-error" << ":" << one_error_rate * 100 << "%, ";
myfile << "Chinese-precise" << ":" << (1 - chinese_error_rate) * 100 << "% " << endl;
myfile << kv->get("seconds") << ":" << seconds << kv->get("sec") << ", ";
myfile << kv->get("seconds") << ": " << seconds << kv->get("sec") << ", ";
myfile << kv->get("seconds_average") << ":" << avgsec << kv->get("sec") << endl;
myfile.close();
}
@ -587,17 +590,10 @@ namespace easypr {
myfile << result << std::endl;
myfile.close();
}
}
}
return 0;
}
}
}
#endif // EASYPR_ACCURACY_HPP

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save