上传原版本C++训练文件

devA
yuxue 5 years ago
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,193 @@
#include "easypr/core/plate_judge.h"
#include "easypr/config.h"
#include "easypr/core/core_func.h"
#include "easypr/core/params.h"
namespace easypr {
PlateJudge* PlateJudge::instance_ = nullptr;
PlateJudge* PlateJudge::instance() {
if (!instance_) {
instance_ = new PlateJudge;
}
return instance_;
}
PlateJudge::PlateJudge() {
bool useLBP = false;
if (useLBP) {
LOAD_SVM_MODEL(svm_, kLBPSvmPath);
extractFeature = getLBPFeatures;
}
else {
LOAD_SVM_MODEL(svm_, kHistSvmPath);
extractFeature = getHistomPlusColoFeatures;
}
}
void PlateJudge::LoadModel(std::string path) {
if (path != std::string(kDefaultSvmPath)) {
if (!svm_->empty())
svm_->clear();
LOAD_SVM_MODEL(svm_, path);
}
}
// set the score of plate
// 0 is plate, -1 is not.
int PlateJudge::plateSetScore(CPlate& plate) {
Mat features;
extractFeature(plate.getPlateMat(), features);
float score = svm_->predict(features, noArray(), cv::ml::StatModel::Flags::RAW_OUTPUT);
//std::cout << "score:" << score << std::endl;
if (0) {
imshow("plate", plate.getPlateMat());
waitKey(0);
destroyWindow("plate");
}
// score is the distance of marginbelow zero is plate, up is not
// when score is below zero, the samll the value, the more possibliy to be a plate.
plate.setPlateScore(score);
if (score < 0.5) return 0;
else return -1;
}
int PlateJudge::plateJudge(const Mat& plateMat) {
CPlate plate;
plate.setPlateMat(plateMat);
return plateSetScore(plate);
}
int PlateJudge::plateJudge(const std::vector<Mat> &inVec,
std::vector<Mat> &resultVec) {
int num = inVec.size();
for (int j = 0; j < num; j++) {
Mat inMat = inVec[j];
int response = -1;
response = plateJudge(inMat);
if (response == 0) resultVec.push_back(inMat);
}
return 0;
}
int PlateJudge::plateJudge(const std::vector<CPlate> &inVec,
std::vector<CPlate> &resultVec) {
int num = inVec.size();
for (int j = 0; j < num; j++) {
CPlate inPlate = inVec[j];
Mat inMat = inPlate.getPlateMat();
int response = -1;
response = plateJudge(inMat);
if (response == 0)
resultVec.push_back(inPlate);
else {
int w = inMat.cols;
int h = inMat.rows;
Mat tmpmat = inMat(Rect_<double>(w * 0.05, h * 0.1, w * 0.9, h * 0.8));
Mat tmpDes = inMat.clone();
resize(tmpmat, tmpDes, Size(inMat.size()));
response = plateJudge(tmpDes);
if (response == 0) resultVec.push_back(inPlate);
}
}
return 0;
}
// non-maximum suppression
void NMS(std::vector<CPlate> &inVec, std::vector<CPlate> &resultVec, double overlap) {
std::sort(inVec.begin(), inVec.end());
std::vector<CPlate>::iterator it = inVec.begin();
for (; it != inVec.end(); ++it) {
CPlate plateSrc = *it;
//std::cout << "plateScore:" << plateSrc.getPlateScore() << std::endl;
Rect rectSrc = plateSrc.getPlatePos().boundingRect();
std::vector<CPlate>::iterator itc = it + 1;
for (; itc != inVec.end();) {
CPlate plateComp = *itc;
Rect rectComp = plateComp.getPlatePos().boundingRect();
float iou = computeIOU(rectSrc, rectComp);
if (iou > overlap) {
itc = inVec.erase(itc);
}
else {
++itc;
}
}
}
resultVec = inVec;
}
// judge plate using nms
int PlateJudge::plateJudgeUsingNMS(const std::vector<CPlate> &inVec, std::vector<CPlate> &resultVec, int maxPlates) {
std::vector<CPlate> plateVec;
int num = inVec.size();
bool useCascadeJudge = true;
for (int j = 0; j < num; j++) {
CPlate plate = inVec[j];
Mat inMat = plate.getPlateMat();
int result = plateSetScore(plate);
if (0 == result) {
if (0) {
imshow("inMat", inMat);
waitKey(0);
destroyWindow("inMat");
}
if (plate.getPlateLocateType() == CMSER) {
int w = inMat.cols;
int h = inMat.rows;
Mat tmpmat = inMat(Rect_<double>(w * 0.05, h * 0.1, w * 0.9, h * 0.8));
Mat tmpDes = inMat.clone();
resize(tmpmat, tmpDes, Size(inMat.size()));
plate.setPlateMat(tmpDes);
if (useCascadeJudge) {
int resultCascade = plateSetScore(plate);
if (plate.getPlateLocateType() != CMSER)
plate.setPlateMat(inMat);
if (resultCascade == 0) {
if (0) {
imshow("tmpDes", tmpDes);
waitKey(0);
destroyWindow("tmpDes");
}
plateVec.push_back(plate);
}
}
else
plateVec.push_back(plate);
}
else
plateVec.push_back(plate);
}
}
std::vector<CPlate> reDupPlateVec;
double overlap = 0.5;
// double overlap = CParams::instance()->getParam1f();
// use NMS to get the result plates
NMS(plateVec, reDupPlateVec, overlap);
// sort the plates due to their scores
std::sort(reDupPlateVec.begin(), reDupPlateVec.end());
// output the plate judge plates
std::vector<CPlate>::iterator it = reDupPlateVec.begin();
int count = 0;
for (; it != reDupPlateVec.end(); ++it) {
resultVec.push_back(*it);
if (0) {
imshow("plateMat", it->getPlateMat());
waitKey(0);
destroyWindow("plateMat");
}
count++;
if (count >= maxPlates)
break;
}
return 0;
}
}

