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:Testdatafire_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,','); //任意地读入,直到读到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://www.voidcn.com/article/p-heydxbeh-bey.html 实现一: ? ??例程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,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,' ' }; 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!= ' '; ) { 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,file ) ) break; } fclose(file); values = cvCreateMat( seq->total,CV_32FC1 ); missing = cvCreateMat( seq->total,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,CV_L1 ) <= FLT_EPSILON ) cvReleaseMat( &missing ); cvReleaseMemStorage( &storage ); delete[]el_ptr; return 0; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |