Java使用PaddleOCR遮盖图片页码

前言:

        因为图片上敲了很多的页码,要求写个程序定位到页码所在位置并去除,翻了很多技术最后决定使用 PaddleOCR。图片如下:

如何在java 中使用参考了这位大佬的博客

Java使用PaddleOCR,这可能是Java目前最通用的OCR_paddleocr java-CSDN博客文章浏览阅读7.1k次,点赞14次,收藏32次。Java代码实现调用RapidOCR(基于PaddleOCR),适配Mac、Win、Linux,支持最新PP-OCRv4_paddleocr javahttps://blog.csdn.net/qq_41793039/article/details/134220607https://blog.csdn.net/qq_41793039/article/details/134220607https://blog.csdn.net/qq_41793039/article/details/134220607https://blog.csdn.net/qq_41793039/article/details/134220607https://blog.csdn.net/qq_41793039/article/details/134220607https://blog.csdn.net/qq_41793039/article/details/134220607https://blog.csdn.net/qq_41793039/article/details/134220607https://blog.csdn.net/qq_41793039/article/details/134220607https://blog.csdn.net/qq_41793039/article/details/134220607

软件安装

1.下载python,这里我使用的是版本为 python-3.9.13-amd64,并配置好环境,可以看这一篇
真小白入门:python的安装(一)_python 安装-CSDN博客文章浏览阅读10w+次,点赞719次,收藏1.9k次。windows下python的安装—–因为我是个真小白,网上的大多入门教程并不适合我这种超级超级小白,有时候还会遇到各种各样的问题,因此记录一下我的安装过程,希望大家都能入门愉快,欢迎指教—–本文针对超级小白,内容可能会引起各路大神不适,请谨慎观看1. 打开官网/www.python.org,选择Downloads 2. 然后在这里选择要安装的版本3.X.X或者2.X.X_python 安装https://blog.csdn.net/nmjuzi/article/details/79075736https://blog.csdn.net/nmjuzi/article/details/79075736https://blog.csdn.net/nmjuzi/article/details/79075736https://blog.csdn.net/nmjuzi/article/details/79075736https://blog.csdn.net/nmjuzi/article/details/79075736https://blog.csdn.net/nmjuzi/article/details/79075736

2.下载PaddleOCR

 首先安装PaddlePaddlePaddleOCR依赖于PaddlePaddle

#CPU(一般都是cpu)
pip install paddlepaddle -i https://pypi.tuna.tsinghua.edu.cn/simple

我这里使用的是2.6.2版本 pip install paddlepaddle==2.6.2 -i https://pypi.tuna.tsinghua.edu.cn/simple

#如果是gpu
pip install paddlepaddle-gpu -i https://pypi.tuna.tsinghua.edu.cn/simple

安装 paddleocr

pip install paddleocr -i https://pypi.tuna.tsinghua.edu.cn/simple

安装完成后

可进入 cmd ,输入python 后,再将以下代码直接粘贴进去,查看是否能识别

from paddleocr import PaddleOCR, draw_ocr
# Paddleocr目前支持的多语言语种可以通过修改lang参数进行切换
# 例如`ch`, `en`, `fr`, `german`, `korean`, `japan`
ocr = PaddleOCR(use_angle_cls=True, lang="ch")  # need to run only once to download and load model into memory
img_path = '你图片的地址'
result = ocr.ocr(img_path, cls=True)
for line in result:
    print(line)

第一种实现方式

代码逻辑

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.benjaminwan.ocrlibrary.OcrResult;
import com.benjaminwan.ocrlibrary.Point;
import com.benjaminwan.ocrlibrary.TextBlock;
import com.xxx.common.utils.file.FileTypeUtils;
import io.github.mymonstercat.Model;
import io.github.mymonstercat.ocr.InferenceEngine;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 使用的是 pp飞浆ocr https://aistudio.baidu.com/modelsdetail/286?modelId=286
 * 1.需要在电脑上安装python 这里推荐版本为 python-3.9.13-amd64
 * 2.参照博客 https://blog.csdn.net/qq_41793039/article/details/134220607
 */
