在ubuntu16.04+opencv3.0环境下使用mnist手写体数据集编写相关程序

来源:互联网 发布:淘宝达摩盘是什么 编辑:程序博客网 时间:2024/06/05 02:25
 因为最近可能做项目需要,因此搜索了手写体数字检测博客,在查看了大量博客后总结了一些自己的学习小体会。但是但是-----敲黑板、划重点了。呵呵,就是还是先把参考的几篇好博客的分享给大家。 http://www.itnose.net/detail/6525586.html,这篇文章里面最可取的就是分析了mnist数据集存在的坑。很多坑我也不是太明白,哈哈。 http://blog.csdn.net/xuan_zizizi/article/details/71102018,这篇博客,对就是这篇,上一个网址我就是在这里找到的。所以这篇博客挺好的。 首先介绍下mnist数据集吧,这个数据集至少在现在看来在手写体方面使用的还是比较多的。下载它可以在这里`http://yann.lecun.com/exdb/mnist/`,打开后你可以看到四个可以下载的包,但是你会发现网传的训练60000张图片,测试10000张图片,下载下来的包怎么这么小,解压下来一看,我靠居然是二进制文件。不着急,因为很多前辈已经给了很多详细的参考,特别是在http://www.itnose.net/detail/6525586.html下,写的非常详细,如果感兴趣可以认真看下。 有3个函数需要先贴出来. 1.大小端转换`int reverseInt(int i)

