【凌智视觉模块】rv1106 部署 pp-humseg 模型

人像分割简介

❀ 凌智视觉模块 是一款基于rv1106芯片开发的视觉模块,专注于视觉模型部署与开发。
人像分割是一种基于计算机视觉的技术,通过深度学习算法精准识别图像或视频中的人物主体,将其与背景进行像素级分离。该技术可实时运行于移动端及嵌入式设备,广泛应用于虚拟背景、智能抠图、视频会议美颜等场景,支持复杂光照、多样姿态和遮挡情况下的高精度分割,兼顾处理速度与效果。

人像分割常用方法

目前对于实现人像分割任务的方法有很多,下面介绍几种常用的人像分割实现方法:

  • 传统算法(如GrabCut):基于颜色直方图与图割优化,适合简单背景,计算量小但精度有限。
  • U-Net系列:编码器-解码器结构,医学图像起家,适合精细边缘,需较高算力。
  • DeepLab系列:采用空洞卷积扩大感受野,擅长复杂场景,模型较大。
  • BiSeNet:双分支结构平衡速度与精度,实时分割首选,移动端友好。
  • PP-HumanSeg:百度自研轻量模型,专为人像优化,支持半监督训练。

PP-HumanSeg模型简介

将人物和背景在像素级别进行区分,是一个图像分割的经典任务,具有广泛的应用。 一般而言,该任务可以分为两类:针对半身人像的分割,简称肖像分割;针对全身和半身人像的分割,简称通用人像分割。

对于肖像分割和通用人像分割,PaddleSeg发布了PP-HumanSeg系列模型,具有分割精度高、推理速度快、通用型强的优点。而且PP-HumanSeg系列模型可以开箱即用,零成本部署到产品中,也支持针对特定场景数据进行微调,实现更佳分割效果。

2022年7月,PaddleSeg重磅升级的PP-HumanSegV2人像分割方案,以96.63%的mIoU精度, 63FPS的手机端推理速度,再次刷新开源人像分割算法SOTA指标。相比PP-HumanSegV1方案,推理速度提升87.15%,分割精度提升3.03%,可视化效果更佳。V2方案可与商业收费方案媲美,而且支持零成本、开箱即用!

PP-HumanSeg由飞桨官方出品,是PaddleSeg团队推出的模型和方案。

这些方法各有优势,其中在工业部署方面 PP-HumanSeg(精度与速度平衡)和 BiSeNet(高性价比)更适合,配合 OpenCV 后处理优化边缘。


API 介绍

RKNPU2Backend 类

####头文件

#include "rknpu2_backend/rknpu2_backend.h"

作用:创建一个 RKNPU2Backend 类,用于实现对 RKNN 模型的处理。

构造类函数
ockzhiner_vision_module::vision::RKNPU2Backend backend;

作用:创建一个 RKNPU2Backend 类型的对象实例,用于实现人像分割。

  • 参数说明:无
  • 返回值:无
Initialize 函数
bool Initialize(const std::string &model_path, const std::string &param_path = "") override;

作用:初始化 RKNN 模型,加载模型文件和可选参数文件,完成推理引擎的准备工作。

  • 参数说明:
    • model_path:必需参数,RKNN 模型文件路径(.rknn 格式)
    • param_path:可选参数,额外参数文件路径(某些场景下用于补充模型配置,默认空字符串)
  • 返回值:返回 true/false,表示模型初始化是否成功。
Run 函数
bool Run();

作用:执行模型推理计算,驱动输入数据通过模型计算得到输出结果。

  • 参数说明:无
  • 返回值:
    • true:推理执行成功
    • false:推理失败(可能原因:输入数据未准备、内存不足等)
GetInputAttrs 函数
const std::vector<rknn_tensor_attr>& GetInputAttrs() const;

作用:获取模型所有输入张量的属性信息(维度/形状、数据类型、量化参数等)。

  • 参数说明:无
  • 返回值:常量引用形式的 rknn_tensor_attr 向量,包含输入张量属性。
GetOutputAttrs 函数
const std::vector<rknn_tensor_mem*>& GetInputMemories() const;

作用:获取模型所有输出张量的属性信息。

  • 参数说明:无
  • 返回值:常量引用形式的 rknn_tensor_attr 向量,包含输出张量属性。

PP-Humanseg 人像分割代码解析

流程图

开始
│
├── 参数检查 (argc == 3)
│   └── 错误 → 输出Usage并退出
│
├── 初始化 RKNN 后端
│   ├── 加载模型
│   └── 初始化失败 → 错误退出
│
├── 加载与预处理输入图像
│   ├── 读取图像文件
│   ├── 获取输入属性
│   ├── 调用 preprocess() 函数
│       ├── 调整尺寸和颜色空间
│       ├── 量化图像数据
│       └── 验证尺寸匹配
│   └── 预处理失败 → 错误退出
│
├── 执行推理
│   ├── 拷贝预处理后的图像数据到输入内存
│   ├── 执行推理
│       └── 推理失败 → 错误退出
│
├── 后处理
│   ├── 获取输出属性及内存
│   ├── 调用 postprocess() 函数
│       ├── 解析输出数据生成概率图
│       ├── 自适应阈值分割
│       ├── 多尺度形态学处理
│       ├── 智能边缘优化
│       └── 多模态结果融合
│
├── 结果展示与保存
│   ├── 计算推理时间
│   ├── 生成并保存结果图像
│   ├── 显示原始图像、掩膜及结果图像
│
└── 程序结束

核心代码解析

初始化模型
backend.Initialize(model_path)
获取输入输出属性
const auto& input_attrs = backend.GetInputAttrs();
const auto& output_attrs = backend.GetOutputAttrs();
对输入图像进行推理
backend.Run()

自定义函数说明

pp-humanseg 输入预处理
cv::Mat preprocess(const cv::Mat& image, const std::vector<size_t>& input_dims) 

作用:对输入图像进行预处理操作,包括 尺寸调整颜色空间转换量化处理,使其符合 RKNN 模型的输入要求。

  • 参数说明:
    • image:输入图像(BGR 格式的 cv::Mat 对象)
    • input_dims:模型输入张量的维度定义(需满足 [1, H, W, 3] 的 NHWC 格式)
  • 返回值:
    • 返回预处理后的量化张量(cv::Mat,数据类型为 CV_8S
    • 若输入维度不合法,返回空矩阵(cv::Mat())并报错

pp-humanseg 输入后处理
cv::Mat postprocess(const rknn_tensor_mem* output_mem, const std::vector<size_t>& output_dims,const cv::Size& target_size) 

作用:将模型输出的原始张量转换为高精度分割掩膜,包含 概率解码动态阈值分割形态学优化边缘增强 等步骤,最终生成与原始图像尺寸匹配的二值化掩膜。

  • 参数说明:
    • output_mem:模型输出的内存指针,包含量化后的原始数据
    • output_dims:模型输出的维度信息,需满足 [1, 2, H, W] 的 NCHW 格式
    • target_size:目标输出尺寸
  • 返回值:返回优化后的二值化掩膜

###完整代码实现

由于篇幅限制,此处仅展示关键代码逻辑。实际开发中请结合具体项目工程使用。

int main(int argc, char* argv[]) {if (argc != 3) {std::cerr << "Usage: " << argv[0] << " <model_path> <image_path>" << std::endl;return 1;}const std::string model_path = argv[1];const std::string image_path = argv[2];// 初始化RKNN后端lockzhiner_vision_module::vision::RKNPU2Backend backend;if (!backend.Initialize(model_path)) {std::cerr << "Failed to initialize RKNN backend" << std::endl;return -1;}// 加载图像cv::Mat image = cv::imread(image_path);if (image.empty()) {std::cerr << "Failed to read image: " << image_path << std::endl;return -1;}// 获取输入属性const auto& input_attrs = backend.GetInputAttrs();if (input_attrs.empty()) {std::cerr << "No input attributes found" << std::endl;return -1;}const auto& input_attr = input_attrs[0];std::vector<size_t> input_dims(input_attr.dims, input_attr.dims + input_attr.n_dims);// 预处理cv::Mat preprocessed = preprocess(image, input_dims);if (preprocessed.empty()) {std::cerr << "Preprocessing failed" << std::endl;return -1;}// 验证输入数据尺寸const size_t expected_input_size = input_attr.size_with_stride;const size_t actual_input_size = preprocessed.total() * preprocessed.elemSize();if (expected_input_size != actual_input_size) {std::cerr << "Input size mismatch! Expected: " << expected_input_size<< ", Actual: " << actual_input_size << std::endl;return -1;}// 拷贝输入数据const auto& input_memories = backend.GetInputMemories();if (input_memories.empty() || !input_memories[0]) {std::cerr << "Invalid input memory" << std::endl;return -1;}memcpy(input_memories[0]->virt_addr, preprocessed.data, actual_input_size);// 执行推理high_resolution_clock::time_point start_time =high_resolution_clock::now();if (!backend.Run()) {std::cerr << "Inference failed" << std::endl;return -1;}// 获取输出const auto& output_attrs = backend.GetOutputAttrs();if (output_attrs.empty()) {std::cerr << "No output attributes found" << std::endl;return -1;}const auto& output_memories = backend.GetOutputMemories();if (output_memories.empty() || !output_memories[0]) {std::cerr << "Invalid output memory" << std::endl;return -1;}// 后处理const auto& output_attr = output_attrs[0];std::vector<size_t> output_dims(output_attr.dims, output_attr.dims + output_attr.n_dims);cv::Mat mask = postprocess(output_memories[0], output_dims, image.size());high_resolution_clock::time_point end_time = high_resolution_clock::now();auto time_span = duration_cast<milliseconds>(end_time - start_time);std::cout << "单张图片推理时间(ms): " << time_span.count() << std::endl;// 生成结果cv::Mat result;cv::bitwise_and(image, image, result, mask);// 保存结果const std::string output_path = "result.jpg";cv::imwrite(output_path, result);std::cout << "Result saved to: " << output_path << std::endl;// 显示调试视图cv::imshow("Original", image);cv::imshow("Mask", mask);cv::imshow("Result", result);cv::waitKey(0);return 0;
}

完整代码可前往我们的仓库 凌智视觉模块 查看


📌 总结

你提到的观点非常有见地,尤其是在嵌入式边缘计算设备上部署深度学习模型时,性能瓶颈往往并不在 NPU 的算力本身,而是在 CPU 与内存之间的协同效率。下面我们来系统性地分析一下 RV1106 G3 芯片(256MB RAM,1.2GHz 单核 CPU,NPU 算力 1TOPS INT8) 在运行 PP-HumanSeg 人像分割模型时可能遇到的瓶颈。


🧠 RV1106G3 性能瓶颈分析 —— 以 PP-HumanSeg 模型为例

✅ 芯片参数概览

参数
CPU单核 ARM Cortex-A7 1.2GHz
内存256MB LPDDR4x
NPU1TOPS INT8 算力
应用场景边缘 AI 推理、图像处理

🔍 从硬件架构角度看瓶颈来源

1. CPU 性能限制

  • 单核设计 + 主频 1.2GHz,对于复杂的数据预处理(如 OpenCV 中的 resize、cvtColor、归一化等操作)、数据搬运、模型输入输出管理、后处理(形态学运算、边缘优化)等任务来说,很容易成为瓶颈。
  • 特别是当模型推理速度很快(NPU 加速),但 CPU 处理图像慢于推理速度时,整体帧率将受限于 CPU 的处理能力。

2. 内存带宽 & 容量限制

  • 仅 256MB 内存,对于图像进行处理时,容易出现:
    • 图像缓存不足
    • 多帧缓冲困难
    • 大尺寸模型加载失败
  • 数据频繁在内存和 NPU 之间搬运,增加访存开销,降低整体吞吐。

3. NPU 并非瓶颈

  • PP-HumanSeg 是轻量化模型,且支持 INT8 推理,其计算量对 1TOPS 的 NPU 来说完全足够。


标签:#图像分割 #PP-HumanSeg #RKNN #OpenCV #C++ #AI部署 #人像分割 #PaddleSeg #边缘计算

🔚 版权声明:本文为原创文章,转载请注明出处。未经许可,禁止转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/907367.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wangeditor富文本编辑器+vue3粘贴内容样式处理

又是一个风格和日立的上午&#xff0c;某只菜鸟高高兴兴的骑着小电驴去上班&#xff0c;本着上班只要不迟到的理念飞速前行&#xff08;迟到扣钱啊~&#xff09;&#xff0c;高高兴兴的行走在路上。来到工位刚拴上我的绳子组长就开始滴滴俺&#xff0c;顿时我心中大感不妙&…

实测,大模型谁更懂数据可视化?

大家好&#xff0c;我是 Ai 学习的老章 看论文时&#xff0c;经常看到漂亮的图表&#xff0c;很多不知道是用什么工具绘制的&#xff0c;或者很想复刻类似图表。 实测&#xff0c;大模型 LaTeX 公式识别&#xff0c;出乎预料 前文&#xff0c;我用 Kimi、Qwen-3-235B-A22B、…

深度学习-梯度消失和梯度爆炸

梯度消失 在某些神经网络中&#xff0c;随着网络深度的增加&#xff0c;梯度在隐藏层反向传播时倾向于变小&#xff0c;这就意味着&#xff0c;前面隐藏层中的神经元要比后面的学习起来更慢&#xff0c;这种现象就叫做“梯度消失”&#xff1b; 梯度爆炸 如果我们进行一些特殊…

Go 语言基础 2 Func,流程控制

更多个人笔记见&#xff1a; github个人笔记仓库 gitee 个人笔记仓库 个人学习&#xff0c;学习过程中还会不断补充&#xff5e; &#xff08;后续会更新在github上&#xff09; 文章目录 Func 函数函数栈概念 函数表示类型 Anonymous func 匿名函数closure 闭包基础示例http利…

【Linux 学习计划】-- 倒计时、进度条小程序

目录 \r 、\n、fflush 倒计时 进度条 进度条进阶版 结语 \r 、\n、fflush 首先我们先来认识这三个东西&#xff0c;这将会是我们接下来两个小程序的重点之一 首先是我们的老演员\n&#xff0c;也就是回车加换行 这里面其实包含了两个操作&#xff0c;一个叫做回车&…

从零实现wss通信示例(WebSocket SSL)

客户端和服务端代码框架跟上一篇一致,仅增加了ssl的证书部分用于加密通信,明文通信(ws协议)见上一篇【https://blog.csdn.net/suoxd123/article/details/148093934】 1. 证书创建 1. 安装openssl 【官网地址】:https://slproweb.com/products/Win32OpenSSL.html 1.2 …

mysql 索引失效有哪些

InnoDB存储引擎根据索引类型不同&#xff0c;分为聚簇索引和二级索引 聚簇索引&#xff1a;叶子节点存放的是实际数据 二级索引&#xff1a;存放的是主键值&#xff0c;不是实际数据 1.对索引使用左或者左右模糊匹配 select * from t_user where name like %林‘&#xff1b…

LabVIEW通用测控平台设计

基于 LabVIEW 图形化编程环境&#xff0c;设计了一套适用于工业自动化、科研测试领域的通用测控平台。通过整合研华、NI等品牌硬件&#xff0c;实现多类型数据采集、实时控制及可视化管理。平台采用模块化架构&#xff0c;支持硬件灵活扩展&#xff0c;解决了传统测控系统开发周…

华为OD机试真题——智能驾驶(2025A卷:200分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 200分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

速卖通,国际站测评补单,如何平衡效率和安全

测评能够帮助卖家让平台更喜欢自己的产品&#xff0c;给予更好排名的同时也让后续进入店铺的买家更容易认可自己的产品。这是进行真实交易后形成的评价&#xff0c;而不是通过机器软件生成&#xff0c;形成虚拟数据后&#xff0c;那种刷评形式产生的评论。它符合任何电商平台的…

学习路之PHP--easyswoole3.3入门及文件热加载

学习路之PHP--easyswoole入门 一、框架说明二、常用命令三、文件热加载 一、框架说明 目录结构 目录结构 project 项目部署目录 ├─App 应用目录(可以有多个) │ ├─HttpController 控制器目录 │ │ └─Index.php …

设计模式26——解释器模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用&#xff0c;主要是下面的UML图可以起到大作用&#xff0c;在你学习过一遍以后可能会遗忘&#xff0c;忘记了不要紧&#xff0c;只要看一眼UML图就能想起来了。同时也请大家多多指教。 解释器模式&#xff08;Interp…

第三届宁波技能大赛网络安全赛项样题

2025 第三届宁波技能大赛网络安全赛项样题 模块A: 网络安全事件响应、数字取证调查和应用安全任务一:应急响应任务二:操作系统取证任务三:网络数据包分析任务四:代码审计 模块B:CTF 夺旗-攻击模块C:CTF 夺旗-防御需要环境培训可以私信博主&#xff01;&#xff01;&#xff01;…

GO语言进阶:掌握进程OS操作与高效编码数据转换

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…

IO进程(进程 Process)

什么是进程&#xff1f; 1.概念 程序&#xff1a;编译好的可执行文件&#xff0c;存放在磁盘上的指令和数据的有序集合。 由此可见程序是静态的&#xff0c;没有执行的概念。 进程&#xff1a;是程序的一次执行的过程&#xff0c;是一个可调度的任务&#xff0c;也是执行一…

CSS传统布局与定位详解与TDK三大标签SEO优化

一、传统布局基础 1. 文档流布局 浏览器默认的文档流布局方式遵循以下规则&#xff1a; 块级元素&#xff08;如<div>、<p>、<h1>&#xff09;&#xff1a; 独占一行宽度默认100%可以设置宽高、内外边距 div {width: 500px;height: 200px;margin: 10px …

【GraphQL】深入解析 Apollo Client:从架构到实践的一站式 GraphQL 解决方案

深入解析 Apollo Client&#xff1a;从架构到实践的一站式 GraphQL 解决方案 1. 引言 GraphQL 作为现代 API 开发的核心技术&#xff0c;其灵活性和高效性正在重塑数据交互模式。Apollo Client 作为 GraphQL 生态中最受欢迎的客户端库&#xff0c;凭借强大的缓存机制、框架集…

docker学习基本使用教程

docker是一款用于开发部署和运行容器化平台&#xff0c;能将应用及其依赖打包成轻量级、可移植的容器&#xff0c;实现一次构建&#xff0c;随处运行。docker是cs架构程序&#xff08;客户端和服务端&#xff09;&#xff0c;docker客户端向docker守护进程发送请求&#xff0c;…

万字详解RTR RTSP SDP RTCP

目录 1 RTSP1.1 RTSP基本简介1.2 RSTP架构1.3 重点内容分析 2 RTR2.1 RTR简介2.2 RTP 封装 H.2642.3 RTP 解封装 H.2642.4 RTP封装 AAC2.5 RTP解封装AAC 3 SDP3.1 基础概念3.2 SDP协议示例解析3.3 重点知识 4 RTCP4.1 RTCP基础概念4.2 重点 5 总结 1 RTSP 1.1 RTSP基本简介 一…

唯一原生适配鸿蒙电脑的远程控制应用,向日葵正式上线

近日&#xff0c;华为正式发布鸿蒙电脑新品&#xff0c;标志着HarmonyOS在PC端生态的进一步拓展。作为远程控制领域的先行者&#xff0c;贝锐科技旗下的向日葵远程控制软件也在第一时间完成了对鸿蒙电脑系统的原生适配&#xff0c;并已正式上线华为鸿蒙电脑应用市场&#xff0c…