☰
SensorsCalibration 中的 matplotlib-cpp 编译指南:依赖配置、链接选项与工程实践
2026/10/15 2:37:49 网站建设 项目流程
  • 自动驾驶
  • 计算机视觉

【免费下载链接】SensorsCalibration

OpenCalib: A Multi-sensor Calibration Toolbox for Autonomous Driving

项目地址:https://gitcode.com/gh_mirrors/se/SensorsCalibration
点击查看免费下载

本文以 OpenCalib(SensorsCalibration)多传感器标定工具箱仓库内置的 matplotlib-cpp 文档《Compiling a program》为骨架,系统讲解如何在 C++ 工程中正确编译、链接并使用这一"头文件式"绘图库。你将从 Python/NumPy 环境准备、-I/-L/-l链接选项、WITHOUT_NUMPY开关到 CMake/Make 工程化集成,完整掌握在标定工具中直接绘制轨迹与曲线图的实战方法,并能对照仓库源码验证每一个链接参数的实际作用。

文档与仓库定位

关联文档位于仓库的第三方依赖目录 compiling.rst,是 matplotlib-cpp 官方 Sphinx 文档中专门讲解"程序编译"的章节。matplotlib-cpp 是一个单头文件(matplotlibcpp.h)的 C++ 绘图库,本质上是 Python matplotlib 的轻量封装:C++ 程序内部启动 Python 解释器并调用matplotlib.pyplot,从而用两行代码即可完成绘图和存图。

在 SensorsCalibration 仓库中,该库被以3rdparty方式整体 vendored 进多个标定模块:

  • SensorX2car/lidar2car:激光雷达到车体(LiDAR→Car)标定,使用 matplotlib-cpp 绘制车辆轨迹trajectory.png与航向角对比图compared_yaw.png;
  • SensorX2car/pose_sensor2car:位姿传感器到车体标定,同样依赖 matplotlib-cpp 输出轨迹与航向对比图。

因此,理解本编译文档是让上述标定工具"跑通并出图"的前提。

一、编译前置依赖

1. 可用的 Python 安装与 matplotlib

文档明确要求:Matplotlib for C++ 需要可用的 Python 安装以及matplotlib库。官方已测试的版本为 Python 2.7 与 Python 3(>= 3.6),其他版本通常也可用;链接阶段可通过链接对应的 Python 库来精确指定版本。

在 Unix 系统上,建议通过包管理器安装 Python,以确保所有依赖被正确装配:

<package-manager> install python3 python3-dev # or -devel depending on the platform

然后通过 pip 安装 matplotlib:

pip3 install matplotlib # or pip for Python 2

注意:文档特别提醒,若 Python 是从源码自行编译安装的,链接阶段可能遇到问题,解决方式见下文"从源码安装 Python 时的链接问题"小节。

2. 可选的 NumPy 依赖

matplotlibcpp.h默认使用 NumPy 数组进行数据交互,因此需要numpy/arrayobject.h头文件;如果环境中无法装配 NumPy,可以通过定义-DWITHOUT_NUMPY关闭该依赖(部分功能将不可用)。从 matplotlibcpp.h 可以看到这一条件编译结构:

#ifndef WITHOUT_NUMPY #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include <numpy/arrayobject.h> #endif // WITHOUT_NUMPY

二、头文件包含与链接选项

matplotlibcpp.h依赖三样东西:Python 头文件Python.h、对应的 Python 库libpython、以及numpy/arrayobject.h。若它们不在标准包含路径中,需要分别用编译器选项-I(头文件路径)、-L(库路径)和-l(库名)指定。关键原则:所有 Python 相关组件必须使用同一 Python 版本(库支持 2.7 与 3.x 两代,但不可混用)。

1. Python 头文件Python.h

该头文件随 Python 安装提供,若系统找不到,应安装 Python 开发包(即上文python3-dev)。头文件位置用-I指定。

常见位置:

  • Linux:/usr/local/include/python3.7
  • Mac(Homebrew 安装):/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/include/python3.7m

2. Python 库libpython*.so

程序必须链接编译好的 Python 库。库名随 Python 版本而异,例如 Python 3.7 对应libpython3.7.so(或libpython3.7m.so),链接时写-lpython3.7(或-lpython3.7m)。

库的搜索路径用-L指定。Linux 系统通常无需额外指定(默认路径已含),Mac 则大多需要:

  • Linux:路径通常已被包含
  • Mac:/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib

3. NumPy 数组头文件numpy/arrayobject.h

