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

作者:石炜贤&曾翔钰

注:本篇博客代码需要使用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
感谢这两篇博客的帮忙。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值