public class ImageOcrUtil {

    //切割整体高度的6分之一
    private static final int SUB_HEIGHT = 6;

    //切割整体宽度的4分之一
    private static final int SUB_WIDTH = 4;

    public static void main(String[] args) {
        smearingPage("E:\\新建文件夹\\1.jpg");
    }

    /**
     * 涂抹页码
     *
     * @param path
     * @return
     */
    public static String smearingPage(String path) {
        File file = new File(path);
        if (!ImageUtil.isImage(file)) return path;

        //获取父级路径
        String parentPath = new File(path).getParent();
        try {
            //原始图片加载
            BufferedImage originalImage = ImageIO.read(file);

            //1.因为图片是固定A4大小的,且出现页码的位置固定在右上角的区域,为了快速识别,直接按比例切割指定区域图片
            String slicingPath = parentPath + File.separator + IdWorker.getIdStr() + ".jpg";
            slicing(originalImage, slicingPath);

            //2.开始识别切割后的图片结果
            InferenceEngine engine = InferenceEngine.getInstance(Model.ONNX_PPOCR_V4);
            OcrResult ocrResult = engine.runOcr(slicingPath);
            ArrayList<TextBlock> textBlocks = ocrResult.getTextBlocks();
            List<PageOcr> ocrCoordinateList = getOcrCoordinate(originalImage, textBlocks);
            //new File(slicingPath).delete();

            //3.开始进行遮盖文字
            if (CollectionUtil.isEmpty(ocrCoordinateList)) return path;
            File sendFile = new File(parentPath + File.separator + "smearing-" + file.getName());
            coverImage(originalImage, ocrCoordinateList, sendFile);
            return sendFile.getPath();
        } catch (Exception e) {
            e.printStackTrace();
            return path;
        }
    }

    /**
     * 过滤并计算出需要文字的坐标
     *
     * @param originalImage
     * @param textBlocks
     * @return
     * @throws Exception
     */
    public static List<PageOcr> getOcrCoordinate(BufferedImage originalImage, ArrayList<TextBlock> textBlocks) throws Exception {
        //开始循环识别集,并获取识别结果
        List<PageOcr> ocrCoordinateList = new ArrayList<>();
        for (TextBlock textBlock : textBlocks) {
            String text = textBlock.getText();
            if (!checkText(text)) continue;

            PageOcr pageOcr = new PageOcr();
            //获取 x y 最大最小位置的坐标
            ArrayList<Point> boxPrint = textBlock.getBoxPoint();
            List<Integer> xList = boxPrint.stream().map(Point::getX).sorted().collect(Collectors.toList());
            List<Integer> yList = boxPrint.stream().map(Point::getY).sorted().collect(Collectors.toList());

            //获取需要绘制区域的宽度与高度
            int g2dWidth = xList.get(xList.size() - 1) - xList.get(0);
            int g2dHeight = yList.get(yList.size() - 1) - yList.get(0);

            //经验,实际测试之后宽度小于32px的也不是需要的,可以根据自己想要的进行更改
            if (g2dHeight < 32) continue;

            // 读取原始图片,并计算起始位置
            int staWidth = originalImage.getWidth() - (originalImage.getWidth() / SUB_WIDTH);
            pageOcr.setX(xList.get(0) + staWidth); // 框的起始横坐标
            pageOcr.setY(yList.get(0)); // 框的起始纵坐标
            pageOcr.setWidth(g2dWidth);
            pageOcr.setHeight(g2dHeight);
            ocrCoordinateList.add(pageOcr);
        }
        return ocrCoordinateList;
    }

