文章目录
最近想要将 mediapipe 中 facemesh 这个功能移植到硬件上,所以第一步是要编译一下 mediapipe,因为 mediapipe 是谷歌出的,自然也是要用 google 的 bazel 编译器进行编译。只是第一次接触,踩的坑有点多,花了将近 3 天的时间才成功地编译。
首先说一下我的系统的是 centos 8,gcc 版本是 8.5,opencv 的版本是 4.1.2。
09/25更新:
如果你是像将 mediapipe 编译成静态库使用到自己的项目里的话,下面就可以不用阅读了,bazel 没办法像 cmake 一样输出你想要的 dll 或者 so 文件,而且也不支持,我看了官方仓库也有人提这个 issue,貌似维护者也说了 google 已经不投入资源在这个项目里了,mediapipe 对 C++ 的支持这么差,属实有些逆天。
后来找到一个别人封装的 C 语言库 libmediapipe,可以编译出各平台所需的头文件和库文件,后续使用这个库文件就不需要再用 bazel 编译了,可以直接用 cmake 编译了。不过里面需要根据自己的环境进行一些调整,也就是还是要进行一轮 bazel 编译,所以还是可以看看这篇文章的。
官网版本建议
Note: To interoperate with OpenCV, OpenCV 3.x to 4.1 are preferred. OpenCV 2.x currently works but interoperability support may be deprecated in the future.
Note: If you plan to use TensorFlow calculators and example apps, there is a known issue with gcc and g++ version 6.3 and 7.3. We recommend installing gcc and g++ version 8.x.
Note: To make Mediapipe work with TensorFlow, please set Python 3.7 as the default Python version and install the Python “six” library by running pip3 install --user six.
bazel 安装
我是按照这篇文章(安装bazelisk)进行安装的,因为不知道为啥,官网的 centos 下的安装指南页面是 404。但是其他系统的安装指南都可以在官网找到。
安装 mediapipe 及其依赖
下载 opencv 和 ffmpeg
opencv 可以用 yum 命令安装,也可以自己源码编译,但是最好版本是要在 3.0 以上,我是之前就源码编译过了。
下载 mediapipe
$ git clone --depth 1 https://github.com/google/mediapipe.git
# Change directory into MediaPipe root directory
$ cd mediapipe
修改编译配置文件
有 3 个文件要进行修改
mediapipe/WORKSPACE
opencv 和 ffmpeg 的 path 改称自己系统的对应路径。
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/local",
)
mediapipe/third_party/opencv_linux.BUILD
按照自己的情况进行修改
cc_library(
name = "opencv",
srcs = glob(
[
"lib/libopencv_core.so",
"lib/libopencv_highgui.so",
"lib/libopencv_imgcodecs.so",
"lib/libopencv_imgproc.so",
"lib/libopencv_video.so",
"lib/libopencv_videoio.so",
],
),
hdrs = glob([
# For OpenCV 3.x
"include/opencv2/**/*.h*",
# For OpenCV 4.x
# "include/opencv4/opencv2/**/*.h*",
]),
includes = [
# For OpenCV 3.x
"include/",
# For OpenCV 4.x
# "include/opencv4/",
],
linkstatic = 1,
visibility = ["//visibility:public"],
)
mediapipe/third_party/ffmpeg_linux.BUILD
也是按照自己的情况修改。
cc_library(
name = "libffmpeg",
srcs = glob(
[
"lib/libav*.so",
],
),
hdrs = glob(["include/libav*/*.h"]),
includes = ["include"],
linkopts = [
"-lavcodec",
"-lavformat",
"-lavutil",
],
linkstatic = 1,
visibility = ["//visibility:public"],
)
编译命令
$ export GLOG_logtostderr=1
# Need bazel flag 'MEDIAPIPE_DISABLE_GPU=1' if you are running on Linux desktop with CPU only
$ bazel run --define MEDIAPIPE_DISABLE_GPU=1 \
mediapipe/examples/desktop/hello_world:hello_world
# Should print:
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
# Hello World!
踩坑记录
上面的自然是顺利的情况下的整个流程,但是到了自己上手的时候哪有这么顺利(悲)。下面就说一下我遇到的问题。
依赖库下载 timeout
就是一些依赖没有下载成功,如果没有科学上网的话,多运行几次,总能下载完成。
numpy 找不到
ModuleNotFoundError: No module named 'numpy'
Is numpy installed?
这是没有找到 numpy,因为是根据 python 的路径来寻找 numpy 的,所以可以指定 python 的路径来解决这个问题。
whereis python
获得 python 的路径之后,加上选项 --action_env PYTHON_BIN_PATH="path to python bin"
来进行编译,就不会再提示这个错误了。
gcc permission denied / linux-sandbox failed
这个是困扰我最久的问题,每次编译到一定程度,就会显示:
gcc: error: mediapipe/framework/<filename>.cc: Permission denied
gcc: fatal error: no input files
虽然这一看就是权限问题,但是我还是走了很多歪路:
- 可能是 gcc 在 root 和 user 的权限不一样,其实两个环境下都可以运行 gcc
- 可能是 linux 的沙盒屏蔽了对某些文件的读写,导致失败,禁用了沙盒,其实也没用
- 可能是 bazel 命令没有使用 sudo 运行,但是用 sudo 运行结果也一样
- 可能是没有清理 bazel 缓存的影响,使用
bazel clean --expunge
清理了也一样 - 也将打印出来无法写入的文件使用
chmod -R 777
给了读写的权限,但是还是不行 - 以为是依赖项目没有链接成功,又重新源码编译了 abseil 和 protobuf,但是还是不行
上面都尝试过多次之后,感觉很绝望,于是去 github 上提 issue。
结果突然好像灵光一闪,比对了了一下 root 和 user 下的 ~/.bashrc 文件内的内容,发现两个的系统路径和库路径是不太一样的,user 下的很多路径都没有加上去。于是都加上去, source 一下生效。
然后再在 user 下使用
export GLOG_logtostderr=1 && bazel build mediapipe/examples/desktop/face_mesh:face_mesh_cpu --action_env PYTHON_BIN_PATH="/home/cai/anaconda3/envs/yolov8/bin/python3.8" --verbose_failures --sandbox_debug -c opt --define MEDIAPIPE_DISABLE_GPU=1
编译一下,顺利的完成了编译,卡了三天的编译终于顺利解决了。
编译tensorflow的时候出错
这是我编译 libmediapipe 出现的,其中的 shell 文件也调用了 bazel 进行编译,出现这个错误之后,我将 bazel 的编译模式改称 -c opt
之后就顺利完成了。