parent
e32dc5a0df
commit
f0634d82f8
@ -0,0 +1,454 @@
|
|||||||
|
#include "easypr/core/chars_identify.h"
|
||||||
|
#include "easypr/core/character.hpp"
|
||||||
|
#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 {
|
||||||
|
|
||||||
|
CharsIdentify* CharsIdentify::instance_ = nullptr;
|
||||||
|
|
||||||
|
CharsIdentify* CharsIdentify::instance() {
|
||||||
|
if (!instance_) {
|
||||||
|
instance_ = new CharsIdentify;
|
||||||
|
}
|
||||||
|
return instance_;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharsIdentify::CharsIdentify() {
|
||||||
|
LOAD_ANN_MODEL(ann_, kDefaultAnnPath);
|
||||||
|
LOAD_ANN_MODEL(annChinese_, kChineseAnnPath);
|
||||||
|
LOAD_ANN_MODEL(annGray_, kGrayAnnPath);
|
||||||
|
|
||||||
|
kv_ = std::shared_ptr<Kv>(new Kv);
|
||||||
|
kv_->load(kChineseMappingPath);
|
||||||
|
|
||||||
|
extractFeature = getGrayPlusProject;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharsIdentify::LoadModel(std::string path) {
|
||||||
|
if (path != std::string(kDefaultAnnPath)) {
|
||||||
|
if (!ann_->empty())
|
||||||
|
ann_->clear();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharsIdentify::LoadGrayChANN(std::string path) {
|
||||||
|
if (path != std::string(kGrayAnnPath)) {
|
||||||
|
if (!annGray_->empty())
|
||||||
|
annGray_->clear();
|
||||||
|
LOAD_ANN_MODEL(annGray_, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharsIdentify::LoadChineseMapping(std::string path) {
|
||||||
|
kv_->clear();
|
||||||
|
kv_->load(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharsIdentify::classify(cv::Mat featureRows, std::vector<int>& out_maxIndexs,
|
||||||
|
std::vector<float>& out_maxVals, std::vector<bool> isChineseVec){
|
||||||
|
int rowNum = featureRows.rows;
|
||||||
|
|
||||||
|
cv::Mat output(rowNum, kCharsTotalNumber, CV_32FC1);
|
||||||
|
ann_->predict(featureRows, output);
|
||||||
|
|
||||||
|
for (int output_index = 0; output_index < rowNum; output_index++) {
|
||||||
|
Mat output_row = output.row(output_index);
|
||||||
|
int result = 0;
|
||||||
|
float maxVal = -2.f;
|
||||||
|
bool isChinses = isChineseVec[output_index];
|
||||||
|
if (!isChinses) {
|
||||||
|
result = 0;
|
||||||
|
for (int j = 0; j < kCharactersNumber; j++) {
|
||||||
|
float val = output_row.at<float>(j);
|
||||||
|
// std::cout << "j:" << j << "val:" << val << std::endl;
|
||||||
|
if (val > maxVal) {
|
||||||
|
maxVal = val;
|
||||||
|
result = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = kCharactersNumber;
|
||||||
|
for (int j = kCharactersNumber; j < kCharsTotalNumber; j++) {
|
||||||
|
float val = output_row.at<float>(j);
|
||||||
|
//std::cout << "j:" << j << "val:" << val << std::endl;
|
||||||
|
if (val > maxVal) {
|
||||||
|
maxVal = val;
|
||||||
|
result = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_maxIndexs[output_index] = result;
|
||||||
|
out_maxVals[output_index] = maxVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CharsIdentify::classify(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();
|
||||||
|
Mat feature = charFeatures(charInput, kPredictSize);
|
||||||
|
featureRows.push_back(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat output(charVecSize, kCharsTotalNumber, CV_32FC1);
|
||||||
|
ann_->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);
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
float maxVal = -2.f;
|
||||||
|
std::string label = "";
|
||||||
|
|
||||||
|
bool isChinses = character.getIsChinese();
|
||||||
|
if (!isChinses) {
|
||||||
|
result = 0;
|
||||||
|
for (int j = 0; j < kCharactersNumber; j++) {
|
||||||
|
float val = output_row.at<float>(j);
|
||||||
|
//std::cout << "j:" << j << "val:" << val << std::endl;
|
||||||
|
if (val > maxVal) {
|
||||||
|
maxVal = val;
|
||||||
|
result = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
label = std::make_pair(kChars[result], kChars[result]).second;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = kCharactersNumber;
|
||||||
|
for (int j = kCharactersNumber; j < kCharsTotalNumber; j++) {
|
||||||
|
float val = output_row.at<float>(j);
|
||||||
|
//std::cout << "j:" << j << "val:" << val << std::endl;
|
||||||
|
if (val > maxVal) {
|
||||||
|
maxVal = val;
|
||||||
|
result = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const char* key = kChars[result];
|
||||||
|
std::string s = key;
|
||||||
|
std::string province = kv_->get(s);
|
||||||
|
label = std::make_pair(s, province).second;
|
||||||
|
}
|
||||||
|
/*std::cout << "result:" << result << std::endl;
|
||||||
|
std::cout << "maxVal:" << maxVal << std::endl;*/
|
||||||
|
character.setCharacterScore(maxVal);
|
||||||
|
character.setCharacterStr(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 = 0;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
if (charVecSize == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Mat featureRows;
|
||||||
|
for (size_t index = 0; index < charVecSize; index++) {
|
||||||
|
Mat charInput = charVec[index].getCharacterMat();
|
||||||
|
Mat feature = charFeatures(charInput, kChineseSize);
|
||||||
|
featureRows.push_back(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat output(charVecSize, kChineseNumber, CV_32FC1);
|
||||||
|
annChinese_->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 = 0;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int CharsIdentify::classify(cv::Mat f, float& maxVal, bool isChinses, bool isAlphabet){
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
cv::Mat output(1, kCharsTotalNumber, CV_32FC1);
|
||||||
|
ann_->predict(f, output);
|
||||||
|
|
||||||
|
maxVal = -2.f;
|
||||||
|
if (!isChinses) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = kCharactersNumber;
|
||||||
|
for (int j = kCharactersNumber; j < kCharsTotalNumber; j++) {
|
||||||
|
float val = output.at<float>(j);
|
||||||
|
//std::cout << "j:" << j << "val:" << val << std::endl;
|
||||||
|
if (val > maxVal) {
|
||||||
|
maxVal = val;
|
||||||
|
result = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//std::cout << "maxVal:" << maxVal << std::endl;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CharsIdentify::isCharacter(cv::Mat input, std::string& label, float& maxVal, bool isChinese) {
|
||||||
|
cv::Mat feature = charFeatures(input, kPredictSize);
|
||||||
|
auto index = static_cast<int>(classify(feature, maxVal, isChinese));
|
||||||
|
|
||||||
|
if (isChinese) {
|
||||||
|
//std::cout << "maxVal:" << maxVal << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
float chineseMaxThresh = 0.2f;
|
||||||
|
|
||||||
|
if (maxVal >= 0.9 || (isChinese && maxVal >= chineseMaxThresh)) {
|
||||||
|
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 = 0;
|
||||||
|
|
||||||
|
cv::Mat output(1, kChineseNumber, CV_32FC1);
|
||||||
|
annChinese_->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::identifyChineseGray(cv::Mat input, float& out, bool& isChinese) {
|
||||||
|
cv::Mat feature;
|
||||||
|
extractFeature(input, feature);
|
||||||
|
float maxVal = -2;
|
||||||
|
int result = 0;
|
||||||
|
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, bool isAlphabet) {
|
||||||
|
cv::Mat feature = charFeatures(input, kPredictSize);
|
||||||
|
float maxVal = -2;
|
||||||
|
auto index = static_cast<int>(classify(feature, maxVal, isChinese, isAlphabet));
|
||||||
|
if (index < kCharactersNumber) {
|
||||||
|
return std::make_pair(kChars[index], kChars[index]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const char* key = kChars[index];
|
||||||
|
std::string s = key;
|
||||||
|
std::string province = kv_->get(s);
|
||||||
|
return std::make_pair(s, province);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int CharsIdentify::identify(std::vector<cv::Mat> inputs, std::vector<std::pair<std::string, std::string>>& outputs,
|
||||||
|
std::vector<bool> isChineseVec) {
|
||||||
|
Mat featureRows;
|
||||||
|
size_t input_size = inputs.size();
|
||||||
|
for (size_t i = 0; i < input_size; i++) {
|
||||||
|
Mat input = inputs[i];
|
||||||
|
cv::Mat feature = charFeatures(input, kPredictSize);
|
||||||
|
featureRows.push_back(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> maxIndexs;
|
||||||
|
std::vector<float> maxVals;
|
||||||
|
classify(featureRows, maxIndexs, maxVals, isChineseVec);
|
||||||
|
|
||||||
|
for (size_t row_index = 0; row_index < input_size; row_index++) {
|
||||||
|
int index = maxIndexs[row_index];
|
||||||
|
if (index < kCharactersNumber) {
|
||||||
|
outputs[row_index] = std::make_pair(kChars[index], kChars[index]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const char* key = kChars[index];
|
||||||
|
std::string s = key;
|
||||||
|
std::string province = kv_->get(s);
|
||||||
|
outputs[row_index] = std::make_pair(s, province);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
#include "easypr/core/chars_recognise.h"
|
||||||
|
#include "easypr/core/character.hpp"
|
||||||
|
#include "easypr/util/util.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
namespace easypr {
|
||||||
|
|
||||||
|
CCharsRecognise::CCharsRecognise() { m_charsSegment = new CCharsSegment(); }
|
||||||
|
|
||||||
|
CCharsRecognise::~CCharsRecognise() { SAFE_RELEASE(m_charsSegment); }
|
||||||
|
|
||||||
|
int CCharsRecognise::charsRecognise(Mat plate, std::string& plateLicense) {
|
||||||
|
std::vector<Mat> matChars;
|
||||||
|
int result = m_charsSegment->charsSegment(plate, matChars);
|
||||||
|
if (result == 0) {
|
||||||
|
int num = matChars.size();
|
||||||
|
for (int j = 0; j < num; j++)
|
||||||
|
{
|
||||||
|
Mat charMat = matChars.at(j);
|
||||||
|
bool isChinses = false;
|
||||||
|
float maxVal = 0;
|
||||||
|
if (j == 0) {
|
||||||
|
bool judge = true;
|
||||||
|
isChinses = true;
|
||||||
|
auto character = CharsIdentify::instance()->identifyChinese(charMat, maxVal, judge);
|
||||||
|
plateLicense.append(character.second);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
isChinses = false;
|
||||||
|
auto character = CharsIdentify::instance()->identify(charMat, isChinses);
|
||||||
|
plateLicense.append(character.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (plateLicense.size() < 7) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CCharsRecognise::charsRecognise(CPlate& plate, std::string& plateLicense) {
|
||||||
|
std::vector<Mat> matChars;
|
||||||
|
std::vector<Mat> grayChars;
|
||||||
|
Mat plateMat = plate.getPlateMat();
|
||||||
|
if (0) writeTempImage(plateMat, "plateMat/plate");
|
||||||
|
Color color;
|
||||||
|
if (plate.getPlateLocateType() == CMSER) {
|
||||||
|
color = plate.getPlateColor();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int w = plateMat.cols;
|
||||||
|
int h = plateMat.rows;
|
||||||
|
Mat tmpMat = plateMat(Rect_<double>(w * 0.1, h * 0.1, w * 0.8, h * 0.8));
|
||||||
|
color = getPlateType(tmpMat, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = m_charsSegment->charsSegmentUsingOSTU(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);
|
||||||
|
if (color != Color::BLUE)
|
||||||
|
grayChar = 255 - grayChar;
|
||||||
|
|
||||||
|
bool isChinses = false;
|
||||||
|
std::pair<std::string, std::string> character;
|
||||||
|
float maxVal;
|
||||||
|
if (0 == j) {
|
||||||
|
isChinses = true;
|
||||||
|
bool judge = true;
|
||||||
|
character = CharsIdentify::instance()->identifyChineseGray(grayChar, maxVal, judge);
|
||||||
|
plateLicense.append(character.second);
|
||||||
|
|
||||||
|
// set plate chinese mat and str
|
||||||
|
plate.setChineseMat(grayChar);
|
||||||
|
plate.setChineseKey(character.first);
|
||||||
|
if (0) writeTempImage(grayChar, "char_data/" + character.first + "/chars_");
|
||||||
|
}
|
||||||
|
else if (1 == j) {
|
||||||
|
isChinses = false;
|
||||||
|
bool isAbc = true;
|
||||||
|
character = CharsIdentify::instance()->identify(charMat, isChinses, isAbc);
|
||||||
|
plateLicense.append(character.second);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
isChinses = false;
|
||||||
|
SHOW_IMAGE(charMat, 0);
|
||||||
|
character = CharsIdentify::instance()->identify(charMat, isChinses);
|
||||||
|
plateLicense.append(character.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
CCharacter charResult;
|
||||||
|
charResult.setCharacterMat(charMat);
|
||||||
|
charResult.setCharacterGrayMat(grayChar);
|
||||||
|
if (isChinses)
|
||||||
|
charResult.setCharacterStr(character.first);
|
||||||
|
else
|
||||||
|
charResult.setCharacterStr(character.second);
|
||||||
|
|
||||||
|
plate.addReutCharacter(charResult);
|
||||||
|
}
|
||||||
|
if (plateLicense.size() < 7) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,466 @@
|
|||||||
|
#include "easypr/core/feature.h"
|
||||||
|
#include "easypr/core/core_func.h"
|
||||||
|
#include "thirdparty/LBP/lbp.hpp"
|
||||||
|
|
||||||
|
namespace easypr {
|
||||||
|
|
||||||
|
|
||||||
|
Mat getHistogram(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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
//Mat img_threshold = grayImage.clone();
|
||||||
|
//spatial_ostu(img_threshold, 8, 2, getPlateType(image, false));
|
||||||
|
|
||||||
|
features = getHistogram(img_threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute color histom
|
||||||
|
void getColorFeatures(const Mat& src, Mat& features) {
|
||||||
|
Mat src_hsv;
|
||||||
|
|
||||||
|
//grayImage = histeq(grayImage);
|
||||||
|
cvtColor(src, src_hsv, CV_BGR2HSV);
|
||||||
|
int channels = src_hsv.channels();
|
||||||
|
int nRows = src_hsv.rows;
|
||||||
|
|
||||||
|
// consider multi channel image
|
||||||
|
int nCols = src_hsv.cols * channels;
|
||||||
|
if (src_hsv.isContinuous()) {
|
||||||
|
nCols *= nRows;
|
||||||
|
nRows = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int sz = 180;
|
||||||
|
int h[sz] = { 0 };
|
||||||
|
|
||||||
|
uchar* p;
|
||||||
|
for (int i = 0; i < nRows; ++i) {
|
||||||
|
p = src_hsv.ptr<uchar>(i);
|
||||||
|
for (int j = 0; j < nCols; j += 3) {
|
||||||
|
int H = int(p[j]); // 0-180
|
||||||
|
if (H > sz - 1) H = sz - 1;
|
||||||
|
if (H < 0) H = 0;
|
||||||
|
h[H]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat mhist = Mat::zeros(1, sz, CV_32F);
|
||||||
|
for (int j = 0; j < sz; j++) {
|
||||||
|
mhist.at<float>(j) = (float)h[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize histogram
|
||||||
|
double min, max;
|
||||||
|
minMaxLoc(mhist, &min, &max);
|
||||||
|
|
||||||
|
if (max > 0)
|
||||||
|
mhist.convertTo(mhist, -1, 1.0f / max, 0);
|
||||||
|
|
||||||
|
features = mhist;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void getHistomPlusColoFeatures(const Mat& image, Mat& features) {
|
||||||
|
// TODO
|
||||||
|
Mat feature1, feature2;
|
||||||
|
getHistogramFeatures(image, feature1);
|
||||||
|
getColorFeatures(image, feature2);
|
||||||
|
hconcat(feature1.reshape(1, 1), feature2.reshape(1, 1), features);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void getSIFTFeatures(const Mat& image, Mat& features) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//HOG Features
|
||||||
|
void getHOGFeatures(const Mat& image, Mat& features) {
|
||||||
|
//HOG descripter
|
||||||
|
HOGDescriptor hog(cvSize(128, 64), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 3); //these parameters work well
|
||||||
|
std::vector<float> descriptor;
|
||||||
|
|
||||||
|
// resize input image to (128,64) for compute
|
||||||
|
Size dsize = Size(128,64);
|
||||||
|
Mat trainImg = Mat(dsize, CV_32S);
|
||||||
|
resize(image, trainImg, dsize);
|
||||||
|
|
||||||
|
// compute descripter
|
||||||
|
hog.compute(trainImg, descriptor, Size(8, 8));
|
||||||
|
|
||||||
|
// copy the result
|
||||||
|
Mat mat_featrue(descriptor);
|
||||||
|
mat_featrue.copyTo(features);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void getHSVHistFeatures(const Mat& image, Mat& features) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
//! LBP feature
|
||||||
|
void getLBPFeatures(const Mat& image, Mat& features) {
|
||||||
|
|
||||||
|
Mat grayImage;
|
||||||
|
cvtColor(image, grayImage, CV_RGB2GRAY);
|
||||||
|
|
||||||
|
Mat lbpimage;
|
||||||
|
lbpimage = libfacerec::olbp(grayImage);
|
||||||
|
Mat lbp_hist = libfacerec::spatial_histogram(lbpimage, 32, 4, 4);
|
||||||
|
|
||||||
|
features = lbp_hist;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat charFeatures(Mat in, int sizeData) {
|
||||||
|
const int VERTICAL = 0;
|
||||||
|
const int HORIZONTAL = 1;
|
||||||
|
|
||||||
|
// cut the cetner, will afect 5% perices.
|
||||||
|
Rect _rect = GetCenterRect(in);
|
||||||
|
Mat tmpIn = CutTheRect(in, _rect);
|
||||||
|
//Mat tmpIn = in.clone();
|
||||||
|
|
||||||
|
// Low data feature
|
||||||
|
Mat lowData;
|
||||||
|
resize(tmpIn, lowData, Size(sizeData, sizeData));
|
||||||
|
|
||||||
|
// Histogram features
|
||||||
|
Mat vhist = ProjectedHistogram(lowData, VERTICAL);
|
||||||
|
Mat hhist = ProjectedHistogram(lowData, HORIZONTAL);
|
||||||
|
|
||||||
|
// Last 10 is the number of moments components
|
||||||
|
int numCols = vhist.cols + hhist.cols + lowData.cols * lowData.cols;
|
||||||
|
|
||||||
|
Mat out = Mat::zeros(1, numCols, CV_32F);
|
||||||
|
// Asign values to
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
for (int x = 0; x < lowData.cols; x++) {
|
||||||
|
for (int y = 0; y < lowData.rows; y++) {
|
||||||
|
out.at<float>(j) += (float)lowData.at <unsigned char>(x, y);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::cout << out << std::endl;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Mat charFeatures2(Mat in, int sizeData) {
|
||||||
|
const int VERTICAL = 0;
|
||||||
|
const int HORIZONTAL = 1;
|
||||||
|
|
||||||
|
// cut the cetner, will afect 5% perices.
|
||||||
|
Rect _rect = GetCenterRect(in);
|
||||||
|
Mat tmpIn = CutTheRect(in, _rect);
|
||||||
|
//Mat tmpIn = in.clone();
|
||||||
|
|
||||||
|
// Low data feature
|
||||||
|
Mat lowData;
|
||||||
|
resize(tmpIn, lowData, Size(sizeData, sizeData));
|
||||||
|
|
||||||
|
// Histogram features
|
||||||
|
Mat vhist = ProjectedHistogram(lowData, VERTICAL);
|
||||||
|
Mat hhist = ProjectedHistogram(lowData, HORIZONTAL);
|
||||||
|
|
||||||
|
// Last 10 is the number of moments components
|
||||||
|
int numCols = vhist.cols + hhist.cols + lowData.cols * lowData.cols;
|
||||||
|
|
||||||
|
Mat out = Mat::zeros(1, numCols, CV_32F);
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
for (int x = 0; x < lowData.cols; x++) {
|
||||||
|
for (int y = 0; y < lowData.rows; y++) {
|
||||||
|
out.at<float>(j) += (float)lowData.at <unsigned char>(x, y);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::cout << out << std::endl;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat charProjectFeatures(const Mat& in, int sizeData) {
|
||||||
|
const int VERTICAL = 0;
|
||||||
|
const int HORIZONTAL = 1;
|
||||||
|
|
||||||
|
SHOW_IMAGE(in, 0);
|
||||||
|
// cut the cetner, will afect 5% perices.
|
||||||
|
|
||||||
|
Mat lowData;
|
||||||
|
resize(in, lowData, Size(sizeData, sizeData));
|
||||||
|
|
||||||
|
SHOW_IMAGE(lowData, 0);
|
||||||
|
// Histogram features
|
||||||
|
Mat vhist = ProjectedHistogram(lowData, VERTICAL);
|
||||||
|
Mat hhist = ProjectedHistogram(lowData, HORIZONTAL);
|
||||||
|
|
||||||
|
// Last 10 is the number of moments components
|
||||||
|
int numCols = vhist.cols + hhist.cols;
|
||||||
|
|
||||||
|
Mat out = Mat::zeros(1, numCols, CV_32F);
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
//std::cout << out << std::endl;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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
|
||||||
|
Mat float_img;
|
||||||
|
if (useConvert) {
|
||||||
|
float scale = 1.f / 255;
|
||||||
|
char_mat.convertTo(float_img, CV_32FC1, scale, 0);
|
||||||
|
} else {
|
||||||
|
float_img = char_mat;
|
||||||
|
}
|
||||||
|
SHOW_IMAGE(float_img, 0);
|
||||||
|
|
||||||
|
// cut from mean, it can be optional
|
||||||
|
|
||||||
|
Mat mean_img;
|
||||||
|
if (useMean) {
|
||||||
|
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 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 = feautreImg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void getGrayPlusProject(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;
|
||||||
|
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
|
||||||
|
Mat float_img;
|
||||||
|
if (useConvert) {
|
||||||
|
float scale = 1.f / 255;
|
||||||
|
char_mat.convertTo(float_img, CV_32FC1, scale, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
float_img = char_mat;
|
||||||
|
}
|
||||||
|
SHOW_IMAGE(float_img, 0);
|
||||||
|
|
||||||
|
// cut from mean, it can be optional
|
||||||
|
|
||||||
|
Mat mean_img;
|
||||||
|
if (useMean) {
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
SHOW_IMAGE(grayChar, 0);
|
||||||
|
Mat binaryChar;
|
||||||
|
threshold(grayChar, binaryChar, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);
|
||||||
|
SHOW_IMAGE(binaryChar, 0);
|
||||||
|
Mat projectFeature = charProjectFeatures(binaryChar, 32);
|
||||||
|
|
||||||
|
hconcat(feautreImg.reshape(1, 1), projectFeature.reshape(1, 1), features);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void getGrayPlusLBP(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 = true;
|
||||||
|
|
||||||
|
Mat char_mat;
|
||||||
|
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
|
||||||
|
Mat float_img;
|
||||||
|
if (useConvert) {
|
||||||
|
float scale = 1.f / 255;
|
||||||
|
char_mat.convertTo(float_img, CV_32FC1, scale, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
float_img = char_mat;
|
||||||
|
}
|
||||||
|
SHOW_IMAGE(float_img, 0);
|
||||||
|
|
||||||
|
// cut from mean, it can be optional
|
||||||
|
|
||||||
|
Mat mean_img;
|
||||||
|
if (useMean) {
|
||||||
|
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 originImage = mean_img.clone();
|
||||||
|
Mat lbpimage = libfacerec::olbp(mean_img);
|
||||||
|
SHOW_IMAGE(lbpimage, 0);
|
||||||
|
lbpimage = libfacerec::spatial_histogram(lbpimage, kCharLBPPatterns, kCharLBPGridX, kCharLBPGridY);
|
||||||
|
|
||||||
|
// 32x20 + 16x16
|
||||||
|
hconcat(mean_img.reshape(1, 1), lbpimage.reshape(1, 1), features);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getLBPplusHistFeatures(const Mat& image, Mat& features) {
|
||||||
|
Mat grayImage;
|
||||||
|
cvtColor(image, grayImage, CV_RGB2GRAY);
|
||||||
|
|
||||||
|
Mat lbpimage;
|
||||||
|
lbpimage = libfacerec::olbp(grayImage);
|
||||||
|
Mat lbp_hist = libfacerec::spatial_histogram(lbpimage, 64, 8, 4);
|
||||||
|
//features = lbp_hist.reshape(1, 1);
|
||||||
|
|
||||||
|
Mat greyImage;
|
||||||
|
cvtColor(image, greyImage, CV_RGB2GRAY);
|
||||||
|
|
||||||
|
//grayImage = histeq(grayImage);
|
||||||
|
Mat img_threshold;
|
||||||
|
threshold(greyImage, img_threshold, 0, 255,
|
||||||
|
CV_THRESH_OTSU + CV_THRESH_BINARY);
|
||||||
|
Mat histomFeatures = getHistogram(img_threshold);
|
||||||
|
|
||||||
|
hconcat(lbp_hist.reshape(1, 1), histomFeatures.reshape(1, 1), features);
|
||||||
|
//std::cout << features << std::endl;
|
||||||
|
//features = histomFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
#include "easypr/core/params.h"
|
||||||
|
|
||||||
|
namespace easypr {
|
||||||
|
CParams* CParams::instance_ = nullptr;
|
||||||
|
|
||||||
|
CParams* CParams::instance() {
|
||||||
|
if (!instance_) {
|
||||||
|
instance_ = new CParams;
|
||||||
|
}
|
||||||
|
return instance_;
|
||||||
|
}
|
||||||
|
}/*! \namespace easypr*/
|
@ -0,0 +1,77 @@
|
|||||||
|
#include "easypr/core/plate_detect.h"
|
||||||
|
#include "easypr/util/util.h"
|
||||||
|
#include "easypr/core/core_func.h"
|
||||||
|
#include "easypr/config.h"
|
||||||
|
|
||||||
|
namespace easypr {
|
||||||
|
|
||||||
|
CPlateDetect::CPlateDetect() {
|
||||||
|
m_plateLocate = new CPlateLocate();
|
||||||
|
m_maxPlates = 3;
|
||||||
|
m_type = 0;
|
||||||
|
m_showDetect = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPlateDetect::~CPlateDetect() { SAFE_RELEASE(m_plateLocate); }
|
||||||
|
|
||||||
|
int CPlateDetect::plateDetect(Mat src, std::vector<CPlate> &resultVec, int type,
|
||||||
|
bool showDetectArea, int img_index) {
|
||||||
|
std::vector<CPlate> sobel_Plates;
|
||||||
|
sobel_Plates.reserve(16);
|
||||||
|
std::vector<CPlate> color_Plates;
|
||||||
|
color_Plates.reserve(16);
|
||||||
|
std::vector<CPlate> mser_Plates;
|
||||||
|
mser_Plates.reserve(16);
|
||||||
|
std::vector<CPlate> all_result_Plates;
|
||||||
|
all_result_Plates.reserve(64);
|
||||||
|
#pragma omp parallel sections
|
||||||
|
{
|
||||||
|
#pragma omp section
|
||||||
|
{
|
||||||
|
if (!type || type & PR_DETECT_SOBEL) {
|
||||||
|
m_plateLocate->plateSobelLocate(src, sobel_Plates, img_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma omp section
|
||||||
|
{
|
||||||
|
if (!type || type & PR_DETECT_COLOR) {
|
||||||
|
m_plateLocate->plateColorLocate(src, color_Plates, img_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma omp section
|
||||||
|
{
|
||||||
|
if (!type || type & PR_DETECT_CMSER) {
|
||||||
|
m_plateLocate->plateMserLocate(src, mser_Plates, img_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto plate : sobel_Plates) {
|
||||||
|
plate.setPlateLocateType(SOBEL);
|
||||||
|
all_result_Plates.push_back(plate);
|
||||||
|
}
|
||||||
|
for (auto plate : color_Plates) {
|
||||||
|
plate.setPlateLocateType(COLOR);
|
||||||
|
all_result_Plates.push_back(plate);
|
||||||
|
}
|
||||||
|
for (auto plate : mser_Plates) {
|
||||||
|
plate.setPlateLocateType(CMSER);
|
||||||
|
all_result_Plates.push_back(plate);
|
||||||
|
}
|
||||||
|
// use nms to judge plate
|
||||||
|
PlateJudge::instance()->plateJudgeUsingNMS(all_result_Plates, resultVec, m_maxPlates);
|
||||||
|
|
||||||
|
if (0)
|
||||||
|
showDectectResults(src, resultVec, m_maxPlates);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CPlateDetect::plateDetect(Mat src, std::vector<CPlate> &resultVec, int img_index) {
|
||||||
|
int result = plateDetect(src, resultVec, m_type, false, img_index);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPlateDetect::LoadSVM(std::string path) {
|
||||||
|
PlateJudge::instance()->LoadModel(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
#include "easypr/core/plate_recognize.h"
|
||||||
|
#include "easypr/config.h"
|
||||||
|
#include "thirdparty/textDetect/erfilter.hpp"
|
||||||
|
|
||||||
|
namespace easypr {
|
||||||
|
|
||||||
|
CPlateRecognize::CPlateRecognize() {
|
||||||
|
m_showResult = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// main method, plate recognize, contain two parts
|
||||||
|
// 1. plate detect
|
||||||
|
// 2. chars recognize
|
||||||
|
int CPlateRecognize::plateRecognize(const Mat& src, std::vector<CPlate> &plateVecOut, int img_index) {
|
||||||
|
// resize to uniform sizes
|
||||||
|
float scale = 1.f;
|
||||||
|
Mat img = uniformResize(src, scale);
|
||||||
|
|
||||||
|
// 1. plate detect
|
||||||
|
std::vector<CPlate> plateVec;
|
||||||
|
int resultPD = plateDetect(img, plateVec, img_index);
|
||||||
|
if (resultPD == 0) {
|
||||||
|
size_t num = plateVec.size();
|
||||||
|
for (size_t j = 0; j < num; j++) {
|
||||||
|
CPlate& item = plateVec.at(j);
|
||||||
|
Mat plateMat = item.getPlateMat();
|
||||||
|
SHOW_IMAGE(plateMat, 0);
|
||||||
|
|
||||||
|
// scale the rect to src;
|
||||||
|
item.setPlateScale(scale);
|
||||||
|
RotatedRect rect = item.getPlatePos();
|
||||||
|
item.setPlatePos(scaleBackRRect(rect, 1.f / scale));
|
||||||
|
|
||||||
|
// get plate color
|
||||||
|
Color color = item.getPlateColor();
|
||||||
|
if (color == UNKNOWN) {
|
||||||
|
color = getPlateType(plateMat, true);
|
||||||
|
item.setPlateColor(color);
|
||||||
|
}
|
||||||
|
std::string plateColor = getPlateColor(color);
|
||||||
|
if (0) {
|
||||||
|
std::cout << "plateColor:" << plateColor << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. chars recognize
|
||||||
|
std::string plateIdentify = "";
|
||||||
|
int resultCR = charsRecognise(item, plateIdentify);
|
||||||
|
if (resultCR == 0) {
|
||||||
|
std::string license = plateColor + ":" + plateIdentify;
|
||||||
|
item.setPlateStr(license);
|
||||||
|
plateVecOut.push_back(item);
|
||||||
|
if (0) std::cout << "resultCR:" << resultCR << std::endl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::string license = plateColor;
|
||||||
|
item.setPlateStr(license);
|
||||||
|
plateVecOut.push_back(item);
|
||||||
|
if (0) std::cout << "resultCR:" << resultCR << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getResultShow()) {
|
||||||
|
// param type: 0 detect, 1 recognize;
|
||||||
|
int showType = 1;
|
||||||
|
if (0 == showType)
|
||||||
|
showDectectResults(img, plateVec, num);
|
||||||
|
else
|
||||||
|
showDectectResults(img, plateVecOut, num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultPD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPlateRecognize::LoadSVM(std::string path) {
|
||||||
|
PlateJudge::instance()->LoadModel(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPlateRecognize::LoadANN(std::string path) {
|
||||||
|
CharsIdentify::instance()->LoadModel(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPlateRecognize::LoadChineseANN(std::string path) {
|
||||||
|
CharsIdentify::instance()->LoadChineseModel(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPlateRecognize::LoadGrayChANN(std::string path) {
|
||||||
|
CharsIdentify::instance()->LoadGrayChANN(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPlateRecognize::LoadChineseMapping(std::string path) {
|
||||||
|
CharsIdentify::instance()->LoadChineseMapping(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// deprected
|
||||||
|
int CPlateRecognize::plateRecognize(const Mat& src, std::vector<std::string> &licenseVec) {
|
||||||
|
vector<CPlate> plates;
|
||||||
|
int resultPR = plateRecognize(src, plates, 0);
|
||||||
|
|
||||||
|
for (auto plate : plates) {
|
||||||
|
licenseVec.push_back(plate.getPlateStr());
|
||||||
|
}
|
||||||
|
return resultPR;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in new issue