I start learning OpenCV and MFC, and my project is License Plate Recognition. However, there is a problem: SVM->predict(Mat) returns weird values and I don’t know why.
This is my code:
#include "TrainSVM.h"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/ml/ml.hpp>
#include <iostream>
using namespace cv::ml;
using namespace std;
using namespace cv;
int TrainSVM::count_pixel(Mat img, bool black_pixel = 1)
{
int black = 0, white = 0;
for (int i = 0; i < img.rows; ++i)
for (int j = 0; j < img.cols; ++j)
{
if (img.at<uchar>(i, j) == 0)
++black;
else
++white;
}
return (black_pixel ? black : white);
}
vector<float> TrainSVM::calculate_feature(Mat src)
{
Mat img = src;
threshold(img, img, 100, 255, THRESH_BINARY);
vector<float> r;
resize(img, img, Size(20, 20));
int h = img.rows / 4;
int w = img.cols / 4;
int S = count_pixel(img);
int T = img.cols * img.rows;
for (int i = 0; i < img.rows; i += h)
{
for (int j = 0; j < img.cols; j += w)
{
Mat cell = img(Rect(i, j, h, w));
int s = count_pixel(cell);
float f = (float)s / S;
r.push_back(f);
}
}
for (int i = 0; i < 16; i += 4)
{
float f = r[i] + r[i + 1] + r[i + 2] + r[i + 3];
r.push_back(f);
}
for (int i = 0; i < 4; ++i)
{
float f = r[i] + r[i + 4] + r[i + 8] + r[i + 12];
r.push_back(f);
}
r.push_back(r[0] + r[5] + r[10] + r[15]);
r.push_back(r[3] + r[6] + r[9] + r[12]);
r.push_back(r[7] + r[10] + r[13] + r[16]);
r.push_back(r[23] + r[24] + r[25] + r[26]);
r.push_back(r[2] + r[7] + r[12] + r[17]);
r.push_back(r[9] + r[11] + r[13] + r[15]);
r.push_back(r[10] + r[15] + r[20] + r[25]);
r.push_back(r[14] + r[16] + r[18] + r[20]);
return r; // 32 features
}
char TrainSVM::char_recog(Mat img_character)
{
char c = '*';
if (img_character.empty())
return c;
vector<float> feature = this->calculate_feature(img_character);
Mat m = Mat(1, number_of_feature, CV_32F);
for (size_t i = 0; i < feature.size(); ++i)
m.at<float>(0, i) = feature[i];
float r = svm->predict(m);
int ri = (int)r;
if (ri >= 0 && ri <= 9)
c = char(ri + 48);
if (ri >= 10 && ri < 18)
c = char(ri + 55);
if (ri >= 18 && ri < 22)
c = char(ri + 55 + 2);
if (ri == 22)
c = 'P';
if (ri == 23)
c = 'S';
if (ri >= 24 && ri < 27)
c = char(ri + 60);
if (ri >= 27 && ri < 30)
c = char(ri + 61);
return c;
}
void TrainSVM::train_model()
{
svm->setC(16);
svm->setGamma(0.5);
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::RBF);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
Mat data = Mat(number_of_sample * number_of_class, number_of_feature, CV_32F);
Mat label = Mat(number_of_sample * number_of_class, 1, CV_32S);
int index = 0;
vector<string> folders = list_folder("D:\\Image Processing\\Data");
for (size_t i = 0; i < folders.size(); ++i)
{
vector<string> files = list_file(folders.at(i));
string folder_path = folders.at(i);
string label_folder = folder_path.substr(folder_path.length() - 1);
for (size_t j = 0; j < files.size(); ++j)
{
Mat src = imread(files.at(j));
if (src.empty())
continue;
vector<float> feature = calculate_feature(src);
if (feature.size() < number_of_feature)
continue;
for (size_t t = 0; t < feature.size(); ++t)
data.at<float>(index, t) = feature.at(t);
label.at<float>(index, 0) = int(i);
++index;
}
}
Ptr<TrainData> trainData = TrainData::create(data, ROW_SAMPLE, label);
this->svm->trainAuto(trainData);
}
I run train_model()
before char_reg()
but char_reg()
always returns large value.
Here are some values that out of number of class:
1.08423e+09
1.09157e+09
1.07374e+09
1.08423e+09
1.08423e+09
1.10258e+09
1.08423e+09
1.09157e+09
1.08842e+09
I have tried to using KNearest:
Mat res;
this->knn->findNearest(m, 1, res);
outFile << res.at<int>(0, 0);
And it returned this:
1.31709e+09
1.31717e+09
1.31701e+09
1.31709e+09
1.31709e+09
1.31709e+09
1.31709e+09
1.31709e+09
1.31713e+09
I have checked Mat data, label and sample. Of course, there is no error.