【凌智视觉模块】rv1106 部署 ppocrv4 检测模型 rknn 推理

PP-OCRv4 文本框检测

1. 模型介绍

如有需要可以前往我们的仓库进行查看 凌智视觉模块

PP-OCRv4在PP-OCRv3的基础上进一步升级。整体的框架图保持了与PP-OCRv3相同的pipeline,针对检测模型和识别模型进行了数据、网络结构、训练策略等多个模块的优化。
请添加图片描述

从算法改进思路上看,分别针对检测和识别模型,进行以下方面的改进:
检测模块:

  • LCNetV3:精度更高的骨干网络
  • PFHead:并行head分支融合结构
  • DSR: 训练中动态增加shrink ratio
  • CML:添加Student和Teacher网络输出的KL div loss

原理可前往PPOCR技术报告查看:https://paddlepaddle.github.io/PaddleOCR/v2.9/ppocr/blog/PP-OCRv4_introduction.html#1pfheadhead

2. 模型转换

参考RKNN Model ZOO将 PPOCRv4 的文本检测模型转化成 RKNN 模型。


import sys
from rknn.api import RKNNDATASET_PATH = '../../../../datasets/PPOCR/imgs/dataset_20.txt'
DEFAULT_RKNN_PATH = '../model/ppocrv4_det.rknn'
DEFAULT_QUANT = Truedef parse_arg():if len(sys.argv) < 3:print("Usage: python3 {} onnx_model_path [platform] [dtype(optional)] [output_rknn_path(optional)]".format(sys.argv[0]));print("       platform choose from [rk3562, rk3566, rk3568, rk3576, rk3588, rv1126b, rv1109, rv1126, rk1808]")print("       dtype choose from    [i8, fp] for [rk3562, rk3566, rk3568, rk3576, rk3588, rv1126b]")print("       dtype choose from    [u8, fp] for [rv1109, rv1126, rk1808]")exit(1)model_path = sys.argv[1]platform = sys.argv[2]do_quant = DEFAULT_QUANTif len(sys.argv) > 3:model_type = sys.argv[3]if model_type not in ['i8', 'u8', 'fp']:print("ERROR: Invalid model type: {}".format(model_type))exit(1)elif model_type in ['i8', 'u8']:do_quant = Trueelse:do_quant = Falseif len(sys.argv) > 4:output_path = sys.argv[4]else:output_path = DEFAULT_RKNN_PATHreturn model_path, platform, do_quant, output_pathif __name__ == '__main__':model_path, platform, do_quant, output_path = parse_arg()# Create RKNN objectrknn = RKNN(verbose=False)# Pre-process configprint('--> Config model')rknn.config(mean_values=[[123.675, 116.28, 103.53]], std_values=[[58.395, 57.12, 57.375]], target_platform=platform)print('done')# Load modelprint('--> Loading model')ret = rknn.load_onnx(model=model_path)if ret != 0:print('Load model failed!')exit(ret)print('done')# Build modelprint('--> Building model')ret = rknn.build(do_quantization=do_quant, dataset=DATASET_PATH)if ret != 0:print('Build model failed!')exit(ret)print('done')# Export rknn modelprint('--> Export rknn model')ret = rknn.export_rknn(output_path)if ret != 0:print('Export rknn model failed!')exit(ret)print('done')# Releaserknn.release()

根据目标平台,完成参数配置,运行程序完成转换。在完成模型转换后可以查看 rv1106 的算子支持手册,确保所有的算子是可以使用的,避免白忙活。

3. 模型部署