    /**
     * 获取指定区域后进行覆盖
     *
     * @param originalImage
     * @param ocrCoordinateList
     * @param sendFile
     * @throws Exception
     */
    public static void coverImage(BufferedImage originalImage, List<PageOcr> ocrCoordinateList, File sendFile) throws Exception {
        // 获取绘图工具
        Graphics2D g2d = originalImage.createGraphics();

        // 绘制白色框进行遮盖
        g2d.setColor(Color.white);
        for (PageOcr pageOcr : ocrCoordinateList) {
            g2d.fillRect(pageOcr.getX(), pageOcr.getY(), pageOcr.getWidth(), pageOcr.getHeight());
        }
        // 释放绘图资源
        g2d.dispose();

        // 保存新图片
        ImageIO.write(originalImage, FileTypeUtils.getFileType(sendFile), sendFile);
    }

    /**
     * 切割指定区域图片图片
     *
     * @param originalImage
     * @param outputPath
     * @throws Exception
     */
    public static void slicing(BufferedImage originalImage, String outputPath) throws Exception {
        int subHeight = originalImage.getHeight() / SUB_HEIGHT;
        int subWidth = originalImage.getWidth() / SUB_WIDTH;
        int staWidth = originalImage.getWidth() - subWidth;
        BufferedImage subImage = originalImage.getSubimage(staWidth, 0, subWidth, subHeight);
        ImageIO.write(subImage, "jpg", new File(outputPath));
    }

    /**
     * 过滤识别后的文字 是否是三位数的数字
     *
     * @param text
     * @return
     */
    public static boolean checkText(String text) {
        if (text.length() > 4) return false;
        if (text.equals("000")) return false;
        text = text.replace("U", "0");
        return isNumeric(text);
    }

    /**
     * 判断是否都是数字
     *
     * @param str
     * @return
     */
    public static boolean isNumeric(String str) {
        if (str == null || str.length() == 0) {
            return false;
        }
        for (char c : str.toCharArray()) {
            if (!Character.isDigit(c)) {
                return false;
            }
        }
        return true;
    }
}

实体类



import lombok.Data;

@Data
public class PageOcr {

    private int x;

    private int y;

    private int width;

    private int height;
}

判断方法


import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * 图片处理工具类
 *
 */
public class ImageUtil {
 

    /**
     * 校验图片是否存在是否可读
     * @param file
     * @return
     */
    public static boolean isImage(File file) {
        try (FileInputStream fis = new FileInputStream(file);
             FileChannel channel = fis.getChannel()) {
            // 分配直接内存缓冲区
            ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
            // 读取文件内容到缓冲区
            int bytesRead = channel.read(buffer);
            if (bytesRead > 0) {
                return true; // 文件可读
            } else {
                return false; // 文件为空或无法读取
            }
        } catch (Exception e) {
            System.out.println("校验err:" + file.getPath());
            return false; // 发生异常,文件不可读
        }
    }
}

效果展示

1.原图

2.截出来的图片

3.效果(这里使用了黑色快,方便查看)

注意:

当我把项目打包部署到其他地方时一直在报错,报错信息如下

