ubuntu下使用C++生成cifar10二进制格式的数据

来源:互联网 发布:苏州php培训 编辑:程序博客网 时间:2024/06/04 19:07

作者:石炜贤&曾翔钰

注:本篇博客代码需要使用opencv,如果还没配置,可以参照这篇博客:
http://blog.csdn.net/code_better/article/details/53287587

学习了tensorflow后我们知道,tensorflow中训练卷积神经网络用的数据是cifar-10的bin版本的。可是我们手上有的只是一堆图片,那我们如何才能将其转化为这种格式的数据呢?

在cifar-10数据官网中查看数据格式后我们知道,其图片大小为32*32,每一个训练样本的大小是3073个字节,其中,第一个字节为label,label的值为0-9。其后的每1024个字节分别为R,G,B三个通道的值。且存储顺序为行主顺序,故3072中的前32个字节为R通道的第一行像素的值。还有一个batches.meta.txt文件,里面存储这label(0-9,充当真正标签的索引)对应的值。
如下图:
bin文件格式

好了,进入主题吧~

主要流程:
①得到图片文件名列表,构建标签(label),这二者均是vector对象;
②使用opencv得到图片每个像素的三个通道的值,同时将标签和像素值写入文件。

简单吧,来看看代码。

主体代码:

#include "BinaryDataset.h"using namespace cv;void BinaDataset::images2BinaryFile(        std::string filefolder, std::vector<std::string> &img_list,        std::vector<int> &img_labels, std::string filename) {    const int size_list = img_list.size();    FILE *fp = fopen(filename.c_str(), "wb");    if (fp == NULL) {        std::cout << "Open error!" << std::endl;        fclose(fp);        return;    }    for (int idx = 0; idx < size_list; ++idx) {        std::string currentPath = filefolder;        currentPath += img_list[idx];        mat2Binary(currentPath, img_labels[idx], fp);#if 1        std::cout << "image " << idx + 1 << " saved." << std::endl;#endif    }    fclose(fp);}void BinaDataset::mat2Binary(        std::string &image_file, int label, FILE *&fp) {    cv::Mat image = cv::imread(image_file, IMREAD_UNCHANGED);    if (!image.data) {        std::cout << "Image " << getFileName(image_file) << " load failed!"                  << std::endl;    } else {        if (image.channels() == 1) { //如果是灰度图            //转化为RGB真彩图            cv::cvtColor(image, image, CV_GRAY2RGB);        } else {            cv::cvtColor(image, image, CV_BGR2RGB);        }        cv::Mat image_reshaped;        //缩放成固定大小        cv::resize(image, image_reshaped, cv::Size(_iWidth, _iHeight), CV_INTER_LINEAR);        convertMat2Bin(image_reshaped, label, fp);    }}/** * 将图片转化为矩阵并将每个元素写入二进制文件 * @param image * @param label * @param fp */void BinaDataset::convertMat2Bin(cv::Mat &image, int label, FILE *&fp) {    //写入标签    fwrite(&label, sizeof(char), 1, fp);    //像素个数    int pixelCount = image.rows * image.cols;    //像素的值    char *pData = (char *) image.data;    //写入图片的三个通道值    for (int i = 0; i < pixelCount; i++)        fwrite(&pData[i * 3], sizeof(char), 1, fp); // R    for (int i = 0; i < pixelCount; i++)        fwrite(&pData[i * 3 + 1], sizeof(char), 1, fp); // G    for (int i = 0; i < pixelCount; i++)        fwrite(&pData[i * 3 + 2], sizeof(char), 1, fp);  // B}/** * 得到文件名列表 * @param file_folder * @return */std::vector<std::string> BinaDataset::getFileLists(string file_folder) {    const char *mystr = file_folder.c_str();    std::vector<std::string> flist;    std::string lineStr;    std::vector<std::string> extendName;    extendName.push_back("jpg");    extendName.push_back("JPG");    extendName.push_back("bmp");    extendName.push_back("png");    extendName.push_back("gif");    wchar_t fn[1000];    mbstowcs(fn, mystr, 999);    DIR *dir;    struct dirent *ptr;    if ((dir = opendir(file_folder.c_str())) == NULL) {        perror("打开文件夹失败...");        exit(1);    }    while ((ptr = readdir(dir)) != NULL) {        if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)    ///current dir OR parrent dir            continue;        else if (ptr->d_type == 8) {            //文件            lineStr = ptr->d_name;            for (int i = 0; i < 4; i++) {                if (lineStr.find(extendName[i]) < 999) {                    flist.push_back(lineStr);                    break;                }            }        }    }    return flist;}/** * 裁剪文件的路径名,得到文件的名称 * @param filename 文件路径 * @return */std::string BinaDataset::getFileName(std::string &filename) {    int iBeginIndex = filename.find_last_of("/") + 1;    int iEndIndex = filename.length();    return filename.substr(iBeginIndex, iEndIndex - iBeginIndex);}

头文件:

#ifndef BINARY_DATASET_H#define BINARY_DATASET_H#pragma once#include <iostream>#include <vector>#include <stdio.h>#include <stdlib.h>#include "string.h"#include <stdio.h>#include <dirent.h>#include <iostream>#include <vector>#include <string.h>#include <algorithm>#include "cv.h"#include "highgui.h"using namespace std;using namespace cv;class BinaDataset {public:    BinaDataset() {        _iHeight = 32;        _iWidth = 32;    }public:    void images2BinaryFile(std::string filefolder, std::vector<std::string> &img_list,                           std::vector<int> &img_labels, std::string filename);    void mat2Binary(std::string &image_file, int label, FILE *&fp);    void convertMat2Bin(cv::Mat &image, int label, FILE *&fp);    std::string getFileName(std::string &filename);    std::vector<std::string> getFileLists(std::string file_folder);public:    int _iHeight;    int _iWidth;};#endif // BINARY_DATASET_H

main方法所在文件:

#include "BinaryDataset.h"int main() {    std::string filefolder = "/home/weixain/workspace/Clion/cifar2/Samples/train/";    BinaDataset binData;    std::vector<std::string> fileLists = binData.getFileLists(filefolder); // load file name    const int size_list = fileLists.size();    std::cout << "image count: " << size_list << std::endl;    std::vector<int> image_labels(size_list, 0);  // generate lables, here are all 0    std::string binfile = "/home/weixain/workspace/Clion/cifar2/Samples/data_batch_1.bin";    binData.images2BinaryFile(filefolder, fileLists, image_labels, binfile);    return 0;}

献上完整的项目(Clion项目):
http://download.csdn.net/detail/code_better/9778433

本篇博客参考资料:
http://blog.csdn.net/yhl_leo/article/details/50801226
http://blog.csdn.net/u012005313/article/details/50687297
感谢这两篇博客的帮忙。

0 0