* add charsegment method : mser segment

v1.6alpha
liuruoze 8 years ago
parent 14384a81f0
commit db253f2979

2
.gitignore vendored

@ -17,7 +17,7 @@ resources/image/native_test/*.py
resources/image/phone_test
*.vsp
*.psess
*.DStore
#ignore thumbnails created by windows
Thumbs.db
#Ignore files build by Visual Studio

@ -1,6 +1,8 @@
#ifndef EASYPR_CONFIG_H_
#define EASYPR_CONFIG_H_
#define CV_VERSION_THREE_ZERO
namespace easypr {
enum Color { BLUE, YELLOW, WHITE, UNKNOWN };
@ -9,7 +11,13 @@ namespace easypr {
enum CharSearchDirection { LEFT, RIGHT };
enum SceneMode { UNCONSTRAINED, CAMERPOHNE, PARKING, HIGHWAY };
enum
{
PR_MODE_UNCONSTRAINED,
PR_MODE_CAMERPOHNE,
PR_MODE_PARKING,
PR_MODE_HIGHWAY
};
enum
{
@ -24,6 +32,7 @@ static const char* kHistSvmPath = "resources/model/svm_hist.xml";
static const char* kDefaultAnnPath = "resources/model/ann.xml";
static const char* kChineseAnnPath = "resources/model/ann_chinese.xml";
static const char* kGrayAnnPath = "resources/model/annCh.xml";
typedef enum {
kForward = 1, // correspond to "has plate"
@ -84,8 +93,13 @@ static const int kCharsTotalNumber = 65;
static bool kDebug = false;
static const int kGrayCharWidth = 20;
static const int kGrayCharHeight = 32;
static const int kGrayCharWidth = 20;
static const int kGrayCharHeight = 32;
static const int kCharLBPGridX = 5;
static const int kCharLBPGridY = 8;
static const int kCharLBPPatterns = 32;
static const int kCharHiddenNeurans = 48;
// Disable the copy and assignment operator for this class.
#define DISABLE_ASSIGN_AND_COPY(className) \
@ -100,11 +114,26 @@ private:\
// Display the image.
#define SHOW_IMAGE(imgName, debug) \
if (debug) { \
namedWindow("imgName", WINDOW_AUTOSIZE); \
moveWindow("imgName", 500, 500); \
imshow("imgName", imgName); \
waitKey(0); \
destroyWindow("imgName"); \
}
// Load model. compatitable withe 3.0, 3.1 and 3.2
#ifdef CV_VERSION_THREE_TWO
#define LOAD_SVM_MODEL(model, path) \
model = ml::SVM::load(path);
#define LOAD_ANN_MODEL(model, path) \
model = ml::ANN_MLP::load(path);
#else
#define LOAD_SVM_MODEL(model, path) \
model = ml::SVM::load<ml::SVM>(path);
#define LOAD_ANN_MODEL(model, path) \
model = ml::ANN_MLP::load<ml::ANN_MLP>(path);
#endif
}
#endif // EASYPR_CONFIG_H_

@ -6,6 +6,7 @@
#include "easypr/util/kv.h"
#include "easypr/core/character.hpp"
#include "easypr/core/feature.h"
namespace easypr {
@ -13,29 +14,34 @@ class CharsIdentify {
public:
static CharsIdentify* instance();
int classify(cv::Mat f, float& maxVal, bool isChinses = false);
int classify(cv::Mat f, float& maxVal, bool isChinses = false, bool isAlphabet = false);
void classify(cv::Mat featureRows, std::vector<int>& out_maxIndexs,
std::vector<float>& out_maxVals, std::vector<bool> isChineseVec);
void classify(std::vector<CCharacter>& charVec);
void classifyChinese(std::vector<CCharacter>& charVec);
void classifyChineseGray(std::vector<CCharacter>& charVec);
std::pair<std::string, std::string> identify(cv::Mat input, bool isChinese = false);
std::pair<std::string, std::string> identify(cv::Mat input, bool isChinese = false, bool isAlphabet = false);
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> identifyChinese(cv::Mat input, float& result, bool& isChinese);
std::pair<std::string, std::string> identifyChineseGray(cv::Mat input, float& result, bool& isChinese);
bool isCharacter(cv::Mat input, std::string& label, float& maxVal, bool isChinese = false);
void LoadModel(std::string path);
void LoadChineseModel(std::string path);
void LoadGrayModel(std::string path);
private:
CharsIdentify();
annCallback extractFeature;
static CharsIdentify* instance_;
cv::Ptr<cv::ml::ANN_MLP> ann_;
cv::Ptr<cv::ml::ANN_MLP> annChinese_;
cv::Ptr<cv::ml::ANN_MLP> annGray_;
std::shared_ptr<Kv> kv_;
};
}

@ -17,6 +17,7 @@ class CCharsSegment {
//! using project the segment chars in plate
int charsSegmentUsingProject(Mat input, std::vector<Mat>& resultVec, std::vector<Mat>& grayChars, Color color = BLUE);
int charsSegmentUsingMSER(Mat input, vector<Mat>& resultVec, vector<Mat>& grayChars, Color color = BLUE);
//! using project
int projectSegment(const Mat& input, Color color, vector<int>& out_indexs);
@ -25,6 +26,7 @@ class CCharsSegment {
// find the best chinese binaranzation method
void judgeChinese(Mat in, Mat& out, Color plateType);
void judgeChineseGray(Mat in, Mat& out, Color plateType);
Mat preprocessChar(Mat in);

@ -117,6 +117,9 @@ Rect rectEnlarge(const Rect& src, const int mat_width, const int mat_height);
// write images to temp folder
void writeTempImage(const Mat& outImg, const string path);
// remove the small lines in character like "zh-cuan"
bool judegMDOratio2(const Mat &image, const Rect &rect, std::vector<Point> &contour, Mat &result);
//! non-maximum surpresion for 1d array
template<typename T>
void NMSfor1D(const vector<T>& arr, vector<int>& index) {

@ -32,6 +32,8 @@ namespace easypr {
CPlate(const CPlate& other) {
m_plateMat = other.m_plateMat;
m_chineseMat = other.m_chineseMat;
m_chineseKey = other.m_chineseKey;
m_score = other.m_score;
m_platePos = other.m_platePos;
m_plateStr = other.m_plateStr;
@ -53,6 +55,8 @@ namespace easypr {
CPlate& operator=(const CPlate& other) {
if (this != &other) {
m_plateMat = other.m_plateMat;
m_chineseMat = other.m_chineseMat;
m_chineseKey = other.m_chineseKey;
m_score = other.m_score;
m_platePos = other.m_platePos;
m_plateStr = other.m_plateStr;
@ -76,6 +80,12 @@ namespace easypr {
inline void setPlateMat(Mat param) { m_plateMat = param; }
inline Mat getPlateMat() const { return m_plateMat; }
inline void setChineseMat(Mat param) { m_chineseMat = param; }
inline Mat getChineseMat() const { return m_chineseMat; }
inline void setChineseKey(String param) { m_chineseKey = param; }
inline String getChineseKey() const { return m_chineseKey; }
inline void setPlatePos(RotatedRect param) { m_platePos = param; }
inline RotatedRect getPlatePos() const { return m_platePos; }
@ -169,6 +179,12 @@ namespace easypr {
int m_charCount;
//! chinese mat;
Mat m_chineseMat;
//! chinese key;
String m_chineseKey;
//! distVec
Vec2i m_distVec;
};

@ -107,7 +107,7 @@ class CPlateDetect {
int m_maxPlates;
SceneMode m_mode;
//SceneMode m_mode;
CPlateLocate* m_plateLocate;

@ -16,13 +16,12 @@ class AnnChTrain : public ITrain {
virtual void test();
std::pair<std::string, std::string> identifyChinese(cv::Mat input);
cv::Mat AnnChTrain::generateGraySyntheticImage(const cv::Mat& image);
std::pair<std::string, std::string> identifyGrayChinese(cv::Mat input);
private:
virtual cv::Ptr<cv::ml::TrainData> tdata();
void AnnChTrain::trainVal(size_t number_for_count = 100);
void trainVal(size_t number_for_count = 100);
cv::Ptr<cv::ml::ANN_MLP> ann_;
const char* ann_xml_;

@ -13,12 +13,12 @@ Namespace where all the C++ EasyPR functionality resides
namespace easypr {
// shift an image
Mat translateImg(Mat img, int offsetx, int offsety);
Mat translateImg(Mat img, int offsetx, int offsety, int bk = 0);
// rotate an image
Mat rotateImg(Mat source, float angle);
Mat rotateImg(Mat source, float angle, int bk = 0);
// crop the image
Mat cropImg(Mat src, int x, int y, int shift);
Mat cropImg(Mat src, int x, int y, int shift, int bk = 0);
Mat generateSyntheticImage(const Mat& image, int use_swap = 1);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -2608,3 +2608,93 @@ Recall:88.2833%, Precise:88.2833%, Fscore:88.2833%.
Recall:88.2833%, Precise:88.2833%, Fscore:88.2833%.
0-error:0%, 1-error:100%, Chinese-precise:100%
总共时间: 14秒, 平均执行时间:14秒
2017-04-08 15:34:25
总图片数:1, Plates count:1, 未定位车牌:0, 检出率:100%
Recall:88.2833%, Precise:88.2833%, Fscore:88.2833%.
0-error:0%, 1-error:100%, Chinese-precise:100%
总共时间: 9秒, 平均执行时间:9秒
2017-04-08 15:53:06
总图片数:256, Plates count:297, 未定位车牌:14, 检出率:95.2862%
Recall:86.6993%, Precise:62.089%, Fscore:72.3588%.
0-error:66.6667%, 1-error:78.6008%, Chinese-precise:83.1276%
总共时间: 271秒, 平均执行时间:1.05859秒
2017-04-08 16:01:46
总图片数:256, Plates count:297, 未定位车牌:12, 检出率:95.9596%
Recall:88.4994%, Precise:66.935%, Fscore:76.2213%.
0-error:62.4%, 1-error:74.8%, Chinese-precise:78.8%
总共时间: 204秒, 平均执行时间:0.796875秒
2017-04-08 16:19:18
总图片数:256, Plates count:297, 未定位车牌:25, 检出率:91.5825%
Recall:84.5843%, Precise:79.6612%, Fscore:82.049%.
0-error:62.5514%, 1-error:74.0741%, Chinese-precise:78.1893%
总共时间: 147秒, 平均执行时间:0.574219秒
2017-04-12 21:47:37
总图片数:256, Plates count:297, 未定位车牌:13, 检出率:95.6229%
Recall:87.5304%, Precise:66.5651%, Fscore:75.6216%.
0-error:60.7143%, 1-error:74.6032%, Chinese-precise:77.381%
总共时间: 118秒, 平均执行时间:0.460938秒
2017-04-12 21:52:38
总图片数:256, Plates count:297, 未定位车牌:14, 检出率:95.2862%
Recall:87.0975%, Precise:66.1603%, Fscore:75.1987%.
0-error:58.9431%, 1-error:72.3577%, Chinese-precise:76.0163%
总共时间: 120秒, 平均执行时间:0.46875秒
2017-04-16 15:39:21
总图片数:1, Plates count:1, 未定位车牌:0, 检出率:100%
Recall:88.2833%, Precise:44.5151%, Fscore:59.1866%.
0-error:0%, 1-error:100%, Chinese-precise:100%
总共时间: 10秒, 平均执行时间:10秒
2017-04-16 15:43:50
总图片数:1, Plates count:1, 未定位车牌:0, 检出率:100%
Recall:89.4983%, Precise:89.4983%, Fscore:89.4983%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总共时间: 7秒, 平均执行时间:7秒
2017-04-16 16:05:38
总图片数:1, Plates count:1, 未定位车牌:0, 检出率:100%
Recall:89.4983%, Precise:89.4983%, Fscore:89.4983%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总共时间: 9秒, 平均执行时间:9秒
2017-04-16 18:11:00
总图片数:1, Plates count:1, 未定位车牌:0, 检出率:100%
Recall:89.4983%, Precise:89.4983%, Fscore:89.4983%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总共时间: 29秒, 平均执行时间:29秒
2017-04-16 19:16:35
总图片数:1, Plates count:1, 未定位车牌:0, 检出率:100%
Recall:89.4983%, Precise:89.4983%, Fscore:89.4983%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总共时间: 9秒, 平均执行时间:9秒
2017-04-16 19:21:58
总图片数:1, Plates count:1, 未定位车牌:0, 检出率:100%
Recall:89.4983%, Precise:89.4983%, Fscore:89.4983%.
0-error:0%, 1-error:0%, Chinese-precise:100%
总共时间: 11秒, 平均执行时间:11秒
2017-04-16 19:31:23
总图片数:1, Plates count:1, 未定位车牌:0, 检出率:100%
Recall:89.4983%, Precise:89.4983%, Fscore:89.4983%.
0-error:0%, 1-error:100%, Chinese-precise:100%
总共时间: 11秒, 平均执行时间:11秒
2017-04-16 19:31:42
总图片数:1, Plates count:1, 未定位车牌:0, 检出率:100%
Recall:89.4983%, Precise:89.4983%, Fscore:89.4983%.
0-error:0%, 1-error:100%, Chinese-precise:100%
总共时间: 9秒, 平均执行时间:9秒
2017-04-16 19:39:53
总图片数:1, Plates count:1, 未定位车牌:0, 检出率:100%
Recall:89.4983%, Precise:89.4983%, Fscore:89.4983%.
0-error:100%, 1-error:100%, Chinese-precise:100%
总共时间: 15秒, 平均执行时间:15秒
2017-04-16 19:43:40
总图片数:256, Plates count:297, 未定位车牌:70, 检出率:76.431%
Recall:69.1472%, Precise:88.9035%, Fscore:77.7906%.
0-error:68.8995%, 1-error:77.512%, Chinese-precise:80.8612%
总共时间: 170秒, 平均执行时间:0.664063秒
2017-04-16 20:41:02
总图片数:256, Plates count:297, 未定位车牌:12, 检出率:95.9596%
Recall:88.4994%, Precise:66.935%, Fscore:76.2213%.
0-error:62.8%, 1-error:74.8%, Chinese-precise:78.8%
总共时间: 284秒, 平均执行时间:1.10938秒
2017-04-16 20:45:21
总图片数:256, Plates count:297, 未定位车牌:25, 检出率:91.5825%
Recall:84.5843%, Precise:79.6612%, Fscore:82.049%.
0-error:62.963%, 1-error:74.0741%, Chinese-precise:78.1893%
总共时间: 186秒, 平均执行时间:0.726563秒

@ -1,9 +1,11 @@
#include "easypr/core/chars_identify.h"
#include "easypr/core/character.hpp"
#include "easypr/config.h"
#include "easypr/core/core_func.h"
#include "easypr/core/feature.h"
#include "easypr/core/params.h"
#include "easypr/config.h"
using namespace cv;
namespace easypr {
@ -17,29 +19,35 @@ namespace easypr {
}
CharsIdentify::CharsIdentify() {
ann_ = ml::ANN_MLP::load<ml::ANN_MLP>(kDefaultAnnPath);
annChinese_ = ml::ANN_MLP::load<ml::ANN_MLP>(kChineseAnnPath);
LOAD_ANN_MODEL(ann_, kDefaultAnnPath);
LOAD_ANN_MODEL(annChinese_, kChineseAnnPath);
LOAD_ANN_MODEL(annGray_, kGrayAnnPath);
kv_ = std::shared_ptr<Kv>(new Kv);
kv_->load("etc/province_mapping");
extractFeature = getGrayCharFeatures;
}
void CharsIdentify::LoadModel(std::string path) {
if (path != std::string(kDefaultAnnPath)) {
if (!ann_->empty())
ann_->clear();
ann_ = ml::ANN_MLP::load<ml::ANN_MLP>(path);
LOAD_ANN_MODEL(ann_, path);
}
}
void CharsIdentify::LoadChineseModel(std::string path) {
if (path != std::string(kChineseAnnPath)) {
if (!annChinese_->empty())
annChinese_->clear();
LOAD_ANN_MODEL(annChinese_, path);
}
}
annChinese_ = ml::ANN_MLP::load<ml::ANN_MLP>(path);
void CharsIdentify::LoadGrayModel(std::string path) {
if (path != std::string(kGrayAnnPath)) {
if (!annGray_->empty())
annGray_->clear();
LOAD_ANN_MODEL(annGray_, path);
}
}
@ -143,6 +151,60 @@ namespace easypr {
}
void CharsIdentify::classifyChineseGray(std::vector<CCharacter>& charVec){
size_t charVecSize = charVec.size();
if (charVecSize == 0)
return;
Mat featureRows;
for (size_t index = 0; index < charVecSize; index++) {
Mat charInput = charVec[index].getCharacterMat();
cv::Mat feature;
extractFeature(charInput, feature);
featureRows.push_back(feature);
}
cv::Mat output(charVecSize, kChineseNumber, CV_32FC1);
annGray_->predict(featureRows, output);
for (size_t output_index = 0; output_index < charVecSize; output_index++) {
CCharacter& character = charVec[output_index];
Mat output_row = output.row(output_index);
bool isChinese = true;
float maxVal = -2;
int result = -1;
for (int j = 0; j < kChineseNumber; j++) {
float val = output_row.at<float>(j);
//std::cout << "j:" << j << "val:" << val << std::endl;
if (val > maxVal) {
maxVal = val;
result = j;
}
}
// no match
if (-1 == result) {
result = 0;
maxVal = 0;
isChinese = false;
}
auto index = result + kCharsTotalNumber - kChineseNumber;
const char* key = kChars[index];
std::string s = key;
std::string province = kv_->get(s);
/*std::cout << "result:" << result << std::endl;
std::cout << "maxVal:" << maxVal << std::endl;*/
character.setCharacterScore(maxVal);
character.setCharacterStr(province);
character.setIsChinese(isChinese);
}
}
void CharsIdentify::classifyChinese(std::vector<CCharacter>& charVec){
size_t charVecSize = charVec.size();
@ -197,7 +259,7 @@ namespace easypr {
}
}
int CharsIdentify::classify(cv::Mat f, float& maxVal, bool isChinses){
int CharsIdentify::classify(cv::Mat f, float& maxVal, bool isChinses, bool isAlphabet){
int result = -1;
cv::Mat output(1, kCharsTotalNumber, CV_32FC1);
@ -205,13 +267,27 @@ namespace easypr {
maxVal = -2.f;
if (!isChinses) {
result = 0;
for (int j = 0; j < kCharactersNumber; j++) {
float val = output.at<float>(j);
// std::cout << "j:" << j << "val:" << val << std::endl;
if (val > maxVal) {
maxVal = val;
result = j;
if (!isAlphabet) {
result = 0;
for (int j = 0; j < kCharactersNumber; j++) {
float val = output.at<float>(j);
// std::cout << "j:" << j << "val:" << val << std::endl;
if (val > maxVal) {
maxVal = val;
result = j;
}
}
}
else {
result = 0;
// begin with 11th char, which is 'A'
for (int j = 10; j < kCharactersNumber; j++) {
float val = output.at<float>(j);
// std::cout << "j:" << j << "val:" << val << std::endl;
if (val > maxVal) {
maxVal = val;
result = j;
}
}
}
}
@ -238,9 +314,7 @@ namespace easypr {
//std::cout << "maxVal:" << maxVal << std::endl;
}
float chineseMaxThresh = 0.2f;
//float chineseMaxThresh = CParams::instance()->getParam2f();
if (maxVal >= 0.9 || (isChinese && maxVal >= chineseMaxThresh)) {
if (index < kCharactersNumber) {
@ -258,33 +332,9 @@ namespace easypr {
return false;
}
/*bool CharsIdentify::charsJudge(std::vector<CCharacter>& charVec) {
cv::Mat feature = charFeatures(input, kPredictSize);
auto index = static_cast<int>(classify(feature, maxVal, isChinese));
if (isChinese)
std::cout << "maxVal:" << maxVal << std::endl;
if (maxVal >= 0.9) {
if (index < kCharactersNumber) {
label = std::make_pair(kChars[index], kChars[index]).second;
}
else {
const char* key = kChars[index];
std::string s = key;
std::string province = kv_->get(s);
label = std::make_pair(s, province).second;
}
return true;
}
else
return false;
}*/
std::pair<std::string, std::string> CharsIdentify::identifyChinese(cv::Mat input, float& out, bool& isChinese) {
cv::Mat feature = charFeatures(input, kChineseSize);
float maxVal = -2;
int result = -1;
cv::Mat output(1, kChineseNumber, CV_32FC1);
@ -313,17 +363,48 @@ namespace easypr {
const char* key = kChars[index];
std::string s = key;
std::string province = kv_->get(s);
out = maxVal;
return std::make_pair(s, province);
}
std::pair<std::string, std::string> CharsIdentify::identifyChineseGray(cv::Mat input, float& out, bool& isChinese) {
cv::Mat feature;
extractFeature(input, feature);
float maxVal = -2;
int result = -1;
cv::Mat output(1, kChineseNumber, CV_32FC1);
annGray_->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;
}
}
// no match
if (-1 == result) {
result = 0;
maxVal = 0;
isChinese = false;
} else if (maxVal > 0.9){
isChinese = true;
}
auto index = result + kCharsTotalNumber - kChineseNumber;
const char* key = kChars[index];
std::string s = key;
std::string province = kv_->get(s);
out = maxVal;
return std::make_pair(s, province);
}
std::pair<std::string, std::string> CharsIdentify::identify(cv::Mat input, bool isChinese) {
std::pair<std::string, std::string> CharsIdentify::identify(cv::Mat input, bool isChinese, bool isAlphabet) {
cv::Mat feature = charFeatures(input, kPredictSize);
float maxVal = -2;
auto index = static_cast<int>(classify(feature, maxVal, isChinese));
auto index = static_cast<int>(classify(feature, maxVal, isChinese, isAlphabet));
if (index < kCharactersNumber) {
return std::make_pair(kChars[index], kChars[index]);
}

@ -48,15 +48,12 @@ int CCharsRecognise::charsRecognise(Mat plate, std::string& plateLicense) {
return result;
}
int char_index = 0;
int plate_index = 0;
int CCharsRecognise::charsRecognise(CPlate& plate, std::string& plateLicense) {
std::vector<Mat> matChars;
std::vector<Mat> grayChars;
Mat plateMat = plate.getPlateMat();
if (1) {
writeTempImage(plateMat, "plateMat/plate");
}
if (1) writeTempImage(plateMat, "plateMat/plate");
Color color;
if (plate.getPlateLocateType() == CMSER) {
color = plate.getPlateColor();
@ -68,38 +65,39 @@ int CCharsRecognise::charsRecognise(CPlate& plate, std::string& plateLicense) {
color = getPlateType(tmpMat, true);
}
int result = m_charsSegment->charsSegmentUsingProject(plateMat, matChars, grayChars,color);
//std::cout << "charsSegment:" << result << std::endl;
if (result == 0) {
int result = m_charsSegment->charsSegmentUsingProject(plateMat, matChars, grayChars, color);
if (result == 0) {
int num = matChars.size();
for (int j = 0; j < num; j++)
{
Mat charMat = matChars.at(j);
Mat grayChar = grayChars.at(j);
bool isChinses = false;
std::pair<std::string, std::string> character;
float maxVal;
if (j == 0) {
if (0 == j) {
isChinses = true;
bool judge = true;
character = CharsIdentify::instance()->identifyChinese(charMat, maxVal, judge);
Mat grayChar = grayChars.at(j);
//character = CharsIdentify::instance()->identifyChinese(charMat, maxVal, judge);
if (color != Color::BLUE)
grayChar = 255 - grayChar;
character = CharsIdentify::instance()->identifyChineseGray(grayChar, maxVal, judge);
plateLicense.append(character.second);
//time_t t = time(0); // get time now
//struct tm* now = localtime(&t);
//char buf[80];
//strftime(buf, sizeof(buf), "%Y-%m-%d %H_%M_%S", now);
//if (1) {
// std::stringstream ss(std::stringstream::in | std::stringstream::out);
// ss << "resources/image/tmp/grayChars/" << character.first << "/chars_" << char_index++ << "_" << std::string(buf) << ".jpg";
// imwrite(ss.str(), grayChar);
//}
if (1) {
writeTempImage(grayChar, "grayChars/" + character.first + "/chars_");
}
// set plate chinese mat and str
plate.setChineseMat(grayChar);
plate.setChineseKey(character.first);
if (0) writeTempImage(grayChar, "grayChars/" + character.first + "/chars_");
}
else {
else if (1 == j) {
isChinses = false;
bool isAbc = true;
character = CharsIdentify::instance()->identify(charMat, isChinses, isAbc);
plateLicense.append(character.second);
}
else {
isChinses = false;
character = CharsIdentify::instance()->identify(charMat, isChinses);
plateLicense.append(character.second);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -233,37 +233,56 @@ Mat charFeatures2(Mat in, int sizeData) {
void getGrayCharFeatures(const Mat& grayChar, Mat& features) {
// TODO: check channnels == 1
SHOW_IMAGE(grayChar, 0);
SHOW_IMAGE(255 - grayChar, 0);
// resize to uniform size, like 20x32
bool useResize = false;
bool useConvert = true;
bool useMean = true;
bool useLBP = false;
Mat char_mat;
char_mat.create(kGrayCharHeight, kGrayCharWidth, CV_32FC1);
resize(grayChar, char_mat, char_mat.size(), 0, 0, INTER_LINEAR);
if (useResize) {
char_mat.create(kGrayCharHeight, kGrayCharWidth, CV_8UC1);
resize(grayChar, char_mat, char_mat.size(), 0, 0, INTER_LINEAR);
} else {
char_mat = grayChar;
}
SHOW_IMAGE(char_mat, 0);
// convert to float
bool useConvert = false;
Mat float_img;
if (useConvert) {
Mat float_img;
float scale = 1.f / 255;
char_mat.convertTo(float_img, CV_32FC1, scale, 0);
SHOW_IMAGE(float_img, 0);
} else {
float_img = char_mat;
}
SHOW_IMAGE(float_img, 0);
// cut from mean, it can be optional
bool useMean = true;
Mat mean_img;
if (useMean) {
char_mat -= mean(char_mat);
SHOW_IMAGE(char_mat, 0);
float_img -= mean(float_img);
mean_img = float_img;
} else {
mean_img = float_img;
}
SHOW_IMAGE(mean_img, 0);
// use lbp to get features, it can be changed to other
Mat lbpimage = libfacerec::olbp(char_mat);
SHOW_IMAGE(lbpimage, 0);
Mat lbp_hist = libfacerec::spatial_histogram(lbpimage, 32, 4, 4);
Mat feautreImg;
if (useLBP) {
Mat lbpimage = libfacerec::olbp(char_mat);
SHOW_IMAGE(lbpimage, 0);
feautreImg = libfacerec::spatial_histogram(lbpimage, kCharLBPPatterns, kCharLBPGridX, kCharLBPGridY);
} else {
feautreImg = mean_img.reshape(1, 1);
}
// return back
features = lbp_hist;
features = feautreImg;
}
void getLBPplusHistFeatures(const Mat& image, Mat& features) {

@ -17,11 +17,11 @@ namespace easypr {
PlateJudge::PlateJudge() {
bool useLBP = false;
if (useLBP) {
svm_ = ml::SVM::load<ml::SVM>(kLBPSvmPath);
LOAD_SVM_MODEL(svm_, kLBPSvmPath);
extractFeature = getLBPFeatures;
}
else {
svm_ = ml::SVM::load<ml::SVM>(kHistSvmPath);
LOAD_SVM_MODEL(svm_, kHistSvmPath);
extractFeature = getHistomPlusColoFeatures;
}
}
@ -30,7 +30,7 @@ namespace easypr {
if (path != std::string(kDefaultSvmPath)) {
if (!svm_->empty())
svm_->clear();
svm_ = ml::SVM::load<ml::SVM>(path);
LOAD_SVM_MODEL(svm_, path);
}
}

@ -32,6 +32,7 @@ int CPlateRecognize::plateRecognize(const Mat& src, std::vector<CPlate> &plateVe
for (size_t j = 0; j < num; j++) {
CPlate item = plateVec.at(j);
Mat plateMat = item.getPlateMat();
if (0) {
imshow("plate", plateMat);
waitKey(0);

File diff suppressed because it is too large Load Diff

@ -252,7 +252,7 @@ cv::Ptr<cv::ml::TrainData> AnnTrain::sdata(size_t number_for_count) {
auto chars_files = utils::getFiles(sub_folder);
size_t char_size = chars_files.size();
fprintf(stdout, ">> Characters count: %d \n", char_size);
fprintf(stdout, ">> Characters count: %d \n", int(char_size));
std::vector<cv::Mat> matVec;
matVec.reserve(number_for_count);
@ -274,7 +274,7 @@ cv::Ptr<cv::ml::TrainData> AnnTrain::sdata(size_t number_for_count) {
}
}
fprintf(stdout, ">> Characters count: %d \n", matVec.size());
fprintf(stdout, ">> Characters count: %d \n", (int)matVec.size());
for (auto img : matVec) {
auto fps = charFeatures2(img, kPredictSize);

@ -2,27 +2,49 @@
namespace easypr {
int getBoderColor(Mat img) {
assert(img.channels() == 1);
assert(img.type() == CV_8UC1);
int w = img.cols;
int h = img.rows;
float sum = 0;
for (int i = 0; i < h; ++i) {
sum += img.at<unsigned char>(i, 0);
sum += img.at<unsigned char>(i, w-1);
}
for (int j = 0; j < w; ++j) {
sum += img.at<unsigned char>(0, j);
sum += img.at<unsigned char>(h-1, j);
}
float avg = sum / float(w + w + h + h);
return int(avg);
}
// shift an image
Mat translateImg(Mat img, int offsetx, int offsety){
Mat translateImg(Mat img, int offsetx, int offsety, int bk){
Mat dst;
//cout << test << endl;
Mat trans_mat = (Mat_<double>(2, 3) << 1, 0, offsetx, 0, 1, offsety);
warpAffine(img, dst, trans_mat, img.size(), 1, 0, Scalar(255));
//cout << trans_mat << endl;
warpAffine(img, dst, trans_mat, img.size(), 1, 0, Scalar(bk));
return dst;
}
// rotate an image
Mat rotateImg(Mat source, float angle){
Mat rotateImg(Mat source, float angle, int bk){
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));
warpAffine(source, dst, rot_mat, source.size(), 1, 0, Scalar(bk));
return dst;
}
// crop the image
Mat cropImg(Mat src, int x, int y, int shift){
int width = kGrayCharWidth;
int height = kGrayCharHeight;
Mat cropImg(Mat src, int x, int y, int shift, int bk){
int width = src.cols;
int height = src.rows;
int crop_width = width - shift;
int crop_height = height - shift;
@ -36,35 +58,28 @@ namespace easypr {
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();
int bkColor = getBoderColor(image);
Mat result = image.clone();
if (rd >> 0 & 1) {
int shift = 4;
if (1 && (rd >> 6 & 1)) {
int shift = 2;
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) {
result = cropImg(result, ran_x, ran_y, shift, bkColor);
}
if (rd >> 3 & 1) {
int ran_x = rand() % 6 - 3;
int ran_y = rand() % 6 - 3;
result = translateImg(result, ran_x, ran_y);
if (1 && (rd >> 4 & 1)) {
int ran_x = rand() % 2 - 1;
int ran_y = rand() % 2 - 1;
result = translateImg(result, ran_x, ran_y, bkColor);
}
if (rd >> 4 & 1) {
float angle = float(rand() % 20 - 10);
result = rotateImg(result, angle);
if (1 && (rd >> 2 & 1)) {
float angle = float(rand() % 500) * 0.01f - 2.5f;
result = rotateImg(result, angle, bkColor);
}
return result;

@ -1,10 +1,12 @@
#include "easypr/train/svm_train.h"
#include "easypr/util/util.h"
#include "easypr/config.h"
#ifdef OS_WINDOWS
#include <ctime>
#endif
using namespace cv;
using namespace cv::ml;
namespace easypr {
@ -55,7 +57,7 @@ void SvmTrain::train() {
void SvmTrain::test() {
// 1.4 bug fix: old 1.4 ver there is no null judge
// if (NULL == svm_)
svm_ = cv::ml::SVM::load<cv::ml::SVM>(svm_xml_);
LOAD_SVM_MODEL(svm_, svm_xml_);
if (test_file_list_.empty()) {
this->prepare();
@ -70,7 +72,6 @@ void SvmTrain::test() {
for (auto item : test_file_list_) {
auto image = cv::imread(item.file);
if (!image.data) {
std::cout << "no" << std::endl;
continue;
}

@ -108,14 +108,25 @@ namespace easypr {
CPlateRecognize pr;
pr.setResultShow(false);
pr.setLifemode(true);
pr.setMaxPlates(max_plates);
//pr.setDetectType(PR_DETECT_COLOR | PR_DETECT_SOBEL);
pr.setDetectType(PR_DETECT_COLOR | PR_DETECT_SOBEL | PR_DETECT_CMSER);
int mode = PR_MODE_UNCONSTRAINED;
//int mode = PR_MODE_CAMERPOHNE;
//int mode = -1;
if (PR_MODE_UNCONSTRAINED == mode) {
pr.setDetectType(PR_DETECT_COLOR | PR_DETECT_CMSER);
pr.setMaxPlates(4);
} else if (PR_MODE_CAMERPOHNE == mode) {
pr.setDetectType(PR_DETECT_COLOR | PR_DETECT_CMSER);
pr.setMaxPlates(1);
} else {
pr.setDetectType(PR_DETECT_CMSER );
pr.setMaxPlates(1);
}
//pr.setDetectType(PR_DETECT_COLOR | PR_DETECT_SOBEL);
// load the maching learning model
//pr.LoadSVM("resources/model/svm.xml");
pr.LoadANN("resources/model/ann.xml");
pr.LoadChineseANN("resources/model/ann_chinese.xml");
// find all the test files (images)
// then sort them by image index
@ -293,10 +304,10 @@ namespace easypr {
chinese_error_count_s++;
vector<CCharacter> charVec = matchPlate->getCopyOfReutCharacters();
CCharacter character = charVec.at(0);
if (0) {
if (1) {
std::stringstream ss(std::stringstream::in | std::stringstream::out);
ss << "resources/image/tmp/chinese" << "/" << i << "_" << t << "_" << character.getCharacterStr() << ".jpg";
imwrite(ss.str(), character.getCharacterMat());
ss << "resources/image/tmp/chinese" << "/" << i << "_" << t << "_" << matchPlate->getChineseKey() << ".jpg";
imwrite(ss.str(), matchPlate->getChineseMat());
}
}
img_ss << " chineseError:" << chineseError << endl;

@ -571,9 +571,8 @@ namespace cv
Rect rect;
};
void detectRegions(InputArray _src, vector<vector<Point>>& msers_blue, vector<Rect>& bboxes_blue,
vector<vector<Point>>& msers_yellow, vector<Rect>& bboxes_yellow);
void preprocess1(const Mat& img, int* level_size)
{
memset(level_size, 0, 256 * sizeof(level_size[0]));
@ -776,6 +775,10 @@ namespace cv
Params params;
void detectRegions(InputArray _src, vector<vector<Point>>& msers_blue, vector<Rect>& bboxes_blue,
vector<vector<Point>>& msers_yellow, vector<Rect>& bboxes_yellow);
void detectRegions(InputArray _src, vector<vector<Point>>& msers, vector<Rect>& bboxes, int type);
};
void MSER_Impl2::detectRegions(InputArray _src, vector<vector<Point>>& msers_blue, vector<Rect>& bboxes_blue,
@ -783,17 +786,12 @@ namespace cv
{
Mat src = _src.getMat();
size_t npix = src.total();
if (npix == 0)
return;
if (npix == 0) return;
Size size = src.size();
if (src.type() == CV_8U)
{
if (src.type() == CV_8U) {
int level_size[256];
if (!src.isContinuous())
{
if (!src.isContinuous()) {
src.copyTo(tempsrc);
src = tempsrc;
}
@ -810,6 +808,32 @@ namespace cv
}
}
void MSER_Impl2::detectRegions(InputArray _src, vector<vector<Point>>& msers, vector<Rect>& bboxes, int type)
{
Mat src = _src.getMat();
size_t npix = src.total();
if (npix == 0) return;
Size size = src.size();
if (src.type() == CV_8U) {
int level_size[256];
if (!src.isContinuous()) {
src.copyTo(tempsrc);
src = tempsrc;
}
// darker to brighter (MSER+)
// dont need when plate is blue
preprocess1(src, level_size);
if (type)
pass(src, msers, bboxes, size, level_size, 0);
// brighter to darker (MSER-)
preprocess2(src, level_size);
pass(src, msers, bboxes, size, level_size, 255);
}
}
Ptr<MSER2> MSER2::create(int _delta, int _min_area, int _max_area,
double _max_variation, double _min_diversity,

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

Loading…
Cancel
Save