//由于本人每天时间非常紧张,所以细节写的不详细,博客仅供各位参考,里面的代码都是运行过的,直接可以运行
本章的学习目标:
1)手写体数字识别数据库MNIST
2)基于SVM训练的具体步骤
1)手写体数字识别数据库MNIST
MNIST(Mixed National Institute of Standards and Technology)是一个大型的手写体数字识别数据库,广泛应用于机器学习领域的训练和测试,由纽约大学Yann LeCun教授整理。MNIST包括60000个训练集和10000个测试集,每张图都已经进行了尺寸归一化,数字居中处理,固定为28*28像素。具体的下载地址如下所示:
mnist数据下载:http://yann.lecun.com/exdb/mnist/
2)基于SVM训练的具体步骤
训练的过程如下所示:
1)读取Mnist训练集数据
2)训练
3)读取Mnist训练集数据,对比预测结果,得到错误率
3)具体的实现如下所示:
1)mnist给出的数据文件是二进制文件,四个文件解压之后的情况如下所示:
1)”train-images.idx3-ubyte”二进制文件,存储了头文件信息以及60000张28*28分辨率的图像信息(用于训练)
2)”train-labels.idx1-ubyte”二进制文件,存储了文件头信息以及60000张label信息
3)”t10k-images.idx-ubyte”二进制文件,存储了文件头信息以及10000张28*28分辨率的图想信息(用于测试)
4)“t10k-labels.idx-ubyte”二进制文件,存储了头文件信息以及10000张图像label信息
2)因为OpenCv中没有直接导入MNIST数据的文件,所以需要自己写函数来读取MNIST的数据文件
1)首先,要知道MNIST数据的数据格式:IMAGE_FILE---包含四个int型的头部数据(magic_number,number_of_images,
number_of_rows,number_of_columns)
2)余下的每一个byte表示一个pixel的数据,范围是0~255(可以在读入的时候scale到0~1的区间)
3)LABEL_FILE包含两个型的头部数据(magic_number,number_of_items),余下的每一个byte表示一个label数据,范围是0~9
我们可以参考下图所示,更加具体的信息可以去MNIST官网了解:
3)此块要注意的第一个坑是:MNIST是大端存储,然而大部分的intel处理器都是小端存储,所以对于int、long、float这些多字节的数据类型,就要一个一个byte地翻转过来,才能正确的显示。
4)此块注意的第二个坑是:如果用第一条打开文件,不会报错,但是数据会出现错误,头部数据仍然正确,但是后面的pixel数据大部分都是0
不能用ifstream file(fileName);
而要改成ifstream file(fileName, ios::binary);
5)此块注意的第三个坑是:training时,IMAGE和LABEL的数据分别都放进一个MAT中存储,但是只能是CV32_F或者是CV32_S的格式,不然会报错,OpenCv文档给出的例子是这样的:(但是predict的时候又会要求label的格式是unsigned int),所以...可以设置data的Mat格式为CV_32FC1,label的Mat格式为CV_32SC1,当然,最好都设置为CV_32FC1
6)顺便地,图像训练数据的转换格式,也就是说,我们都进来的图像数据都是二维的矩阵,但是我们在训练的时候,需要把二维的图像矩阵拉为一维的向量
7)最后,为了验证数据的正确性,一个有效的办法就是输出第一个和最后一个数据和原始图像的数据进行对比
8)还有需要说明的一点是,此处,我们是直接对原始图像进行训练,并没有对任何对图像的任何特征进行提取;我们也可以在图像进行训练之前,先利用Harris,SIFT,SURF,FAST,BRIRF,ORB,HOG这些提取图像的特征,然后再把提取的特征向量组成训练集进行训练。
/*****************************************************************************************************
文件描述:
头文件mnist.h
开发环境:
VS2012 + OpenGl(GLUT3.7) + OpenCv2.4.9 + Halcon10.0
时间地点:
陕西师范大学----2017.3.3
作 者:
九月
*****************************************************************************************************/
#ifndef MNIST_H
#define MNIST_H
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
int ReverseInt(int i); //[1]大小端存储转换
cv::Mat ReadMnistImage(const string fileName); //[2]读取Image的数据信息
cv::Mat ReadMnistLabel(const string fileName); //[3]读取Label数据信息
#endif
/*****************************************************************************************************
文件描述:
头文件mnist.h的实现文件mnist.cpp
开发环境:
VS2012 + OpenGl(GLUT3.7) + OpenCv2.4.9 + Halcon10.0
时间地点:
陕西师范大学----2017.3.3
作 者:
九月
*****************************************************************************************************/
#include"mnist.h"
#include
#include
using namespace std;
int testNum = 10000;
/*****************************************************************************************************
函数功能:
大小端存储模式的数据转换
*****************************************************************************************************/
int ReverseInt(int i)
{
unsigned char c1;
unsigned char c2;
unsigned char c3;
unsigned char c4;
c1 = i&255;
c2 = (i>>8)&255;
c3 = (i>>16)&255;
c4 = (i>>24)&255;
return ((int)c1<<24)+((int)c2<<16)+((int)c3<<8)+c4;
}
/*****************************************************************************************************
函数功能:
读取Minst数据库的图像二进制文件
注意问题:
此块我们需要注意的问题是:当我们从MINIST数据库中读进来图像文件后,我们将读进来的文件存储在
dataMat矩阵容器中,这就是我们送给SVM的训练样本;要注意的是,在这个矩阵容器中,矩阵dataMat
中的一行,就代表一个样本,就是实际中的一幅图片;
我们有多少张图片,我们就有多少训练样本,这个矩阵就有多少行。
*****************************************************************************************************/
cv::Mat ReadMnistImage(const string fileName)
{
double constTime;
std::clock_t startTime;
std::clock_t endTime;
int magicNumber = 0;
int numberOfImages = 0;
int nRows = 0;
int nCols = 0;
cv::Mat dataMat;
std::ifstream file(fileName,ios::binary);
if(file.is_open())
{
std::cout<<"[NOTICE]The set of Images is opened sucessfully!"<>Start!"<(i,j) = pixelValue;
//打印第一张和最后一张图像数据
if(i==0)
{
s.at(j/nCols,j%nCols) = pixelValue;
}
else if(i==numberOfImages-1)
{
e.at(j/nCols,j%nCols) = pixelValue;
}
}//for j
}//for i
endTime = std::clock();
constTime= (endTime-startTime);
std::cout<<"[NOTICE]Read the data of Images---->>Finish!"<>Start!"<(i, 0) = (unsigned int)temp;
//打印第一个和最后一个label
if(i == 0)
{
s = (unsigned int)temp;
}
else if(i == numberOfItems-1)
{
e = (unsigned int)temp;
}
}
endTime = clock();
constTime= (endTime-startTime);
std::cout<<"[NOTICE]Read the data of Images---->>Finish!"</*****************************************************************************************************
程序功能:
基于OpenCv中SVM的Minist手写体字符识别
开发环境:
VS2012 + OpenGl(GLUT3.7) + OpenCv2.4.9 + Halcon10.0
时间地点:
陕西师范大学----2017.3.3
作 者:
九月
*****************************************************************************************************/
#include"mnist.h"
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
std::string trainImage = "mnist_dataset/train-images.idx3-ubyte";
std::string trainLabel = "mnist_dataset/train-labels.idx1-ubyte";
std::string testImage = "mnist_dataset/t10k-images.idx3-ubyte";
std::string testLabel = "mnist_dataset/t10k-labels.idx1-ubyte";
int main()
{
double consumeTime = 0;
std::clock_t startTime = 0;
std::clock_t endTime = 0;
cv::Mat trainData;
cv::Mat trainDataLabels;
//【1】读入训练样本
trainData = ReadMnistImage(trainImage);
trainDataLabels = ReadMnistLabel(trainLabel);
std::cout<<"[1]trainData.rows*trainData.cols = "<(i,0)<=FLT_EPSILON?1.f:0.f);
count += result;
}
//【6】统计预测的正确个数和错误率
std::cout<<"[NOTICE]Correct identification number = "<
下面两幅图片是博主训练1000张图片的准确率,具体怎样设置,请看代码