红联Linux门户
Linux帮助

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

发布时间:2017-02-07 11:08:56来源:石炜贤的工作室作者:石炜贤&曾翔钰
注:本文代码需要使用OpenCV,如果还没配置,可以参照这篇文章:
http://www.linuxdiyf.com/linux/28212.html
 
学习了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,充当真正标签的索引)对应的值。
如下图:
ubuntu下使用C++生成cifar10二进制格式的数据
 
好了,进入主题吧。
 
主要流程:
①得到图片文件名列表,构建标签(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;
}
 
本文永久更新地址:http://www.linuxdiyf.com/linux/28213.html