从零开发短视频电商 PaddleOCR Java推理 (二)优化Translator模型输入和输出

PaddleOCR提供了一系列测试图片,你可以通过点击这里来下载。

值得注意的是,PaddleOCR的模型更新速度远远快于DJL,这导致了一些DJL的优化滞后问题。因此,我们需要采取一些策略来跟上PaddleOCR的最新进展。

针对文本识别模型,你可以参考以下资源:

  • 文档:PaddleOCR文本识别模型推理文档
  • Python推理代码:PaddleOCR文本识别模型推理代码

请注意,PP-OCRv4的识别模型使用的输入形状为3,48,320。此外,PP-OCRv4的识别模型默认使用的rec_algorithmSVTR_LCNet,需要留意其与原始SVTR的区别。

默认的识别模型算法可以在这里找到。

模型的输入和输出在PpWordRecognitionTranslator.java中。

Criteria<Image, String> criteria = Criteria.builder().optEngine("PaddlePaddle").setTypes(Image.class, String.class).optModelPath(Paths.get("C:\\laker-1")).optTranslator(new PpWordRecognitionTranslator()).build();
public class PpWordRecognitionTranslator implements NoBatchifyTranslator<Image, String> {private List<String> table;/** * 准备方法,用于加载模型所需的数据。* * @param ctx 翻译上下文* @throws IOException 如果读取数据时发生错误*/@Overridepublic void prepare(TranslatorContext ctx) throws IOException {try (InputStream is = ctx.getModel().getArtifact("ppocr_keys_v1.txt").openStream()) {// 从文本文件中读取表格数据table = Utils.readLines(is, true);// 在表格开头添加"blank"table.add(0, "blank");// 在表格末尾添加空字符串table.add("");}}/** * 处理输出方法,将模型的输出转换为字符串。* * @param ctx 翻译上下文* @param list 模型的输出列表* @return 转换后的字符串*/@Overridepublic String processOutput(TranslatorContext ctx, NDList list) {StringBuilder sb = new StringBuilder();NDArray tokens = list.singletonOrThrow();long[] indices = tokens.get(0).argMax(1).toLongArray();int lastIdx = 0;for (int i = 0; i < indices.length; i++) {if (indices[i] > 0 && !(i > 0 && indices[i] == lastIdx)) {// 将索引映射为相应的字符串并添加到结果字符串中sb.append(table.get((int) indices[i]));}}return sb.toString();}/** * 处理输入方法,将图像数据转换为模型可接受的格式。* * @param ctx 翻译上下文* @param input 输入图像* @return 转换后的NDList对象*/@Overridepublic NDList processInput(TranslatorContext ctx, Image input) {NDArray img = input.toNDArray(ctx.getNDManager());int[] hw = resize32(input.getWidth());// 调整图像大小、转换为张量并归一化img = NDImageUtils.resize(img, hw[1], hw[0]);img = NDImageUtils.toTensor(img).sub(0.5f).div(0.5f);// 在第一个维度上添加一个维度,通常用于将单个图像添加到批处理中img = img.expandDims(0);return new NDList(img);}private int[] resize32(double w) {// Paddle不依赖于宽高比// 计算新的图像宽度,确保它是32的倍数int width = ((int) Math.max(32, w)) / 32 * 32;return new int[]{32, width};}
}

这里有很多过时的了。

  • 输入尺寸最新为3,48,320
  • 输出的置信度没输出。

我们就来优化这2点。

1.修改模型加载这个地方

Criteria<Image, String> criteria = Criteria.builder().optEngine("PaddlePaddle").setTypes(Image.class, String.class).optModelPath(Paths.get("C:\\laker-1")).optTranslator(new PpWordRecognitionTranslator2()).build();

2.新增PpWordRecognitionTranslator2类