#include <iostream>
#include <cmath>
#include <opencv2/opencv.hpp>
#include "rknpu2_backend/rknpu2_backend.h"
#include <cstdlib>
#include <ctime>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "postprocess.h"
#include <lockzhiner_vision_module/edit/edit.h>
#include <lockzhiner_vision_module/vision/utils/visualize.h>// 用于计时的头文件
#include <chrono>using namespace std::chrono;int main(int argc, char *argv[])
{if (argc != 2){std::cerr << "Usage: " << argv[0] << " <model_path>" << std::endl;return 1;}const std::string model_path = argv[1];// 初始化RKNN后端lockzhiner_vision_module::vision::RKNPU2Backend backend;if (!backend.Initialize(model_path)){std::cerr << "Failed to initialize RKNN backend" << std::endl;return -1;}lockzhiner_vision_module::edit::Edit edit;if (!edit.StartAndAcceptConnection()){std::cerr << "Error: Failed to start and accept connection." << std::endl;return EXIT_FAILURE;}std::cout << "Device connected successfully." << std::endl;// 打开摄像头cv::VideoCapture cap;cap.set(cv::CAP_PROP_FRAME_WIDTH, 640);cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480);cap.open(0);if (!cap.isOpened()){std::cerr << "Error: Could not open camera." << std::endl;return 1;}cv::Mat image;int frame_count = 0; // 帧计数器while (true){cap >> image;if (image.empty())continue;frame_count++;// 每隔3帧处理一次(即每4帧处理1次)if (frame_count % 4 == 1){// 获取输入Tensor的信息auto input_tensor = backend.GetInputTensor(0);std::vector<size_t> input_dims = input_tensor.GetDims();float input_scale = input_tensor.GetScale();int input_zp = input_tensor.GetZp();// 预处理cv::Mat preprocessed = preprocess(image, input_dims, input_scale, input_zp);if (preprocessed.empty()){std::cerr << "Preprocessing failed" << std::endl;goto skip_inference;}// 验证输入数据尺寸size_t expected_input_size = input_tensor.GetElemsBytes();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;goto skip_inference;}// 拷贝输入数据void *input_data = input_tensor.GetData();memcpy(input_data, preprocessed.data, actual_input_size);// 开始计时auto start = high_resolution_clock::now();// 推理if (!backend.Run()){std::cerr << "Inference failed!" << std::endl;free(input_data);goto skip_inference;}// 结束计时auto end = high_resolution_clock::now();auto duration_ms = duration_cast<milliseconds>(end - start).count();std::cout << "Inference time: " << duration_ms << " ms" << std::endl;// 获取输出结果const auto &output_tensor = backend.GetOutputTensor(0);std::vector<size_t> output_dims = output_tensor.GetDims();float output_zp = output_tensor.GetZp();float output_scale = output_tensor.GetScale();const int8_t *output_data_int8 = static_cast<const int8_t *>(output_tensor.GetData());// 转换为浮点型std::vector<float> output_data_float(output_tensor.GetNumElems());for (size_t i = 0; i < output_tensor.GetNumElems(); ++i){output_data_float[i] = (output_data_int8[i] - output_zp) * output_scale;}// 获取原始图像宽高int original_width = image.cols;int original_height = image.rows;float scale_w = (float)original_width / 480;float scale_h = (float)original_height / 480;// 后处理ppocr_det_result results = {0};dbnet_postprocess(output_data_float.data(),output_dims[2], output_dims[3],0.5, 0.3, true, "slow", 2.0, "quad",scale_w, scale_h, &results);// 绘制检测框draw_boxes(&image, results);}skip_inference:// 显示当前帧(无论是否进行了推理)edit.Print(image);// 按下 ESC 键退出if (cv::waitKey(1) == 27){break;}}cap.release();return 0;
}

4. 编译程序

使用 Docker Destop 打开 LockzhinerVisionModule 容器并执行以下命令来编译项目

# 进入Demo所在目录
cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule/Cpp_example/D11_PPOCRv4-Det
# 创建编译目录
rm -rf build && mkdir build && cd build
# 配置交叉编译工具链
export TOOLCHAIN_ROOT_PATH="/LockzhinerVisionModuleWorkSpace/arm-rockchip830-linux-uclibcgnueabihf"
# 使用cmake配置项目
cmake ..
# 执行编译项目
make -j8 

在执行完上述命令后,会在build目录下生成可执行文件。

5. 执行结果

5.1 运行前准备

  • 请确保你已经下载了 凌智视觉模块字符检测模型权重文件

5.2 运行过程

chmod 777 Test-ppocrv4
./Test-ppocrv4 ppocrv4_det.rknn 

5.3 运行效果

5.3.1 ppocrv4字符识别
  • 测试结果

请添加图片描述

  • 测试时间

请添加图片描述

瓶颈分析,虽然 ppocrv4 的文本检测模型的推理时间为 90ms 左右,但是在实际使用时建议使用跳帧检测,不每一帧都进行推理,可以有效降低卡顿。

5.3.2 注意事项

