📝 场景描述
在 Ascend 310B4 部署中,为了追求极致的运行效率和环境纯净度,我们采用“PC 端交叉编译、板端直接运行”的模式。本文将演示如何使用 aarch64-target-linux-gnu 工具链定制 OpenCV 库,并在 Jupyter Lab 中直接加载 .om 模型完成姿态检测任务。
🛠️ 第一步:获取 OpenCV 源码(国内高速镜像)
针对 GitHub 访问不畅的问题,我们使用 GitCode 镜像。
# 进入工作目录
cd /mnt/d/work/Ascend/
# 使用 GitCode 高速下载 OpenCV 源码
git clone https://gitcode.com/opencv/opencv.git
cd opencv
# 切换到稳定的 4.5.4 版本
git checkout 4.5.4
# 创建构建目录
mkdir build && cd build

⚙️ 第二步:核心配置(PC 交叉编译魔法)
我们需要将编译器指向图片中的 aarch64-target-linux-gnu 工具链。这一步的关键是精简模块,只保留核心视觉功能。
# 1. 设置工具链根目录 (根据您的 D 盘路径映射)
export TOOLCHAIN_HOME=/mnt/d/work/Ascend/CANN/toolchain
export PATH=$TOOLCHAIN_HOME/bin:$PATH
# 2. 执行 CMake 交叉编译配置
cmake .. \
-DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
-DCMAKE_C_COMPILER=aarch64-target-linux-gnu-gcc \
-DCMAKE_CXX_COMPILER=aarch64-target-linux-gnu-g++ \
-DCMAKE_FIND_ROOT_PATH=$TOOLCHAIN_HOME/sysroot \
-DCMAKE_INSTALL_PREFIX=./install \
-DBUILD_opencv_world=ON \
-DBUILD_SHARED_LIBS=ON \
-DWITH_GTK=OFF \
-DWITH_QT=OFF \
-DBUILD_EXAMPLES=OFF \
-DBUILD_TESTS=OFF \
-DBUILD_PERF_TESTS=OFF \
-DWITH_IPP=OFF \
-DVIDEOIO_ENABLE_PLUGINS=OFF

💡 配置解析: BUILD_opencv_world 将所有库合并为一个 .so,极大简化了后续在板子上的库挂载。
🔨 第三步:编译与同步
在 PC 上利用多核优势快速完成编译:
# 编译
make -j8
# 将编译好的头文件和库提取到 install 文件夹
make install
# 将生成的 install 文件夹打包
tar -czvf opencv_arm64.tar.gz install/



opencv_arm64.tar.gz 拷贝到 310B4 开发板的 ~/userdata/ 目录下。🚀 第四步:开发板项目构建与一键部署
在 PC 端交叉编译完成后,我们得到的是一个 opencv_arm64.tar.gz。为了实现“解压即用”,我们需要在板子上进行一次标准化的目录对齐。
1. 准备工作:解压与目录对齐
首先,将压缩包上传至板子的 ~/userdata/(即 /root/userdata/)目录下,然后执行以下指令:
# 进入工作目录
cd /root/userdata/
# 创建项目根文件夹
mkdir -p yolo26
# 将压缩包解压到指定位置(重点:将 install 改名为 opencv_install 保持结构清晰)
tar -zxvf opencv_arm64.tar.gz -C ./yolo26/
mv ./yolo26/install ./yolo26/opencv_install
# 创建其他必要文件夹
mkdir -p /root/userdata/yolo26/{model,scripts}
/root/userdata/yolo26/
├── model/
│ └── yolo26s-pose_aipp.om # 第一阶段生成的模型文件
├── opencv_install/ # PC端交叉编译出来的 install 文件夹
│ ├── include/
│ └── lib/ # 存放 libopencv_world.so
├── scripts/
│ └── pose_inference.py # 核心 Python 推理逻辑
├── test.jpg # 测试图片
├── start_jupyter.sh # 自动化启动脚本
└── yolo26_demo.ipynb # Jupyter Notebook 演示文件
2. 编写一键启动脚本 (start_jupyter.sh)
在嵌入式端手动配路径非常麻烦。编写此脚本可以自动挂载你交叉编译的 OpenCV 库并启动服务:
cat << 'EOF' > /root/userdata/yolo26/start_jupyter.sh
#!/bin/bash
# 自动定位项目根目录
PROJECT_DIR=$(cd $(dirname $0); pwd)
cd $PROJECT_DIR
echo "--- 正在初始化 yolo26 开发环境 ---"
# 1. 挂载交叉编译的 OpenCV 库
export LD_LIBRARY_PATH=$PROJECT_DIR/opencv_install/lib:$LD_LIBRARY_PATH
# 2. 激活昇腾 CANN 环境变量
if [ -f "/usr/local/Ascend/ascend-toolkit/set_env.sh" ]; then
source /usr/local/Ascend/ascend-toolkit/set_env.sh
fi
echo " 环境初始化完成,准备启动 Jupyter Lab..."
# 3. 启动服务 (允许远程 IP 访问)
jupyter lab --ip=0.0.0.0 --allow-root --no-browser --port=8888 --notebook-dir=$PROJECT_DIR
EOF
🚀 第五步:远程调试与推理验证
1. 启动服务
在开发板终端执行以下命令:
chmod +x /root/userdata/yolo26/start_jupyter.sh
./root/userdata/yolo26/start_jupyter.sh

