从零开发短视频电商 PaddleOCR Java推理 (三)优化文本检测模型输入和输出

news2024/11/30 10:31:06

背景

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

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

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

  • 文档:PaddleOCR文本检测模型推理文档
  • Python推理代码:PaddleOCR文本检测模型推理代码

文本检测模型推理,默认使用DB模型的配置参数。

通过参数limit_typedet_limit_side_len来对图片的尺寸进行限制, limit_type可选参数为[max, min], det_limit_size_len 为正整数,一般设置为32 的倍数,比如960。

参数默认设置为limit_type='max', det_limit_side_len=960。表示网络输入图像的最长边不能超过960, 如果超过这个值,会对图像做等宽比的resize操作,确保最长边为det_limit_side_len。 设置为limit_type='min', det_limit_side_len=960 则表示限制图像的最短边为960。

如果输入图片的分辨率比较大,而且想使用更大的分辨率预测,可以设置det_limit_side_len 为想要的值。

DJL原始输入输出

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

Criteria<Image, DetectedObjects> criteria1 = Criteria.builder()
                .optEngine("PaddlePaddle")
                .setTypes(Image.class, DetectedObjects.class)
                .optModelUrls("https://paddleocr.bj.bcebos.com/PP-OCRv4/chinese/ch_PP-OCRv4_det_infer.tar")
                .optTranslator(new PpWordDetectionTranslator(new ConcurrentHashMap<String, String>()))
                .build();
public class PpWordDetectionTranslator implements NoBatchifyTranslator<Image, DetectedObjects> {

    private final int maxLength;

    /**
     * Creates the {@link PpWordDetectionTranslator} instance.
     *
     * @param arguments the arguments for the translator
     */
    public PpWordDetectionTranslator(Map<String, ?> arguments) {
        maxLength = ArgumentsUtil.intValue(arguments, "maxLength", 960);
    }

    /** {@inheritDoc} */
    @Override
    public DetectedObjects processOutput(TranslatorContext ctx, NDList list) {
        NDArray result = list.singletonOrThrow();
        ImageFactory factory = ImageFactory.getInstance();
        List<BoundingBox> boxes;
        // faster mechanism
        if ("ai.djl.opencv.OpenCVImageFactory".equals(factory.getClass().getName())) {
            result = result.squeeze(0);
            Image image = factory.fromNDArray(result);
            boxes =
                    image.findBoundingBoxes().parallelStream()
                            .filter(
                                    box -> {
                                        Rectangle rect = (Rectangle) box;
                                        return rect.getWidth() * image.getWidth() > 5
                                                || rect.getHeight() * image.getHeight() > 5;
                                    })
                            .collect(Collectors.toList());
        } else {
            result = result.squeeze().mul(255f).toType(DataType.UINT8, true).neq(0);
            boolean[] flattened = result.toBooleanArray();
            Shape shape = result.getShape();
            int w = (int) shape.get(0);
            int h = (int) shape.get(1);
            boolean[][] grid = new boolean[w][h];
            IntStream.range(0, flattened.length)
                    .parallel()
                    .forEach(i -> grid[i / h][i % h] = flattened[i]);
            boxes = new BoundFinder(grid).getBoxes();
        }
        List<String> names = new ArrayList<>();
        List<Double> probs = new ArrayList<>();
        int boxSize = boxes.size();
        for (int i = 0; i < boxSize; i++) {
            names.add("word");
            probs.add(1.0);
        }
        return new DetectedObjects(names, probs, boxes);
    }

    /** {@inheritDoc} */
    @Override
    public NDList processInput(TranslatorContext ctx, Image input) {
        NDArray img = input.toNDArray(ctx.getNDManager());
        int h = input.getHeight();
        int w = input.getWidth();
        int[] hw = scale(h, w, maxLength);

        img = NDImageUtils.resize(img, hw[1], hw[0]);
        img = NDImageUtils.toTensor(img);
        img =
                NDImageUtils.normalize(
                        img,
                        new float[] {0.485f, 0.456f, 0.406f},
                        new float[] {0.229f, 0.224f, 0.225f});
        img = img.expandDims(0);
        return new NDList(img);
    }