    /** * 处理输出方法,将模型的输出转换为字符串。* * @param ctx 翻译上下文* @param list 模型的输出列表* @return 转换后的字符串* @throws IOException 如果处理输出时发生错误*/@Overridepublic String processOutput(TranslatorContext ctx, NDList list) throws IOException {StringBuilder sb = new StringBuilder();NDArray tokens = list.singletonOrThrow();System.out.println("输出:" + tokens);// 计算出每行中最大值的索引位置 ND: (20, 97) 即 20行 97列,97列// 97列是初始化字典的行数,所以肯定是97列。// 20为图片中可能的字符数long[] indices = tokens.get(0).argMax(1).toLongArray();// 字符置信度float[] probs = new float[indices.length];for (int row = 0; row < indices.length; row++) {long dictIndex = indices[row];if (dictIndex > 0) { // 剔除 blankfloat[] v = tokens.get(0).get(row).toFloatArray();NDArray value = tokens.get(0).get(new NDIndex("" + row + ":" + (row + 1) + "," + dictIndex + ":" + (dictIndex + 1)));probs[row] = value.toFloatArray()[0];System.out.println(table.get((int) dictIndex) + " " + probs[row]);// 剔除置信度小于 0.6的if (probs[row] < 0.6f) {continue;}sb.append(table.get((int) dictIndex));}}return sb.toString();}/** * 处理输入方法,将图像数据转换为模型可接受的格式。* * @param ctx 翻译上下文* @param input 输入图像* @return 转换后的NDList对象*/@Overridepublic NDList processInput(TranslatorContext ctx, Image input) {NDArray img = input.toNDArray(ctx.getNDManager());System.out.println(img);int[] hw = resize48(input.getWidth(), input.getHeight());img = NDImageUtils.resize(img, hw[1], hw[0]);// 将图像转换为张量,并进行归一化操作,减去0.5并除以0.5。img = NDImageUtils.toTensor(img).sub(0.5f).div(0.5f);// 在张量的第一个维度上添加一个维度,通常用于将单个图像添加到批处理中。img = img.expandDims(0);System.out.println("输入 :" + img);return new NDList(img);}/** * 计算新的图像宽度和高度,确保宽度不超过48,并按比例调整高度。* * @param w 图像原始宽度* @param h 图像原始高度* @return 包含新的宽度和高度的整数数组*/private int[] resize48(double w, double h) {double maxWhRatio = w / h;int imgW = (int) (48 * maxWhRatio);// 检查按比例调整高度后是否超过了目标宽度int resizedW = (int) Math.ceil(48 * maxWhRatio);return new int[]{48, resizedW};}

输出为

// 原始图片 高 39,宽105 
: (39, 105, 3) cpu() uint8
[ Exceed max print size ]
// resize后的 高 48,宽130
输入 :ND: (1, 3, 48, 130) cpu() float32
[ Exceed max print size ]
// 字符识别个数为16个,字符是97个的英文字典
输出:softmax_2.tmp_0: (1, 16, 97) cpu() float32
[ Exceed max print size ]
[ 0.932977
1 0.99981683
+ 0.99966896
1 0.99980944
= 0.9967675
2 0.9998343
] 0.9975802[1+1=2]

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

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

相关文章

3 - AOP

1. 快速入门 1.1 基本说明 AOP(aspect oriented programming) &#xff0c;面向切面编程 切面类中声明通知方法&#xff1a; 前置通知&#xff1a;Before返回通知&#xff1a;AfterReturning异常通知&#xff1a;AfterThrowing后置通知&#xff1a;After环绕通知&#xff1…

2、Redis持久化、主从与哨兵:构建强大而稳定的数据生态

Redis作为一款高性能的内存数据库&#xff0c;其在持久化、主从复制和哨兵系统方面的支持使其在大规模应用和高可用性场景中脱颖而出。本文将深入探讨Redis的持久化机制、主从复制以及哨兵系统&#xff0c;为构建强大而稳定的数据生态揭示关键技术。 持久化&#xff1a;数据的…

http状态码对照表

状态码含义100客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收&#xff0c;且仍未被拒绝。客户端应当继续发送请求的剩余部分&#xff0c;或者如果请求已经完成&#xff0c;忽略这个响应。服务器必须在请求完成后向客户端发送一个最终响应。…

开发React应用的多语言支持最佳实践

前言 VoerkaI18n是一款非常优秀的全新的开源国际化多语言解决方案&#xff0c;主要特性包括&#xff1a; 全面工程化解决方案&#xff0c;提供初始化、提取文本、自动翻译、编译等工具链支持。符合直觉&#xff0c;不需要手动定义文本Key映射。强大的插值变量格式化器机制&am…

二进制与十六进制,二进制与八进制之间的相互转换技巧

目录 1.二进制转换为八进制 2.八进制转换为二进制 3.二进制转换为十六进制 4.十六进制转换为二进制 1.二进制转换为八进制 转换为8进制 第一步&#xff1a;以小数点为分界线&#xff0c;整数部分自右向左&#xff0c;小数部分自左向右每3位取成1位&#xff1a; 整数部分…

【python入门】day28:记录用户登录日志

演示 代码 #-*- coding:utf-8 -*- print(记录用户登录日志----------------------------) import time def show_info():print(输入提示数字,执行相应操作:0退出,1查看登录日志) def write_logininfo(username):#----------记录日志with open(log.txt,a,encodingutf-8)as file…

如何高效阅读Linux的man page

有时候需要在man page中查某个命令的用法&#xff0c;我们一般会使用man command的方式来查询&#xff0c;例如man vmstat.但是对于一些bash内置的命令&#xff0c;如alias,如果使用man alias会打开General Commands Manual ,如下图 可以看到&#xff0c;内置命令很多&#xff…

COBOL语言 :一种主要专注于解决业务问题的编程语言

译文&#xff1a; 什么是COBOL? COBOL是一种主要专注于解决业务问题的编程语言。COBOL的完整形式是面向业务的通用语言。它主要用于公司和政府的商业、金融和行政系统。这种语言也被用来解决许多数据处理问题。 它是由CODASYL(数据系统语言会议)开发的。它被用作大型机中的一…

基于 InternLM 和 LangChain 搭建你的知识库

如何打造垂域大模型是一个重要落地方向。 如何打造个人专属的大模型应用也是重要的问题。 RAG 外挂一个知识库 优势&#xff1a;成本低&#xff0c;实时更新 劣势&#xff1a;能力受基座模型影响大&#xff0c;RAG每次需要将检索文档和问题提交给大模型&#xff0c;极大占用上下…

工程项目管理系统源码与Spring Cloud:实现高效系统管理与二次开发

随着企业规模的不断扩大和业务的快速发展&#xff0c;传统的工程项目管理方式已经无法满足现代企业的需求。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;企业需要借助先进的数字化技术进行转型。本文将介绍一款采用Spring CloudSpring BootMybat…

C++力扣题目701--二叉搜索树中的插入操作

给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和要插入树中的值 value &#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 &#xff0c;新值和原始二叉搜索树中的任意节点值都不同。 注意&#xff0c;可能存在多种有效的插入方式&a…

苏州倍丰智能新型雾化粉末技术量产成功!金属3D打印全产业链更进一步

苏州倍丰智能深耕金属3D打印技术领域&#xff0c;以金属3D打印全产业链为目标&#xff0c;围绕金属3D打印设备&#xff0c;涵盖包括金属粉末前后处理设备、金属粉末原材料制备、先进工艺研发等多个领域&#xff0c;完成了一整条自上而下的金属3D打印全产业链。 近日&#xff0c…

大数据Doris(五十四):SQL函数之日期函数(二)

文章目录 SQL函数之日期函数(二) 一、DAYOFMONTH(DATETIME date) 二、dayofweek(DATETIME date)

HarmonyOS 通过 animateTo讲解尺寸动画效果

上文 HarmonyOS讲解并演示 animateTo 动画效果 我们已经做出了基本的动画效果 也对 animateTo 的使用比较熟悉了 第一个参数是 配置动画参数的json 第二个参数 则是改变我们元素属性值的事件 但属性值 远远不止位置属性 本文 我们来说 通过尺寸变化 完成动画效果 如果你有看过…

代码随想录算法训练营第4天 | 24. 两两交换链表中的节点 , 19.删除链表的倒数第N个节点 , 面试题 02.07. 链表相交 , 142.环形链表II

链表知识基础 文章链接&#xff1a;https://programmercarl.com/%E9%93%BE%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html# 24. 两两交换链表中的节点 题目链接&#xff1a;https://leetcode.cn/problems/swap-nodes-in-pairs/ 使用虚拟头结点&#xff0c;这样会方便很…

Promise和箭头函数和普通函数的区别

\1. Promise 的理解 Promise 是一种为了避免回调地狱的异步解决方案 2. Promise 是一种状态机&#xff1a; pending&#xff08;进行中&#xff09;、fulfilled&#xff08;已成功&#xff09;和rejected&#xff08;已失败&#xff09; 只有异步操作的结果&#xff0c;可以决…

Centos7编译Python3.11源码并安装完成的详细教程

Python3.11的Linux源码&#xff1a; Index of /ftp/python/https://www.python.org/ftp/python/由于Centos7里自带的openssl是1.0版本的&#xff0c;而Centos Stream8和9用的是openssl-1.1.1版本的。 注意&#xff1a;openssl必须是openssl-1.1.1版本的&#xff0c;虽然最高版…

QT的事件机制

QT的事件机制 文章目录 QT的事件机制 1、QT的事件机制。2、QT事件的整体流程。1、事件处理函数。1、鼠标按下与鼠标释放事件。2、事件的接收与忽略(accept()和ignore()函数&#xff09;。 2.事件的分发enevt()1、事件分发的dome。2、enevt事件的缺点。 3、事件的过滤器。 3、总…

通过本质看现象:关于Integer受内部初始化赋值范围限制而出现的有趣现象

文/朱季谦 这是我很多年前的第一篇技术博客&#xff0c;当时作为一名技术小菜鸟&#xff0c;总体而言显得很拙见&#xff0c;但也算是成长路上的一个小脚印&#xff0c;希望能在以后的日子里&#xff0c;可以对JAVA技术有一个更加深入的思考与认识。 前几天我在逛论坛的时候&a…

SSM基础入门

SSM Mybatis、Spring和SpringMVC这三个框架整合在一起完成业务功能开发 文章目录 SSM5.1 流程5.2 详细步骤5.2.1 基本配置5.2.2 功能模块开发5.2.3 测试5.2.3.1 单元测试5.2.3.2 PostMan测试 5.3 统一结果封装5.3.1 概念5.3.2 实现 5.4 统一异常处理5.4.1 异常处理器的使用5.4…