KNN+HOG手写体数字识别

今天来介绍一下KNN+HOG手写体数字识别,首先贴出图片,这是opencv自带的一张图片,

E:\opencv\opencv\sources\samples\data,在此文件夹里,我们会发现一张手写体的图片


之前单纯用像素点训练,他的准确率是这样的



发现准确率有点低,于是我们改用KNN+HOG来进行训练,可以看到识别数字的准确率提高了很多



接下来贴出代码

#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
using namespace cv::ml;
int main()
{
	Mat img = imread("digits.png");
	Mat gray;
	cvtColor(img, gray, CV_BGR2GRAY);
	int b = 20;
	int rows = gray.rows / b;   //原图为1000*2000
	int cols = gray.cols / b;   //裁剪为5000个20*20的小图块
	cout << "rows :" << rows << endl;
	cout << "cols :" << cols << endl;
	Mat data(5000, 576, CV_32FC1);
	Mat labels;   //特征矩阵
	//创建HOG
	HOGDescriptor detector(Size(20, 20), Size(8, 8), Size(4, 4), Size(4, 4), 9);
	vector<float> descriptor;
	for (int col = 0; col < cols; col++)
	{
		int offsetCol = col*b; //列上的偏移量
		for (int row = 0; row < rows; row++)
		{
			int offsetRow = row*b;  //行上的偏移量
									//截取20*20的小块
			Mat tmp;
			gray(Range(offsetRow, offsetRow + b), Range(offsetCol, offsetCol + b)).copyTo(tmp);
			imshow("t", tmp);
			detector.compute(tmp, descriptor);
			for (int k = 0;k < descriptor.size();k++) {
				data.at<float>(col*rows + row, k) = descriptor[k];
			}
			labels.push_back((int)row / 5);  //对应的标注
		}

	}
	data.convertTo(data, CV_32F); //uchar型转换为cv_32f
	int samplesNum = data.rows;
	cout << "samplesNum :" <<samplesNum;
	int trainNum = 3000;
	Mat trainData, trainLabels;
	trainData = data(Range(0, trainNum), Range::all());   //前3000个样本为训练数据
	trainLabels = labels(Range(0, trainNum), Range::all());

	//使用KNN算法
	int K = 5;
	Ptr<TrainData> tData = TrainData::create(trainData, ROW_SAMPLE, trainLabels);
	Ptr<KNearest> model = KNearest::create();
	//Ptr<KNearest> model = StatModel::load<KNearest>("KNN.xml");
	model->setDefaultK(K);
	model->setIsClassifier(true);
	model->train(tData);
	model->save("KNN+HOG.xml");

	//预测分类
	double train_hr = 0, test_hr = 0;
	Mat response;
	// compute prediction error on train and test data
	for (int i = 0; i < samplesNum; i++)
	{
		Mat sample = data.row(i);
		float r = model->predict(sample);   //对所有行进行预测
											//预测结果与原结果相比,相等为1,不等为0
		r = std::abs(r - labels.at<int>(i)) <= FLT_EPSILON ? 1.f : 0.f;

		if (i < trainNum)
			train_hr += r;  //累积正确数
		else
			test_hr += r;
	}
	cout << "train_hr :" << train_hr << endl << "test_hr :" << test_hr << endl;
	test_hr /= samplesNum - trainNum;
	train_hr = trainNum > 0 ? train_hr / trainNum : 1.;

	printf("accuracy: train = %.1f%%, test = %.1f%%\n",
		train_hr*100., test_hr*100.);

	waitKey(0);
	return 0;
}

然后就就会发现工程目录下生成了KNN+HOG.xml的文件

然后就用Algorithm类的load方法加载图片,进行手写体图片的预测了

识别有误差主要还是训练集的问题,可以在该基础上不断添加数据集进行训练,成功率会更高。

猜你喜欢

转载自blog.csdn.net/nienelong3319/article/details/79508274