简介
这是基于svm实现字符识别,不过只是个大概模板,需要能够准确识别,需要的训练样本太多,没去收集。
代码讲解
具体代码
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv/cv.h>
#include <stdio.h>
#include <opencv2/ml/ml.hpp>
using namespace cv;
#define match_all 10
#define match_detect 10
#define pic_size 512
int main(int argc, char* argv[]){
const char *match_pic[match_all] = {
"rightPic/0.bmp", "rightPic/1.bmp", "rightPic/2.bmp", "rightPic/3.bmp", "rightPic/4.bmp",
"rightPic/5.bmp", "errorPic/6.bmp", "errorPic/7.bmp", "errorPic/8.bmp", "errorPic/9.bmp",
};
int i, j, k;
float labels[10]={1, 1, 1, 1, 1, 1, -1, -1, -1, -1};
Mat labelsMat(10, 1, CV_32FC1, labels);
float trainingData[10][pic_size];
for(i=0; i<match_detect; i++){
cv::Mat mat1 = cv::imread(match_pic[i], 0);
uchar* ptr = mat1.ptr(0);
int length = mat1.rows * mat1.cols;
for(j=0; j<length; j++){
trainingData[i][j] = (float)ptr[j];
}
}
Mat trainingDataMat(10, pic_size, CV_32FC1, trainingData);
// Set up SVM's parameters
CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.C = 0.1;
params.kernel_type = CvSVM::LINEAR;
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
// Train the SVM
CvSVM SVM;
SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
cv::Mat mat2 = cv::imread(argv[1], 0);
uchar* ptr2 = mat2.ptr(0);
float testData[pic_size];
for(k=0; k<pic_size; k++){
testData[k] = (float)ptr2[k];
}
cv::Mat mat3(1, pic_size, CV_32FC1, testData);
float response = SVM.predict(mat3);
printf("response:%f\n", response);
cv::imshow("SVM Simple Example", mat2);
waitKey(0);
}
建立训练样本
const char *match_pic[match_all] = {
"rightPic/0.bmp", "rightPic/1.bmp", "rightPic/2.bmp", "rightPic/3.bmp", "rightPic/4.bmp",
"rightPic/5.bmp", "errorPic/6.bmp", "errorPic/7.bmp", "errorPic/8.bmp", "errorPic/9.bmp",
};
int i, j, k;
float labels[10]={1, 1, 1, 1, 1, 1, -1, -1, -1, -1};
Mat labelsMat(10, 1, CV_32FC1, labels);
float trainingData[10][pic_size];
for(i=0; i<match_detect; i++){
cv::Mat mat1 = cv::imread(match_pic[i], 0);
uchar* ptr = mat1.ptr(0);
int length = mat1.rows * mat1.cols;
for(j=0; j<length; j++){
trainingData[i][j] = (float)ptr[j];
}
}
Mat trainingDataMat(10, pic_size, CV_32FC1, trainingData);
首先是定义使用了10个训练样本,在labels中,利用1和-1,将前6个分为一类,后四个分为一类。接着match_pic定义了训练样本的路径,所谓的训练样本也就是
10张图片,前面6张是字符0的图片,后面4张是其他1-9的图片。这样通过大量训练之后,就能在这个svm中将0从0-9的字符中识别出来。但是训练样本必须大。。不能
如本例这般小。
分配一个结构保存训练样本数据:trainingData[10][pic_size];将10张16X32的训练图片都导入到该数组中。在本例中,因为训练的样本图片都不大,所以没有取
图片的特征值,而是整个图片导入训练。
训练支持向量机
// Set up SVM's parameters
CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.C = 0.1;
params.kernel_type = CvSVM::LINEAR;
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
// Train the SVM
CvSVM SVM;
SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
也是用函数SVM.train用之前填充的trainingDataMat进行训练。
字符识别
cv::Mat mat2 = cv::imread(argv[1], 0);
uchar* ptr2 = mat2.ptr(0);
float testData[pic_size];
for(k=0; k<pic_size; k++){
testData[k] = (float)ptr2[k];
}
cv::Mat mat3(1, pic_size, CV_32FC1, testData);
float response = SVM.predict(mat3);
printf("response:%f\n", response);
分配mat2来接收,我们需要识别的图片:argv[1],然后一样的使用SVM.predict进行识别。最后如果response 返回为1,表示需要识别的图片是字符0,否则就是0-9
的其他图片。