* add Chinese ANN model and synthetic data generate and train TLFN model.

v1.6alpha
liuruoze 9 years ago
parent 04f4cab35f
commit b9b249eba5

@ -12,8 +12,16 @@ typedef enum {
} SvmLabel;
static const float kSvmPercentage = 0.7f;
static const int kPredictSize = 10;
static const int kNeurons = 40;
static const int kCharacterInput = 120;
static const int kChineseInput = 440;
static const int kAnnInput = kCharacterInput;
static const int kCharacterSize = 10;
static const int kChineseSize = 20;
static const int kPredictSize = kCharacterSize;
static const int kNeurons = 40;
static const char *kChars[] = {
"0", "1", "2",

@ -22,6 +22,8 @@ class CharsIdentify {
int identify(std::vector<cv::Mat> inputs, std::vector<std::pair<std::string, std::string>>& outputs,
std::vector<bool> isChineseVec);
std::pair<std::string, std::string> CharsIdentify::identifyChinese(cv::Mat input);
bool isCharacter(cv::Mat input, std::string& label, float& maxVal, bool isChinese = false);
void LoadModel(std::string path);

@ -24,8 +24,7 @@ namespace easypr {
public:
CPlate() { }
CPlate(const CPlate& plate)
{
CPlate(const CPlate& plate) {
m_plateMat = plate.m_plateMat;
m_score = plate.m_score;
m_platePos = plate.m_platePos;
@ -42,6 +41,26 @@ namespace easypr {
m_mserCharVec = plate.m_mserCharVec;
}
CPlate& operator=(const CPlate& plate) {
if (this != &plate) {
m_plateMat = plate.m_plateMat;
m_score = plate.m_score;
m_platePos = plate.m_platePos;
m_plateStr = plate.m_plateStr;
m_locateType = plate.m_locateType;
m_line = plate.m_line;
m_leftPoint = plate.m_leftPoint;
m_rightPoint = plate.m_rightPoint;
m_mergeCharRect = plate.m_mergeCharRect;
m_maxCharRect = plate.m_maxCharRect;
m_distVec = plate.m_distVec;
m_mserCharVec = plate.m_mserCharVec;
}
return *this;
}
inline void setPlateMat(Mat param) { m_plateMat = param; }
inline Mat getPlateMat() const { return m_plateMat; }

@ -2,6 +2,8 @@
#define EASYPR_TRAIN_ANNTRAIN_H_
#include "easypr/train/train.h"
#include "easypr/util/kv.h"
#include <memory>
namespace easypr {
@ -13,13 +15,18 @@ class AnnTrain : public ITrain {
virtual void test();
std::pair<std::string, std::string> identifyChinese(cv::Mat input);
private:
virtual cv::Ptr<cv::ml::TrainData> tdata();
cv::Ptr<cv::ml::TrainData> sdata(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;
};
}

@ -204,6 +204,32 @@ namespace easypr {
return false;
}*/
std::pair<std::string, std::string> CharsIdentify::identifyChinese(cv::Mat input) {
cv::Mat feature = charFeatures(input, kPredictSize);
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);
}
std::pair<std::string, std::string> CharsIdentify::identify(cv::Mat input, bool isChinese) {
cv::Mat feature = charFeatures(input, kPredictSize);

@ -3,32 +3,79 @@
#include "easypr/core/chars_identify.h"
#include "easypr/core/core_func.h"
#include "easypr/util/util.h"
#include <numeric>
#include <ctime>
namespace easypr {
AnnTrain::AnnTrain(const char* chars_folder, const char* xml)
: chars_folder_(chars_folder), ann_xml_(xml) {
ann_ = cv::ml::ANN_MLP::create();
type = 0;
type = 1;
kv_ = std::shared_ptr<Kv>(new Kv);
kv_->load("etc/province_mapping");
}
void AnnTrain::train() {
int classNumber = 0;
if (type == 0) classNumber = kCharsTotalNumber;
if (type == 1) classNumber = kChineseNumber;
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) = classNumber; // the output layer
cv::Mat layers;
int input_number = 0;
int hidden_number = 0;
int output_number = 0;
if (type == 0) {
classNumber = kCharsTotalNumber;
input_number = kAnnInput;
hidden_number = kNeurons;
output_number = classNumber;
}
else if (type == 1) {
classNumber = kChineseNumber;
input_number = kAnnInput;
hidden_number = kNeurons;
output_number = classNumber;
}
int N = input_number;
int m = output_number;
int first_hidden_neurons = int(std::sqrt((m + 2) * N) + 2 * std::sqrt(N / (m + 2)));
int second_hidden_neurons = int(m * std::sqrt(N / (m + 2)));
bool useTLFN = false;
if (!useTLFN) {
layers.create(1, 3, CV_32SC1);
layers.at<int>(0) = input_number;
layers.at<int>(1) = hidden_number;
layers.at<int>(2) = output_number;
}
else {
fprintf(stdout, ">> Use two-layers neural networks,\n");
fprintf(stdout, ">> First_hidden_neurons: %d \n", first_hidden_neurons);
fprintf(stdout, ">> Second_hidden_neurons: %d \n", second_hidden_neurons);
layers.create(1, 4, CV_32SC1);
layers.at<int>(0) = input_number;
layers.at<int>(1) = first_hidden_neurons;
layers.at<int>(2) = second_hidden_neurons;
layers.at<int>(3) = output_number;
}
ann_->setLayerSizes(layers);
ann_->setActivationFunction(cv::ml::ANN_MLP::SIGMOID_SYM, 1, 1);
ann_->setTrainMethod(cv::ml::ANN_MLP::TrainingMethods::BACKPROP);
ann_->setTermCriteria(cvTermCriteria(CV_TERMCRIT_ITER, 10000, 0.001));
ann_->setBackpropWeightScale(0.1);
ann_->setBackpropMomentumScale(0.1);
auto traindata = tdata();
//using raw data or raw + synthic data.
//auto traindata = tdata();
auto traindata = sdata();
std::cout << "Training ANN model, please wait..." << std::endl;
long start = utils::getTimestamp();
ann_->train(traindata);
@ -39,15 +86,47 @@ void AnnTrain::train() {
ann_->save(ann_xml_);
std::cout << "Your ANN Model was saved to " << ann_xml_ << std::endl;
//test();
test();
}
std::pair<std::string, std::string> AnnTrain::identifyChinese(cv::Mat input) {
cv::Mat feature = charFeatures(input, kPredictSize);
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 AnnTrain::test() {
assert(chars_folder_);
for (int i = 0; i < kCharsTotalNumber; ++i) {
auto char_key = kChars[i];
char sub_folder[512] = {0};
int classNumber = 0;
if (type == 0) classNumber = kCharsTotalNumber;
if (type == 1) classNumber = kChineseNumber;
int corrects_all = 0, sum_all = 0;
std::vector<float> rate_list;
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);
@ -58,18 +137,21 @@ void AnnTrain::test() {
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);
std::pair<std::string, std::string> ch = identifyChinese(img);
if (ch.first == char_key) {
++corrects;
++corrects_all;
} else {
error_files.push_back(
std::make_pair(utils::getFileName(file), ch.second));
}
++sum;
++sum_all;
}
fprintf(stdout, ">> [sum: %d, correct: %d, rate: %.2f]\n", sum, corrects,
(float)corrects / (sum == 0 ? 1 : sum));
float rate = (float)corrects / (sum == 0 ? 1 : sum);
fprintf(stdout, ">> [sum: %d, correct: %d, rate: %.2f]\n", sum, corrects, rate);
rate_list.push_back(rate);
std::string error_string;
auto end = error_files.end();
if (error_files.size() >= 10) {
@ -87,6 +169,79 @@ void AnnTrain::test() {
}
fprintf(stdout, ">> [\n%s\n ]\n", error_string.c_str());
}
fprintf(stdout, ">> [sum_all: %d, correct_all: %d, rate: %.4f]\n", sum_all, corrects_all,
(float)corrects_all / (sum_all == 0 ? 1 : sum_all));
double rate_sum = std::accumulate(rate_list.begin(), rate_list.end(), 0.0);
double rate_mean = rate_sum / (rate_list.size() == 0 ? 1 : rate_list.size());
fprintf(stdout, ">> [classNumber: %d, avg_rate: %.4f]\n", classNumber, rate_mean);
}
cv::Mat getSyntheticImage(const Mat& image) {
Mat result = image.clone();
return result;
}
cv::Ptr<cv::ml::TrainData> AnnTrain::sdata(size_t number_for_count) {
assert(chars_folder_);
cv::Mat samples;
std::vector<int> labels;
int classNumber = 0;
if (type == 0) classNumber = kCharsTotalNumber;
if (type == 1) classNumber = kChineseNumber;
for (int i = 0; i < classNumber; ++i) {
srand((unsigned)time(0));
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, 0); // a grayscale image
matVec.push_back(img);
}
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 = getSyntheticImage(img);
matVec.push_back(simg);
}
fprintf(stdout, ">> Characters count: %d \n", matVec.size());
for (auto img : matVec) {
auto fps = charFeatures(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);
}
cv::Ptr<cv::ml::TrainData> AnnTrain::tdata() {

Loading…
Cancel
Save