Model dbnet file not found: C:\Users\ADMINI~1\AppData\Local\Temp\1\ocrJava/onnx/ch_PP-OCRv4_det_infer.onnx.param
17:52:14.884 [http-nio-8115-exec-2] INFO  c.b.o.OcrEngine - [initEngine,29] - 推理引擎初始化完成,当前使用的推理引擎为:onnx-v1.1.1
17:52:14.884 [http-nio-8115-exec-2] INFO  c.b.o.OcrEngine - [initEngine,30] - 初始化时模型配置为:Model.ONNX_PPOCR_V4(modelsDir=/models, modelType=onnx, detName=ch_PP-OCRv4_det_infer.onnx, clsName=ch_ppocr_mobile_v2.0_cls_infer.onnx, recName=ch_PP-OCRv4_rec_infer.onnx, keysName=ppocr_keys_v1.txt), 硬件配置为:HardwareConfig(numThread=4, gpuIndex=-1)
17:52:14.885 [http-nio-8115-exec-2] INFO  i.g.m.o.InferenceEngine - [runOcr,57] - 图片路径:D:\图片\1888163925386035201.jpg, 参数配置:ParamConfig(padding=50, maxSideLen=0, boxScoreThresh=0.5, boxThresh=0.3, unClipRatio=1.6, doAngle=false, mostAngle=false)
imgDir=, imgName=D:\图片\1888163925386035201.jpg
find_blob_index_by_name input failed
Try
find_blob_index_by_name output failed
Try
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007fffb6dc694b, pid=5140, tid=0x0000000000002334
#
# JRE version: Java(TM) SE Runtime Environment (8.0_291-b10) (build 1.8.0_291-b10)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.291-b10 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  [RapidOcr.dll+0x7b694b]
#
# Core dump written. Default location: C:\Home\Project\hs_err_pid5140.mdmp
#
# An error report file with more information is saved as:
# C:\Home\Project\hs_err_pid5140.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.

产生原因是我打包部署到其他服务器后系统temp文件夹下不存在需要的文件(需要文件如下)

逐步排查中!!!

注意调用该方法时控制台打印的
OcrResult ocrResult = engine.runOcr(slicingPath);

#打印内容
当前库加载器: OnnxWindowsX8664LibraryLoader
将文件models/ch_PP-OCRv3_det_infer.onnx复制到/onnx,加载此文件:false,JVM退出时删除此文件:false
将文件models/ch_ppocr_mobile_v2.0_cls_infer.onnx复制到/onnx,加载此文件:false,JVM退出时删除此文件:false
将文件models/ch_PP-OCRv3_rec_infer.onnx复制到/onnx,加载此文件:false,JVM退出时删除此文件:false
将文件models/ppocr_keys_v1.txt复制到/onnx,加载此文件:false,JVM退出时删除此文件:false

跟着debug走一下,最后会走到 

JarFileUtil这个类

会看到如下代码

会将这几个包下的文件复制到临时文件

所以就直接把自己电脑的C:\Users\xxxx\AppData\Local\Temp\ocrJava\这个包下的丢到服务器的临时文件夹里就行了。

第二种使用java调用python 文件来进行获取返回 ( 巨慢巨慢巨慢!!!!!)

 1.新建 imageOcr.py文件,并把代码复制进去

from paddleocr import PaddleOCR
import sys
 
def ocrImageData(path):
    # 初始化 PaddleOCR 对象
    ocr = PaddleOCR(use_angle_cls=True, lang='ch')
    ocr_data = [];
    # 进行文字识别
    result = ocr.ocr(path, cls=True)
    for idx in range(len(result)):
     res = result[idx]
     for line in res:
       ocr_data.append(line)
    
    return ocr_data
    


if __name__ == "__main__":
    # 从命令行参数中获取数字
    path = sys.argv[1]
    result = ocrImageData(path)
    print('--splitImage--')
    print(result)  # 输出结果

可以在cmd窗口执行,

 python [路径]\imageOcr.py [要识别图片的地址]
如:
 python C:\Users\xxx\Desktop\1\imageOcr.py C:\Users\xxx\2.jpg

识别图片

返回结果:

2.在java内进行调用获取 直接上完整代码

package com.xxx.common.utils.image;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.benjaminwan.ocrlibrary.OcrResult;
import com.benjaminwan.ocrlibrary.Point;
import com.benjaminwan.ocrlibrary.TextBlock;
import com.xxx.common.utils.StringUtils;
import com.xxx.common.utils.file.FileTypeUtils;
import io.github.mymonstercat.Model;
import io.github.mymonstercat.ocr.InferenceEngine;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 去除页码
 * 使用的是 pp飞浆ocr https://aistudio.baidu.com/modelsdetail/286?modelId=286
 * 1.需要在电脑上安装python 这里推荐版本为 python-3.9.13-amd64
 * 2.参照博客 https://blog.csdn.net/qq_41793039/article/details/134220607
 */
