- 自动驾驶
- 计算机视觉
【免费下载链接】SensorsCalibration
OpenCalib: A Multi-sensor Calibration Toolbox for Autonomous Driving
本文以 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.72. 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.74. 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
相关推荐
matplotlib-cpp 实战指南:在 SensorsCalibration 多传感器标定中用 C++ 直接驱动 matplotlib 绘图
matplotlib cpp 实战指南:在 SensorsCalibration 多传感器标定中用 C++ 直接驱动 matplotlib 绘图 matplot
自动驾驶计算机视觉ComfyUI-LTXVideo终极指南:3步安装LTX-2视频生成模型
ComfyUI LTXVideo终极指南:3步安装LTX 2视频生成模型 ComfyUI LTXVideo是专为ComfyUI平台设计的强大AI视频生成插件,让
人工智能大模型AI 应用媒体生成本地部署仓颉 stdx 源码依赖集成指南:三种依赖方式、OpenHarmony 交叉编译与 FFI 链接配置
仓颉 stdx 源码依赖集成指南:三种依赖方式、OpenHarmony 交叉编译与 FFI 链接配置 本篇指南以仓库文档 doc/libs_stdx/sourc
标准库网络密码学并发编程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考