项目链接:SAMLabeler-MNN 个人开源主页:地址
本文档面向需要在 Linux 上编译、运行和使用 SAMLabeler-MNN 的开发者与标注 人员。内容包括环境准备、MNN 路径配置、编译与测试、标注流程、项目输出,以及常见 配置、链接和运行问题的排查方法。
本文命令默认在项目根目录执行。当前项目根目录示例为:
/path/to/SAMLabeler-MNN
为便于迁移,正文优先使用相对路径和 /path/to/… 占位符。
1. 项目简介
SAMLabeler-MNN 是一个基于 C++11、Qt 5、OpenCV、MNN 和 MobileSAM vit_t 的 本地半自动化交互标注工具,主要用于制作语义分割和实例分割标注。
当前主要能力:
- 正点、负点和矩形框 Prompt;
- 多类别及自定义显示颜色;
- 同图、同类别下的顺序实例标注;
- 已确认实例的重新编辑和删除;
- 从模型 mask 转换为 Polygon 后精调边界;
- 语义 mask、实例 mask、类别映射和可恢复编辑状态保存;
- 独立的 C++/OpenCV/MNN 后端和兼容 OpenCV 示例。
当前没有实现 Pascal VOC、COCO、YOLO Segmentation 等通用数据集格式的直接导入 或导出。项目目录中的 PNG、JSON 和状态文件是 SAMLabeler-MNN 当前的项目格式。
2. 目录和主要目标
常用目录:
SAMLabeler-MNN/
├── app/ # Qt 界面
├── include/ # 公共 C++ 头文件
├── src/ # MNN 后端和标注业务实现
├── tests/ # 自动测试
├── examples/ # 原 OpenCV 交互示例
├── data/models/ # 默认 MobileSAM MNN 模型
├── demo/ # README 演示图片
├── docs/ # 使用文档
└── CMakeLists.txt
CMake 主要目标:
| SAMLabeler-MNN | Qt 标注应用程序 |
| MobileSamCore | MobileSAM/MNN 后端静态库 |
| AnnotationDomain | 标注业务静态库 |
| InteractiveSegmenter | MobileSamCore 的兼容别名 |
| TestInteractiveSegmenter | OpenCV 单图交互示例 |
| TestMobileSamBackend | MobileSAM 后端真实模型测试 |
| TestAnnotationSession | 标注项目和持久化测试 |
3. 编译依赖
最低或当前约束:
| C++ 编译器 | 支持 C++11 |
| CMake | 3.10 或更高 |
| Ninja | 推荐;也可使用其他 CMake 生成器 |
| Qt | 5.15,组件为 Core、Gui、Widgets |
| OpenCV | 4.x,组件为 core、imgproc、imgcodecs、highgui |
| MNN | 兼容 3.3.x 的头文件和共享库 libMNN.so |
| 模型 | MobileSAM vit_t encoder 和 decoder 的 MNN 文件 |
3.1 环境检查
cmake –version
ninja –version
c++ –version
pkg-config –modversion opencv4
pkg-config –modversion Qt5Core
pkg-config 查不到 Qt 并不一定表示 Qt 不存在;CMake 也可能通过 Qt5Config.cmake 找到它。最终应以 CMake 配置结果为准。
检查默认模型:
test -f data/models/mobile_sam_encoder.mnn && echo "encoder OK"
test -f data/models/mobile_sam_decoder.mnn && echo "decoder OK"
检查外部 MNN:
test -f /path/to/MNN/include/MNN/Interpreter.hpp && echo "MNN headers OK"
test -f /path/to/MNN/build/libMNN.so && echo "MNN library OK"
3.2 Ubuntu/Debian 依赖示例
以下命令仅是常见 Ubuntu/Debian 环境的参考,请先根据系统版本审核包名,再由用户 手动执行:
sudo apt update
sudo apt install build-essential cmake ninja-build pkg-config \\
qtbase5-dev libopencv-dev
MNN 不由本项目自动下载或编译。请准备与项目兼容的 MNN 源码头文件和已构建的 libMNN.so,然后通过 CMake 参数提供路径。
4. 配置和编译
4.1 推荐构建命令
进入项目根目录:
cd /home/panguofeng/pgf_ai_deploy/SAMLabeler-MNN
配置:
cmake -S . -B build-qt -G Ninja \\
-DMNN_ROOT=/path/to/MNN \\
-DMNN_LIBRARY=/path/to/MNN/build/libMNN.so
编译:
cmake –build build-qt
成功后应生成:
build-qt/SAMLabeler-MNN
build-qt/TestInteractiveSegmenter
build-qt/TestMobileSamBackend
build-qt/TestAnnotationSession
只编译 Qt 应用:
cmake –build build-qt –target SAMLabeler-MNN
4.2 使用项目默认 MNN 路径
当前 CMakeLists.txt 的默认值是:
MNN_ROOT=/home/panguofeng/project/MNN
MNN_LIBRARY=/home/panguofeng/project/MNN/build/libMNN.so
如果这两个路径在当前机器上有效,可以简化为:
cmake -S . -B build-qt -G Ninja
cmake –build build-qt
在其他机器上不应依赖这个开发者路径,应显式传入实际位置。
4.3 严格警告编译
建议开发或提交前在独立构建目录执行:
cmake -S . -B build-strict -G Ninja \\
-DCMAKE_CXX_FLAGS="-Wall -Wextra -Wpedantic" \\
-DMNN_ROOT=/path/to/MNN \\
-DMNN_LIBRARY=/path/to/MNN/build/libMNN.so
cmake –build build-strict
独立目录可避免严格选项与日常构建缓存互相影响。
4.4 Debug 或 Release 构建
单配置生成器(如 Ninja)可使用:
cmake -S . -B build-release -G Ninja \\
-DCMAKE_BUILD_TYPE=Release \\
-DMNN_ROOT=/path/to/MNN \\
-DMNN_LIBRARY=/path/to/MNN/build/libMNN.so
cmake –build build-release
调试时将 Release 改为 Debug。
5. 运行程序
5.1 使用仓库内默认模型
程序默认从当前工作目录读取:
data/models/mobile_sam_encoder.mnn
data/models/mobile_sam_decoder.mnn
因此应从项目根目录运行:
./build-qt/SAMLabeler-MNN
5.2 显式指定模型
./build-qt/SAMLabeler-MNN \\
/path/to/mobile_sam_encoder.mnn \\
/path/to/mobile_sam_decoder.mnn
必须同时提供 encoder 和 decoder。面向用户的正常启动形式只有:
SAMLabeler-MNN
SAMLabeler-MNN <encoder.mnn> <decoder.mnn>
5.3 动态库搜索路径
Linux 构建会把配置时 MNN_LIBRARY 所在目录写入构建产物的 RUNPATH。可检查:
readelf -d build-qt/SAMLabeler-MNN | grep -E 'RPATH|RUNPATH'
ldd build-qt/SAMLabeler-MNN | grep -E 'MNN|not found'
如果移动了 MNN 库或二进制文件,可以重新配置构建,或临时指定:
export LD_LIBRARY_PATH=/path/to/MNN/build:${LD_LIBRARY_PATH}
./build-qt/SAMLabeler-MNN
6. 标注操作流程
6.1 选择目录
界面中的两个目录相互独立:
- 选择图像文件夹:读取待标注图片,不把项目文件写入源图片目录;
- 选择标注文件夹:加载或保存 SAMLabeler-MNN 项目。
支持大小写不敏感的 PNG、JPG/JPEG、BMP、TIF/TIFF。两个目录的选择顺序不受 限制。更换目录前如有未保存修改,程序会请求确认。
6.2 创建类别
类别 ID 是稳定的正整数。删除类别会同时删除该类别在所有图片中的标注状态,操作前 应确认项目已正确备份或保存。
6.3 使用 Prompt 生成 mask
- 正点:标记目标内部,decoder label 为 1;
- 负点:标记不属于目标的区域,decoder label 为 0;
- 矩形框:拖动目标包围框,两个角分别使用 label 2 和 3。
当前 decoder 使用固定 8 槽位输入:
- 一个点占 1 个槽位;
- 一个矩形框占 2 个槽位;
- 容量不足时当前请求会被拒绝,不会覆盖已有 mask 和 feedback。
同一图片的不同类别、不同实例各自保存 Prompt、mask 和 decoder feedback,不会相互 复用编辑状态。
6.4 顺序实例标注
实例 ID 在单张图片内从 1 单调递增,0 表示背景,删除后的 ID 不复用。已确认实例 不能直接追加 Prompt;应先点击“重新编辑”。“重置当前实例”只清空当前编辑实例。
6.5 Polygon 精调
模型生成有效 mask 后,可以进入“Polygon 精调”:
- 拖动顶点改变边界;
- 双击轮廓边插入顶点;
- 删除选中顶点,但每个 ring 至少保留 3 个点;
- 删除轮廓时,关联孔洞也会一起处理;
- 外轮廓和孔洞分别显示,坐标保存为相对原图的归一化值。
Polygon 模式下点和矩形框工具被禁用,避免模型推理覆盖人工边界。退出 Polygon 模式时,界面可能提示是否放弃 Polygon 修改并返回模型 mask,请根据需要确认。
6.6 缩放和平移
- Ctrl + 鼠标滚轮:以光标为中心缩放;
- 鼠标中键拖动:平移;
- “适应窗口”:显示完整图片;
- “100%”:按原始像素比例显示。
7. 保存结果和项目恢复
选择标注文件夹后点击“保存标注”,输出结构如下:
<annotation-directory>/
├── project.json
├── categories.json
├── masks/
│ └── <image>.png
├── instances/
│ ├── <image>.png
│ └── <image>.json
└── states/
└── g<generation>/
├── categories.json
└── <image-key>/instance-<id>.yml.gz
文件含义:
- project.json:项目清单、图片信息、实例映射和状态路径;
- categories.json:类别 ID、名称及 RGB 颜色;
- masks/*.png:与原图同尺寸的单通道 16 位语义 mask,像素值为类别 ID;
- instances/*.png:单通道 16 位实例 mask,像素值为图片内实例 ID;
- instances/*.json:实例 ID 与类别及状态文件的映射;
- states/:Prompt、decoder feedback、模型 mask、Polygon 和编辑生命周期状态。
只有人工确认的实例进入正式语义/实例 mask;未确认草稿仍会保存在项目状态中,便于 下次继续编辑。每次保存创建新的 generation,并在状态写入完成后更新项目清单。
8. 测试和验证
8.1 运行 CTest
ctest –test-dir build-qt –output-on-failure
当前应运行:
- MobileSamBackend:使用仓库内真实 encoder/decoder 模型;
- AnnotationSession:验证文件夹、类别、实例和项目持久化。
查看测试列表:
ctest –test-dir build-qt -N
8.2 Qt 启动冒烟测试
在无桌面的 CI 或远程终端中可使用 Qt offscreen 平台,程序会在指定毫秒数后退出:
QT_QPA_PLATFORM=offscreen \\
./build-qt/SAMLabeler-MNN –smoke-test-ms 1500
该测试会加载默认模型,因此必须从项目根目录运行并确保模型存在。offscreen 插件 可能输出不支持某些窗口提示能力的警告;只要程序成功启动并按时返回,通常不表示 应用逻辑失败。
8.3 检查文本和改动
开发修改后可执行:
git diff –check
git status –short
提交前应特别确认没有误加入构建目录、模型、用户图片、mask 或标注状态。
9. 编译和运行问题解决
排查问题时建议先保留完整的 CMake/编译输出,并记录所用的 MNN、Qt、OpenCV、 编译器和构建目录。不要只截取最后一行错误。
9.1 MNN headers were not found
典型错误:
MNN headers were not found under …/include
原因:MNN_ROOT/include/MNN/Interpreter.hpp 不存在,或 MNN_ROOT 指向了错误层级。
检查:
ls -l /path/to/MNN/include/MNN/Interpreter.hpp
解决:
cmake -S . -B build-qt -G Ninja \\
-DMNN_ROOT=/correct/path/to/MNN \\
-DMNN_LIBRARY=/correct/path/to/MNN/build/libMNN.so
MNN_ROOT 应指向包含 include/MNN/Interpreter.hpp 的 MNN 根目录,而不是 include/ 本身。
9.2 MNN runtime library was not found
典型错误:
MNN runtime library was not found at …/libMNN.so
原因:MNN 尚未生成共享库、库位于其他目录,或缓存中仍保存旧路径。
检查:
find /path/to/MNN -name 'libMNN.so' -type f
把找到的真实文件传给 MNN_LIBRARY:
cmake -S . -B build-qt \\
-DMNN_ROOT=/path/to/MNN \\
-DMNN_LIBRARY=/actual/path/libMNN.so
9.3 CMake 仍使用旧的 MNN 路径
原因:MNN_ROOT 和 MNN_LIBRARY 是 CMake Cache 变量,已有构建目录会记住首次 配置值。
先查看缓存:
grep -E '^(MNN_ROOT|MNN_LIBRARY):' build-qt/CMakeCache.txt
直接用新值重新配置通常即可:
cmake -S . -B build-qt \\
-DMNN_ROOT=/new/path/to/MNN \\
-DMNN_LIBRARY=/new/path/to/MNN/build/libMNN.so
如果构建目录混入了不同生成器或完全不同环境,建议保留旧目录用于检查,改用新的 构建目录,例如 build-qt-new,而不是直接删除尚未确认用途的目录。
9.4 Could not find Qt5 或缺少 Qt Widgets
典型信息:
Could not find a package configuration file provided by "Qt5"
检查 Qt 配置文件:
find /usr /opt -name Qt5Config.cmake 2>/dev/null | head
如果 Qt 安装在自定义位置,设置:
cmake -S . -B build-qt -G Ninja \\
-DCMAKE_PREFIX_PATH=/path/to/Qt/5.15/gcc_64 \\
-DMNN_ROOT=/path/to/MNN \\
-DMNN_LIBRARY=/path/to/MNN/build/libMNN.so
也可设置 Qt5_DIR 指向包含 Qt5Config.cmake 的目录。必须安装 Qt 的开发包,而 不只是运行库。
9.5 Could not find OpenCV 或版本低于 4
检查:
pkg-config –modversion opencv4
find /usr /opt -name OpenCVConfig.cmake 2>/dev/null | head
自定义 OpenCV 安装可指定:
cmake -S . -B build-qt \\
-DOpenCV_DIR=/path/to/opencv/lib/cmake/opencv4 \\
-DMNN_ROOT=/path/to/MNN \\
-DMNN_LIBRARY=/path/to/MNN/build/libMNN.so
项目要求 OpenCV 4 的 core、imgproc、imgcodecs 和 highgui 组件,缺少开发头文件或 组件库都会导致配置或链接失败。
9.6 ninja: command not found
原因:使用了 -G Ninja,但系统未安装 Ninja 或不在 PATH。
检查:
command -v ninja
可以安装 Ninja,或改用系统可用的生成器:
cmake -S . -B build-make \\
-DMNN_ROOT=/path/to/MNN \\
-DMNN_LIBRARY=/path/to/MNN/build/libMNN.so
cmake –build build-make
不要在同一个构建目录中切换生成器;请使用新的构建目录。
9.7 编译器不支持 C++11
典型表现为无法识别 C++11 语法,或 CMake 报告 C++ 标准能力不足。
检查:
c++ –version
cmake –build build-qt –verbose
安装或选择支持 C++11 的 GCC/Clang,并在首次配置新构建目录时指定:
CC=/path/to/gcc CXX=/path/to/g++ \\
cmake -S . -B build-qt-gcc -G Ninja \\
-DMNN_ROOT=/path/to/MNN \\
-DMNN_LIBRARY=/path/to/MNN/build/libMNN.so
编译器应与外部 MNN 库的 ABI 兼容。
9.8 链接阶段出现 MNN 未定义符号
可能原因:
- MNN 头文件和 libMNN.so 来自不同版本;
- MNN 的编译器 ABI、架构或构建选项不兼容;
- MNN_LIBRARY 指向了错误的同名库。
检查:
file /path/to/MNN/build/libMNN.so
file build-qt/SAMLabeler-MNN
ldd /path/to/MNN/build/libMNN.so
确保头文件与库来自同一 MNN 源码树和同一次兼容构建。修改后在新的项目构建目录中 重新配置,避免旧对象文件干扰。
9.9 运行时报 libMNN.so: cannot open shared object file
检查动态链接:
ldd build-qt/SAMLabeler-MNN | grep -E 'MNN|not found'
readelf -d build-qt/SAMLabeler-MNN | grep -E 'RPATH|RUNPATH'
优先重新配置到正确的 MNN_LIBRARY 并重新链接。临时运行可使用:
LD_LIBRARY_PATH=/path/to/MNN/build:${LD_LIBRARY_PATH} \\
./build-qt/SAMLabeler-MNN
不要把来源不明或版本不匹配的 libMNN.so 复制到系统库目录。
9.10 程序提示“模型不存在”
无参数启动时,模型路径相对于当前工作目录,而不是相对于可执行文件。
检查:
pwd
ls -lh data/models/mobile_sam_encoder.mnn \\
data/models/mobile_sam_decoder.mnn
从项目根目录启动,或显式传入两个绝对路径:
./build-qt/SAMLabeler-MNN /abs/path/encoder.mnn /abs/path/decoder.mnn
9.11 模型存在但加载失败
可能原因:
- 模型不是项目要求的 MobileSAM vit_t MNN encoder/decoder;
- MNN 运行时与模型版本不兼容;
- 模型损坏或 encoder/decoder 顺序传反;
- decoder 不符合静态 8 Prompt 槽位契约。
检查文件大小和校验值,并确认来源:
ls -lh /path/to/encoder.mnn /path/to/decoder.mnn
sha256sum /path/to/encoder.mnn /path/to/decoder.mnn
再运行后端测试获得更明确的契约错误:
ctest –test-dir build-qt -R MobileSamBackend –output-on-failure
9.12 Qt 报 could not connect to display
原因:当前终端没有可用的 X11/Wayland 显示环境,常见于 SSH、容器和 CI。
只做启动测试:
QT_QPA_PLATFORM=offscreen \\
./build-qt/SAMLabeler-MNN –smoke-test-ms 1500
需要人工操作 GUI 时,应在有桌面会话的终端运行,或正确配置 SSH X11 转发。不要把 offscreen 模式用于实际交互标注。
9.13 Qt 平台插件 xcb 无法初始化
典型信息:
Could not load the Qt platform plugin "xcb"
检查插件搜索过程:
QT_DEBUG_PLUGINS=1 ./build-qt/SAMLabeler-MNN
检查 Qt 插件依赖:
find /usr -name libqxcb.so 2>/dev/null | head
ldd /path/to/libqxcb.so | grep 'not found'
根据缺失库安装与当前 Qt 版本匹配的系统依赖,避免混用系统 Qt、Conda Qt 和自定义 Qt 的插件目录。必要时检查并清理当前 shell 中错误的 QT_PLUGIN_PATH,但应先记录 其原值。
9.14 编译进程被 Killed 或内存不足
原因通常是并行编译占用过多内存。
限制并行度:
cmake –build build-qt –parallel 1
确认是否由 OOM 引起:
dmesg | tail -n 50
free -h
也可关闭其他高内存程序,或在资源更充足的机器上构建。
9.15 修改代码后界面或行为没有变化
检查实际运行的是哪个二进制:
realpath build-qt/SAMLabeler-MNN
stat build-qt/SAMLabeler-MNN
cmake –build build-qt –verbose
确认当前源码目录和构建目录匹配:
grep '^SAMLabeler-MNN_SOURCE_DIR:' build-qt/CMakeCache.txt
项目移动后,旧构建目录可能仍引用旧绝对路径。此时应在新项目路径创建新的构建目录 并重新配置。
9.16 CTest 找不到测试或测试使用错误模型
先确认配置和测试列表:
ctest –test-dir build-qt -N
grep '^SAMLabeler-MNN_SOURCE_DIR:' build-qt/CMakeCache.txt
测试中的模型路径在 CMake 配置时由源码目录生成。项目移动后应重新运行 CMake, 最好使用新构建目录,确保测试引用当前仓库的 data/models/。
9.17 图片目录为空或图片没有出现
确认目录包含受支持扩展名:PNG、JPG/JPEG、BMP、TIF/TIFF,并检查当前用户有读取 权限:
find /path/to/images -maxdepth 1 -type f | head
namei -l /path/to/images
图像文件夹只负责源图片;如果误选标注输出目录,列表可能没有可识别的源图。
9.18 保存失败或项目无法恢复
检查:
- 标注文件夹是否已选择;
- 当前用户是否有目录写权限;
- 磁盘空间和 inode 是否充足;
- project.json、categories.json 与 states/ 是否来自同一个项目保存过程;
- 源图片文件名和尺寸是否被外部修改。
诊断命令:
df -h /path/to/annotation-directory
df -i /path/to/annotation-directory
namei -l /path/to/annotation-directory
不要手工只移动 project.json 而遗漏其引用的 states/ 文件。迁移项目时应整体复制 标注文件夹,并保留相对目录结构。
10. 问题报告建议
提交问题时建议附上:
请勿上传包含隐私的原始图片、业务标注、模型权重或本机凭据。必要时使用可公开的 最小复现数据,并对绝对路径和用户名做脱敏处理。