public class ImageOcrUtil {

    /**
     * 识别类型
     */
    public static final String PA_OCR = "paddleOCR";

    public static final String PY_OCR = "pythonOCR";

    //切割整体高度的6分之一
    private static final int SUB_HEIGHT = 6;

    //切割整体宽度的4分之一 17:43:05.379
    private static final int SUB_WIDTH = 4;

    //.py文件的地址
    private static final String PYTHON_PATH = "C:\\xxxxx\\imageOcr.py";

    private static final Logger log = LoggerFactory.getLogger(ImageOcrUtil.class);

    public static void main(String[] args) {
        File file = new File("E:\\图片集");
        for (File listFile : file.listFiles()) {
            smearingPage(listFile.getPath(), PY_OCR);
        }
    }

    /**
     * 涂抹页码
     *
     * @param path
     * @return
     */
    public static String smearingPage(String path, String type) {
        File file = new File(path);
        if (!ImageUtil.isImage(file)) return path;

        //获取父级路径
        String parentPath = new File(path).getParent();
        try {
            //原始图片加载
            BufferedImage originalImage = ImageIO.read(file);

            //1.因为图片是固定A4大小的,且出现页码的位置固定在右上角的区域,为了快速识别,直接按比例切割指定区域图片
            String slicingPath = parentPath + File.separator + IdWorker.getIdStr() + ".jpg";
            slicing(originalImage, slicingPath);

            //2.开始识别切割后的图片结果
            List<PageOcr> ocrCoordinateList = new ArrayList<>();
            if (StringUtils.equals(type, ImageOcrUtil.PA_OCR)) {
                InferenceEngine engine = InferenceEngine.getInstance(Model.ONNX_PPOCR_V3);
                OcrResult ocrResult = engine.runOcr(slicingPath);
                ArrayList<TextBlock> textBlocks = ocrResult.getTextBlocks();
                ocrCoordinateList.addAll(getOcrCoordinate(originalImage, textBlocks));
            }
            if (StringUtils.equals(type, ImageOcrUtil.PY_OCR)) {
                ocrCoordinateList.addAll(getPythonOcrCoordinate(originalImage, slicingPath));
            }
            new File(slicingPath).delete();

            //3.开始进行遮盖文字
            if (CollectionUtil.isEmpty(ocrCoordinateList)) return path;
            File sendFile = new File(parentPath + File.separator + "smearing-" + file.getName());
            coverImage(originalImage, ocrCoordinateList, sendFile);
            return sendFile.getPath();
        } catch (Exception e) {
            System.out.println("错误信息是:" + e.getMessage());
            e.printStackTrace();
            return path;
        }
    }


    /**
     * 过滤并计算出需要文字的坐标
     *
     * @param originalImage
     * @param textBlocks
     * @return
     * @throws Exception
     */
    public static List<PageOcr> getOcrCoordinate(BufferedImage originalImage, ArrayList<TextBlock> textBlocks) throws Exception {
        //开始循环识别集,并获取识别结果
        List<PageOcr> ocrCoordinateList = new ArrayList<>();
        for (TextBlock textBlock : textBlocks) {
            String text = textBlock.getText();
            if (!checkText(text)) continue;

            PageOcr pageOcr = new PageOcr();
            //获取 x y 最大最小位置的坐标
            ArrayList<Point> boxPrint = textBlock.getBoxPoint();
            List<Integer> xList = boxPrint.stream().map(Point::getX).sorted().collect(Collectors.toList());
            List<Integer> yList = boxPrint.stream().map(Point::getY).sorted().collect(Collectors.toList());

            //获取需要绘制区域的宽度与高度
            int g2dWidth = xList.get(xList.size() - 1) - xList.get(0);
            int g2dHeight = yList.get(yList.size() - 1) - yList.get(0);

            //经验,实际测试之后宽度小于32px的也不是需要的,可以根据自己想要的进行更改
            if (g2dHeight < 32) continue;

            // 读取原始图片,并计算起始位置
            int staWidth = originalImage.getWidth() - (originalImage.getWidth() / SUB_WIDTH);
            pageOcr.setX(xList.get(0) + staWidth); // 框的起始横坐标
            pageOcr.setY(yList.get(0)); // 框的起始纵坐标
            pageOcr.setWidth(g2dWidth);
            pageOcr.setHeight(g2dHeight);
            ocrCoordinateList.add(pageOcr);
        }
        return ocrCoordinateList;
    }

