自己制作机器学习训练和测试使用的二进制数据集(C++)
程序员文章站
2022-06-03 13:58:44
...
本文主要分享笔者仿照Cifar-10二进制数据库的格式,自己制作机器学习使用的二进制数据库。经过封装后,非常方便使用。代码可用Github下载:BinaryDataset
关于Cifar-10
CIFAR-10数据集由10个类的60000个32x32彩色图像组成,每个类有6000个图像。 有50000个训练图像和10000个测试图像:
其数据在文件中的存贮格式如下:
<1 x label><3072 x pixel>
...
<1 x label><3072 x pixel>
正是根据这种格式,实现了BinaryDataset对二进制文件的读写。
首先是1个字节来存储label,然后存放image的数据。image大小没有限制,代码中会根据图像的大小自动调整(但是要求所有的图像尺寸一致,比如说,所有的图像的尺寸都为100*100,或者1000*1000或者其他)。如果图像为多个通道,则格式为label R G B。
BinaryDataset详解
BinaryDataset源文件列表如下:
main.cpp 提供了一个制作人脸检测二进制数据库的例子。
BinaryDatasetWriter.h和BinaryDatasetWriter.cpp 用于生成二进制文件。
BinaryDatasetReader.hBinaryDatasetReader.cpp 用于从二进制文件中读取labels和images。
用法
生成二进制文件
把不同的种类的图片放置到不同的文件夹下面,然后在代码中分别指定类别和对应的文件夹,实例如下:
std::vector<std::pair<int, std::string>> all(2);
all.at(0).first = 1;
all.at(0).second = "E:\\dataset\\TrainingImages\\FACES";
all.at(1).first = 0;
all.at(1).second = "E:\\dataset\\TrainingImages\\NFACES";
然后调用BinaryDatasetWriter实例的genBinaryDataset方法生成二进制文件。生成二进制文件之前会随机的打乱顺序。
BinaryDatasetWriter bdw;
bdw.genBinaryDataset(all);
读取二进制文件
调用 BinaryDatasetReader::readBina 方法会得到std::shared_ptr
std::string binfile = "E:\\dataset\\face_detection.bin";
auto labelAndImages = BinaryDatasetReader::readBina(binfile,19,19,1);
完整的示例
#include "BinaryDatasetWriter.h"
#include "BinaryDatasetReader.h"
#include <random>
#define WITER 0
void main()
{
#if WITER
//首先,把不同类别的图片放到不同的文件夹下,比如,人脸图片放到一个文件夹下,非人脸放到一个文件夹下
//在Vector中的pair下添加所有的类别文件夹和其标签,比如人脸为1,非人脸为0
//生成二进制文件的过程不需要知道图片的大小,通过opencv读入图片后,就可以知道图片的大小了
//这种方式目前只适合打包大小相同的图片
std::vector<std::pair<int, std::string>> all(2);
all.at(0).first = 1;
all.at(0).second = "E:\\dataset\\TrainingImages\\FACES";
all.at(1).first = 0;
all.at(1).second = "E:\\dataset\\TrainingImages\\NFACES";
BinaryDatasetWriter bdw;
bdw.genBinaryDataset(all);
#else
//测试的时候,我们必须事前知道图像的大小和通道数目
std::string binfile = "E:\\dataset\\face_detection.bin";
auto labelAndImages = BinaryDatasetReader::readBina(binfile,19,19,1);
std::random_device rd;//来产生一个随机数当作种子
std::uniform_int_distribution<int> uni_dist(0, labelAndImages.get()->size()-10); //指定范围的随机数发生器
int startIndex = uni_dist(rd);
for (int i = startIndex;i < startIndex + 10;i++)
{
std::pair<int, std::vector<uint8_t>> oneLabelAndData = labelAndImages.get()->at(i);
std::cout << "label is " << oneLabelAndData.first << std::endl;
cv::Mat img(19, 19, CV_8UC1, oneLabelAndData.second.data(), 19);
cv::imshow("test", img);
cv::waitKey(0);
}
#endif
cv::waitKey(0);
WITER为1是生成二进制文件,WITER为0时读取二进制文件。