Merge commit '6898b2dca327ee25facb57459af251d18c867054'

# Conflicts:
#	include/easypr/plate_detect.h
#	include/easypr/plate_locate.h
#	include/easypr/plate_recognize.h
#	src/core/chars_identify.cpp
#	src/core/core_func.cpp
#	src/core/plate_detect.cpp
#	src/core/plate_judge.cpp
#	src/core/plate_locate.cpp
#	test/accuracy.hpp
v1.6alpha
Micooz 10 years ago
commit 8cc64eab8b

@ -2,7 +2,17 @@ cmake_minimum_required(VERSION 2.8)
project (easypr)
# c++11 required
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} doesnt support C++11. Please upgrade or use a different C++ compiler.")
endif()
# opencv package required
find_package(OpenCV REQUIRED)

@ -1077,3 +1077,31 @@
总图片数:173张, 未识出图片:5张, 定位率:97.1098%
平均字符差距:0.482143个, 完全匹配数:130张, 完全匹配率:77.381%
总时间:152秒, 平均执行时间:0.878613秒
2015-06-11 19:24:04
总图片数:173张, 未识出图片:5张, 定位率:97.1098%
平均字符差距:0.47619个, 完全匹配数:130张, 完全匹配率:77.381%
总时间:59秒, 平均执行时间:0.34104秒
2015-06-11 19:26:37
总图片数:173张, 未识出图片:5张, 定位率:97.1098%
平均字符差距:0.47619个, 完全匹配数:130张, 完全匹配率:77.381%
总时间:54秒, 平均执行时间:0.312139秒
2015-06-12 20:30:57
总图片数:173张, 未识出图片:5张, 定位率:97.1098%
平均字符差距:0.458333个, 完全匹配数:130张, 完全匹配率:77.381%
总时间:132秒, 平均执行时间:0.763006秒
2015-06-12 20:37:48
总图片数:173张, 未识出图片:5张, 定位率:97.1098%
平均字符差距:0.458333个, 完全匹配数:130张, 完全匹配率:77.381%
总时间:129秒, 平均执行时间:0.745665秒
2015-06-17 07:28:05
总图片数:173张, 未识出图片:5张, 定位率:97.1098%
平均字符差距:0.458333个, 完全匹配数:130张, 完全匹配率:77.381%
总时间:153秒, 平均执行时间:0.884393秒
2015-06-17 07:37:42
总图片数:173张, 未识出图片:5张, 定位率:97.1098%
平均字符差距:0.458333个, 完全匹配数:130张, 完全匹配率:77.381%
总时间:245秒, 平均执行时间:1.41618秒
2015-06-17 07:44:25
总图片数:173张, 未识出图片:5张, 定位率:97.1098%
平均字符差距:0.458333个, 完全匹配数:130张, 完全匹配率:77.381%
总时间:214秒, 平均执行时间:1.23699秒