由于本章节只部署了一个 PPOCRv4 的文字识别模型,并没有训练检测模型,如需训练自己的数据集,可使用 paddleOCR 训练检测模型。

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

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

相关文章

uniapp Vue2 获取电量的独家方法:绕过官方插件限制

在使用 uniapp 进行跨平台应用开发时&#xff0c;获取设备电量信息是一个常见的需求。然而&#xff0c;uniapp 官方提供的uni.getBatteryInfo方法存在一定的局限性&#xff0c;它不仅需要下载插件&#xff0c;而且目前仅支持 Vue3&#xff0c;这让使用 Vue2 进行开发的开发者陷…

Go语言中的if else控制语句

if else是Go语言中最基础也最常用的条件控制语句&#xff0c;用于根据条件执行不同的代码块。下面我将详细介绍Go语言中if else的各种用法和特性。 1. 基本语法 1.1. 最简单的if语句 if 条件表达式 {// 条件为true时执行的代码 } 示例&#xff1a; if x > 10 {fmt.Prin…

[Spring]-AOP

AOP场景 AOP: Aspect Oriented Programming (面向切面编程) OOP: Object Oriented Programming (面向对象编程) 场景设计 设计: 编写一个计算器接口和实现类&#xff0c;提供加减乘除四则运算 需求: 在加减乘除运算的时候需要记录操作日志(运算前参数、运算后结果)实现方案:…

Web3 借贷与清算机制全解析:链上金融的运行逻辑

Web3 借贷与清算机制全解析&#xff1a;链上金融的运行逻辑 超额抵押借款 例如&#xff0c;借款人用ETH为抵押借入DAI&#xff1b;借款人的ETH的价值一定是要超过DAI的价值&#xff1b;借款人可以任意自由的使用自己借出的DAI 稳定币 第一步&#xff1a;借款人需要去提供一定…

RK3588开发笔记-GNSS-RTK模块调试

目录 前言 一、什么是GNSS/RTK 二、硬件连接 三、内核配置 四、模块调试 五、ntripclient使用 总结 前言 在RK3588平台上集成高精度定位功能是许多工业级应用的需求。本文记录了我调试GNSS-RTK模块的全过程,包含硬件连接、驱动移植、数据解析和精度优化等关键环节,希望对…

Vue.js $emit的介绍和简单使用

前言 在 Vue.js 开发中&#xff0c;组件化是核心思想之一。但组件间的通信是一个重要课题&#xff0c;特别是子组件向父组件传递数据的场景。Vue 提供了多种通信方式&#xff0c;而$emit正是实现子→父通信的关键方法。本文将深入解析$emit的原理、使用场景及最佳实践。 一、$e…

【Linux 学习计划】-- 简易版shell编写

