特征库 --> 使用文件或现有 std::vector<string> content (c++) 中的数据初始化矩阵



我的问题是如何初始化特征矩阵,但不是这样:

matrix << 1,0,1,0,
          1,0,1,0,
          1,0,1,0,

我有一个看起来像上面的矩阵(逗号或没有逗号无关紧要)存储在 TXT 文件中。

我已经编写了一个函数来读取每一行并将其放入向量中现在我想用这些数据创建一个矩阵

但它不起作用,我找不到任何页面来解释如何在不只写入值的情况下将数据分配给矩阵。(如上例)

我所需要的只是特征矩阵中文件中的数据

到目前为止我尝试过:(PS:有迭代器的想法,但我想对于非常大的矩阵会花费太长时间,我刚刚用 1-2 维矩阵尝试了这个例子)

int readFromFile (const char * path, vector <string> & mv)
{
    fstream file;
    string line;
    file.open(path);
    while (getline(file,line))
    {
        mv.push_back(line);
    }
    file.close();
    return 0;
}

typedef Matrix <int, 1, 2> MyMatrix;
int fromVectoEigen (vector<string> & source, MyMatrix & target)
{   //for (int i = source.size(); i<0 ; i--)
    //{
        string valuerow = source.back();
        string::iterator it = valuerow.begin();
        target.row(0)<< *it;
        target.row(0)<<*it+1;
        //source.pop_back();
    //}
    return 0;
}

不幸的是,不能只说Matrix.row(i) = vector.back()那行不通。

以下代码适用于包含任意大小矩阵的文件:

#include <iostream>
#include <fstream>
#include <string>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
#define MAXBUFSIZE  ((int) 1e6)
MatrixXd readMatrix(const char *filename)
    {
    int cols = 0, rows = 0;
    double buff[MAXBUFSIZE];
    // Read numbers from file into buffer.
    ifstream infile;
    infile.open(filename);
    while (! infile.eof())
        {
        string line;
        getline(infile, line);
        int temp_cols = 0;
        stringstream stream(line);
        while(! stream.eof())
            stream >> buff[cols*rows+temp_cols++];
        if (temp_cols == 0)
            continue;
        if (cols == 0)
            cols = temp_cols;
        rows++;
        }
    infile.close();
    rows--;
    // Populate matrix with numbers.
    MatrixXd result(rows,cols);
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < cols; j++)
            result(i,j) = buff[ cols*i+j ];
    return result;
    };

问候。

我刚刚发布了 Eigen 包的扩展,它可以做一些你想要的事情。它定义了>>运算符,因此您可以说:

矩阵Xd A(5,5);cin>> A;

它还允许您分配一个 VectorXd 以等于 std::vector。可以在此处找到 Eigen 的扩展版本。但是,它(尚)不允许您将 std::vector 复制到不是矢量的 MatrixXd 对象中。您想要的功能是特征中的映射函数。

我想我找到了解决方案!它既不快速也不高效,但它有效:

#include "topo.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <iterator>
#include <algorithm>

using namespace std;
using namespace Eigen;
/**Read data from File and store it in vector as string**/
int readFromFile (const char * path, vector <string> & mv) // muss vector vorher resized werden? wenn ja lese zeilenanzahl
{
    fstream file;
    string line;
    file.open(path);
    while (getline(file,line)) // lese zeile für zeile
    {
        mv.push_back(line); //fülle vector von hinten last in first
    }
    file.close();
    return 0;
}

typedef Matrix <int, 4, 4> MyMatrix; // Matrix später dynamisch
/**Parsing data to be used as Eigen Matrix**/
int fromVectoEigen (vector<string> & source, MyMatrix & target)
{   /**convert string to int and write it to the two dimensional array **/
    int array [4][4]; // noch resize nach vectorsize -->matrizen sind quadratisch
    int i = source.size();
    for ( i= i-1 ; i >= 0 ; i-- ) // da nur von hintern auf vector zugreifbar auch von hinten bei array anfangen
    {
        string myString = source.back(); // leztzes Element von Vector als String
        stringstream ssin(myString);
        int j = 0;
        while (ssin.good() && j < 4) // auch hier vectorsize später dynamisch
            {
            ssin >> array[j][i]; // fülle spalten in i.ter zeile
            ++j;
            }

        source.pop_back(); //lösche letztes element
    }
//        cout<<array[0][0]<<array[1][0]<<array[2][0]<<array[3][0]<<'n';
//        cout<<array[0][1]<<array[1][1]<<array[2][1]<<array[3][1]<<'n';
//        cout<<array[0][2]<<array[1][2]<<array[2][2]<<array[3][2]<<'n';
//        cout<<array[0][3]<<array[1][3]<<array[2][3]<<array[3][3]<<'n';
//
    /** from 2 dimensional array to one dimensional array**/
    int newarray [16]; // vectorsize * vectorsize
    int k = 0;
    for ( int i = 0 ; i< 4 ; i++) // vectorsize
    {   for (int j = 0 ; j<4; j++) // vectorsize
            {
                newarray[k]=array[j][i];
                k++;
            }
    }
    /**create Eigen Matrix from Array**/
    target= Map<Matrix4i>(newarray);
    target.transposeInPlace();
    cout<<target<<'n';

return 0 ;
}