@ -0,0 +1,999 @@
#include "easypr/core/plate_locate.h"
#include "easypr/core/core_func.h"
#include "easypr/util/util.h"
#include "easypr/core/params.h"
using namespace std;
namespace easypr {
const float DEFAULT_ERROR = 0.9f; // 0.6
const float DEFAULT_ASPECT = 3.75f; // 3.75
CPlateLocate::CPlateLocate() {
m_GaussianBlurSize = DEFAULT_GAUSSIANBLUR_SIZE;
m_MorphSizeWidth = DEFAULT_MORPH_SIZE_WIDTH;
m_MorphSizeHeight = DEFAULT_MORPH_SIZE_HEIGHT;
m_error = DEFAULT_ERROR;
m_aspect = DEFAULT_ASPECT;
m_verifyMin = DEFAULT_VERIFY_MIN;
m_verifyMax = DEFAULT_VERIFY_MAX;
m_angle = DEFAULT_ANGLE;
m_debug = DEFAULT_DEBUG;
}
void CPlateLocate::setLifemode(bool param) {
if (param) {
setGaussianBlurSize(5);
setMorphSizeWidth(10);
setMorphSizeHeight(3);
setVerifyError(0.75);
setVerifyAspect(4.0);
setVerifyMin(1);
setVerifyMax(200);
} else {
setGaussianBlurSize(DEFAULT_GAUSSIANBLUR_SIZE);
setMorphSizeWidth(DEFAULT_MORPH_SIZE_WIDTH);
setMorphSizeHeight(DEFAULT_MORPH_SIZE_HEIGHT);
setVerifyError(DEFAULT_ERROR);
setVerifyAspect(DEFAULT_ASPECT);
setVerifyMin(DEFAULT_VERIFY_MIN);
setVerifyMax(DEFAULT_VERIFY_MAX);
}
}
bool CPlateLocate::verifySizes(RotatedRect mr) {
float error = m_error;
// Spain car plate size: 52x11 aspect 4,7272
// China car plate size: 440mm*140mmaspect 3.142857
// Real car plate size: 136 * 32, aspect 4
float aspect = m_aspect;
// Set a min and max area. All other patchs are discarded
// int min= 1*aspect*1; // minimum area
// int max= 2000*aspect*2000; // maximum area
int min = 34 * 8 * m_verifyMin; // minimum area
int max = 34 * 8 * m_verifyMax; // maximum area
// Get only patchs that match to a respect ratio.
float rmin = aspect - aspect * error;
float rmax = aspect + aspect * error;
float area = mr.size.height * mr.size.width;
float r = (float) mr.size.width / (float) mr.size.height;
if (r < 1) r = (float) mr.size.height / (float) mr.size.width;
// cout << "area:" << area << endl;
// cout << "r:" << r << endl;
if ((area < min || area > max) || (r < rmin || r > rmax))
return false;
else
return true;
}
//! mser search method
int CPlateLocate::mserSearch(const Mat &src, vector<Mat> &out,
vector<vector<CPlate>>& out_plateVec, bool usePlateMser, vector<vector<RotatedRect>>& out_plateRRect,
int img_index, bool showDebug) {
vector<Mat> match_grey;
vector<CPlate> plateVec_blue;
plateVec_blue.reserve(16);
vector<RotatedRect> plateRRect_blue;
plateRRect_blue.reserve(16);
vector<CPlate> plateVec_yellow;
plateVec_yellow.reserve(16);
vector<RotatedRect> plateRRect_yellow;
plateRRect_yellow.reserve(16);
mserCharMatch(src, match_grey, plateVec_blue, plateVec_yellow, usePlateMser, plateRRect_blue, plateRRect_yellow, img_index, showDebug);
out_plateVec.push_back(plateVec_blue);
out_plateVec.push_back(plateVec_yellow);
out_plateRRect.push_back(plateRRect_blue);
out_plateRRect.push_back(plateRRect_yellow);
out = match_grey;
return 0;
}
int CPlateLocate::colorSearch(const Mat &src, const Color r, Mat &out,
vector<RotatedRect> &outRects) {
Mat match_grey;
// width is important to the final results;
const int color_morph_width = 10;
const int color_morph_height = 2;
colorMatch(src, match_grey, r, false);
SHOW_IMAGE(match_grey, 0);
Mat src_threshold;
threshold(match_grey, src_threshold, 0, 255,
CV_THRESH_OTSU + CV_THRESH_BINARY);
Mat element = getStructuringElement(
MORPH_RECT, Size(color_morph_width, color_morph_height));
morphologyEx(src_threshold, src_threshold, MORPH_CLOSE, element);
//if (m_debug) {
// utils::imwrite("resources/image/tmp/color.jpg", src_threshold);
//}
src_threshold.copyTo(out);
vector<vector<Point>> contours;
findContours(src_threshold,
contours, // a vector of contours
CV_RETR_EXTERNAL,
CV_CHAIN_APPROX_NONE); // all pixels of each contours
vector<vector<Point>>::iterator itc = contours.begin();
while (itc != contours.end()) {
RotatedRect mr = minAreaRect(Mat(*itc));
if (!verifySizes(mr))
itc = contours.erase(itc);
else {
++itc;
outRects.push_back(mr);
}
}
return 0;
}
int CPlateLocate::sobelFrtSearch(const Mat &src,
vector<Rect_<float>> &outRects) {
Mat src_threshold;
sobelOper(src, src_threshold, m_GaussianBlurSize, m_MorphSizeWidth,
m_MorphSizeHeight);
vector<vector<Point>> contours;
findContours(src_threshold,
contours, // a vector of contours
CV_RETR_EXTERNAL,
CV_CHAIN_APPROX_NONE); // all pixels of each contours
vector<vector<Point>>::iterator itc = contours.begin();
vector<RotatedRect> first_rects;
while (itc != contours.end()) {
RotatedRect mr = minAreaRect(Mat(*itc));
if (verifySizes(mr)) {
first_rects.push_back(mr);
float area = mr.size.height * mr.size.width;
float r = (float) mr.size.width / (float) mr.size.height;
if (r < 1) r = (float) mr.size.height / (float) mr.size.width;
}
++itc;
}
for (size_t i = 0; i < first_rects.size(); i++) {
RotatedRect roi_rect = first_rects[i];
Rect_<float> safeBoundRect;
if (!calcSafeRect(roi_rect, src, safeBoundRect)) continue;
outRects.push_back(safeBoundRect);
}
return 0;
}
int CPlateLocate::sobelSecSearchPart(Mat &bound, Point2f refpoint,
vector<RotatedRect> &outRects) {
Mat bound_threshold;
sobelOperT(bound, bound_threshold, 3, 6, 2);
Mat tempBoundThread = bound_threshold.clone();
clearLiuDingOnly(tempBoundThread);
int posLeft = 0, posRight = 0;
if (bFindLeftRightBound(tempBoundThread, posLeft, posRight)) {
// find left and right bounds to repair
if (posRight != 0 && posLeft != 0 && posLeft < posRight) {
int posY = int(bound_threshold.rows * 0.5);
for (int i = posLeft + (int) (bound_threshold.rows * 0.1);
i < posRight - 4; i++) {
bound_threshold.data[posY * bound_threshold.cols + i] = 255;
}
}
utils::imwrite("resources/image/tmp/repaireimg1.jpg", bound_threshold);
// remove the left and right boundaries
for (int i = 0; i < bound_threshold.rows; i++) {
bound_threshold.data[i * bound_threshold.cols + posLeft] = 0;
bound_threshold.data[i * bound_threshold.cols + posRight] = 0;
}
utils::imwrite("resources/image/tmp/repaireimg2.jpg", bound_threshold);
}
vector<vector<Point>> contours;
findContours(bound_threshold,
contours, // a vector of contours
CV_RETR_EXTERNAL,
CV_CHAIN_APPROX_NONE); // all pixels of each contours
vector<vector<Point>>::iterator itc = contours.begin();
vector<RotatedRect> second_rects;
while (itc != contours.end()) {
RotatedRect mr = minAreaRect(Mat(*itc));
second_rects.push_back(mr);
++itc;
}
for (size_t i = 0; i < second_rects.size(); i++) {
RotatedRect roi = second_rects[i];
if (verifySizes(roi)) {
Point2f refcenter = roi.center + refpoint;
Size2f size = roi.size;
float angle = roi.angle;
RotatedRect refroi(refcenter, size, angle);
outRects.push_back(refroi);
}
}
return 0;
}
int CPlateLocate::sobelSecSearch(Mat &bound, Point2f refpoint,
vector<RotatedRect> &outRects) {
Mat bound_threshold;
sobelOper(bound, bound_threshold, 3, 10, 3);
utils::imwrite("resources/image/tmp/sobelSecSearch.jpg", bound_threshold);
vector<vector<Point>> contours;
findContours(bound_threshold,
contours, // a vector of contours
CV_RETR_EXTERNAL,
CV_CHAIN_APPROX_NONE); // all pixels of each contours
vector<vector<Point>>::iterator itc = contours.begin();
vector<RotatedRect> second_rects;
while (itc != contours.end()) {
RotatedRect mr = minAreaRect(Mat(*itc));
second_rects.push_back(mr);
++itc;
}
for (size_t i = 0; i < second_rects.size(); i++) {
RotatedRect roi = second_rects[i];
if (verifySizes(roi)) {
Point2f refcenter = roi.center + refpoint;
Size2f size = roi.size;
float angle = roi.angle;
RotatedRect refroi(refcenter, size, angle);
outRects.push_back(refroi);
}
}
return 0;
}
int CPlateLocate::sobelOper(const Mat &in, Mat &out, int blurSize, int morphW,
int morphH) {
Mat mat_blur;
mat_blur = in.clone();
GaussianBlur(in, mat_blur, Size(blurSize, blurSize), 0, 0, BORDER_DEFAULT);
Mat mat_gray;
if (mat_blur.channels() == 3)
cvtColor(mat_blur, mat_gray, CV_RGB2GRAY);
else
mat_gray = mat_blur;
int scale = SOBEL_SCALE;
int delta = SOBEL_DELTA;
int ddepth = SOBEL_DDEPTH;
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
Sobel(mat_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x);
Mat grad;
addWeighted(abs_grad_x, SOBEL_X_WEIGHT, 0, 0, 0, grad);
Mat mat_threshold;
double otsu_thresh_val =
threshold(grad, mat_threshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);
Mat element = getStructuringElement(MORPH_RECT, Size(morphW, morphH));
morphologyEx(mat_threshold, mat_threshold, MORPH_CLOSE, element);
out = mat_threshold;
return 0;
}
void deleteNotArea(Mat &inmat, Color color = UNKNOWN) {
Mat input_grey;
cvtColor(inmat, input_grey, CV_BGR2GRAY);
int w = inmat.cols;
int h = inmat.rows;
Mat tmpMat = inmat(Rect_<double>(w * 0.15, h * 0.1, w * 0.7, h * 0.7));
Color plateType;
if (UNKNOWN == color) {
plateType = getPlateType(tmpMat, true);
}
else {
plateType = color;
}
Mat img_threshold;
if (BLUE == plateType) {
img_threshold = input_grey.clone();
Mat tmp = input_grey(Rect_<double>(w * 0.15, h * 0.15, w * 0.7, h * 0.7));
int threadHoldV = ThresholdOtsu(tmp);
threshold(input_grey, img_threshold, threadHoldV, 255, CV_THRESH_BINARY);
// threshold(input_grey, img_threshold, 5, 255, CV_THRESH_OTSU +
// CV_THRESH_BINARY);
utils::imwrite("resources/image/tmp/inputgray2.jpg", img_threshold);
} else if (YELLOW == plateType) {
img_threshold = input_grey.clone();
Mat tmp = input_grey(Rect_<double>(w * 0.1, h * 0.1, w * 0.8, h * 0.8));
int threadHoldV = ThresholdOtsu(tmp);
threshold(input_grey, img_threshold, threadHoldV, 255,
CV_THRESH_BINARY_INV);
utils::imwrite("resources/image/tmp/inputgray2.jpg", img_threshold);
// threshold(input_grey, img_threshold, 10, 255, CV_THRESH_OTSU +
// CV_THRESH_BINARY_INV);
} else
threshold(input_grey, img_threshold, 10, 255,
CV_THRESH_OTSU + CV_THRESH_BINARY);
//img_threshold = input_grey.clone();
//spatial_ostu(img_threshold, 8, 2, plateType);
int posLeft = 0;
int posRight = 0;
int top = 0;
int bottom = img_threshold.rows - 1;
clearLiuDing(img_threshold, top, bottom);
if (0) {
imshow("inmat", inmat);
waitKey(0);
destroyWindow("inmat");
}
if (bFindLeftRightBound1(img_threshold, posLeft, posRight)) {
inmat = inmat(Rect(posLeft, top, w - posLeft, bottom - top));
if (0) {
imshow("inmat", inmat);
waitKey(0);
destroyWindow("inmat");
}
}
}
int CPlateLocate::deskew(const Mat &src, const Mat &src_b,
vector<RotatedRect> &inRects,
vector<CPlate> &outPlates, bool useDeteleArea, Color color) {
Mat mat_debug;
src.copyTo(mat_debug);
for (size_t i = 0; i < inRects.size(); i++) {
RotatedRect roi_rect = inRects[i];
float r = (float) roi_rect.size.width / (float) roi_rect.size.height;
float roi_angle = roi_rect.angle;
Size roi_rect_size = roi_rect.size;
if (r < 1) {
roi_angle = 90 + roi_angle;
swap(roi_rect_size.width, roi_rect_size.height);
}
if (m_debug) {
Point2f rect_points[4];
roi_rect.points(rect_points);
for (int j = 0; j < 4; j++)
line(mat_debug, rect_points[j], rect_points[(j + 1) % 4],
Scalar(0, 255, 255), 1, 8);
}
// changed
// rotation = 90 - abs(roi_angle);
// rotation < m_angel;
// m_angle=60
if (roi_angle - m_angle < 0 && roi_angle + m_angle > 0) {
Rect_<float> safeBoundRect;
bool isFormRect = calcSafeRect(roi_rect, src, safeBoundRect);
if (!isFormRect) continue;
Mat bound_mat = src(safeBoundRect);
Mat bound_mat_b = src_b(safeBoundRect);
if (0) {
imshow("bound_mat_b", bound_mat_b);
waitKey(0);
destroyWindow("bound_mat_b");
}
Point2f roi_ref_center = roi_rect.center - safeBoundRect.tl();
Mat deskew_mat;
if ((roi_angle - 5 < 0 && roi_angle + 5 > 0) || 90.0 == roi_angle ||
-90.0 == roi_angle) {
deskew_mat = bound_mat;
} else {
Mat rotated_mat;
Mat rotated_mat_b;
if (!rotation(bound_mat, rotated_mat, roi_rect_size, roi_ref_center, roi_angle))
continue;
if (!rotation(bound_mat_b, rotated_mat_b, roi_rect_size, roi_ref_center, roi_angle))
continue;
// we need affine for rotatioed image
double roi_slope = 0;
// imshow("1roated_mat",rotated_mat);
// imshow("rotated_mat_b",rotated_mat_b);
if (isdeflection(rotated_mat_b, roi_angle, roi_slope)) {
affine(rotated_mat, deskew_mat, roi_slope);
} else
deskew_mat = rotated_mat;
}
Mat plate_mat;
plate_mat.create(HEIGHT, WIDTH, TYPE);
// haitungaga addaffect 25% to full recognition.
if (useDeteleArea)
deleteNotArea(deskew_mat, color);
if (deskew_mat.cols * 1.0 / deskew_mat.rows > 2.3 && deskew_mat.cols * 1.0 / deskew_mat.rows < 6) {
if (deskew_mat.cols >= WIDTH || deskew_mat.rows >= HEIGHT)
resize(deskew_mat, plate_mat, plate_mat.size(), 0, 0, INTER_AREA);
else
resize(deskew_mat, plate_mat, plate_mat.size(), 0, 0, INTER_CUBIC);
CPlate plate;
plate.setPlatePos(roi_rect);
plate.setPlateMat(plate_mat);
if (color != UNKNOWN) plate.setPlateColor(color);
outPlates.push_back(plate);
}
}
}
return 0;
}
bool CPlateLocate::rotation(Mat &in, Mat &out, const Size rect_size,
const Point2f center, const double angle) {
if (0) {
imshow("in", in);
waitKey(0);
destroyWindow("in");
}
Mat in_large;
in_large.create(int(in.rows * 1.5), int(in.cols * 1.5), in.type());
float x = in_large.cols / 2 - center.x > 0 ? in_large.cols / 2 - center.x : 0;
float y = in_large.rows / 2 - center.y > 0 ? in_large.rows / 2 - center.y : 0;
float width = x + in.cols < in_large.cols ? in.cols : in_large.cols - x;
float height = y + in.rows < in_large.rows ? in.rows : in_large.rows - y;
/*assert(width == in.cols);
assert(height == in.rows);*/
if (width != in.cols || height != in.rows) return false;
Mat imageRoi = in_large(Rect_<float>(x, y, width, height));
addWeighted(imageRoi, 0, in, 1, 0, imageRoi);
Point2f center_diff(in.cols / 2.f, in.rows / 2.f);
Point2f new_center(in_large.cols / 2.f, in_large.rows / 2.f);
Mat rot_mat = getRotationMatrix2D(new_center, angle, 1);
/*imshow("in_copy", in_large);
waitKey(0);*/
Mat mat_rotated;
warpAffine(in_large, mat_rotated, rot_mat, Size(in_large.cols, in_large.rows),
CV_INTER_CUBIC);
/*imshow("mat_rotated", mat_rotated);
waitKey(0);*/
Mat img_crop;
getRectSubPix(mat_rotated, Size(rect_size.width, rect_size.height),
new_center, img_crop);
out = img_crop;
if (0) {
imshow("out", out);
waitKey(0);
destroyWindow("out");
}
/*imshow("img_crop", img_crop);
waitKey(0);*/
return true;
}
bool CPlateLocate::isdeflection(const Mat &in, const double angle,
double &slope) { /*imshow("in",in);
waitKey(0);*/
if (0) {
imshow("in", in);
waitKey(0);
destroyWindow("in");
}
int nRows = in.rows;
int nCols = in.cols;
assert(in.channels() == 1);
int comp_index[3];
int len[3];
comp_index[0] = nRows / 4;
comp_index[1] = nRows / 4 * 2;
comp_index[2] = nRows / 4 * 3;
const uchar* p;
for (int i = 0; i < 3; i++) {
int index = comp_index[i];
p = in.ptr<uchar>(index);
int j = 0;
int value = 0;
while (0 == value && j < nCols) value = int(p[j++]);
len[i] = j;
}
// cout << "len[0]:" << len[0] << endl;
// cout << "len[1]:" << len[1] << endl;
// cout << "len[2]:" << len[2] << endl;
// len[0]/len[1]/len[2] are used to calc the slope
double maxlen = max(len[2], len[0]);
double minlen = min(len[2], len[0]);
double difflen = abs(len[2] - len[0]);
double PI = 3.14159265;
double g = tan(angle * PI / 180.0);
if (maxlen - len[1] > nCols / 32 || len[1] - minlen > nCols / 32) {
double slope_can_1 =
double(len[2] - len[0]) / double(comp_index[1]);
double slope_can_2 = double(len[1] - len[0]) / double(comp_index[0]);
double slope_can_3 = double(len[2] - len[1]) / double(comp_index[0]);
// cout<<"angle:"<<angle<<endl;
// cout<<"g:"<<g<<endl;
// cout << "slope_can_1:" << slope_can_1 << endl;
// cout << "slope_can_2:" << slope_can_2 << endl;
// cout << "slope_can_3:" << slope_can_3 << endl;
// if(g>=0)
slope = abs(slope_can_1 - g) <= abs(slope_can_2 - g) ? slope_can_1
: slope_can_2;
// cout << "slope:" << slope << endl;
return true;
} else {
slope = 0;
}
return false;
}
void CPlateLocate::affine(const Mat &in, Mat &out, const double slope) {
// imshow("in", in);
// waitKey(0);
Point2f dstTri[3];
Point2f plTri[3];
float height = (float) in.rows;
float width = (float) in.cols;
float xiff = (float) abs(slope) * height;
if (slope > 0) {
// right, new position is xiff/2
plTri[0] = Point2f(0, 0);
plTri[1] = Point2f(width - xiff - 1, 0);
plTri[2] = Point2f(0 + xiff, height - 1);
dstTri[0] = Point2f(xiff / 2, 0);
dstTri[1] = Point2f(width - 1 - xiff / 2, 0);
dstTri[2] = Point2f(xiff / 2, height - 1);
} else {
// left, new position is -xiff/2
plTri[0] = Point2f(0 + xiff, 0);
plTri[1] = Point2f(width - 1, 0);
plTri[2] = Point2f(0, height - 1);
dstTri[0] = Point2f(xiff / 2, 0);
dstTri[1] = Point2f(width - 1 - xiff + xiff / 2, 0);
dstTri[2] = Point2f(xiff / 2, height - 1);
}
Mat warp_mat = getAffineTransform(plTri, dstTri);
Mat affine_mat;
affine_mat.create((int) height, (int) width, TYPE);
if (in.rows > HEIGHT || in.cols > WIDTH)
warpAffine(in, affine_mat, warp_mat, affine_mat.size(),
CV_INTER_AREA);
else
warpAffine(in, affine_mat, warp_mat, affine_mat.size(), CV_INTER_CUBIC);
out = affine_mat;
}
int CPlateLocate::plateColorLocate(Mat src, vector<CPlate> &candPlates,
int index) {
vector<RotatedRect> rects_color_blue;
rects_color_blue.reserve(64);
vector<RotatedRect> rects_color_yellow;
rects_color_yellow.reserve(64);
vector<CPlate> plates_blue;
plates_blue.reserve(64);
vector<CPlate> plates_yellow;
plates_yellow.reserve(64);
Mat src_clone = src.clone();
Mat src_b_blue;
Mat src_b_yellow;
#pragma omp parallel sections
{
#pragma omp section
{
colorSearch(src, BLUE, src_b_blue, rects_color_blue);
deskew(src, src_b_blue, rects_color_blue, plates_blue, true, BLUE);
}
#pragma omp section
{
colorSearch(src_clone, YELLOW, src_b_yellow, rects_color_yellow);
deskew(src_clone, src_b_yellow, rects_color_yellow, plates_yellow, true, YELLOW);
}
}
candPlates.insert(candPlates.end(), plates_blue.begin(), plates_blue.end());
candPlates.insert(candPlates.end(), plates_yellow.begin(), plates_yellow.end());
return 0;
}
//! MSER plate locate
int CPlateLocate::plateMserLocate(Mat src, vector<CPlate> &candPlates, int img_index) {
std::vector<Mat> channelImages;
std::vector<Color> flags;
flags.push_back(BLUE);
flags.push_back(YELLOW);
bool usePlateMser = false;
int scale_size = 1000;
//int scale_size = CParams::instance()->getParam1i();
double scale_ratio = 1;
// only conside blue plate
if (1) {
Mat grayImage;
cvtColor(src, grayImage, COLOR_BGR2GRAY);
channelImages.push_back(grayImage);
}
for (size_t i = 0; i < channelImages.size(); ++i) {
vector<vector<RotatedRect>> plateRRectsVec;
vector<vector<CPlate>> platesVec;
vector<Mat> src_b_vec;
Mat channelImage = channelImages.at(i);
Mat image = scaleImage(channelImage, Size(scale_size, scale_size), scale_ratio);
// vector<RotatedRect> rects;
mserSearch(image, src_b_vec, platesVec, usePlateMser, plateRRectsVec, img_index, false);
for (size_t j = 0; j < flags.size(); j++) {
vector<CPlate>& plates = platesVec.at(j);
Mat& src_b = src_b_vec.at(j);
Color color = flags.at(j);
vector<RotatedRect> rects_mser;
rects_mser.reserve(64);
std::vector<CPlate> deskewPlate;
deskewPlate.reserve(64);
std::vector<CPlate> mserPlate;
mserPlate.reserve(64);
// deskew for rotation and slope image
for (auto plate : plates) {
RotatedRect rrect = plate.getPlatePos();
RotatedRect scaleRect = scaleBackRRect(rrect, (float)scale_ratio);
plate.setPlatePos(scaleRect);
plate.setPlateColor(color);
rects_mser.push_back(scaleRect);
mserPlate.push_back(plate);
}
Mat resize_src_b;
resize(src_b, resize_src_b, Size(channelImage.cols, channelImage.rows));
deskew(src, resize_src_b, rects_mser, deskewPlate, false, color);
for (auto dplate : deskewPlate) {
RotatedRect drect = dplate.getPlatePos();
Mat dmat = dplate.getPlateMat();
for (auto splate : mserPlate) {
RotatedRect srect = splate.getPlatePos();
float iou = 0.f;
bool isSimilar = computeIOU(drect, srect, src.cols, src.rows, 0.95f, iou);
if (isSimilar) {
splate.setPlateMat(dmat);
candPlates.push_back(splate);
break;
}
}
}
}
}
if (0) {
imshow("src", src);
waitKey(0);
destroyWindow("src");
}
return 0;
}
int CPlateLocate::sobelOperT(const Mat &in, Mat &out, int blurSize, int morphW,
int morphH) {
Mat mat_blur;
mat_blur = in.clone();
GaussianBlur(in, mat_blur, Size(blurSize, blurSize), 0, 0, BORDER_DEFAULT);
Mat mat_gray;
if (mat_blur.channels() == 3)
cvtColor(mat_blur, mat_gray, CV_BGR2GRAY);
else
mat_gray = mat_blur;
utils::imwrite("resources/image/tmp/grayblure.jpg", mat_gray);
// equalizeHist(mat_gray, mat_gray);
int scale = SOBEL_SCALE;
int delta = SOBEL_DELTA;
int ddepth = SOBEL_DDEPTH;
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
Sobel(mat_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x);
Mat grad;
addWeighted(abs_grad_x, 1, 0, 0, 0, grad);
utils::imwrite("resources/image/tmp/graygrad.jpg", grad);
Mat mat_threshold;
double otsu_thresh_val =
threshold(grad, mat_threshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);
utils::imwrite("resources/image/tmp/grayBINARY.jpg", mat_threshold);
Mat element = getStructuringElement(MORPH_RECT, Size(morphW, morphH));
morphologyEx(mat_threshold, mat_threshold, MORPH_CLOSE, element);
utils::imwrite("resources/image/tmp/phologyEx.jpg", mat_threshold);
out = mat_threshold;
return 0;
}
int CPlateLocate::plateSobelLocate(Mat src, vector<CPlate> &candPlates,
int index) {
vector<RotatedRect> rects_sobel_all;
rects_sobel_all.reserve(256);
vector<CPlate> plates;
plates.reserve(32);
vector<Rect_<float>> bound_rects;
bound_rects.reserve(256);
sobelFrtSearch(src, bound_rects);
vector<Rect_<float>> bound_rects_part;
bound_rects_part.reserve(256);
// enlarge area
for (size_t i = 0; i < bound_rects.size(); i++) {
float fRatio = bound_rects[i].width * 1.0f / bound_rects[i].height;
if (fRatio < 3.0 && fRatio > 1.0 && bound_rects[i].height < 120) {
Rect_<float> itemRect = bound_rects[i];
itemRect.x = itemRect.x - itemRect.height * (4 - fRatio);
if (itemRect.x < 0) {
itemRect.x = 0;
}
itemRect.width = itemRect.width + itemRect.height * 2 * (4 - fRatio);
if (itemRect.width + itemRect.x >= src.cols) {
itemRect.width = src.cols - itemRect.x;
}
itemRect.y = itemRect.y - itemRect.height * 0.08f;
itemRect.height = itemRect.height * 1.16f;
bound_rects_part.push_back(itemRect);
}
}
// second processing to split one
#pragma omp parallel for
for (int i = 0; i < (int)bound_rects_part.size(); i++) {
Rect_<float> bound_rect = bound_rects_part[i];
Point2f refpoint(bound_rect.x, bound_rect.y);
float x = bound_rect.x > 0 ? bound_rect.x : 0;
float y = bound_rect.y > 0 ? bound_rect.y : 0;
float width =
x + bound_rect.width < src.cols ? bound_rect.width : src.cols - x;
float height =
y + bound_rect.height < src.rows ? bound_rect.height : src.rows - y;
Rect_<float> safe_bound_rect(x, y, width, height);
Mat bound_mat = src(safe_bound_rect);
vector<RotatedRect> rects_sobel;
rects_sobel.reserve(128);
sobelSecSearchPart(bound_mat, refpoint, rects_sobel);
#pragma omp critical
{
rects_sobel_all.insert(rects_sobel_all.end(), rects_sobel.begin(), rects_sobel.end());
}
}
#pragma omp parallel for
for (int i = 0; i < (int)bound_rects.size(); i++) {
Rect_<float> bound_rect = bound_rects[i];
Point2f refpoint(bound_rect.x, bound_rect.y);
float x = bound_rect.x > 0 ? bound_rect.x : 0;
float y = bound_rect.y > 0 ? bound_rect.y : 0;
float width =
x + bound_rect.width < src.cols ? bound_rect.width : src.cols - x;
float height =
y + bound_rect.height < src.rows ? bound_rect.height : src.rows - y;
Rect_<float> safe_bound_rect(x, y, width, height);
Mat bound_mat = src(safe_bound_rect);
vector<RotatedRect> rects_sobel;
rects_sobel.reserve(128);
sobelSecSearch(bound_mat, refpoint, rects_sobel);
#pragma omp critical
{
rects_sobel_all.insert(rects_sobel_all.end(), rects_sobel.begin(), rects_sobel.end());
}
}
Mat src_b;
sobelOper(src, src_b, 3, 10, 3);
deskew(src, src_b, rects_sobel_all, plates);
//for (size_t i = 0; i < plates.size(); i++)
// candPlates.push_back(plates[i]);
candPlates.insert(candPlates.end(), plates.begin(), plates.end());
return 0;
}
int CPlateLocate::plateLocate(Mat src, vector<Mat> &resultVec, int index) {
vector<CPlate> all_result_Plates;
plateColorLocate(src, all_result_Plates, index);
plateSobelLocate(src, all_result_Plates, index);
plateMserLocate(src, all_result_Plates, index);
for (size_t i = 0; i < all_result_Plates.size(); i++) {
CPlate plate = all_result_Plates[i];
resultVec.push_back(plate.getPlateMat());
}
return 0;
}
int CPlateLocate::plateLocate(Mat src, vector<CPlate> &resultVec, int index) {
vector<CPlate> all_result_Plates;
plateColorLocate(src, all_result_Plates, index);
plateSobelLocate(src, all_result_Plates, index);
plateMserLocate(src, all_result_Plates, index);
for (size_t i = 0; i < all_result_Plates.size(); i++) {
resultVec.push_back(all_result_Plates[i]);
}
return 0;
}
}

@ -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…
Cancel
Save