{
unsigned char c1, c2, c3, 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;//左移
}`
因为MNIST是大端存储,然而大部分的Intel处理器都是小端存储,所以对于int、long、float这些多字节的数据类型,就要一个一个byte地翻转过来,才能正确显示。
2.读取训练图片

Mat read_mnist_image(const char* fileName){int magic_number = 0;int number_of_images = 0;int n_rows = 0;int n_cols = 0;Mat DataMat;ifstream file;file.open(fileName, std::ifstream::binary);//fstream file;//(fileName, ios_base::binary);//file.open(fileName,  ios_base::binary);if (file.is_open()){cout << "成功打开图像集\n";file.read((char*)&magic_number, sizeof(magic_number));file.read((char*)&number_of_images, sizeof(number_of_images));file.read((char*)&n_rows, sizeof(n_rows));file.read((char*)&n_cols, sizeof(n_cols));cout << "magic_number=/n"<<magic_number << "number_of_images=\n " << number_of_images << " " << n_rows << " " << n_cols << endl;magic_number = reverseInt(magic_number);number_of_images = reverseInt(number_of_images);n_rows = reverseInt(n_rows);n_cols = reverseInt(n_cols);cout << "MAGIC NUMBER = " << magic_number<< " ;NUMBER OF IMAGES = " << number_of_images<< " ; NUMBER OF ROWS = " << n_rows << " ; NUMBER OF COLS = " << n_cols << endl;//-test-//输出第一张和最后一张图,检测读取数据无误Mat s = Mat::zeros(n_rows, n_rows * n_cols, CV_32FC1);Mat e = Mat::zeros(n_rows, n_rows * n_cols, CV_32FC1);cout << "开始读取Image数据......\n";DataMat = Mat::zeros(number_of_images, n_rows * n_cols, CV_32FC1);for (int i = 0; i < number_of_images; i++){for (int j = 0; j < n_rows * n_cols; j++){unsigned char temp = 0;file.read((char*)&temp, sizeof(temp));float pixel_value = float((temp + 0.0) / 255.0);DataMat.at<float>(i, j) = pixel_value;//打印第一张和最后一张图像数据if (i == 0){s.at<float>(j / n_cols, j % n_cols) = pixel_value;}else if (i == number_of_images - 1){e.at<float>(j / n_cols, j % n_cols) = pixel_value;}}}//imshow("first image", s);//cout << "first image = " << s << endl;//imshow("last image", e);waitKey(0);}file.close();return DataMat;}

3.读取标签

Mat read_mnist_label(const char* fileName){int magic_number;int number_of_items;Mat LabelMat;ifstream file;file.open(fileName, std::ifstream::binary);//fstream file;//(fileName, ios_base::binary);//file.open(fileName, ios_base::binary);if (file.is_open()){cout << "成功打开标签\n";file.read((char*)&magic_number, sizeof(magic_number));file.read((char*)&number_of_items, sizeof(number_of_items));magic_number = reverseInt(magic_number);number_of_items = reverseInt(number_of_items);cout << "MAGIC NUMBER = " << magic_number << "  ; NUMBER OF ITEMS = " << number_of_items << endl;//-test-//number_of_items = testNum;//记录第一个label和最后一个labelunsigned int s = 0, e = 0;cout << "开始读取Label数据......\n";LabelMat = Mat::zeros(number_of_items, 1, CV_32SC1);for (int i = 0; i < number_of_items; i++){unsigned char temp = 0;file.read((char*)&temp, sizeof(temp));LabelMat.at<unsigned int>(i, 0) = (unsigned int)temp;//打印第一个和最后一个labelif (i == 0) s = (unsigned int)temp;else if (i == number_of_items - 1) e = (unsigned int)temp;}cout << "first label = " << s << endl;   cout << "last label = " << e << endl;}file.close();return LabelMat;}

其中在读图片和读标签函数中做了一点修改,不知道是因为什么原因,当把文件名以string 类型赋值的时候,file.open()一直报错,所以最后只能改成char testImage[] = “t10k-images.idx3-ubyte”。
最后就是在主函数中进行训练数据集和测试数据集。

int main(){//读取训练数据Mat trainData;Mat labels;trainData = read_mnist_image(trainImage);labels = read_mnist_label(trainLabel);cout << " 训练数据行数:" << trainData.rows << "训练数据列数:" << trainData.cols << endl;cout << " 训练标签行数:" << labels.rows << "训练数据列数: " << labels.cols << endl;cout << "训练数据读取完成" << endl;//训练参数Ptr<SVM> svm = SVM::create();svm->setType(SVM::C_SVC);svm->setKernel(SVM::RBF);svm->setGamma(0.01);svm->setC(10.0);svm->setTermCriteria(TermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON));cout << "参数设置完成" << endl;//训练分类器cout << "开始训练分类器" << endl;svm->train(trainData, ROW_SAMPLE, labels);cout << "分类器训练完成" << endl;//保存训练器svm->save("./mnist_svm.xml");cout << "save as ./mnist_svm.xml" << endl;//下载分类器//cout << "开始导入SVM文件...\n";//Ptr<SVM> svm1 = StatModel::load<SVM>("mnist_dataset/mnist_svm.xml");//cout << "成功导入SVM文件...\n";//读取测试数据Mat testData;Mat tLabel;testData = read_mnist_image(testImage);tLabel = read_mnist_label(testLabel);cout << "测试数据读取完成" << endl;float count = 0;for (int i = 0; i < testData.rows; i++) {Mat sample = testData.row(i);float res=0.0;res=svm->predict(sample);res = abs(res - tLabel.at<unsigned int>(i, 0)) <= FLT_EPSILON ? 1.f : 0.f;count += res;}cout << "正确的识别个数: " << count << endl;cout << "错误率为:" << (10000 - count + 0.0) / 10000 * 100.0 << "%\n";system("pause");return 0;}
 那么最后程序成功运行完成后就会在build文件夹或者项目的根目录下存在一个mnist_svm.xml。这就是我们训练出来的模型了。以后需要预测手写体数字直接加载这个模型就可以了,不用每次都训练数据集。 好了这就是训练模型的程序了。 -------------------------------我是分割线 哈哈,但是此时,如果你要读取自己的视频或者本地图片进行预测,你会发现很多坑的,哈哈。 例如预测结果......en  ,都是些什么玩意儿。完全对不上,说好准确率98%以上的,结果错误率。具体原因,请听下回分解。

(mnisit读出来的图片是黑底白字)。

阅读全文
0 0
原创粉丝点击