@ -42,10 +42,10 @@ class CPlateDetect {
inline void setPDLifemode(bool param) { m_plateLocate->setLifemode(param); }
//! 是否开启调试模式
inline void setPDDebug(int param) { m_plateLocate->setDebug(param); }
inline void setPDDebug(bool param) { m_plateLocate->setDebug(param); }
//! 获取调试模式状态
inline int getPDDebug() { return m_plateLocate->getDebug(); }
inline bool getPDDebug() { return m_plateLocate->getDebug(); }
//! 设置与读取变量
inline void setGaussianBlurSize(int param) {

@ -114,10 +114,10 @@ class CPlateLocate {
inline void setJudgeAngle(int param) { m_angle = param; }
//! 是否开启调试模式
inline void setDebug(int param) { m_debug = param; }
inline void setDebug(bool param) { m_debug = param; }
//! 获取调试模式状态
inline int getDebug() { return m_debug; }
inline bool getDebug() { return m_debug; }
//! PlateLocate所用常量
static const int DEFAULT_GAUSSIANBLUR_SIZE = 5;
@ -162,7 +162,7 @@ class CPlateLocate {
int m_angle;
//! 是否开启调试模式0关闭非0开启
int m_debug;
bool m_debug;
};
} /*! \namespace easypr*/

@ -32,7 +32,7 @@ class CPlateRecognize : public CPlateDetect, public CCharsRecognise {
inline void setLifemode(bool param) { CPlateDetect::setPDLifemode(param); }
//! 是否开启调试模式
inline void setDebug(int param) {
inline void setDebug(bool param) {
CPlateDetect::setPDDebug(param);
CCharsRecognise::setCRDebug(param);
}

@ -14,14 +14,6 @@
#define OS_LINUX
#endif
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
namespace easypr {
class Utils {
public:
@ -104,6 +96,12 @@ class Utils {
* if not, create it, then call cv::imwrite.
*/
static bool imwrite(const std::string& file, const cv::Mat& image);
private:
/*
* Get the last slash from a path, compatible with Windows and *unix.
*/
static std::size_t get_last_slash(const std::string& path);
};
typedef Utils utils;

@ -6,8 +6,6 @@
*/
namespace easypr {
#define NDEBUG
//中国车牌
const char strCharacters[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G',

@ -8,8 +8,8 @@ Namespace where all the C++ EasyPR functionality resides
*/
namespace easypr {
const float DEFAULT_BLUEPERCEMT = 0.3;
const float DEFAULT_WHITEPERCEMT = 0.1;
const float DEFAULT_BLUEPERCEMT = 0.3f;
const float DEFAULT_WHITEPERCEMT = 0.1f;
CCharsSegment::CCharsSegment() {
// cout << "CCharsSegment" << endl;
@ -29,18 +29,18 @@ bool CCharsSegment::verifyCharSizes(Mat r) {
// Char sizes 45x90
float aspect = 45.0f / 90.0f;
float charAspect = (float)r.cols / (float)r.rows;
float error = 0.7;
float minHeight = 10;
float maxHeight = 35;
float error = 0.7f;
float minHeight = 10.f;
float maxHeight = 35.f;
// We have a different aspect ratio for number 1, and it can be ~0.2
float minAspect = 0.05;
float minAspect = 0.05f;
float maxAspect = aspect + aspect * error;
// area of pixels
float area = countNonZero(r);
int area = cv::countNonZero(r);
// bb area
float bbArea = r.cols * r.rows;
int bbArea = r.cols * r.rows;
//% of pixel in area
float percPixels = area / bbArea;
int percPixels = area / bbArea;
if (percPixels <= 1 && charAspect > minAspect && charAspect < maxAspect &&
r.rows >= minHeight && r.rows < maxHeight)
@ -57,8 +57,8 @@ Mat CCharsSegment::preprocessChar(Mat in) {
int charSize = CHAR_SIZE; //统一每个字符的大小
Mat transformMat = Mat::eye(2, 3, CV_32F);
int m = max(w, h);
transformMat.at<float>(0, 2) = m / 2 - w / 2;
transformMat.at<float>(1, 2) = m / 2 - h / 2;
transformMat.at<float>(0, 2) = float(m / 2 - w / 2);
transformMat.at<float>(1, 2) = float(m / 2 - h / 2);
Mat warpImage(m, m, in.type());
warpAffine(in, warpImage, transformMat, warpImage.size(), INTER_LINEAR,
@ -86,7 +86,7 @@ int CCharsSegment::charsSegment(Mat input, vector<Mat>& resultVec) {
int w = input.cols;
int h = input.rows;
Mat tmpMat = input(Rect(w * 0.1, h * 0.1, w * 0.8, h * 0.8));
Mat tmpMat = input(Rect_<double>(w * 0.1, h * 0.1, w * 0.8, h * 0.8));
//判断车牌颜色以此确认threshold方法
Color plateType = getPlateType(tmpMat, true);
@ -101,7 +101,7 @@ int CCharsSegment::charsSegment(Mat input, vector<Mat>& resultVec) {
int w = input_grey.cols;
int h = input_grey.rows;
Mat tmp = input_grey(Rect(w * 0.1, h * 0.1, w * 0.8, h * 0.8));
Mat tmp = input_grey(Rect_<double>(w * 0.1, h * 0.1, w * 0.8, h * 0.8));
int threadHoldV = ThresholdOtsu(tmp);
// utils::imwrite("E:/img_inputgray2.jpg", input_grey);
@ -116,7 +116,7 @@ int CCharsSegment::charsSegment(Mat input, vector<Mat>& resultVec) {
img_threshold = input_grey.clone();
int w = input_grey.cols;
int h = input_grey.rows;
Mat tmp = input_grey(Rect(w * 0.1, h * 0.1, w * 0.8, h * 0.8));
Mat tmp = input_grey(Rect_<double>(w * 0.1, h * 0.1, w * 0.8, h * 0.8));
int threadHoldV = ThresholdOtsu(tmp);
utils::imwrite("resources/image/tmp/inputgray2.jpg", input_grey);
@ -200,7 +200,7 @@ int CCharsSegment::charsSegment(Mat input, vector<Mat>& resultVec) {
std::sort(sortedRect.begin(), sortedRect.end(),
[](const Rect& r1, const Rect& r2) { return r1.x < r2.x; });
int specIndex = 0;
size_t specIndex = 0;
//获得特殊字符对应的Rectt,如苏A的"A"
specIndex = GetSpecificRect(sortedRect);
@ -241,7 +241,7 @@ int CCharsSegment::charsSegment(Mat input, vector<Mat>& resultVec) {
if (newSortedRect.size() == 0) return -3;
for (int i = 0; i < newSortedRect.size(); i++) {
for (size_t i = 0; i < newSortedRect.size(); i++) {
Rect mr = newSortedRect[i];
Mat auxRoi(img_threshold, mr);
@ -266,17 +266,17 @@ int CCharsSegment::SortRect(const vector<Rect>& vecRect, vector<Rect>& out) {
vector<int> orderIndex;
vector<int> xpositions;
for (int i = 0; i < vecRect.size(); i++) {
for (size_t i = 0; i < vecRect.size(); i++) {
orderIndex.push_back(i);
xpositions.push_back(vecRect[i].x);
}
float min = xpositions[0];
int min = xpositions[0];
int minIdx = 0;
for (int i = 0; i < xpositions.size(); i++) {
for (size_t i = 0; i < xpositions.size(); i++) {
min = xpositions[i];
minIdx = i;
for (int j = i; j < xpositions.size(); j++) {
for (size_t j = i; j < xpositions.size(); j++) {
if (xpositions[j] < min) {
min = xpositions[j];
minIdx = j;
@ -287,13 +287,13 @@ int CCharsSegment::SortRect(const vector<Rect>& vecRect, vector<Rect>& out) {
orderIndex[i] = aux_min;
orderIndex[minIdx] = aux_i;
float aux_xi = xpositions[i];
float aux_xmin = xpositions[minIdx];
int aux_xi = xpositions[i];
int aux_xmin = xpositions[minIdx];
xpositions[i] = aux_xmin;
xpositions[minIdx] = aux_xi;
}
for (int i = 0; i < orderIndex.size(); i++) {
for (size_t i = 0; i < orderIndex.size(); i++) {
out.push_back(vecRect[orderIndex[i]]);
}
@ -303,7 +303,7 @@ int CCharsSegment::SortRect(const vector<Rect>& vecRect, vector<Rect>& out) {
//! 根据特殊车牌来构造猜测中文字符的位置和大小
Rect CCharsSegment::GetChineseRect(const Rect rectSpe) {
int height = rectSpe.height;
float newwidth = rectSpe.width * 1.15;
float newwidth = rectSpe.width * 1.15f;
int x = rectSpe.x;
int y = rectSpe.y;
@ -321,7 +321,7 @@ int CCharsSegment::GetSpecificRect(const vector<Rect>& vecRect) {
int maxHeight = 0;
int maxWidth = 0;
for (int i = 0; i < vecRect.size(); i++) {
for (size_t i = 0; i < vecRect.size(); i++) {
xpositions.push_back(vecRect[i].x);
if (vecRect[i].height > maxHeight) {
@ -333,7 +333,7 @@ int CCharsSegment::GetSpecificRect(const vector<Rect>& vecRect) {
}
int specIndex = 0;
for (int i = 0; i < vecRect.size(); i++) {
for (size_t i = 0; i < vecRect.size(); i++) {
Rect mr = vecRect[i];
int midx = mr.x + mr.width / 2;

@ -63,10 +63,13 @@ Mat colorMatch(const Mat& src, Mat& match, const Color r,
min_h = min_white;
max_h = max_white;
break;
default:
// Color::UNKNOWN
break;
}
float diff_h = float((max_h - min_h) / 2);
int avg_h = min_h + diff_h;
float avg_h = min_h + diff_h;
int channels = src_hsv.channels();
int nRows = src_hsv.rows;
@ -98,7 +101,7 @@ Mat colorMatch(const Mat& src, Mat& match, const Color r,
bool colorMatched = false;
if (H > min_h && H < max_h) {
int Hdiff = 0;
float Hdiff = 0;
if (H > avg_h)
Hdiff = H - avg_h;
else
@ -150,7 +153,7 @@ Mat colorMatch(const Mat& src, Mat& match, const Color r,
bool bFindLeftRightBound1(Mat& bound_threshold, int& posLeft, int& posRight) {
//从两边寻找边界
int span = bound_threshold.rows * 0.2;
float span = bound_threshold.rows * 0.2f;
//左边界检测
for (int i = 0; i < bound_threshold.cols - span - 1; i += 3) {
int whiteCount = 0;
@ -166,7 +169,7 @@ bool bFindLeftRightBound1(Mat& bound_threshold, int& posLeft, int& posRight) {
break;
}
}
span = bound_threshold.rows * 0.2;
span = bound_threshold.rows * 0.2f;
//右边界检测
for (int i = bound_threshold.cols - 1; i > span; i -= 2) {
int whiteCount = 0;
@ -198,7 +201,7 @@ bool bFindLeftRightBound1(Mat& bound_threshold, int& posLeft, int& posRight) {
bool bFindLeftRightBound(Mat& bound_threshold, int& posLeft, int& posRight) {
//从两边寻找边界
int span = bound_threshold.rows * 0.2;
float span = bound_threshold.rows * 0.2f;
//左边界检测
for (int i = 0; i < bound_threshold.cols - span - 1; i += 2) {
int whiteCount = 0;
@ -214,7 +217,7 @@ bool bFindLeftRightBound(Mat& bound_threshold, int& posLeft, int& posRight) {
break;
}
}
span = bound_threshold.rows * 0.2;
span = bound_threshold.rows * 0.2f;
//右边界检测
for (int i = bound_threshold.cols - 1; i > span; i -= 2) {
int whiteCount = 0;
@ -240,7 +243,7 @@ bool bFindLeftRightBound(Mat& bound_threshold, int& posLeft, int& posRight) {
bool bFindLeftRightBound2(Mat& bound_threshold, int& posLeft, int& posRight) {
//从两边寻找边界
int span = bound_threshold.rows * 0.2;
float span = bound_threshold.rows * 0.2f;
//左边界检测
for (int i = 0; i < bound_threshold.cols - span - 1; i += 3) {
int whiteCount = 0;
@ -256,7 +259,7 @@ bool bFindLeftRightBound2(Mat& bound_threshold, int& posLeft, int& posRight) {
break;
}
}
span = bound_threshold.rows * 0.2;
span = bound_threshold.rows * 0.2f;
//右边界检测
for (int i = bound_threshold.cols - 1; i > span; i -= 3) {
int whiteCount = 0;
@ -286,7 +289,7 @@ bool bFindLeftRightBound2(Mat& bound_threshold, int& posLeft, int& posRight) {
bool plateColorJudge(const Mat& src, const Color r, const bool adaptive_minsv,
float& percent) {
// 判断阈值
const float thresh = 0.45;
const float thresh = 0.45f;
Mat src_gray;
colorMatch(src, src_gray, r, adaptive_minsv);
@ -343,12 +346,12 @@ void clearLiuDingOnly(Mat& img) {
for (int j = 0; j < img.cols - 1; j++) {
if (img.at<char>(i, j) != img.at<char>(i, j + 1)) jumpCount++;
if (img.at<char>(i, j) == 255) {
if (img.at<uchar>(i, j) == 255) {
whiteCount++;
}
}
jump.at<float>(i) = jumpCount;
jump.at<float>(i) = (float)jumpCount;
}
for (int i = 0; i < img.rows; i++) {
@ -379,7 +382,7 @@ bool clearLiuDing(Mat& img) {
}
}
jump.at<float>(i) = jumpCount;
jump.at<float>(i) = (float)jumpCount;
}
int iCount = 0;

@ -3,12 +3,10 @@
/*! \namespace easypr
Namespace where all the C++ EasyPR functionality resides
*/
namespace easypr{
namespace easypr {
CPlate::CPlate()
{
//cout << "CPlate" << endl;
bColored = true;
}
CPlate::CPlate() {
bColored = true;
}
} /*! \namespace easypr*/
} /*! \namespace easypr*/

@ -66,7 +66,7 @@ int CPlateDetect::plateDetectDeep(Mat src, vector<CPlate>& resultVec,
// color_result_Plates.push_back(color_Plates[i]);
//}
for (int i = 0; i < color_result_Plates.size(); i++) {
for (size_t i = 0; i < color_result_Plates.size(); i++) {
CPlate plate = color_result_Plates[i];
plate.setPlateLocateType(COLOR);
@ -83,7 +83,7 @@ int CPlateDetect::plateDetectDeep(Mat src, vector<CPlate>& resultVec,
sobel_result_Plates.push_back(sobel_Plates[i]);
}*/
for (int i = 0; i < sobel_result_Plates.size(); i++) {
for (size_t i = 0; i < sobel_result_Plates.size(); i++) {
CPlate plate = sobel_result_Plates[i];
if (0) {
@ -99,7 +99,7 @@ int CPlateDetect::plateDetectDeep(Mat src, vector<CPlate>& resultVec,
}
}
for (int i = 0; i < all_result_Plates.size(); i++) {
for (size_t i = 0; i < all_result_Plates.size(); i++) {
// 把截取的车牌图像依次放到左上角
CPlate plate = all_result_Plates[i];
resultVec.push_back(plate);
@ -110,7 +110,7 @@ int CPlateDetect::plateDetectDeep(Mat src, vector<CPlate>& resultVec,
int CPlateDetect::showResult(const Mat& result) {
namedWindow("EasyPR", CV_WINDOW_AUTOSIZE);
const int RESULTWIDTH = 640; // 640 930
const int RESULTWIDTH = 640; // 640 930
const int RESULTHEIGHT = 540; // 540 710
Mat img_window;

@ -52,7 +52,7 @@ int CPlateJudge::plateJudge(const Mat& inMat, int& result) {
p.convertTo(p, CV_32FC1);
float response = svm.predict(p);
result = response;
result = (int)response;
return 0;
}
@ -88,7 +88,7 @@ int CPlateJudge::plateJudge(const vector<CPlate>& inVec,
int w = inMat.cols;
int h = inMat.rows;
//再取中间部分判断一次
Mat tmpmat = inMat(Rect(w * 0.05, h * 0.1, w * 0.9, h * 0.8));
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()));

File diff suppressed because it is too large Load Diff

@ -21,7 +21,7 @@ cv::Mat detectAndMaskFace(cv::Mat& img, cv::CascadeClassifier& cascade,
cv::Size(30, 30));
for (auto r = faces.begin(); r != faces.end(); r++) {
cv::Rect facerect = *r;
cv::Mat roi = img(cv::Rect(facerect.x * scale, facerect.y * scale,
cv::Mat roi = img(cv::Rect_<double>(facerect.x * scale, facerect.y * scale,
facerect.width * scale,
facerect.height * scale));
int W = 18;

@ -30,7 +30,7 @@ int generate_gdts() {
std::cout << "Begin to prepare generate_gdts!" << std::endl;
for (int i = 0; i < size; i++) {
for (size_t i = 0; i < size; i++) {
std::string filepath = files[i].c_str();
std::cout << "------------------" << std::endl;
std::cout << filepath << std::endl;
@ -65,7 +65,7 @@ int generate_gdts() {
cv::Mat imageProcess(cv::Mat img) {
int width = img.size().width;
int height = img.size().height;
cv::Rect rect(width * 0.01, height * 0.01, width * 0.99, height * 0.99);
cv::Rect_<double> rect(width * 0.01, height * 0.01, width * 0.99, height * 0.99);
cv::Mat dst = img(rect);
//GaussianBlur( dst, dst, Size(1, 1), 0, 0, BORDER_DEFAULT );

@ -117,7 +117,7 @@ int saveTrainData() {
auto files = Utils::getFiles(ss.str());
size_t size = files.size();
for (int j = 0; j < size; j++) {
for (size_t j = 0; j < size; j++) {
cout << files[j].c_str() << endl;
Mat img = imread(files[j].c_str(), 0);
Mat f5 = features(img, 5);

@ -6,13 +6,13 @@
namespace easypr {
Svm::Svm(const char* forward_data_folder, const char* inverse_data_folder)
: forward_(forward_data_folder), inverse_(inverse_data_folder) {
: forward_(forward_data_folder), inverse_(inverse_data_folder) {
assert(forward_);
assert(inverse_);
}
void Svm::divide(const char* images_folder, float percentage /* = 0.7 */) {
auto files = Utils::getFiles(images_folder);
auto files = utils::getFiles(images_folder);
if (files.empty()) {
std::cout << "No file found in " << images_folder << std::endl;
return;
@ -25,14 +25,14 @@ void Svm::divide(const char* images_folder, float percentage /* = 0.7 */) {
for (size_t i = 0; i < files.size(); ++i) {
// TODO: Move files directly to improve efficiency.
auto f = files[i];
auto file_name = Utils::getFileName(f, true).c_str();
auto file_name = utils::getFileName(f, true);
auto image = cv::imread(f);
char save_to[255] = {0};
assert(!image.empty());
if (i < split_index) {
sprintf(save_to, "%s/train/%s", images_folder, file_name);
sprintf(save_to, "%s/train/%s", images_folder, file_name.c_str());
} else {
sprintf(save_to, "%s/test/%s", images_folder, file_name);
sprintf(save_to, "%s/test/%s", images_folder, file_name.c_str());
}
utils::imwrite(save_to, image);
std::cout << f << " -> " << save_to << std::endl;
@ -62,7 +62,7 @@ void Svm::get_train() {
features = features.reshape(1, 1);
this->trainingData_.push_back(features);
labels.push_back(Label::kForward); // Note here
labels.push_back(Label::kForward); // Note here
}
// iterate inverse data
@ -84,7 +84,7 @@ void Svm::get_train() {
features = features.reshape(1, 1);
this->trainingData_.push_back(features);
labels.push_back(Label::kInverse); // Note here
labels.push_back(Label::kInverse); // Note here
}
//
@ -154,8 +154,10 @@ void Svm::train(bool divide /* = true */, float divide_percentage /* = 0.7 */,
// need to be trained first
CvSVMParams SVM_params;
SVM_params.svm_type = CvSVM::C_SVC;
//SVM_params.kernel_type = CvSVM::LINEAR; //CvSVM::LINEAR; 线型,也就是无核
SVM_params.kernel_type = CvSVM::RBF; //CvSVM::RBF 径向基函数,也就是高斯核
// SVM_params.kernel_type = CvSVM::LINEAR; //CvSVM::LINEAR;
// 线型,也就是无核
SVM_params.kernel_type =
CvSVM::RBF; // CvSVM::RBF 径向基函数,也就是高斯核
SVM_params.degree = 0.1;
SVM_params.gamma = 1;
SVM_params.coef0 = 0.1;
@ -167,27 +169,25 @@ void Svm::train(bool divide /* = true */, float divide_percentage /* = 0.7 */,
std::cout << "Generating svm model file, please wait..." << std::endl;
try {
//CvSVM svm(trainingData, classes, cv::Mat(), cv::Mat(), SVM_params);
// CvSVM svm(trainingData, classes, cv::Mat(), cv::Mat(), SVM_params);
svm.train_auto(this->trainingData_, this->classes_, cv::Mat(),
cv::Mat(),
SVM_params,
10,
cv::Mat(), SVM_params, 10,
CvSVM::get_default_grid(CvSVM::C),
CvSVM::get_default_grid(CvSVM::GAMMA),
CvSVM::get_default_grid(CvSVM::P),
CvSVM::get_default_grid(CvSVM::NU),
CvSVM::get_default_grid(CvSVM::COEF),
CvSVM::get_default_grid(CvSVM::DEGREE),
true);
CvSVM::get_default_grid(CvSVM::DEGREE), true);
} catch (const cv::Exception& err) {
std::cout << err.what() << std::endl;
}
utils::mkdir(out_svm_path);
cv::FileStorage fsTo(out_svm_path, cv::FileStorage::WRITE);
svm.write(*fsTo, "svm");
std::cout << "Generate done! The model file is located at " <<
out_svm_path << std::endl;
std::cout << "Generate done! The model file is located at "
<< out_svm_path << std::endl;
} else {
// don't train, use ready-made model file
try {
@ -196,10 +196,10 @@ void Svm::train(bool divide /* = true */, float divide_percentage /* = 0.7 */,
std::cout << err.what() << std::endl;
}
}
} // if train
} // if train
// TODO Check whether the model file exists or not.
svm.load(out_svm_path, "svm"); // make sure svm model was loaded
svm.load(out_svm_path, "svm"); // make sure svm model was loaded
// 30% testing procedure
this->get_test();
@ -220,17 +220,13 @@ void Svm::train(bool divide /* = true */, float divide_percentage /* = 0.7 */,
cv::Mat out;
features.convertTo(out, CV_32FC1);
Label predict = ((int) svm.predict(out)) == 1 ? kForward : kInverse;
Label predict = ((int)svm.predict(out)) == 1 ? kForward : kInverse;
Label real = test_labels_[label_index++];
if (predict == kForward && real == kForward)
ptrue_rtrue++;
if (predict == kForward && real == kInverse)
ptrue_rfalse++;
if (predict == kInverse && real == kForward)
pfalse_rtrue++;
if (predict == kInverse && real == kInverse)
pfalse_rfalse++;
if (predict == kForward && real == kForward) ptrue_rtrue++;
if (predict == kForward && real == kInverse) ptrue_rfalse++;
if (predict == kInverse && real == kForward) pfalse_rtrue++;
if (predict == kInverse && real == kInverse) pfalse_rfalse++;
}
std::cout << "count_all: " << count_all << std::endl;
@ -244,7 +240,8 @@ void Svm::train(bool divide /* = true */, float divide_percentage /* = 0.7 */,
precise = ptrue_rtrue / (ptrue_rtrue + ptrue_rfalse);
std::cout << "precise: " << precise << std::endl;
} else {
std::cout << "precise: " << "NA" << std::endl;
std::cout << "precise: "
<< "NA" << std::endl;
}
double recall = 0;
@ -252,7 +249,8 @@ void Svm::train(bool divide /* = true */, float divide_percentage /* = 0.7 */,
recall = ptrue_rtrue / (ptrue_rtrue + pfalse_rtrue);
std::cout << "recall: " << recall << std::endl;
} else {
std::cout << "recall: " << "NA" << std::endl;
std::cout << "recall: "
<< "NA" << std::endl;
}
double Fsocre = 0;
@ -260,9 +258,9 @@ void Svm::train(bool divide /* = true */, float divide_percentage /* = 0.7 */,
Fsocre = 2 * (precise * recall) / (precise + recall);
std::cout << "Fsocre: " << Fsocre << std::endl;
} else {
std::cout << "Fsocre: " << "NA" << std::endl;
std::cout << "Fsocre: "
<< "NA" << std::endl;
}
}
} // namespace easypr
} // namespace easypr

@ -6,6 +6,13 @@
#include <direct.h>
#include <io.h>
#define PATH_DELIMITER '\\'
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#elif defined(OS_LINUX) || defined(OS_UNIX)
#include <cstring>
@ -53,24 +60,7 @@ long Utils::getTimestamp() {
std::string Utils::getFileName(const std::string& path,
const bool postfix /* = false */) {
if (!path.empty()) {
#ifdef OS_WINDOWS
size_t last_slash_1 = path.find_last_of("\\");
size_t last_slash_2 = path.find_last_of("/");
size_t last_slash;
if (last_slash_1 != std::string::npos &&
last_slash_2 != std::string::npos) {
// C:/path\\to/file.postfix
last_slash = max(last_slash_1, last_slash_2);
} else {
// C:\\path\\to\\file.postfix
// C:/path/to/file.postfix
last_slash =
(last_slash_1 == std::string::npos) ? last_slash_2 : last_slash_1;
}
#else
size_t last_slash = path.find_last_of('/');
#endif
size_t last_slash = utils::get_last_slash(path);
size_t last_dot = path.find_last_of('.');
if (last_dot < last_slash || last_dot == std::string::npos) {
@ -150,7 +140,7 @@ std::vector<std::string> Utils::getFiles(const std::string& folder,
}
} else {
// it's a file
std::string file_path;
std::string file_path;
// current_folder.pop_back();
file_path.assign(current_folder.c_str()).pop_back();
file_path.append(file_info.name);
@ -234,13 +224,13 @@ bool Utils::mkdir(const std::string folder) {
if (c == PATH_DELIMITER || it == folder.end() - 1) {
folder_builder.append(sub);
#ifdef OS_WINDOWS
if (0 != ::_access(folder_builder.c_str(), 0)) {
if (0 != ::_access(folder_builder.c_str(), 0)) {
#else
if (0 != ::access(folder_builder.c_str(), 0)) {
#endif
// this folder not exist
// this folder not exist
#ifdef OS_WINDOWS
if (0 != ::_mkdir(folder_builder.c_str())) {
if (0 != ::_mkdir(folder_builder.c_str())) {
#else
if (0 != ::mkdir(folder_builder.c_str(), S_IRWXU)) {
#endif
@ -255,9 +245,30 @@ bool Utils::mkdir(const std::string folder) {
}
bool Utils::imwrite(const std::string& file, const cv::Mat& image) {
auto folder = file.substr(0, file.find_last_of(PATH_DELIMITER));
auto folder = file.substr(0, utils::get_last_slash(file));
Utils::mkdir(folder);
return cv::imwrite(file, image);
}
} // namespace easypr
std::size_t Utils::get_last_slash(const std::string& path) {
#ifdef OS_WINDOWS
size_t last_slash_1 = path.find_last_of("\\");
size_t last_slash_2 = path.find_last_of("/");
size_t last_slash;
if (last_slash_1 != std::string::npos && last_slash_2 != std::string::npos) {
// C:/path\\to/file.postfix
last_slash = std::max(last_slash_1, last_slash_2);
} else {
// C:\\path\\to\\file.postfix
// C:/path/to/file.postfix
last_slash =
(last_slash_1 == std::string::npos) ? last_slash_2 : last_slash_1;
}
#else
size_t last_slash = path.find_last_of('/');
#endif
return last_slash;
}
} // namespace easypr

@ -40,6 +40,8 @@ int accuracyTest(const char* test_path) {
int count_err = 0;
// 未识别的图片数量
int count_norecogin = 0;
// not recognized pictures
std::list<std::string> not_recognized_files;
// 总的字符差距
float diff_all = 0;
@ -76,7 +78,10 @@ int accuracyTest(const char* test_path) {
if (num == 0) {
cout << "无车牌" << endl;
if (plateLicense != "无车牌") count_norecogin++;
if (plateLicense != "无车牌") {
not_recognized_files.push_back(plateLicense);
count_norecogin++;
}
} else if (num > 1) {
// 多车牌使用diff最小的那个记录
int mindiff = 10000;
@ -142,11 +147,15 @@ int accuracyTest(const char* test_path) {
float count_recogin = float(count_all - (count_err + count_norecogin));
float count_rate = count_recogin / count_all;
// float count_norate = 1 - count_rate;
cout << "定位率:" << count_rate * 100 << "% " << endl;
diff_avg = diff_all / count_recogin;
match_rate = match_count / count_recogin * 100;
if (count_recogin > 0) {
diff_avg = diff_all / count_recogin;
}
if (count_recogin > 0) {
match_rate = match_count / count_recogin * 100;
}
cout << "平均字符差距:" << diff_avg << "个, ";
cout << "完全匹配数:" << match_count << "张, ";
@ -156,7 +165,14 @@ int accuracyTest(const char* test_path) {
double avgsec = seconds / double(count_all);
cout << "总时间:" << seconds << "秒, ";
cout << "平均执行时间:" << avgsec << "" << endl;
cout << "平均执行时间:" << avgsec << "" << endl;
cout << "未识出图片:" << endl;
for (auto it = not_recognized_files.begin(); it != not_recognized_files.end();
++it) {
cout << *it << endl;
}
cout << endl;
@ -178,7 +194,7 @@ int accuracyTest(const char* test_path) {
myfile << "完全匹配数:" << match_count << "张, ";
myfile << "完全匹配率:" << match_rate << "% " << endl;
myfile << "总时间:" << seconds << "秒, ";
myfile << "平均执行时间:" << avgsec << " " << endl;
myfile << "平均执行时间:" << avgsec << "" << endl;
myfile.close();
} else {
cout << "Unable to open file";

Loading…
Cancel
Save