默认情况下 Matplotlib for C++ 使用 NumPy 数组,需要该头文件;定义-DWITHOUT_NUMPY可避免此依赖。

常见位置:

  • Linux:/usr/local/lib/python3.7/site-packages/numpy/core/include
  • Mac(Homebrew 安装):与 Linux 相同

4. 从源码安装 Python 时的链接问题

若 Python 不是通过包管理器安装(例如源码编译),链接 libpython 时可能遇到两类问题:

  • Python 库的依赖缺失:通过追加-lpthread -lutil -ldl补全;
  • 动态库未能导出:通过追加-Xlinker -export-dynamic解决。

三、官方编译示例

1. Linux + g++ + C++11(Python 2.7)

# using Python 2.7 g++ main.cpp -std=c++11 -I/usr/local/include/python2.7 \ -I/usr/local/lib/python2.7/site-packages/numpy/core/include -lpython2.7

2. Python 3.7 且不使用 NumPy

# using Python3.7 and no Numpy g++ main.cpp -std=c++11 -DWITHOUT_NUMPY -I/usr/local/include/python2.7 -lpython2.7

(注意:该命令行示例仍以 Python 2.7 的头文件与库为例,核心在于展示-DWITHOUT_NUMPY的用法;若需切换 Python 3.7,只需同步替换-I与-l为对应的 3.7 路径与库名。)

3. Mac + g++ + C++14(Homebrew Python 3.7)

g++ main.cpp -std=c++14 \ -I /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/include/python3.7m \ -I /usr/local/lib/python3.7/site-packages/numpy/core/include \ -L /usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib \ -lpython3.7

4. Linux 下导出动态库并补齐依赖

g++ main.cpp -std=c++11 -I/usr/local/include/python3.7m \ -I/usr/local/lib/python3.7/site-packages/numpy/core/include \ -lpython3.7m \ -lpthread -lutil -ldl \ # library dependencies -Xlinker -export-dynamic \ # export dynamic libraries

四、工程化集成:CMake 与 Make

除了裸g++命令行,仓库还提供了两套工程化构建配置,可直接对照使用。

1. 仓库自带 CMake 支持

仓库根目录的 CMakeLists.txt 展示了官方推荐的 CMake 集成方式:先探测 Eigen3(可选),再强制要求 Python3 的 Interpreter 与 Development 组件,随后探测 NumPy:

find_package(Python3 COMPONENTS Interpreter Development) if (${Python3_FOUND}) include_directories(${Python3_INCLUDE_DIRS}) else() message(FATAL_ERROR "Python3 not found, please install it.") endif() find_package(NumPy) if (${PYTHON_NUMPY_FOUND}) include_directories(${PYTHON_NUMPY_INCLUDE_DIR}) else() message(WARNING "Python3 NumPy not found, proceeding with -DWITHOUT_NUMPY." " Some functions might not work.") add_definitions(-DWITHOUT_NUMPY) endif()

可见:NumPy 缺失时不会编译失败,而是自动退化为-DWITHOUT_NUMPY模式并给出警告。README 中给出的最小 CMake 片段则面向使用者自己的工程:

find_package(PythonLibs 2.7) target_include_directories(myproject PRIVATE ${PYTHON_INCLUDE_DIRS}) target_link_libraries(myproject ${PYTHON_LIBRARIES})

2. Makefile 方式

仓库根目录的 Makefile 把所有编译要素集中为顶层变量,便于按环境修改:

includes = -I /usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/include/python3.7m includes += -I /usr/local/lib/python3.7/site-packages/numpy/core/include includes += -L /usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib linkings = -lpython3.7 definitions = -std=c++11

其中includes(含-I与-L)、linkings(-l)、definitions(C++ 标准)分别对应编译文档中的三类参数,make all会按examples/%.cpp模式规则逐一编译全部示例。

3. 示例工程的 C++ 标准要求

examples/CMakeLists.txt 将每个示例的CMAKE_CXX_STANDARD设为 17,并通过target_link_libraries(${basename} ${Python3_LIBRARIES})完成链接。README 亦说明:C++11 是当前必须满足的最低标准(曾支持 C++98 的提交为717e98e752260245407c5329846f5d62605eff08),因此无论是-std=c++11还是-std=c++14均可正常编译。

五、SensorsCalibration 中的真实集成案例

下面结合仓库源码,看 matplotlib-cpp 如何在标定工程中落地,帮助你验证上文所有链接参数的实际作用。

1. 标定工程的 CMake 集成(Python 2.7)

lidar2car 的 CMakeLists.txt 中,matplotlib 依赖被显式声明:

