自己制作机器学习训练和测试使用的二进制数据集(C++)

本文主要分享笔者仿照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时读取二进制文件。

猜你喜欢

转载自blog.csdn.net/u011913612/article/details/79507535