C++ :: 如何捕获由 void 函数创建的矩阵

C++ :: how to capture matrix created by void function

我通常在python中编写代码,但由于组合爆炸,我决定使用C++来解决一个问题。我的想法是将 numpy 数组保存在一个 npy 文件中,然后我将向我的 C++ 函数提供该 npy 文件。由于我对 C++ 指针和引用的了解有限,所以我不能全神贯注于如何获取 void 函数的值。 void 函数不返回任何东西,所以我不能使用通常的赋值操作。如何将新的 (&mat_out) 分配给我想要的变量,比如 A。或者通过返回值的另一种方法(如第二个注释函数),但在这种方法中我遇到了类型不匹配。我的主要问题是如何使其中一种方法起作用。但是从知识的角度来看,我也想知道如何使用在 void 函数中创建的新对象。

#include <iostream>
#include <Eigen/Dense>
#include "cnpy.h"
#include "opencv2/highgui.hpp"

using namespace std;
using namespace Eigen;
using namespace cv;

void cnpy2eigen(string data_fname, Eigen::MatrixXd& mat_out){
    cnpy::NpyArray npy_data = cnpy::npy_load(data_fname);
    // double* ptr = npy_data.data<double>();
    int data_row = npy_data.shape[0];
    int data_col = npy_data.shape[1];
    double* ptr = static_cast<double *>(malloc(data_row * data_col * sizeof(double)));
    memcpy(ptr, npy_data.data<double>(), data_row * data_col * sizeof(double));
    cv::Mat dmat = cv::Mat(cv::Size(data_col, data_row), CV_64F, ptr); // CV_64F is equivalent double
    new (&mat_out) Eigen::Map<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic>>(reinterpret_cast<double *>(dmat.data), data_col, data_row);
}

/*
Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > * cnpy2eigen(string data_fname){
    cnpy::NpyArray npy_data = cnpy::npy_load(data_fname);
    // double* ptr = npy_data.data<double>();
    int data_row = npy_data.shape[0];
    int data_col = npy_data.shape[1];
    double* ptr = static_cast<double *>(malloc(data_row * data_col * sizeof(double)));
    memcpy(ptr, npy_data.data<double>(), data_row * data_col * sizeof(double));
    cv::Mat dmat = cv::Mat(cv::Size(data_col, data_row), CV_64F, ptr); // CV_64F is equivalent double
    return new (&mat_out) Eigen::Map<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic>>(reinterpret_cast<double *>(dmat.data), data_col, data_row);
}
*/

int main()
{
   Eigen::MatrixXd& A = cnpy2eigen("/Users/osmanmamun/Play_Ground/C++_practice/bayesframe/X_data.npy", Eigen::MatrixXd& A);
   cout << "Here is the matrix A:\n" << A << endl;
}

免责声明:cnpy2eigen函数是从博客上得到的

您发布的代码有很多问题

#include <iostream>
#include <Eigen/Dense>          // minor remark: Often you just need <Eigen/Core> here
#include "cnpy.h"
#include "opencv2/highgui.hpp"  // Do you actually need OpenCV here?

using namespace std;
using namespace Eigen;
using namespace cv;

(几乎)从不将 using namespace X; 放在全局范围内! [1]

void cnpy2eigen(string data_fname, Eigen::MatrixXd& mat_out){ // minor remark: Better pass `std::string` by const reference
    cnpy::NpyArray npy_data = cnpy::npy_load(data_fname);
    // double* ptr = npy_data.data<double>();
    int data_row = npy_data.shape[0];
    int data_col = npy_data.shape[1];

    double* ptr = static_cast<double *>(malloc(data_row * data_col * sizeof(double)));

您正在 malloc-ing 数据,但没有匹配 free。首先,标准 "low-level" C++ 将使用 newdelete(不过最好使用 std::vector)。但是您实际上可以改用 Eigen 的内存分配。

    memcpy(ptr, npy_data.data<double>(), data_row * data_col * sizeof(double));

标准 C++ 会使用,例如 std::copy(不过对于 POD 类型,这在内部也会转换为 memcpy)。但是这里其实不需要手动复制。

    cv::Mat dmat = cv::Mat(cv::Size(data_col, data_row), CV_64F, ptr); // CV_64F is equivalent double

您在任何地方使用 dmat 吗?如果没有,请将其删除。另请注意,OpenCV 使用行优先存储(我假设 numpy 使用列优先存储?)

    new (&mat_out) Eigen::Map<Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic>>(reinterpret_cast<double *>(dmat.data), data_col, data_row);

在这里,您正在 Eigen::Matrix 的内存位置上进行 Eigen::Map 的新放置。这可能部分有效,因为这两种类型意外地共享了它们的一些内存布局(但是 Eigen::Map 有额外的成员变量)。此外,Eigen::Matrix 拥有它的内存,而 Eigen::Map 没有,即当 Eigen::Matrix 被破坏时,它将释放它不拥有的内存。通常,除非您知道自己在做什么,否则避免放置新的——尤其是对于不匹配的类型。 (实际上,您几乎不应该在用户代码中要求 new

}

这是一个 fixed/cleaned 升级版本:

void cnpy2eigen(std::string const& data_fname, Eigen::MatrixXd& mat_out){
    cnpy::NpyArray npy_data = cnpy::npy_load(data_fname);
    double* ptr = npy_data.data<double>();
    int data_row = npy_data.shape[0];
    int data_col = npy_data.shape[1];
    mat_out = Eigen::MatrixXd::Map(ptr, data_row, data_col); // assuming NumPy is column major
}

这样称呼它:

int main()
{
   Eigen::MatrixXd A;
   cnpy2eigen("filename", A);
   std::cout << "Here is the matrix A:\n" << A << '\n';
}

如果您更喜欢按值 return,这应该可行:

Eigen::MatrixXd cnpy2eigen(std::string const& data_fname){
    cnpy::NpyArray npy_data = cnpy::npy_load(data_fname);
    double* ptr = npy_data.data<double>();
    int data_row = npy_data.shape[0];
    int data_col = npy_data.shape[1];
    return Eigen::MatrixXd::Map(ptr, data_row, data_col); // assuming NumPy is column major
}

这样称呼它:

int main()
{
   Eigen::MatrixXd A = cnpy2eigen("filename");
   std::cout << "Here is the matrix A:\n" << A << '\n';
}

如果你想避免复制,你需要让 npy_data 对象保持活动状态并直接使用 Eigen::Map (我认为没有办法从cnpy to Eigen).