如何通过SWIG将NumPy ndarray转为Eigen::Vector3d并解决内存泄漏
解决SWIG封装Eigen类型函数的类型转换与内存泄漏问题
核心问题
- 初始调用时NumPy数组无法匹配
Eigen::Vector3d const &类型,触发类型错误 - 添加输入typemap后,返回的
Eigen::Matrix<double,3,4>因SWIG无法自动管理内存,出现泄漏提示
完整解决方案
需要同时处理输入参数的类型转换和返回值的内存管理与类型转换,以下是修正后的关键代码:
1. 修正后的kinematics.i
%module kinematics %{ #define SWIG_FILE_WITH_INIT #include "kinematicsExample.h" #include <eigen3/Eigen/Dense> %} // 初始化NumPy接口支持 %include <numpy.i> %numpy_include %init %{ import_array(); %} // 输入typemap:NumPy ndarray → Eigen::Vector3d const & %typemap(in) Eigen::Vector3d const & (Eigen::Vector3d temp_vec) { if (!PyArray_Check($input)) { PyErr_SetString(PyExc_TypeError, "必须传入NumPy数组"); return NULL; } PyArrayObject* arr = reinterpret_cast<PyArrayObject*>($input); // 检查数组维度、长度和类型 if (PyArray_NDIM(arr) != 1 || PyArray_DIM(arr, 0) != 3) { PyErr_SetString(PyExc_ValueError, "必须是长度为3的一维NumPy数组"); return NULL; } if (PyArray_TYPE(arr) != NPY_DOUBLE) { PyErr_SetString(PyExc_TypeError, "数组类型必须为float64"); return NULL; } double* data = reinterpret_cast<double*>(PyArray_DATA(arr)); temp_vec << data[0], data[1], data[2]; $1 = &temp_vec; } // 返回值typemap:Eigen::Matrix<double,3,4> → NumPy ndarray %typemap(out) Eigen::Matrix<double,3,4> { npy_intp dims[2] = {3, 4}; PyObject* arr = PyArray_SimpleNew(2, dims, NPY_DOUBLE); double* out_data = reinterpret_cast<double*>(PyArray_DATA(reinterpret_cast<PyArrayObject*>(arr))); // 将Eigen矩阵数据复制到NumPy数组 for (int i = 0; i < 3; ++i) { for (int j = 0; j < 4; ++j) { out_data[i * 4 + j] = $1(i, j); } } $result = arr; } // 声明封装的函数(修正原代码中缺少的闭合括号) Eigen::Matrix<double, 3, 4> forward_kinematics(const Eigen::Vector3d& q);
2. 关键修改说明
- 输入typemap增强:增加了数组维度、长度、类型的严格检查,避免非法输入;用Eigen原生语法赋值更规范
- 返回值typemap:直接将Eigen矩阵数据复制到NumPy数组并返回,替代SWIG默认生成的指针对象,彻底解决内存泄漏
- NumPy初始化:添加
%init块调用import_array(),确保NumPy接口正常工作
3. 测试验证
运行原test.py,现在会直接返回NumPy数组,无类型错误和内存泄漏提示:
import kinematics import numpy as np q_input = np.array([30,45,60], dtype=np.float64) q_input = np.radians(q_input) print(type(q_input)) print(q_input) pose_matrix = kinematics.forward_kinematics(q_input) print("Pose Matrix:") print(pose_matrix) print(type(pose_matrix)) # 输出:<class 'numpy.ndarray'>
额外提示
编译时需确保链接Eigen库,例如使用g++编译时添加参数-I/usr/include/eigen3;若需封装更多Eigen类型,可直接使用成熟的SWIG-Eigen接口库减少重复开发。
内容的提问来源于stack exchange,提问作者Anmar27
相关产品推荐
相关产品推荐