我使用了逐元素初始化(假设我们知道 nrows 和 ncols):

MatrixXf X = MatrixXf::Zero(nrows,ncols);
ifstream fin ("./data.txt");
if (fin.is_open())
{
    for (int row = 0; row < nrows; row++)
        for (int col = 0; col < ncols; col++)
        {
            float item = 0.0;
            fin >> item;
            X(row, col) = item;
        }
    fin.close();
}
cout << "X = " << endl << X << endl;

使用 Eigen::Map 的变体,用于从 std::vector 映射数据,基于 https://eigen.tuxfamily.org/dox/group__TutorialMapClass.html 的示例

#include <vector>
#include <Eigen/Dense>
std::vector<double> myStdVector;
// Insert code for filling myStdVector here
// ....
// Detect or set number of rows/columns
size_t numRows = 3;
size_t numCols = 7;
typedef Eigen::Map<Eigen::MatrixXd> Mapper;
Mapper myMatrix(&myStdVector.data()[0], numRows, numCols);

这是我的解决方案:

#include <istream>
#include <string>
#include <sstream>
#include <vector>
#include <fstream>
#include <iostream>
#include <eigen>
using namespace std;
using namespace Eigen;
// load matrix from an ascii text file.
vector<vector<double>> LoadMatrix(istream* filePath, const string &delim = " t")
{
    string line;
    string strnum;
    auto data = vector<vector<double>>();
    // clear first
    data.clear();
    // parse line by line
    while (getline(*filePath, line))
    {
        data.push_back(vector<double>());
        for (string::const_iterator i = line.begin(); i != line.end(); ++i)
        {
            // If i is not a delim, then append it to strnum
            if (delim.find(*i) == string::npos)
            {
                strnum += *i;
                if (i + 1 != line.end()) // If it's the last char, do not continue
                    continue;
            }
            // if strnum is still empty, it means the previous char is also a
            // delim (several delims appear together). Ignore this char.
            if (strnum.empty())
                continue;
            // If we reach here, we got a number. Convert it to double.
            double       number;
            istringstream(strnum) >> number;
            data.back().push_back(number);
            strnum.clear();
        }
    }
    return data;
}
Eigen::MatrixXd ConvertToEigenMatrix(std::vector<std::vector<double>> data)
{
    Eigen::MatrixXd eMatrix(data.size(), data[0].size());
    for (int i = 0; i < data.size(); ++i)
        eMatrix.row(i) = Eigen::VectorXd::Map(&data[i][0], data[0].size());
    return eMatrix;
}
MatrixXd LoadEigenMatrix(istream* filePath, const string &delim = " t")
{
    auto data = LoadMatrix(filePath, delim);
    return ConvertToEigenMatrix(data);
}

我使用迭代器在向量中收集数据,然后初始化矩阵。转换为vector<double>似乎是该方法耗时的部分,其速度与上述解决方案大致相同。关于如何改善这一点的想法会很有趣。

template <class T>
using Tmat = Eigen::Matrix<T,Dynamic,Dynamic>;
Tmat<double> txt_to_mat(std::string path, int rows, int cols)
{
    std::ifstream fstr(path.c_str());
    std::vector<double> data_vec = std::vector<double>{
        std::istream_iterator<double>(fstr),
        std::istream_iterator<double>()
    };
    Tmat<double> mat(rows, cols);
    for(int i=0; i<rows; i++){
        for(int j=0; j<cols; j++){
            mat(i,j) = data_vec[i*cols + j];
        }
    }
    return mat;
}

模板化流运算符可用于从流中读取所有特征密集矩阵类型:

#include <Eigen/Dense>
#include <fstream>
template <typename Derived>
std::ifstream& operator>>(std::ifstream& in, Eigen::MatrixBase<Derived>& b)
{
  for(int row = 0; row < b.rows(); ++row)
    for(int col = 0; col < b.cols(); ++col)
      in >> b(row, col);
  return in;
}

这将实例化任何特征的密集矩阵类型。下面是使用上述模板化流运算符从文件中读取相机内部函数和外部函数以进行Eigen::Matrix3dEigen::Vector3d的示例:

std::ifstream input(krtPath);
Eigen::Matrix3d K, R;
Eigen::Vector3d t;
input >> K >> R >> t;
Eigen::Vector3d C = -R.transpose() * t;

最新更新