    private int[] scale(int h, int w, int max) {
        int localMax = Math.max(h, w);
        float scale = 1.0f;
        if (max < localMax) {
            scale = max * 1.0f / localMax;
        }
        // paddle model only take 32-based size
        return resize32(h * scale, w * scale);
    }

    private int[] resize32(double h, double w) {
        double min = Math.min(h, w);
        if (min < 32) {
            h = 32.0 / min * h;
            w = 32.0 / min * w;
        }
        int h32 = (int) h / 32;
        int w32 = (int) w / 32;
        return new int[] {h32 * 32, w32 * 32};
    }
}

DJL输出优化 一

// 原输出如下:
[
	{"class": "word", "probability": 1.00000, "bounds": {"x"=0.121, "y"=0.873, "width"=0.262, "height"=0.021}}
	{"class": "word", "probability": 1.00000, "bounds": {"x"=0.384, "y"=0.854, "width"=0.538, "height"=0.031}}
	{"class": "word", "probability": 1.00000, "bounds": {"x"=0.395, "y"=0.670, "width"=0.335, "height"=0.020}}
	...
	置信度`probability`是写死的,`bounds`是按比例缩小的不对。
	
// 优化后输出如下:	
[
	{"class": "word", "probability": 1.00000, "bounds": {"x"=0.099, "y"=0.852, "width"=0.305, "height"=0.064}}
	{"class": "word", "probability": 1.00000, "bounds": {"x"=0.353, "y"=0.822, "width"=0.600, "height"=0.094}}
	{"class": "word", "probability": 1.00000, "bounds": {"x"=0.376, "y"=0.650, "width"=0.374, "height"=0.059}}
	...
	修复了`bounds`是按比例缩小的不对问题 置信度 没啥用,优化还不如 过滤掉过大或者过小的box

多引入个djl opencv包

  <dependency>
            <groupId>ai.djl.opencv</groupId>
            <artifactId>opencv</artifactId>
            <version>0.25.0</version>
        </dependency>

代码我尝试着翻译python为java但是很痛苦,我们还是在dlj上修改吧,如下:

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

Criteria<Image, DetectedObjects> criteria1 = Criteria.builder()
                .optEngine("PaddlePaddle")
                .setTypes(Image.class, DetectedObjects.class)
                .optModelUrls("https://paddleocr.bj.bcebos.com/PP-OCRv4/chinese/ch_PP-OCRv4_det_infer.tar")
                .optTranslator(new PpWordDetectionTranslator2(new ConcurrentHashMap<String, String>()))
                .build();

2.新增PpWordDetectionTranslator2类,仅修改如下内容

   public DetectedObjects processOutput(TranslatorContext ctx, NDList list) {
        NDArray result = list.singletonOrThrow();
        ImageFactory factory = ImageFactory.getInstance();
        List<BoundingBox> boxes;
        // faster mechanism
        if ("ai.djl.opencv.OpenCVImageFactory".equals(factory.getClass().getName())) {
            result = result.squeeze(0);
            Image image = factory.fromNDArray(result);
            boxes =
                    image.findBoundingBoxes().parallelStream()
                            .filter(
                                    box -> {
                                        Rectangle rect = (Rectangle) box;
                                        return rect.getWidth() * image.getWidth() > 5
                                                || rect.getHeight() * image.getHeight() > 5;
                                    })
                            .collect(Collectors.toList());
        } else {
            result = result.squeeze().mul(255f).toType(DataType.UINT8, true).neq(0);
            boolean[] flattened = result.toBooleanArray();
            Shape shape = result.getShape();
            int w = (int) shape.get(0);
            int h = (int) shape.get(1);
            boolean[][] grid = new boolean[w][h];
            IntStream.range(0, flattened.length)
                    .parallel()
                    .forEach(i -> grid[i / h][i % h] = flattened[i]);
            boxes = new BoundFinder(grid).getBoxes();
        }
        List<String> names = new ArrayList<>();
        List<Double> probs = new ArrayList<>();
        // 对矩形区域进行扩展处理 start
        List<BoundingBox> extendBoxes = new ArrayList<>();
        for (BoundingBox box : boxes) {
            names.add("word");
            probs.add(1.0);

            Rectangle rect = box.getBounds();
            double[] extended = extendRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
            extendBoxes.add(new Rectangle(extended[0], extended[1], extended[2], extended[3]));
        }
        // 对矩形区域进行扩展处理 end
        return new DetectedObjects(names, probs, extendBoxes);
    }

优化前

优化后

优化输入

会多识别出来一些内容。

    private int[] scale(int h, int w, int max) {
        int localMax = Math.max(h, w);
        float ratio = 1.0f;
        if (Math.max(h, w) > max) {
            if (h > w) {
                ratio = (float) max / (float) h;
            } else {
                ratio = (float) max / (float) w;
            }
        }
        // paddle model only take 32-based size
        return resize32(h * ratio, w * ratio);
    }

    private int[] resize32(double h, double w) {

        int resize_h = Math.round((float) h / 32f) * 32;
        int resize_w = Math.round((float) w / 32f) * 32;
        return new int[]{resize_h, resize_w};
    }

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

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

相关文章

Postgresql 12.2 + PostGIS 3.0.1 安装部署

参考文档&#xff1a; 按照该文档安装即可&#xff0c;如果遇到报错&#xff0c;可以参考下文&#xff1a; https://blog.csdn.net/weixin_41166785/article/details/127674169 所需的安装包 在资源里面&#xff08;我看下怎么可以不用积分下载&#xff09; 1、no acceptable…

项目01——《3D滚球跑酷》

布局通常2 by 3 接下来我们布置场景&#xff0c;我们的预期结果&#xff08;功能分析&#xff09;是&#xff1a; 游戏中中的小球会以恒定速度向前移动&#xff0c;而玩家控制着小球左右移动来躲避跑道中的红色障碍物&#xff0c;如果玩家能控制小球在跑到上移动一定距离则视为…

从CISC到RISC-V:揭开指令集的面纱

对于大多数同学来说&#xff0c;计算机或智能手机的运行似乎就像魔法一样神奇。你可能知道它们内部都是一些复杂的电子组件&#xff0c;比如CPU、内存等等&#xff0c;但这些组件是如何协同工作&#xff0c;让我们可以在电脑上打字&#xff0c;或者在手机上看视频呢&#xff1f…

基于SSM的在线宠物商城设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue、HTML 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是…

Tide Quencher 7.1WS azide,TQ7.1WS N3,适用于多种荧光物质的分析

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;Tide Quencher 7.1WS 叠氮&#xff0c;TQ7.1WS 叠氮&#xff0c;Tide Quencher 7.1WS azide&#xff0c;TQ7.1WS N3&#xff0c;TQ7.1WS azide&#xff0c;Tide Quencher 7.1WS N3 一、基本信息 产品简介&#xff1…

java SECS管理系统 将逐步推出 SECS 客户端(Passive) 管理系统 SECS快速开发平台 springboot secs开发平台

SECS管理系统 这是一套SECS客户端(Passive)&#xff0c;可以直接连接PLC设备,支持Modbus、三菱MC、欧姆龙Fine、OPC-UA、西门子S7设备等通信。 企业已经有了EAP软件&#xff0c;但是设备没有SECS通信功能&#xff0c;这时候可以使用这套框架&#xff0c;直接连接设备&#xff…

springboot集成shiro+前端vue,前后端分离项目遇到跨域以及sessionid拿不到等问题

近期在写前后端分离的项目&#xff0c;由于前后端分离导致原来使用的shiro配置无法满足现有系统要求。同时在前后端分离项目中存在的一些问题。例如&#xff0c;一些用户信息需要存储在后端方便进行安全性判断&#xff0c;但这些存储在后端的session前端却获取不到&#xff08;…

专业140+总410+哈尔滨工业大学803信号与系统和数字逻辑电路考研经验哈工大电子信息(信息与通信工程-信通)

一年的努力付出终于有了收获&#xff0c;今年专业课140&#xff0c;总分410顺利上岸哈工大803电子信息&#xff08;信息与通信-信通&#xff09;&#xff0c;回顾总结了自己这一年的复习&#xff0c;有得有失&#xff0c;希望对大家复习有所帮助。 数学 时间安排&#xff1a;…

C++力扣题目40--组合总和II

力扣题目链接(opens new window) 给定一个数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 说明&#xff1a; 所有数字&#xff08;包括目标数&#xff09;都是…

linux pxe高效批量网络装机

系统装机的三种方式 U盘&#xff08;pe&#xff09; 光驱 网络启动&#xff08;pxe&#xff09; pxe PXE 的全称是 preboot execute environment它其实是Intel在很久以前提出来的一项用于通过网络来引导系统的标准。允许客户机通过网络从远程服务器上下载引导镜像&#…

252:vue+openlayers 绘制锥形渐变填充色的圆形

第252个 点击查看专栏目录 本示例的目的是介绍如何在vue+openlayer中绘制带有锥形渐变填充色的圆形。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共131行)相关API参考专栏目标示例效果 </

【论文阅读】Speech Driven Video Editing via an Audio-Conditioned Diffusion Model

DiffusionVideoEditing&#xff1a;基于音频条件扩散模型的语音驱动视频编辑 code&#xff1a;GitHub - DanBigioi/DiffusionVideoEditing: Official project repo for paper "Speech Driven Video Editing via an Audio-Conditioned Diffusion Model" paper&#…

IOS-高德地图SDK接入-Swift

申请key 这个要前往高德开发平台注册成为个人开发者然后在控制台创建一个应用&#xff1a; 高德开发平台 注册步骤就不写了&#xff0c;写一下创建应用的步骤&#xff1a; 1、点击应用管理——>我的应用 2、点击右上角的创建新应用 3、输入内容&#xff1a; 4、点击添加ke…

计算机视觉丨基于OpenCV的人脸识别打卡系统

文章目录 写在前面项目分析需求分析1.数据模型2.打卡功能3.数据维护4.考勤报表 系统设计项目设计1.文件系统2.数据模块3.工具模块4.服务模块5.人脸识别6.主函数 运行结果写在后面 写在前面 本期内容&#xff1a;基于OpenCV的WANT公司人脸识别打卡系统。 项目需求&#xff1a;…

Flink(十三)【Flink SQL(上)】

前言 最近在假期实训&#xff0c;但是实在水的不行&#xff0c;三天要学完SSM&#xff0c;实在一言难尽&#xff0c;浪费那时间干什么呢。SSM 之前学了一半&#xff0c;等后面忙完了&#xff0c;再去好好重学一遍&#xff0c;毕竟这玩意真是面试必会的东西。 今天开始学习 Flin…

阿里云 linux Centos7 安装 Miniconda3 + 创建Python环境

1.下载miniconda &#xff08;1&#xff09;法一&#xff1a;可以去下载清华源的miniconda镜像源&#xff0c;选择自己需要的版本&#xff0c;然后上传到Linux服务器上&#xff0c;linux上使用请选择linux版本&#xff0c;如下&#xff1a; &#xff08;2&#xff09;法二&…

在Excel中如何打开VBA,这里提供两种方法

想在Excel中创建或添加自己的自定义Visual Basic脚本吗&#xff1f;第一步是了解如何在Excel中打开VBA编辑器。 在易用性和整体功能方面&#xff0c;没有其他电子表格应用程序能与Excel相提并论。无论你想做什么&#xff0c;只要你能深入挖掘Excel的深层菜单&#xff0c;就有很…

Ubuntu 22.04 Cron使用

需要定时处理的场景还是比较多的&#xff0c;比如信息推送、日志清理等。 这篇文章我们来说说如何使用cron来实现定时处理&#xff0c;以及监控任务的执行。 使用 Ubuntu中使用cron&#xff0c;要用到的命令是crontab。不加sudo时&#xff0c;处理的是个人的定时任务。当加上…

HarmonyOS应用开发者高级认证试题库(鸿蒙)

目录 考试链接&#xff1a; 流程&#xff1a; 选择&#xff1a; 判断 单选 多选 考试链接&#xff1a; 华为开发者学堂华为开发者学堂https://developer.huawei.com/consumer/cn/training/dev-certification/a617e0d3bc144624864a04edb951f6c4 流程&#xff1a; 先进行…

支持华为GaussDB数据库的免费开源ERP:人力资源管理解决方案概述

开源智造所推出的Odoo SuperPeople数字化解决方案将HR和薪资数据与财务、项目规划、预算和采购流程连接起来&#xff0c;消除了多套系统给企业带来的信息孤岛问题。 ——复星集团 人力资源中心 高经理 一种更具吸引力、更有洞察力的人员管理方式 什么是开源智造Odoo的人力资源…