目标
最近正在做热图像的实验数据处理,热像仪上位机导出热图像视频数据是,每一帧为一个csv文件,每行像素值由逗号分隔,行与行之间是换行符,数据格式是纯文本,科学计数法。需要将全部数据存至一个mat中,以便后续使用opencv库处理。
思路
- 将读取CSV文件的函数和当前正在读取的文件操作符等放在一个类中,构造类似句柄的一个类,代表一个帧的文件。
- 类中包含如打开、关闭、检查列数、(没有写检查行数的函数)、科学计数法转浮点数等基本操作。
- Mat类引用传参。
- 以固定格式打开CSV文件,比如打开一段视频的第一帧就传入参数1。
代码
程序
读取CSV的类
//read_csv.h
#ifndef READ_CSV_H
#define READ_CSV_H
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>//istringstream 必须包含这个头文件
#include <opencv2\opencv.hpp>
using namespace std;
using namespace cv;
class CSV {
public:
CSV(int b, int r);//b为列数
~CSV();
void check_columns(void);//判断该数据有多少列
void read_csv(int n,Mat& dest);//读取哪一帧数据
void file_close(void);//--关闭所有打开的文件
void open_csv(int idx);//打开第idx帧的文件
/*
void creat_new_csv(void);//--创建一个新的csv文件
void write_csv(void);//--将需要的数据写入新csv文件中
*/
public:
int columns;
private:
string filename_base = "H:/data/2__";//--打开的文件名
string oneline;//--保存一行数据
ifstream infile;//--输入文件流
ofstream outfile;//--输出文件流
int blank_rows = 0, rows, current_frame = 0;//无效行数,列数,当前帧
};
double sci2db(string& strSci);
#endif // !READ_CSV_H
filename_base 是基础文件名,在上位机导出时设置,后面跟着上位机自动补全的第几帧。
blank_rows是无效的行数,上位机会生成几行记录相关信息。
#include "read_csv.h"
/*
每一帧是一个文件
*/
CSV::CSV(int b,int r=240)//构造函数
{
this->blank_rows = b; //设定空白行数
check_columns();//检查列数
this->rows = r;
}
CSV::~CSV() //析构函数
{
if(this->infile.is_open())
this->infile.close();//有文件打开则关闭文件
}
void CSV::check_columns(void)
{
open_csv(1);//打开第一帧,编号从一开始
string tmp;
for (int i = 0; i < blank_rows; i++)
{
getline(this->infile, tmp);//--读取一行
}
getline(this->infile, tmp);//--读取一行
this->columns = 1;
for (int i = 0; i < tmp.size(); i++) {
if (tmp[i] == ',')this->columns++;
}
cout <<"There exists "<<this->columns <<" columns in the file "<< endl;
file_close();//关闭文件
}
void CSV::read_csv(int n,Mat& dest)
{
dest.create(this->rows, this->columns, CV_64FC1);
open_csv(n);
for (int i = 0; i < this->rows; i++) {
getline(this->infile, this->oneline);//--读取一行
istringstream tempstream(this->oneline);//将整行字符串line读入到字符串流istringstream中
string field;
int m = 0;
for (int j = 0; j < this->columns; j++) {
getline(tempstream, field, ',');
/* 注意 Mat::at 函数是个模板函数, 需要指明参数类型, 因为这张图是具有红蓝绿三通道的图,
所以它的参数类型可以传递一个 Vec3b, 这是一个存放 3 个 uchar 数据的 Vec(向量). 这里
提供了索引重载, [2]表示的是返回第三个通道, 在这里是 Red 通道, 第一个通道(Blue)用[0]返回 */
dest.at<double>(i, j) = sci2db(field);
}
}
file_close();//关闭文件
}
void CSV::open_csv(int idx)
{
string filename = filename_base + to_string(idx) + ".csv";//--写入文件名
this->infile.open(filename); //--打开文件
}
void CSV::file_close(void)
{
this->infile.close();
}
double sci2db(string& strSci)
{
int iPower = 0; //幂
double dMntsa = 0; //尾数
double dCoefficient = 1; //系数
std::string strPower, strMntsa;
if (std::string::npos == strSci.find("E"))
{
return atof(strSci.c_str());
}
strMntsa = strSci.substr(0, strSci.find("E"));
strPower = strSci.substr(strSci.find("E") + 1);
dMntsa = atof(strMntsa.c_str());
iPower = atoi(strPower.c_str());
while (iPower != 0)
{
if (iPower > 0)
{
dCoefficient *= 10;
iPower--;
}
else
{
dCoefficient *= 0.1;
iPower++;
}
}
return dMntsa * dCoefficient;
}
/*temp
void CSV::write_csv(void)
{
this->outfile << this->fields[8] << "," << this->fields[10] << endl;
}
void CSV::creat_new_csv(void)
{
this->outfile.open("out.csv", ios::out | ios::trunc);
}
void CSV::open_csv(void)
{
if(filename.size()!=0)
this->infile.open(this->filename); //--打开文件
}
*/
主函数示例
简单写一个读取每一帧吧
#include <opencv2\opencv.hpp>
#include "read_csv.h"
using namespace cv;
using namespace std;
int start_frame = 1000, end_frame = 6000;//起始帧和终点帧
int main()
{
CSV csv_1(0,240);
Mat read_tmp;
for (int i = start_frame; i < end_frame;i++) {
csv_1.read_csv(i, read_tmp);//读取第i帧图像
//···
}
//···
//system("PAUSE ");
return 0;
}