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

猜你喜欢

转载自blog.csdn.net/u012617944/article/details/78128218
今日推荐