此时终端会显示一个带有 token 的链接,记录下这个 token。
2. PC 端浏览器访问
打开 Windows 浏览器,输入:http://[开发板IP]:8888,输入 token 登录。
比如 http://127.0.0.1:8888/lab?token=fd1abf93ab3608181dd043c11777b67566938ab34aa65de3
就是输入 http://192.168.137.100:8888/lab?token=fd1abf93ab3608181dd043c11777b67566938ab34aa65de3
3. 编写 Notebook 推理代码
在 yolo26_demo.ipynb 中运行以下代码,验证 NPU 推理与定制化 OpenCV 的联动:
import acl
import cv2
import numpy as np
import matplotlib.pyplot as plt
import os
# ================= 1. 环境初始化 =================
ret = acl.init()
acl.rt.set_device(0)
context, _ = acl.rt.create_context(0)
current_dir = os.getcwd()
MODEL_PATH = os.path.join(current_dir, "model/yolo26s-pose.om")
model_id, ret = acl.mdl.load_from_file(MODEL_PATH)
model_desc = acl.mdl.create_desc()
acl.mdl.get_desc(model_desc, model_id)
# ================= 2. 预处理 =================
frame = cv2.imread("test.jpg")
h, w = frame.shape[:2]
ratio = min(640/w, 640/h)
new_w, new_h = int(w * ratio), int(h * ratio)
resized = cv2.resize(frame, (new_w, new_h))
canvas = np.full((640, 640, 3), 114, dtype=np.uint8)
pad_w, pad_h = (640 - new_w) // 2, (640 - new_h) // 2
canvas[pad_h:pad_h+new_h, pad_w:pad_w+new_w] = resized
# 归一化与维度转置
img = cv2.cvtColor(canvas, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0
img = np.ascontiguousarray(img.transpose(2, 0, 1))
input_bytes = img.tobytes()
input_size = len(input_bytes)
# ================= 3. NPU 推理 =================
dev_ptr_in, _ = acl.rt.malloc(input_size, 0)
acl.rt.memcpy(dev_ptr_in, input_size, acl.util.bytes_to_ptr(input_bytes), input_size, 1)
dataset_in = acl.mdl.create_dataset()
acl.mdl.add_dataset_buffer(dataset_in, acl.create_data_buffer(dev_ptr_in, input_size))
out_size = acl.mdl.get_output_size_by_index(model_desc, 0)
dev_ptr_out, _ = acl.rt.malloc(out_size, 0)
dataset_out = acl.mdl.create_dataset()
acl.mdl.add_dataset_buffer(dataset_out, acl.create_data_buffer(dev_ptr_out, out_size))
acl.mdl.execute(model_id, dataset_in, dataset_out)
host_ptr_out, _ = acl.rt.malloc_host(out_size)
acl.rt.memcpy(host_ptr_out, out_size, dev_ptr_out, out_size, 2)
output_array = np.frombuffer(acl.util.ptr_to_bytes(host_ptr_out, out_size), dtype=np.float32)
# ================= 4. 骨架连线与渲染 =================
if output_array.size > 0:
output = output_array.reshape(300, -1)
valid_poses = output[output[:, 4] > 0.3]
display_img = canvas.copy()
# 定义 COCO 17点骨架连接关系
SKELETON = [[16, 14], [14, 12], [17, 15], [15, 13], [12, 13], [6, 12], [7, 13], [6, 7],
[6, 8], [7, 9], [8, 10], [9, 11], [2, 3], [1, 2], [1, 3], [2, 4], [3, 5], [4, 6], [5, 7]]
for person in valid_poses:
offset = 6 if output.shape[1] == 57 else 5
kpts_flat = person[offset : offset + 51]
kpts = [[kpts_flat[i*3], kpts_flat[i*3+1], kpts_flat[i*3+2]] for i in range(17)]
# 1. 绘制骨架连线 (关键补全)
for conn in SKELETON:
i1, i2 = conn[0]-1, conn[1]-1
if kpts[i1][2] > 0.5 and kpts[i2][2] > 0.5:
pt1 = (int(kpts[i1][0]), int(kpts[i1][1]))
pt2 = (int(kpts[i2][0]), int(kpts[i2][1]))
cv2.line(display_img, pt1, pt2, (0, 255, 0), 2)
# 2. 绘制关键点圆点
for kp in kpts:
if kp[2] > 0.5:
cv2.circle(display_img, (int(kp[0]), int(kp[1])), 4, (0, 255, 255), -1)
plt.figure(figsize=(8, 8))
plt.imshow(cv2.cvtColor(display_img, cv2.COLOR_BGR2RGB))
plt.title(f"Pose Estimation Result (Detected: {len(valid_poses)})")
plt.show()
# ================= 5. 资源释放 =================
acl.rt.free(dev_ptr_in)
acl.rt.free(dev_ptr_out)
acl.rt.free_host(host_ptr_out)
acl.mdl.unload(model_id)
print("渲染完成")

🚀 总结:为什么这套方案更优?
-
隔离性:通过
LD_LIBRARY_PATH局部挂载,不修改板子全局库,避免污染系统环境。 -
便携性:
yolo26文件夹就是一个完整的“离线工作站”,拷贝即运行。 -
交互性:利用 Jupyter Lab 在 PC 端浏览器直接看 310B4 的推理画面,调试效率比纯命令行提升数倍。
💡 技术贴士: 如果 import cv2 报错,请务必检查 start_jupyter.sh 中的路径是否与你解压的 lib 目录绝对一致。这种“库随项目走”的模式是目前嵌入式 AI 开发的最优实践!

没有回复内容