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

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

本文关键字:创建 函数 void 何捕获 C++      更新时间:2023-10-16

我通常用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数据,但没有匹配的free。首先,标准的"低级"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(

}

这是一个修复/清理的版本:

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';
}

如果您更喜欢按值返回,这应该有效:

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 转移到 Eigen(。