# Get matplotlib include_directories("/usr/include/python2.7") include_directories(${PROJECT_SOURCE_DIR}/3rdparty/matplotlib-cpp) # ... SET(DEP_LIBS ... python2.7 ...)

对应编译文档的三要素:-I指向 Python 2.7 头文件目录与3rdparty/matplotlib-cpp(使#include "matplotlibcpp.h"可被找到),-l链接python2.7库。这里同样印证了"同一 Python 版本"原则——头文件、库均为 2.7。

2. 源码中的实际绘图调用

在 yawCalib.cpp 中,库以别名方式引入:

#include "matplotlibcpp.h" namespace plt = matplotlibcpp;

加载数据后,直接绘制激光雷达轨迹并保存:

plt::plot(lidar_pose_x_, lidar_pose_y_); plt::savefig(output_dir_ + "trajectory.png"); // plt::show(); plt::close();

标定过程中则叠加多段 B 样条拟合的航向曲线,并开启图例:

plt::plot(sample_yaw.getTableX()[0], sample_yaw.getVectorY(), "k--", {{"label", "trajectory yaw"}}); // ... plt::plot(times, lidar_pose_yaw_, "k-", {{"label", "lidar pose yaw"}}); plt::legend(); plt::savefig(output_dir_ + "compared_yaw.png"); plt::close();

其中"k--"、"k-"即 README 提到的格式化字符串(颜色+线型),{{"label", ...}}以键值对形式传入关键字参数——这正是 matplotlib-cpp 封装 MPL 命令的典型用法。pose_sensor2car 的 yawCalib.cpp 中也有几乎相同的调用模式。

3. 无显示环境(远程/后台)运行

标定程序常运行在无图形界面的服务器或容器中,此时plt::show()会因缺少显示后端而报错。仓库代码 yawCalib.cpp 预留了解决方案:

// plt::backend("Agg"); // plt run in background

取消注释后,matplotlib 将使用Agg无头后端在后台渲染。这对应 matplotlibcpp.h 中解释器初始化流程:Py_SetProgramName与Py_Initialize启动内嵌解释器后,先import matplotlib,若通过plt::backend()设置了后端,则会在首次导入pyplot之前调用matplotlib.use()——这一调用顺序正是 matplotlib 官方要求的。

4. 编译成功后的运行产物

编译并运行run_lidar2car后,可在输出目录得到calib_result.txt、pose.txt、trajectory.png与compared_yaw.png。其中compared_yaw.png展示了标定前后 LiDAR 位姿航向角与 B 样条拟合轨迹航向角的对比,可用于粗略验证标定结果:

六、常见问题速查

结合编译文档、README 与仓库现状,整理高频问题如下:

现象原因与解法
找不到Python.h未安装开发包,执行<package-manager> install python3-dev(或-devel);确认-I指向正确的 include 目录
找不到libpython*.so用-L指定库目录;Mac 上 Homebrew 安装时几乎必须显式指定
链接报 undefined symbol使用源码安装的 Python 时,追加-lpthread -lutil -ldl与-Xlinker -export-dynamic
头文件与库版本不一致所有-I、-L、-l必须对应同一 Python 版本,Python 2.7 与 3.x 不可混用
无法装配 NumPy编译时定义-DWITHOUT_NUMPY,代价是部分依赖数组转换的功能不可用
多线程程序崩溃/行为异常库不是线程安全的(Python 解释器本身非线程安全),并发访问需用 mutex 保护
无显示环境运行报错在首次绘图前调用plt::backend("Agg"),让 matplotlib 在后台渲染

结语

从单条g++命令到 CMake/Make 工程化配置,matplotlib-cpp 的编译核心始终是"让 C++ 找到 Python 头文件、链接上 Python 库、并保证版本一致"。SensorsCalibration 的 lidar2car 与 pose_sensor2car 模块已经给出了可复制的参考实现:头文件目录指到3rdparty/matplotlib-cpp,链接python2.7,无头环境切换Agg后端。按本文梳理的依赖与链接清单,你可以在自己的 C++ 标定或算法工程中快速复现同样的"两行代码出图"体验。

  • 自动驾驶
  • 计算机视觉

【免费下载链接】SensorsCalibration

OpenCalib: A Multi-sensor Calibration Toolbox for Autonomous Driving

项目地址:https://gitcode.com/gh_mirrors/se/SensorsCalibration
点击查看免费下载

相关推荐

上一篇:Ascend C矩阵搬入边界设置
下一篇:WezTerm 完整配置指南:如何 5 分钟上手这款 Rust 编写的 GPU 加速终端

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询