安装 JDK
JetPack 一般不带 JDK,可以先安装 OpenJDK 11:
sudo apt install openjdk-11-jdk
安装 Bazel
针对 MediaPipe 这个项目,需要使用的 Bazel 版本通常取决于当前 MediaPipe 版本指定的 Bazel 版本。更稳妥的做法是优先按照仓库中的 .bazelversion 来安装对应版本。Bazel 版本过低可能缺少构建规则或 API,版本过高也可能因为规则行为变化导致编译失败。
要问 CMake 能不能编,肯定能编,但重写 CMakeLists.txt 的工作量非常大。况且 MediaPipe 作为一个 Google 的开源项目,使用自家的 Bazel 非常合理。
MediaPipe 根目录中的 version.bzl 文件注明了当前项目的版本,我使用的是:
MEDIAPIPE_FULL_VERSION = "0.10.13"
在 .bazelversion 文件中,注明了这个版本的 MediaPipe 使用的 Bazel 版本:
6.1.1
Bazel 的下载链接为 Bazel Release。如果是 x86 架构,可以选择使用 .sh 脚本安装;Jetson 是 ARM 架构,我当时没有找到合适的 .sh 安装包,因此选择源码安装,也就是下载 bazel-6.1.1-dist.zip 这个文件。
下载完成后,解压。解压完成后运行 compile.sh 脚本,等待编译安装完成。
安装完成后修改 ~/.bashrc 文件,加入 Bazel 输出目录。这里的路径需要替换成你自己的 Bazel 编译输出路径:
export PATH=/home/jetson/Documents/Bazel/output:$PATH
然后执行:
source ~/.bashrc
在 Terminal 中输入 bazel 会有一个短暂的初始化过程,之后会显示类似下面的内容:
jetson@ubuntu:~$ bazel
WARNING: Invoking Bazel in batch mode since it is not invoked from within a workspace (below a directory having a WORKSPACE file).
[bazel release 6.1.1- (@non-git)]
这里的 @non-git 不用管,因为我们是源码编译的。自此 Bazel 安装完成。
编译 MediaPipe
先修改 OpenCV 和 FFmpeg 的路径,需要修改的文件为 WORKSPACE 和 third_party 中的 opencv_linux.BUILD。
- WORKSPACE:将 path 改成你的 OpenCV 和 FFmpeg 安装路径。
new_local_repository(
name = "linux_opencv",
build_file = "@//third_party:opencv_linux.BUILD",
path = "/usr/local",
)
new_local_repository(
name = "linux_ffmpeg",
build_file = "@//third_party:ffmpeg_linux.BUILD",
path = "/usr",
)
这里需要注意,linux_ffmpeg 的 path 通常应指向 FFmpeg 的安装前缀,例如 /usr 或 /usr/local,而不是只指向 ffmpeg 命令所在的 /usr/bin。因为 Bazel 的 BUILD 文件需要同时找到头文件和库文件。
- opencv_linux.BUILD:取消注释 ARM 架构对应的 OpenCV 4.x 路径。
cc_library(
name = "opencv",
hdrs = glob([
# For OpenCV 4.x
"include/aarch64-linux-gnu/opencv4/opencv2/cvconfig.h",
#"include/arm-linux-gnueabihf/opencv4/opencv2/cvconfig.h",
#"include/x86_64-linux-gnu/opencv4/opencv2/cvconfig.h",
"include/opencv4/opencv2/**/*.h*",
]),
includes = [
# For OpenCV 4.x
"include/aarch64-linux-gnu/opencv4/",
#"include/arm-linux-gnueabihf/opencv4/",
#"include/x86_64-linux-gnu/opencv4/",
"include/opencv4/",
],
linkopts = [
"-l:libopencv_core.so",
"-l:libopencv_calib3d.so",
"-l:libopencv_features2d.so",
"-l:libopencv_highgui.so",
"-l:libopencv_imgcodecs.so",
"-l:libopencv_imgproc.so",
"-l:libopencv_video.so",
"-l:libopencv_videoio.so",
],
visibility = ["//visibility:public"],
)
可以参考官方文档中的 MediaPipe getting started,先编译一个 Hello World。这个示例编译速度比较快,可以快速验证 Bazel 和 GCC 编译器有没有问题。
我当然遇到问题了,见下面 TroubleShooting 部分。
随后编译 Hand Detection 功能。编译之前,先把 mediapipe/examples/desktop/demo_run_graph_main_gpu.cc 路径中 OpenCV VideoCapture 使用的相机路径改好。
- CPU 版本:
bazel build -c opt --define MEDIAPIPE_DISABLE_GPU=1 mediapipe/examples/desktop/hand_tracking:hand_tracking_cpu
运行:
GLOG_logtostderr=1 bazel-bin/mediapipe/examples/desktop/hand_tracking/hand_tracking_cpu \
--calculator_graph_config_file=mediapipe/graphs/hand_tracking/hand_tracking_desktop_live.pbtxt
- GPU 版本:
bazel build -c opt \
--copt -DMESA_EGL_NO_X11_HEADERS \
--copt -DEGL_NO_X11 \
mediapipe/examples/desktop/hand_tracking:hand_tracking_gpu
运行:
GLOG_logtostderr=1 bazel-bin/mediapipe/examples/desktop/hand_tracking/hand_tracking_gpu \
--calculator_graph_config_file=mediapipe/graphs/hand_tracking/hand_tracking_desktop_live_gpu.pbtxt
运行效果:

然后可以编译 GPU 版 Holistic 检测,命令如下:
bazel build -c opt \
--copt -DMESA_EGL_NO_X11_HEADERS \
--copt -DEGL_NO_X11 \
mediapipe/examples/desktop/holistic_tracking:holistic_tracking_gpu
根据 GitHub 中的一个 Issue,当时 CUDA 的支持范围主要集中在部分 Object Detection 相关功能上,因此 Holistic 示例一般不需要额外启用 CUDA。
运行:
GLOG_logtostderr=1 bazel-bin/mediapipe/examples/desktop/holistic_tracking/holistic_tracking_gpu \
--calculator_graph_config_file=mediapipe/graphs/holistic_tracking/holistic_tracking_gpu.pbtxt
运行效果:

TroubleShooting
- 报错包含 gcc failed
比如我遇到的报错:
ERROR: /home/funnywii/.cache/bazel/_bazel_funnywii/4274885c1bcb543952ac607fcb912a97/external/XNNPACK/BUILD.bazel:2613:19: Compiling src/amalgam/gen/avx512amx.c failed: (Exit 1): gcc failed: error executing command (from target @XNNPACK//:avx512amx_prod_microkernels) /usr/bin/gcc -U_FORTIFY_SOURCE -fstack-protector -Wall -Wunused-but-set-parameter -Wno-free-nonheap-object -fno-omit-frame-pointer -MD -MF ... (remaining 41 arguments skipped)
一大串信息里,关键在于 gcc failed。在我的环境中,Ubuntu 20.04 自带的 GCC 9.4.0 编译某些 XNNPACK 源码时出现了问题,升级到 GCC 10 后解决。
sudo apt-get install gcc-10 g++-10
不建议直接删除 /usr/bin 下的 gcc 和 g++ 软链接,这可能影响系统中其他依赖默认编译器的任务。最好用 update-alternatives 管理多个 gcc 版本:
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100
如果只想让这次 Bazel 编译使用 GCC 10,也可以在构建命令前指定:
CC=/usr/bin/gcc-10 CXX=/usr/bin/g++-10 bazel build ...
可以使用下面的命令查看当前编译器版本:
gcc --version
g++ --version
- 找不到 'stddef.h'、‘stdarg.h'、'stdint.h'
具体报错为:
this rule is missing dependency declarations for the following files included by 'src/raw_logging.cc': '/usr/lib/gcc/x86_64-linux-gnu/9/include/stddef.h' '/usr/lib/gcc/x86_64-linux-gnu/9/include/stdarg.h' '/usr/lib/gcc/x86_64-linux-gnu/9/include/stdint.h'
这是因为先前使用 GCC 9 编译时留下的 Bazel 缓存还在。切换编译器后,需要清理 Bazel 工作环境:
bazel clean --expunge
然后重新编译即可。
- 找不到 face_detection_short_range
具体报错为:
Can't find file: mediapipe/modules/face_detection/face_detection_short_range.tflite
不同 MediaPipe 版本的模型文件路径和下载方式可能会变化。建议优先查看当前 checkout 版本对应的文档或脚本,确认模型文件名和保存目录。
我当时使用的版本缺少这个文件,可以在 MediaPipe models 文档 中下载 Face Detection 的 Short-range model。文件名为 face_detection_short_range.tflite,放在目录 mediapipe/mediapipe/modules/face_detection 下。
将 MediaPipe 编译为库
Python 版本可能还好些,只需要导入 mediapipe 库即可使用,后续改成 ROS 节点或者接入其他通信方式也比较方便。但是 C++ 版本使用 Bazel 编译,因此改成基于 CMake 和 Catkin 的 ROS 工程会比较困难。
因此,如果想把检测结果的 API 暴露出来,最好通过编译为库的方式,在外部 C++ 程序中调用 MediaPipe 库并使用它的检测结果。
这部分工作我暂时还没开始做,先贴几个参考链接:
[1] GoogleMediapipePackageDll:编译为 Windows DLL 库
[2] mediapipe-qt-integration-example:编译为 Ubuntu 上的 Qt 示例
[3] mediapipe_hand_tracking:编译为 macOS 的 SO 库
可以参照上述几个链接,做一下库的编译工作。后面我腾出手来会单独写一篇 Ubuntu 的 SO 库编译的 Blog。
评论