    /**
     * 获取指定区域后进行覆盖
     *
     * @param originalImage
     * @param ocrCoordinateList
     * @param sendFile
     * @throws Exception
     */
    public static void coverImage(BufferedImage originalImage, List<PageOcr> ocrCoordinateList, File sendFile) throws Exception {
        // 获取绘图工具
        Graphics2D g2d = originalImage.createGraphics();

        // 绘制白色框进行遮盖
        g2d.setColor(Color.white);
        for (PageOcr pageOcr : ocrCoordinateList) {
            g2d.fillRect(pageOcr.getX(), pageOcr.getY(), pageOcr.getWidth(), pageOcr.getHeight());
        }
        // 释放绘图资源
        g2d.dispose();

        // 保存新图片
        ImageIO.write(originalImage, FileTypeUtils.getFileType(sendFile), sendFile);
    }

    /**
     * 切割指定区域图片图片
     *
     * @param originalImage
     * @param outputPath
     * @throws Exception
     */
    public static void slicing(BufferedImage originalImage, String outputPath) throws Exception {
        int subHeight = originalImage.getHeight() / SUB_HEIGHT;
        int subWidth = originalImage.getWidth() / SUB_WIDTH;
        int staWidth = originalImage.getWidth() - subWidth;
        BufferedImage subImage = originalImage.getSubimage(staWidth, 0, subWidth, subHeight);
        ImageIO.write(subImage, "jpg", new File(outputPath));
    }

    /**
     * 过滤识别后的文字 是否是三位数的数字
     *
     * @param text
     * @return
     */
    public static boolean checkText(String text) {
        if (text.length() > 4) return false;
        if (text.equals("000")) return false;
        text = text.replace("U", "0");
        return isNumeric(text);
    }

    /**
     * 判断是否都是数字
     *
     * @param str
     * @return
     */
    public static boolean isNumeric(String str) {
        if (str == null || str.length() == 0) {
            return false;
        }
        for (char c : str.toCharArray()) {
            if (!Character.isDigit(c)) {
                return false;
            }
        }
        return true;
    }


    //-------------------------------------------------------------

