上回书说到,如何将matlab中的函数转换成可以在vs中用c++调用的dll库。但是在使用的过程中,matlab对应的函数必须要用指定的数据格式—mwarray—作为输入。问题是,c++的数据操作是按行读取,但是matlab的函数在使用mwarray过程中是按列调用数据的。笔者调用过程主要的时间精力都放在数据格式上了,这里写一点相关的心得。
最大的心得:不管按行按列,只要把mwarray的格式内容和matlab使用过程中的一模一样即可。
比如,笔者用到的一个函数输入是500x19,那只要mwarray也是500x19即可。这里的实际意义是用于决策树的输入信息,500条信息,每条信息有18维特征和1维ID。数据按列输入,也就是每次将这一维(特征)的信息全部输入。
int readInToMatrix(string FilePath)
{
int row = 30;
int col = 8;
std::vector<std::vector<double> > TLabelVV,TFeatureVV;// 二位数据组
//std::vector<double> one_row; //行向量
std::vector<double> TLabelV,TFeatureV;
std::vector<double>::iterator it; //迭代器
std::ifstream ifstr_data(FilePath); //读文件
//double aa = ifstr_data;
double TF,TL; //传值中间值
int row_count = 0; //换行标记
int line_count = 0; //列标记
for (line_count = 0; line_count < row; line_count++)
{
for (row_count = 0; row_count < col; row_count++)
{
if (row_count == 7)
{
ifstr_data >> TL;
TLabelV.push_back(TL);//将数据压入堆栈。
}
else
{
ifstr_data >> TF;
TFeatureV.push_back(TF);//将数据压入堆栈。
}
}
TLabelVV.push_back(TLabelV);
TFeatureVV.push_back(TFeatureV);
TLabelV.clear();
TFeatureV.clear();
}
ifstr_data.close();
//定义训练数据
double * trainf = new double[210];
int trainNum = 0;
double * trainl = new double[30];
//trainNum = 0;
for (int i = 0; i < TLabelVV.size(); i++)
{
for (int j = 0; j < TLabelVV[0].size(); j++)
{
trainl[trainNum] = TLabelVV[i][j];
trainNum++;
}
}
trainNum = 0;
for (int i = 0; i < TFeatureVV[0].size(); i++)
{
for (int j = 0; j < TFeatureVV.size(); j++)
{
trainf[trainNum] = TFeatureVV[j][i];//第一个放7.2[0][0] 下一个7.7[1][0]直到[30][0]
trainNum++;
}
}
mwArray TrainLabelData(trainNum / 7,1, mxDOUBLE_CLASS, mxREAL);
mwArray TrainFeatureData(trainNum/7,col-1, mxDOUBLE_CLASS, mxREAL);
TrainLabelData.SetData(trainl, 30);
TrainFeatureData.SetData(trainf, 7*30);
}
在ICP算法中,我用的是2x650的数据格式作为输入,2是指x和y的坐标,650是点的个数。这时候和上面的情况有所不同,每次输入的是一个点的两个信息。
vector<vector<Point>> fun1::ICPget(vector<vector<Point>> Modelpoint, vector<vector<Point>> Datapoint)
{
vector<vector<Point>> dataout;
//将modelpoint的轮廓信息导入model
size_t M_n = Modelpoint.size();
//统计点的个数
int M_PointNum=0;
for (int i = 0; i < M_n; i++)
{
//在第i个点集组,e.g.i=0即为外轮廓
for (int j = 0; j < Modelpoint[i].size(); j++)
{
M_PointNum++;
}
}
M_PointNum = M_PointNum * 2;
double * M_p = new double[M_PointNum];
int M_num = 0;
//double M_p[188];
//不同的轮廓点集个数不同=1+内轮廓个数。若无内轮廓,i=0就解决了。
for (int i = 0; i < M_n; i++)
{
//在第i个点集组,e.g.i=0即为外轮廓
for (int j = 0; j < Modelpoint[i].size(); j++)
{
//按列写、读,x1,y1,x2,y2
M_p[M_num] = Modelpoint[i][j].x;
M_num++;
M_p[M_num] = Modelpoint[i][j].y;
M_num++;
}
}
//将datapoint的轮廓信息导入data
size_t D_n = Datapoint.size();
int D_PointNum = 0;
for (int i = 0; i < D_n; i++)
{
//在第i个点集组,e.g.i=0即为外轮廓
for (int j = 0; j < Datapoint[i].size(); j++)
{
D_PointNum++;
}
}
D_PointNum = D_PointNum * 2;
double * D_p = new double[D_PointNum];
int D_num = 0;
//不同的轮廓点集个数不同=1+内轮廓个数。若无内轮廓,i=0就解决了。
for (int i = 0; i < Datapoint.size(); i++)
{
//在第i个点集组,e.g.i=0即为外轮廓
for (int j = 0; j < Datapoint[i].size(); j++)
{
D_p[D_num] = Datapoint[i][j].x;
D_num++;
D_p[D_num] = Datapoint[i][j].y;
D_num++;
}
}
//为了后续计算RMS方便
//此处选取点较少的作为model,点较多的作为data
//mwArray model;
//mwArray data;
if (M_num <= D_num)
{
}
else
{
int a = D_num;
D_num = M_num;
M_num = a;
}
mwArray model(2, D_num / 2, mxDOUBLE_CLASS, mxREAL);
mwArray data(2, M_num / 2, mxDOUBLE_CLASS, mxREAL);
//存放内容是MP,数量是size*2
model.SetData(D_p, D_num);
data.SetData(M_p, M_num);
//千万别忘了以防指针泄露 M_P要和下面的OUT比较rms后面删除
delete[]D_p;
}
关于mwarray数据写入和读取,可参考下文
https://blog.youkuaiyun.com/qq_29567701/article/details/84872932