OpenCV下的CSV文件读、写

1.CSV文件格式简介

    逗号分隔值(Comma-SeparatedValues,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据。CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符。通常,所有记录都有完全相同的字段序列。

    CSV文件格式的通用标准并不存在,但是在RFC 4180中有基础性的描述。使用的字符编码同样没有被指定,但是7-bitASCII是最基本的通用编码。

    一般情况下,CSV文件格式规则如下:

    1.  开头是不留空,以行为单位。

    2.  可含或不含列名,含列名则居文件第一行。

    3.   一行数据不跨行,无空行。

    4.  以半角逗号(即,)作分隔符,列为空也要表达其存在。

    5.  列内容如存在半角逗号(即,)则用半角双引号(即"")将该字段值包含起来。

    6.  列内容如存在半角引号(即")则应替换成半角双引号("")转义,并用半角引号(即"")将该字段值包含起来。

    7.  文件读写时引号,逗号操作规则互逆。

    8.  内码格式不限,可为 ASCII、Unicode 或者其他。

    9.  不支持特殊字符

2. Mat矩阵数据存储到CSV文件中

    博文“C++读写CSV文件”提出了一种CSV文件的读取遍历算法和写入算法,http://www.cnblogs.com/snake-hand/p/3170483.html,并利用C++实现了对CSV文件的读、写操作。

    本文结合OpenCV的CSV风格格式化输出与流缓冲重定向,比较巧妙地实现了“将Mat 矩阵数据存储到CSV文件”功能。

代码如下:

//保存cout流缓冲区指针
	streambuf *coutBuf = cout.rdbuf();
	fstream matData("E:\\Test\\data\\fire_2.csv",ios::out|ios::trunc);
	if(!matData){
		cerr<<"File open or create error!"<<endl;
		exit(1);
	}
	//获取文件fire.csv的流缓冲区指针
	streambuf *fileBuf = matData.rdbuf();
	//设置cout流缓冲区指针为文件的流缓冲区指针
	cout.rdbuf(fileBuf);
	cout<<format(svmMat,"csv");
	matData.flush();
	matData.close();
	//恢复cout原来的流缓冲区指针
	cout.rdbuf(coutBuf);

测试结果:


3.从CSV文件读取数据到Mat 矩阵

    以下代码为我自己写的read_csv函数,实现了从CSV文件读取数据到Mat矩阵中的功能。

/**
*函数功能:将csv文件数据提取到Mat类型矩阵中
*输入:filepath 文件路径数组指针;img_size Mat类型数据的Size;img_type Mat类型数据的类型(32FC1)
*返回值:Mat 矩阵
*/
Mat read_csv(const char *filepath, Size img_size, int img_type)
{
	Mat image;
	image.create(img_size,img_type);
	string pixel;

	ifstream file(filepath, ifstream::in);
	if (!file)
		cout << "CSV read fail" << endl;

	int nl= image.rows;  // number of lines   
	int nc= image.cols ; // number of columns   
	int eolElem = image.cols - 1;		//每行最后一个元素的下标
	int elemCount = 0;
	if (image.isContinuous())
	{   
		nc= nc*nl;    // then no padded pixels   
		nl= 1;		  // it is now a 1D array   
	}  
	for (int i = 0; i<nl; i++)
	{
		float* data = (float*)image.ptr<ushort>(i);  
		for (int j = 0; j < nc; j++)
		{  
			if(elemCount == eolElem){
				getline(file,pixel,'\n');				//任意地读入,直到读到delim字符 '\n',delim字符不会被放入buffer中
				data[j] = (float)atof(pixel.c_str());	//将字符串str转换成一个双精度数值并返回结果
				elemCount = 0;							//计数器置零
			}
			else{
				getline(file,pixel,',');				//任意地读入,直到读到delim字符 ','delim字符不会被放入buffer中
				data[j] = (float)atof(pixel.c_str());	//将字符串str转换成一个双精度数值并返回结果
				elemCount++;
			}
		}                  
	}
	return image;
}
测试结果:


注意事项:

    注意每一个记录结束时以’\n’结尾,而非’,’因此需要特别处理。

OpenCV 的实现:

    在我调用read_csv函数时,发现OpenCV已经有实现类似功能的函数:intCvMLData::read_csv(const char* filename)。利用CMake编译OpenCV,点击鼠标右键->转到定义可以方便查看opencv的源代码。(具体方法见以下链接博文)http://blog.csdn.net/solomon1558/article/details/43780533

实现一:

    例程Fisherfaces in OpenCV中的read_csv函数

static void read_csv(const string& filename, vector<Mat>&images, vector<int>& labels, char separator = ';'){
    std::ifstream file(filename.c_str(),ifstream::in);
    if (!file){
        string error_message = "No valid input file was given, please check thegiven filename.";
        CV_Error(CV_StsBadArg, error_message);
    }
    string line, path, classlabel;
    while(getline(file, line)) {
        stringstream liness(line);
        getline(liness, path, separator);
        getline(liness, classlabel);
        if(!path.empty()&& !classlabel.empty()) {
            images.push_back(imread(path, 0));
           labels.push_back(atoi(classlabel.c_str()));
        }
    }
}

实现二:int CvMLData::read_csv(const char* filename)

int CvMLData::read_csv(constchar* filename)
{
    const int M = 1000000;
    const char str_delimiter[3] = { '', delimiter, '\0' };
    FILE* file = 0;
    CvMemStorage* storage;
    CvSeq* seq;
    char *ptr;
    float*el_ptr;
    CvSeqReader reader;
    intcols_count = 0;
    uchar *var_types_ptr = 0;
    clear();
    file = fopen( filename, "rt" );
    if( !file )
        return-1;
    // read the firstline and determine the number of variables
    std::vector<char>_buf(M);
    char* buf =&_buf[0];
    if(!fgets_chomp( buf, M, file ))
    {
        fclose(file);
        return-1;
    }
    ptr = buf;
    while( *ptr== ' ' )
        ptr++;
    for( ; *ptr!= '\0'; )
    {
        if(*ptr== delimiter || *ptr == ' ')
        {
            cols_count++;
            ptr++;
            while(*ptr == ' ' ) ptr++;
        }
        else
            ptr++;
    }
    cols_count++;
    if (cols_count == 0)
    {
        fclose(file);
        return-1;
    }
    // createtemporary memory storage to store the whole database
    el_ptr = newfloat[cols_count];
    storage = cvCreateMemStorage();
    seq = cvCreateSeq( 0, sizeof(*seq), cols_count*sizeof(float), storage );
    var_types = cvCreateMat( 1, cols_count,CV_8U );
    cvZero( var_types );
    var_types_ptr = var_types->data.ptr;
    for(;;)
    {
        char*token = NULL;
        inttype;
        token = strtok(buf, str_delimiter);
        if(!token)
            break;
        for (int i = 0; i < cols_count-1; i++)
        {
            str_to_flt_elem( token, el_ptr[i],type);
            var_types_ptr[i] |= type;
            token = strtok(NULL,str_delimiter);
            if(!token)
            {
                fclose(file);
                delete[] el_ptr;
                return-1;
            }
        }
        str_to_flt_elem( token,el_ptr[cols_count-1], type);
        var_types_ptr[cols_count-1] |= type;
        cvSeqPush( seq, el_ptr );
        if(!fgets_chomp( buf, M, file ) )
            break;
    }
    fclose(file);
    values = cvCreateMat( seq->total,cols_count, CV_32FC1 );
    missing = cvCreateMat( seq->total,cols_count, CV_8U );
    var_idx_mask = cvCreateMat( 1,values->cols, CV_8UC1 );
    cvSet( var_idx_mask, cvRealScalar(1) );
    train_sample_count = seq->total;
 
    cvStartReadSeq( seq, &reader );
    for(int i = 0; i < seq->total; i++ )
    {
        const float* sdata = (float*)reader.ptr;
        float*ddata = values->data.fl + cols_count*i;
        uchar* dm = missing->data.ptr +cols_count*i;
        for( int j = 0; j < cols_count; j++ )
        {
            ddata[j] = sdata[j];
            dm[j] = ( fabs( MISS_VAL - sdata[j]) <= FLT_EPSILON );
        }
        CV_NEXT_SEQ_ELEM( seq->elem_size,reader );
    }
    if (cvNorm( missing, 0, CV_L1 ) <= FLT_EPSILON )
        cvReleaseMat( &missing );
    cvReleaseMemStorage( &storage );
    delete[]el_ptr;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值