    /**
     * 通过python 识别
     *
     * @param originalImage
     * @param path
     * @return
     * @throws Exception
     */
    public static List<PageOcr> getPythonOcrCoordinate(BufferedImage originalImage, String path) throws Exception {
        log.info("开始识别,{}", path);
        try {
            // 要调用的Python脚本路径
            String pythonScriptPath = PYTHON_PATH;
            // 传递给Python脚本的参数
            String inputNumber = path;

            // 创建ProcessBuilder
            ProcessBuilder processBuilder = new ProcessBuilder("python", pythonScriptPath, inputNumber);
            processBuilder.redirectErrorStream(true); // 合并错误输出与正常输出

            // 启动进程
            Process process = processBuilder.start();

            // 读取Python脚本的输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
            String line;
            StringBuilder output = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                output.append(line);
            }

            // 等待进程结束并获取退出码
            int exitCode = process.waitFor();
            if (exitCode == 0) {
                // 输出结果
                String s = String.valueOf(output);
                String[] split = s.split("--splitImage--");
                return analysisPythonOcr(originalImage, split[1]);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    /**
     * 解析识别后的数据
     *
     * @param originalImage
     * @param input
     * @return
     */
    public static List<PageOcr> analysisPythonOcr(BufferedImage originalImage, String input) {
        List<DataStructure> dataStructures = parseInput(input);

        //开始循环识别集,并获取识别结果
        List<PageOcr> ocrCoordinateList = new ArrayList<>();
        for (DataStructure data : dataStructures) {
            String text = data.getTuple().getCode();
            if (!checkText(text)) continue;


            PageOcr pageOcr = new PageOcr();
            //获取 x y 最大最小位置的坐标
            List<Integer> xList = data.getPoints().stream().map(x -> x.get(0).intValue()).sorted().collect(Collectors.toList());
            List<Integer> yList = data.getPoints().stream().map(x -> x.get(1).intValue()).sorted().collect(Collectors.toList());

            //获取需要绘制区域的宽度与高度
            int g2dWidth = xList.get(xList.size() - 1) - xList.get(0);
            int g2dHeight = yList.get(yList.size() - 1) - yList.get(0);

            //经验,实际测试之后宽度小于32px的也不是需要的,可以根据自己想要的进行更改
            if (g2dHeight < 32) continue;

            // 读取原始图片,并计算起始位置
            int staWidth = originalImage.getWidth() - (originalImage.getWidth() / SUB_WIDTH);
            pageOcr.setX(xList.get(0) + staWidth); // 框的起始横坐标
            pageOcr.setY(yList.get(0)); // 框的起始纵坐标
            pageOcr.setWidth(g2dWidth);
            pageOcr.setHeight(g2dHeight);
            ocrCoordinateList.add(pageOcr);
        }
        return ocrCoordinateList;
    }

    // 解析整个输入字符串
    private static List<DataStructure> parseInput(String input) {
        List<DataStructure> result = new ArrayList<>();

        // 使用正则表达式匹配每个数据块
        Pattern pattern = Pattern.compile("\\[\\[(.*?)\\]\\], \\((.*?)\\)");
        Matcher matcher = pattern.matcher(input);

        while (matcher.find()) {
            // 解析二维坐标
            String pointsStr = matcher.group(1);
            List<List<Double>> points = parsePoints(pointsStr);

            // 解析元组
            String tupleStr = matcher.group(2);
            Tuple tuple = parseTuple(tupleStr);

            // 封装为 DataStructure 对象
            result.add(new DataStructure(points, tuple));
        }

        return result;
    }

    // 解析二维坐标
    private static List<List<Double>> parsePoints(String pointsStr) {
        List<List<Double>> result = new ArrayList<>();

        // 分割每个坐标点
        String[] points = pointsStr.split("\\], \\[");
        for (String point : points) {
            List<Double> coordinates = new ArrayList<>();
            String[] nums = point.replaceAll("[\\[\\]]", "").split(",\\s*");
            for (String num : nums) {
                coordinates.add(Double.parseDouble(num));
            }
            result.add(coordinates);
        }

        return result;
    }

    // 解析元组
    private static Tuple parseTuple(String tupleStr) {
        String[] parts = tupleStr.split(",\\s*");
        String code = parts[0].replaceAll("['\"]", ""); // 去除引号
        double value = Double.parseDouble(parts[1]);
        return new Tuple(code, value);
    }

}

// 自定义数据结构类
@Data
class DataStructure {
    private final List<List<Double>> points;
    private final Tuple tuple;

    public DataStructure(List<List<Double>> points, Tuple tuple) {
        this.points = points;
        this.tuple = tuple;
    }

    public List<List<Double>> getPoints() {
        return points;
    }

    public Tuple getTuple() {
        return tuple;
    }
}

// 自定义元组类
@Data
class Tuple {
    private final String code;
    private final double value;

    public Tuple(String code, double value) {
        this.code = code;
        this.value = value;
    }

    @Override
    public String toString() {
        return String.format("(%s, %f)", code, value);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值