目录 思路 创建自己的命令行 获取用户命令 分割命令 检查是否是内建命令 cd命令实现 进程程序替换执行程序 总代码 结语 思路 int main() {while (1){// 1. 自己的命令行PrintCommandLine();// 2. 获取用户命令char command[SIZE];int n GetUserCommand(command, si…

一个完整的日志收集方案:Elasticsearch + Logstash + Kibana+Filebeat (二)

&#x1f4c4; 本地 Windows 部署 Logstash 连接本地 Elasticsearch 指南 ✅ 目标 在本地 Windows 上安装并运行 Logstash配置 Logstash 将数据发送至本地 Elasticsearch测试数据采集与 ES 存储流程 &#x1f9f0; 前提条件 软件版本要求安装说明Java17Oracle JDK 下载 或 O…

Java使用Selenium反爬虫优化方案

当我们爬取大站的时候&#xff0c;就得需要对抗反爬虫机制的场景&#xff0c;因为项目要求使用Java和Selenium。Selenium通常用于模拟用户操作&#xff0c;但效率较低&#xff0c;所以需要我们结合其他技术来实现高效。 在 Java 中使用 Selenium 进行高效反爬虫对抗时&#xff…

状态管理方案对比与决策

1. 状态管理的基本概念 现代前端应用随着功能复杂度提升&#xff0c;状态管理已成为架构设计的核心挑战。状态管理本质上解决的是数据的存储、变更追踪和响应式更新问题&#xff0c;以确保UI与底层数据保持同步。 核心挑战: 状态共享与组件通信可预测的状态变更性能优化与重…

Fetch与Axios:区别、联系、优缺点及使用差异

Fetch与Axios&#xff1a;区别、联系、优缺点及使用差异 文章目录 Fetch与Axios&#xff1a;区别、联系、优缺点及使用差异一、联系二、区别1. 浏览器支持与兼容性2. 响应处理3. 请求拦截和响应拦截4. 错误处理 三、优缺点1. Fetch API优点缺点 2. Axios优点缺点 四、使用上的差…

【Docker】快速入门与项目部署实战

我们在部署一个项目时&#xff0c;会出现一系列问题比如&#xff1a; 命令太多了&#xff0c;记不住软件安装包名字复杂&#xff0c;不知道去哪里找安装和部署步骤复杂&#xff0c;容易出错 其实上述问题不仅仅是新手&#xff0c;即便是运维在安装、部署的时候一样会觉得麻烦…

Java面试题尚硅谷版第1季

1、写出如下代码运行结果 1.1、 使用局部变量表和操作数栈解题 1.2、使用前置和后置递增解题 2、写一个单例模式 2.1、考察知识点 2.2、单例模式实现 3、类加载和初始化顺序 package classload;public class Father {private int i test();private static int j method();st…

关于Qt阻断样式继承的解决办法

引言 在使用 Qt 开发桌面应用时&#xff0c;借助样式表&#xff08;StyleSheet&#xff09;来统一定义界面风格是非常常见的做法。通常&#xff0c;你会在主程序中通过 qApp->setStyleSheet(...) 或者直接给某个父控件设置样式表&#xff0c;让所有的子控件都采用相同的配色…

鼠标右键添加新建某种文件的方法

场景 我经常用到.emmx&#xff0c;.eddx文件&#xff0c;电脑上装的是wpsX亿图&#xff08;因为有wps会员&#xff09;&#xff0c;没有开亿图会员。 然后问题就是&#xff0c;思维导图和流程图我都能正常开&#xff0c;正常编辑&#xff0c;但鼠标右键没有新建这两个文件的按…

Inxpect安全雷达传感器与控制器:动态检测 + 抗干扰技术重构工业安全防护体系

Inxpect 推出工业安全领域新型智能传感器与控制器&#xff0c;其核心产品为雷达扫描仪&#xff0c;具备动态调整检测区域、抗干扰能力强等特点&#xff0c;可精准检测危险区域人员进入或存在情况&#xff0c;适用于移动机器人等场景。 Inxpect安全雷达传感器核心功能 动态检测…

【AI学习】李广密与阶跃星辰首席科学家张祥雨对谈:多模态发展的历史和未来

仔细阅读了文章《专访张祥雨&#xff1a;多模态推理和自主学习是未来的 2 个 「GPT-4」 时刻》 https://mp.weixin.qq.com/s/892QuRPH9uP6zN6dS-HZMw 非常赞叹的一篇文章&#xff0c;说清楚了NLP、CV发展中的许多重大问题&#xff0c;读来醍醐灌顶&#xff01;这样的文章&…

C++中std::deque详解和实战工程代码示例

C中std::deque详解和实战工程代码示例 std::deque&#xff08;双端队列&#xff09;是 C 标准库中的一个序列容器&#xff0c;与 std::vector 类似&#xff0c;但它支持从头部和尾部高效地插入和删除元素。它底层采用分段连续空间实现&#xff0c;兼具灵活性与性能。 一、基本…

【AI大模型入门指南】概念与专有名词详解 (二)

【AI大模型入门指南】概念与专有名词详解 &#xff08;二&#xff09; 一 、前言 当你和聊天机器人聊得天花乱坠时&#xff0c;当你用文字让AI生成精美图片时&#xff0c;当手机相册自动帮你分类照片时 —— 这些看似智能的操作背后&#xff0c;都藏着 AI 大模型的身影。 本…

AIStor 的模型上下文协议 (MCP) 服务器:管理功能

在本系列的上一篇博文中&#xff0c;我们讨论了 MinIO AIStor 的模型上下文协议 (MCP) 服务器的基本用户级功能。我们学习了如何使用人类语言命令查看存储桶的内容、分析对象并标记它们以便将来处理&#xff0c;以及如何通过 LLM&#xff08;例如 Anthropic Claude&#xff09;…