caffe学习系列一——图像预处理
1.批量读取文件夹内文件:(windows下)
1)读取某给定路径下所有文件夹与文件名称,并带完整路径,写入txt文件。代码如下:
1 void getAllFiles(string path, vector<string>& files) {
2 //文件句柄
3 long hFile = 0;
4 //文件信息
5 struct _finddata_t fileinfo; //很少用的文件信息读取结构
6 string p; //string类很有意思的一个赋值函数:assign(),有很多重载版本
7 if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(),&fileinfo)) != -1) {
8 do {
9 if ((fileinfo.attrib & _A_SUBDIR)) { //比较文件类型是否是文件夹
10 if (strcmp(fileinfo.name,".") != 0 && strcmp(fileinfo.name,"..") != 0) {
11 files.push_back(p.assign(path).append("\\").append(fileinfo.name));
12 getAllFiles(p.assign(path).append("\\").append(fileinfo.name), files);
13 }
14 } else {
15 files.push_back(p.assign(path).append("\\").append(fileinfo.name));
16 }
17 } while (_findnext(hFile, &fileinfo) == 0); //寻找下一个,成功返回0,否则-1
18 _findclose(hFile);
19 }
20 }
2)只读取某给定路径下的当前文件夹名(以下类似,只给出函数,调用案例同上):
1 void getJustCurrentDir(string path, vector<string>& files) {
2 //文件句柄
3 long hFile = 0;
4 //文件信息
5 struct _finddata_t fileinfo;
6 string p;
7 if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(),&fileinfo)) != -1) {
8 do {
9 if ((fileinfo.attrib & _A_SUBDIR)) {
10 if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0) {
11 files.push_back(fileinfo.name);
12 //files.push_back(p.assign(path).append("\\").append(fileinfo.name));
13 }
14 }
15 } while (_findnext(hFile, &fileinfo) == 0);
16 _findclose(hFile);
17 }
18 }
3)只读取某给定路径下的当前文件名:
1 void getJustCurrentFile(string path, vector<string>& files) {
2 //文件句柄
3 long hFile = 0;
4 //文件信息
5 struct _finddata_t fileinfo;
6 string p;
7 if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1) {
8 do {
9 if ((fileinfo.attrib & _A_SUBDIR)) {
10 ;
11 } else {
12 files.push_back(fileinfo.name);
13 //files.push_back(p.assign(path).append("\\").append(fileinfo.name));
14 }
15 } while (_findnext(hFile, &fileinfo) == 0);
16 _findclose(hFile);
17 }
18 }
4)只读取某给定路径下的所有文件名(即包含当前目录及子目录的文件):
1 void getFilesAll(string path, vector<string>& files) {
2 //文件句柄
3 long hFile = 0;
4 //文件信息
5 struct _finddata_t fileinfo;
6 string p;
7 if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1) {
8 do {
9 if ((fileinfo.attrib & _A_SUBDIR)) {
10 if (strcmp(fileinfo.name,".") != 0 && strcmp(fileinfo.name,"..") != 0) {
11 //files.push_back(p.assign(path).append("\\").append(fileinfo.name));
12 getFilesAll(p.assign(path).append("\\").append(fileinfo.name), files);
13 }
14 } else {
15 files.push_back(p.assign(path).append("\\").append(fileinfo.name));
16 }
17 } while (_findnext(hFile, &fileinfo) == 0);
18 _findclose(hFile);
19 }
20 }
5)提取文件夹下特定类型的文件:
void GetAllFormatFiles( string path, vector<string>& files,string format)
{
//文件句柄
long hFile = 0;
//文件信息
struct _finddata_t fileinfo;
string p;
if((hFile = _findfirst(p.assign(path).append("\\*" + format).c_str(),&fileinfo)) != -1)
{
do
{
if((fileinfo.attrib & _A_SUBDIR))
{
if(strcmp(fileinfo.name,".") != 0 && strcmp(fileinfo.name,"..") != 0)
{
//files.push_back(p.assign(path).append("\\").append(fileinfo.name) );
GetAllFormatFiles( p.assign(path).append("\\").append(fileinfo.name), files,format);
}
}
else
{
files.push_back(p.assign(path).append("\\").append(fileinfo.name) );
}
}while(_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
}
参考调用主函数:
#include <io.h>
#include <fstream>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
string filePath = "E:\\program-file\\vs_project\\face_pro\\dlib_test\\dlib_test\\crop0";
vector<string> files;
char * distAll = "AllFiles.txt";
//读取所有的文件,包括子文件的文件
//GetAllFiles(filePath, files);
//读取所有格式为jpg的文件
string format = ".png";
GetAllFormatFiles(filePath, files, format);
ofstream ofn(distAll);
int size = files.size();
ofn << size << endl;
for (int i = 0; i<size; i++)
{
ofn << files[i] << endl;
cout << files[i] << endl;
}
ofn.close();
return 0;
}
6)按行读取txt文件并存入数组
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
int main(int args, char **argv)
{
std::ifstream fin("split.txt", std::ios::in);//定义读取的文本文件
char line[1024]={0};//定义读取的每行内容的变量
std::string x = "";
std::string y = "";
std::string z = "";
while(fin.getline(line, sizeof(line)))
{
std::stringstream word(line);//stringstream按空格切分每行内容
word >> x;
word >> y;
word >> z;
std::cout << "x: " << x << std::endl;
std::cout << "y: " << y << std::endl;
std::cout << "z: " << z << std::endl;
}
fin.clear();//刷新缓存并关闭文件
fin.close();
return 0;
}
2. dir批量访问文件(windows下):
1)bat文件生成文件名列表
第一步,在要提取文件名的目录下新建一个txt格式的记事本文件;
第二步,在记事本文件中输入:DIR *.* /B >LIST.TXT;
第三步,将此记事本文件后辍名,由txt改为bat。会弹出重命名对话框,单击“是”;
第四步,双击文件“新建文本文档.bat”即可生成list.txt文件。打开txt文件就可以看到当前文件夹内的所有文件名列表。
(温馨提示:你也可以把文件“新建文本文档.bat”放在其他文件夹里运行,获取当前文件夹下面的所有文件名哦!)
2)DOS下批量访问文件名:
步骤:CMD 进入dos,然后进入cd 命令进入文件夹,输入这个命令 dir /s /b > 1.txt
**命令详解**:dir 列出文件表
/s 是指列出当前目录包含子目录下的所有文件。
/b 是仅列出文件名称,而日期、大小等信息不列出;如果不加这个,则是显示所有信息。
>1.txt 将列出的文件名保存到1.txt。
注:>符也可以用>>符代替,
如果“文件名.txt”文件不存在,则>>是创建一个新文件,是没有区别的;
如果“文件名.txt”文件已存在,则>是往文件里追加内容,>>是覆盖原有内容
总结:本文的提取文件夹内文件名的方法,思路就是将文件保存到要提取文件名的目录下,保存为.bat(为文件名),然后双击执行就OK了。这也是传送说中的批处理命令还可以对dir命令进行扩展,以过滤和筛选文件。
3.借助bash文件生成文件名清单并标签(linux)
bash文件示例代码:(将cat.jpg和bike.jpg分类并标签,保存为train.txt)
# /usr/bin/env sh
DATA=examples/images
echo "Create train.txt..."
rm -rf $DATA/train.txt
find $DATA -name *cat.jpg | cut -d '/' -f3 | sed "s/$/ 1/">>$DATA/train.txt
find $DATA -name *bike.jpg | cut -d '/' -f3 | sed "s/$/ 2/">>$DATA/tmp.txt
cat $DATA/tmp.txt>>$DATA/train.txt
rm -rf $DATA/tmp.txt
echo "Done.."
代码解释:用到了rm,find, cut, sed,cat等linux命令。
rm: 删除文件
find: 寻找文件
cut: 截取路径
sed: 在每行的最后面加上标注。本例中将找到的*cat.jpg文件加入标注为1,找到的*bike.jpg文件加入标注为2
cat: 将两个类别合并在一个文件里。
注:重定向符号>与>>,前者表示新建重定向文件或者截断,后者表示向文件中接着添加或注入内容;
类比上面代码,生成相应的val.txt和test.txt文件,可以作为caffe自带的convert_imageset.cpp文件第三个参数,进而生成caffe支持的db文件:
convert_imageset.cpp的使用:
convert_imageset [FLAGS] ROOTFOLDER/ LISTFILE DB_NAME
需要带四个参数:
FLAGS: 图片参数组,后面详细介绍
ROOTFOLDER/: 图片存放的绝对路径,从linux系统根目录开始
LISTFILE: 图片文件列表清单,一般为一个txt文件,一行一张图片
DB_NAME: 最终生成的db文件存放目录
如果图片已经下载到本地电脑上了,那么我们首先需要创建一个图片列表清单,保存为txt;
其中FLAGS参数介绍:
-gray: 是否以灰度图的方式打开图片。程序调用opencv库中的imread()函数来打开图片,默认为false
-shuffle: 是否随机打乱图片顺序。默认为false
-backend:需要转换成的db文件格式,可选为leveldb或lmdb,默认为lmdb
-resize_width/resize_height: 改变图片的大小。在运行中,要求所有图片的尺寸一致,因此需要改变图片大小。 程序调用opencv库的resize()函数来对图片放大缩小,默认为0,不改变
-check_size: 检查所有的数据是否有相同的尺寸。默认为false,不检查
-encoded: 是否将原图片编码放入最终的数据中,默认为false
-encode_type: 与前一个参数对应,将图片编码为哪一个格式:‘png’,’jpg’……
好了,知道这些参数后,我们就可以调用命令来生成最终的lmdb格式数据了
由于参数比较多,因此我们可以编写一个sh脚本来执行命令:vim create_lmdb.sh
#!/usr/bin/en sh
DATA=examples/images
rm -rf $DATA/img_train_lmdb
build/tools/convert_imageset --shuffle \
--resize_height=256 --resize_width=256 \
/home/xxx/caffe/examples/images/ $DATA/train.txt $DATA/img_train_lmdb
注释:设置参数-shuffle,打乱图片顺序。
设置参数-resize_height和-resize_width将所有图片尺寸都变为256*256.
/home/xxx/caffe/examples/images/ 为图片保存的绝对路径
运行脚本文件,就会在examples/images/ 目录下生成一个名为 img_train_lmdb的文件夹,里面的文件就是我们需要的db文件了。
4.caffe.proto文件自带的文件与处理功能
(1)levelDB,LMDB,hdf5绝大部分数据层在设置时,都可以先对数据进行一定的预处理,包括归一化scale,去中心化(减去平均值),水平镜像flip,随机裁剪crop等四种预处理方式。
该四种预处理方式可以靠该Layer的transform_params属性(HDF5 Layer没有该属性。。。)来指定。指定方式如下:
transform_param {
# randomly horizontally mirror the image
mirror: 1
# crop a `crop_size` x `crop_size` patch:
# - at random during training
# - from the center during testing
crop_size: 227
# substract mean value(RGB three channel): these mean_values can equivalently be replaced with a mean.binaryproto file as
# mean_file: name_of_mean_file.binaryproto
mean_value: 104
mean_value: 117
mean_value: 123
}
(2)caffe关于数据不同读取方式下的数据层设置:caffe.proto
数据类型levelDB和lmdb,从数据库读取数据,数据层设置:
数据类型hdf5(支持向量形式):
图片格式文件,数据层设置,参见如下连接:
http://blog.csdn.net/u012177034/article/details/52134205