【SpringBoot框架篇】36.整合Tess4J搭建提供图片文字识别的Web服务

news2024/11/16 11:59:46

文章目录

  • 简介
  • 文件下载
  • 引入依赖
  • main函数中使用
  • 基于Springboot搭建OCR Web服务
    • 配置traineddata路径
    • 枚举用到的语种类型
    • 定义接口响应的json数据格式
    • 封装OCR服务引擎
    • 编写web提供服务的接口
    • 启动服务并且测试
    • html demo扩展
  • 项目配套代码

简介

  • Tess4J是一个基于Tesseract OCR引擎的Java接口,可以用来识别图像中的文本。
  • Tesseract是一个开源的光学字符识别(OCR)引擎,它可以将图像中的文字转换为计算机可读的文本。支持多种语言和书面语言,并且可以在命令行中执行。它是一个流行的开源OCR工具,可以在许多不同的操作系统上运行。

文件下载

目前我测试只用到简体中文和英文,所以只下载了两个
简体中文下载
英文下载

其它语种请按需下载

把下载后的文件统一放到一个目录下
在这里插入图片描述

引入依赖

      	<dependency>
            <groupId>net.sourceforge.tess4j</groupId>
            <artifactId>tess4j</artifactId>
            <version>5.10.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

main函数中使用

    public static void main(String[] args) throws Exception {
        ITesseract tesseract = new Tesseract();
        // 设置训练集文件存储目录
        tesseract.setDatapath("D:/traineddata");
        
        // 设置引擎为中文简体 文件名不含后缀
        tesseract.setLanguage("chi_sim");
        String result = tesseract.doOCR(ImageIO.read(new File("D:\\test\\zh.png")));
        System.out.println(result);
        
        // 设置引擎为英文
        tesseract.setLanguage("eng");
        result = tesseract.doOCR(ImageIO.read(new File("D:\\test\\en.png")));
        System.out.println(result);
    }

识别结果如下
在这里插入图片描述
在这里插入图片描述

基于Springboot搭建OCR Web服务

配置traineddata路径

application.yaml中配置如下内容

server:
  port: 8036
#ocr引擎存放路径
tess4j:
  datapath: D:/traineddata

枚举用到的语种类型

/**
 * @Description 自行扩展需要的OCR引擎语种
 * @Author Dominick Li
 **/
@Getter
@AllArgsConstructor
public enum LanguageTypeEnum {

    CHINESE_SIMPLIFIED("chi_sim", "简体中文"),
    ENGLISH("eng", "英文");

    private final String value;
    private final String language;

    /**
     * 根据语种查找枚举对象
     * @param language 前端传的参数
     * @return 没找到对应的则默认使用简单中文
     */
    public static LanguageTypeEnum getLanguageByType(String language) {
        for (LanguageTypeEnum languageTypeEnum : LanguageTypeEnum.values()) {
            if (languageTypeEnum.getValue().equals(language)) {
                return languageTypeEnum;
            }
        }
        return CHINESE_SIMPLIFIED;
    }

}

定义接口响应的json数据格式

@Data
@Builder
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class OcrResult {

    /**
     * 是否识别成功
     */
    public boolean success;

    /**
     * 识别时间
     */
    public long time;

    /**
     * 识别结果
     */
    public String[] texts;

    /**
     * 异常信息
     */
    public String msg;

    public static OcrResult success(String text, long time) {
        return OcrResult.builder()
                .success(true)
                .texts(text.split("\n"))
                .time(time)
                .build();
    }

    public static OcrResult fail(String msg) {
        return OcrResult.builder()
                .success(false)
                .msg(msg)
                .build();
    }

}

封装OCR服务引擎

@Slf4j
@Service
public class TesseractServer {

    @Value("${tess4j.datapath}")
    private String datapath;

    private final static Map<LanguageTypeEnum, ITesseract> SERVER_INSTANCE = new HashMap<>();

    /**
     * 根据枚举配置的语种初始化Tesseract引擎
     */
    @PostConstruct
    public void init() {
        ITesseract iTesseract;
        for (LanguageTypeEnum languageTypeEnum : LanguageTypeEnum.values()) {
            iTesseract = new Tesseract();
            //设置训练集文件存储目录
            iTesseract.setDatapath(datapath);
            //设置语种
            iTesseract.setLanguage(languageTypeEnum.getValue());
            SERVER_INSTANCE.put(languageTypeEnum, iTesseract);
            log.info("load {}  ocr model", languageTypeEnum.getLanguage());
        }
    }

    /**
     * ocr识别
     */
    private OcrResult doOCR(ITesseract iTesseract, BufferedImage bufferedImage) throws Exception {
        String result = null;
        long startTime = System.currentTimeMillis();
        result = iTesseract.doOCR(bufferedImage);
        long time = System.currentTimeMillis()-startTime;
        log.info("Time is: {} 毫秒", time);
        return OcrResult.success(result, time);
    }

    public OcrResult ocrImage(LanguageTypeEnum languageTypeEnum, File file) throws Exception {
        return doOCR(SERVER_INSTANCE.get(languageTypeEnum), ImageIO.read(file));
    }

    public OcrResult ocrImage(LanguageTypeEnum languageTypeEnum, MultipartFile file) throws Exception {
        return ocrImage(languageTypeEnum, ImageIO.read(new ByteArrayInputStream(file.getBytes())));

    }

    public OcrResult ocrImage(LanguageTypeEnum languageTypeEnum, BufferedImage bufferedImage) throws Exception {
        return doOCR(SERVER_INSTANCE.get(languageTypeEnum), bufferedImage);
    }

}

编写web提供服务的接口

@Slf4j
@RestController
@RequestMapping("/api")
public class OcrController {

    @Resource
    private TesseractServer tesseractServer;

    /**
     * OCR识别  /ocr/chi_sim          /ocr/eng
     * @param language 使用的模型语种  chi_sim=简体中文  eng=英文
     * @param file 需要识别的图片
     */
    @PostMapping("/ocr/{language}")
    public OcrResult recognize(@PathVariable String language, MultipartFile file) {
        try {
            // 对图片进行文字识别
            return tesseractServer.ocrImage(LanguageTypeEnum.getLanguageByType(language), file);
        } catch (Exception e) {
            log.error("error:{}", e.getMessage());
            return OcrResult.fail(e.getMessage());
        }
    }

}

启动服务并且测试

http://127.0.0.1:8036/api/ocr/chi_sim 中文引擎识别
http://127.0.0.1:8036/api/ocr/eng 英文引擎识别
在这里插入图片描述

到此基于Springboot框架搭建提供Ocr能力的Web服务就完成

html demo扩展

基于html + jquery 搭建的简陋的demo, 访问路径http://127.0.0.1:8036/index.html
在这里插入图片描述

index.html文件源码,放到项目resources/static目录下即可

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>OCR测试页面</title>
</head>
<style type="text/css">
    #app {
        display: flex;
        margin: 50px;
        height: 1000px;
    }

    #app div {
        padding: 50px;
        width: 50%;
        border: solid 1px #000;
        height: 100%;
    }
</style>
<body>
<div id="app">
    <div id="left" class="upload-box clear">
        <input type="file" id="fileInput">
        选择OCR识别使用的语种
        <input type="radio" name="language" value="zh_sim" checked="checked"/> 简体中文
        <input type="radio" name="language" value="eng"/> 英文
        <input id="summit" type="button" value="识别">
        </br>
        <img id="previewImage" src="" alt="Preview Image" width="100%">
    </div>
    <div>
        <h2>识别结果</h2>
        <p>识别时间:<span id="time"></span>毫秒</p>
        <p id="resust"></p>
    </div>
</div>

<script src="https://cdn.staticfile.org/jquery/3.1.0/jquery.min.js"></script>
<script type="text/javascript">
    const fileInput = document.getElementById('fileInput');
    const previewImage = document.getElementById('previewImage');
    fileInput.addEventListener('change', function () {
        const file = fileInput.files[0]; // 获取选中的文件对象
        if (file) {
            let language = $('input[name="language"]:checked').val();
            uploadOcr(file, language);
            const reader = new FileReader();

            reader.addEventListener('load', function () {
                // 当文件读取完成时触发的事件处理函数
                previewImage.src = reader.result;
            });
            reader.readAsDataURL(file);
        }
    });

    document.getElementById('summit').addEventListener('click', function () {
        const file = fileInput.files[0]; // 获取选中的文件对象
        let language = $('input[name="language"]:checked').val();
        uploadOcr(file, language);
    })

    function uploadOcr(file, language) {
        var formData = new FormData();
        formData.append('file', file);

        $.ajax({
            url: "/api/ocr/" + language, // 上传图片的后端接口地址
            type: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: function (response) {
                // 上传成功后的处理逻辑
                console.log('上传成功' + response);
                $("#time").html(response.time);
                if (response.success) {
                    $("#resust").html("");
                    for (var i = 0; i < response.texts.length; i++) {
                        $("#resust").append(response.texts[i]).append("<br/>");
                    }
                }
            },
            error: function (xhr, status, error) {
                // 上传失败后的处理逻辑
                console.log('上传失败');
            }
        });
    }
</script>
</body>
</html>

项目配套代码

gitee代码地址

创作不易,要是觉得我写的对你有点帮助的话,麻烦在gitee上帮我点下 Star

【SpringBoot框架篇】其它文章如下,后续会继续更新。

  • 1.搭建第一个springboot项目
  • 2.Thymeleaf模板引擎实战
  • 3.优化代码,让代码更简洁高效
  • 4.集成jta-atomikos实现分布式事务
  • 5.分布式锁的实现方式
  • 6.docker部署,并挂载配置文件到宿主机上面
  • 7.项目发布到生产环境
  • 8.搭建自己的spring-boot-starter
  • 9.dubbo入门实战
  • 10.API接口限流实战
  • 11.Spring Data Jpa实战
  • 12.使用druid的monitor工具查看sql执行性能
  • 13.使用springboot admin对springboot应用进行监控
  • 14.mybatis-plus实战
  • 15.使用shiro对web应用进行权限认证
  • 16.security整合jwt实现对前后端分离的项目进行权限认证
  • 17.使用swagger2生成RESTful风格的接口文档
  • 18.使用Netty加websocket实现在线聊天功能
  • 19.使用spring-session加redis来实现session共享
  • 20.自定义@Configuration配置类启用开关
  • 21.对springboot框架编译后的jar文件瘦身
  • 22.集成RocketMQ实现消息发布和订阅
  • 23.集成smart-doc插件零侵入自动生成RESTful格式API文档
  • 24.集成FastDFS实现文件的分布式存储
  • 25.集成Minio实现文件的私有化对象存储
  • 26.集成spring-boot-starter-validation对接口参数校验
  • 27.集成mail实现邮件推送带网页样式的消息
  • 28.使用JdbcTemplate操作数据库
  • 29.Jpa+vue实现单模型的低代码平台
  • 30.使用sharding-jdbc实现读写分离和分库分表
  • 31.基于分布式锁或xxx-job实现分布式任务调度
  • 32.基于注解+redis实现表单防重复提交
  • 33.优雅集成i18n实现国际化信息返回
  • 34.使用Spring Retry完成任务的重试
  • 35.kafka环境搭建和收发消息
  • 36.整合Tess4J搭建提供图片文字识别的Web服务

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

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

相关文章

[Java安全入门]三.URLDNS链

一.前言 在初步学习java的序列化和反序列化之后&#xff0c;这里学习java反序列化漏洞的一个利用链&#xff0c;也是比较基础的一条链。 由于URLDNS不需要依赖第三方的包&#xff0c;同时不限制jdk的版本&#xff0c;所以通常用于检测反序列化的点。 二.代码展开分析 构造链 …

Learn OpenGL 03 着色器

GLSL 着色器的开头总是要声明版本&#xff0c;接着是输入和输出变量、uniform和main函数。每个着色器的入口点都是main函数&#xff0c;在这个函数中我们处理所有的输入变量&#xff0c;并将结果输出到输出变量中。 一个典型的着色器有下面的结构&#xff1a; #version vers…

[java入门到精通] 10 常用API , 正则表达式 , Collection集合

今日目标 BigInteger类BigDecimal类Arrays类包装类String类的常用方法正则表达式Collection集合 1 BigInteger类 1.1 概述 概述 : java.math.BigInteger类是一个引用数据类型 , 可以用于计算一些大的整数 , 当超出基本数据类型数据范围的整数运算时就可以使用BigInteger了。…

Arduino Uno使用Mind+实现图形化编程

文章目录&#xff1a; 一&#xff1a;软件下载安装 1.下载安装 1.1 开发软件 2.辅助软件 2.主控板 二&#xff1a;基础 1.LED 2.传感器 3.智能小车 三&#xff1a;学习资源 一&#xff1a;软件下载安装 1.下载安装 1.1 开发软件 Arduino IDE代码编程软件&#…

集合和数组的相关操作

目录 1.数组转集合(引用类型数组) 2.数组转集合(基础类型数组) 3.集合转数组 4.集合之间是否相交 5.获取两个集合的交集 6.集合转为字符串 1.数组转集合(引用类型数组) (1)Arrays.asList 示例&#xff1a; String[] colArr new String[6];colArr[0] "1";co…

Fastgithub

上Github太慢、打不开怎么办&#xff1f; 选择之一是Fastgithub工具&#xff0c;同时支持win, linux, mac。 1. 工作原理 从公共dns服务器拿到github的大量ip数据&#xff0c;检测哪些ip可用&#xff0c;哪些ip访问速度最佳&#xff0c;然后编写一个本地版的dns服务&#xff0…

小巧设备,大能量:探索口袋中的远程控制神器

在这个科技日新月异的时代&#xff0c;我们的生活被各种手机软件所包围。几乎每个人都有一个甚至多个手机&#xff0c;你是否也有遇到过需要远程操作自己某一台手机的场景呢&#xff1f;今天&#xff0c;我要向大家推荐一款神奇的手机远程操作神器&#xff0c;让你可以随时随地…

【EtherCAT实践篇】十、SSC工具使用说明

EtherCAT Slave Stack Code&#xff08;SSC&#xff09;是倍福提供的EtherCAT从站源代码生成工具&#xff0c;基于SSC工具&#xff0c;可以大大降低EtherCAT数据通讯程序及xml设计难度。 本操作参考SSC软件包中的EtherCAT Slave Design Quick Guide.pdf文档。 1、创建一个SSC工…

项目解决方案:视频监控接入和录像系统设计方案(下)

目 录 1.概述 2. 建设目标及需求 2.1建设总目标 2.2 需求描述 ​2.3 需求分析 3.设计依据与设计原则 3.1设计依据 3.2 设计原则 4.建设方案设计 4.1系统方案设计 4.2组网说明 5.产品介绍 5.1视频监控综合资源管理平台介绍 5.2视频录像服务器和存储 5.2.…

后勤管理系统|基于SSM 框架+vue+ Mysql+Java+B/S架构技术的后勤管理系统设计与实现(可运行源码+数据库+设计文档+部署说明+视频演示)

目录 文末获取源码 前台首页功能 员工注册、员工登录 个人中心 公寓信息 员工功能模块 员工积分管理 管理员登录 ​编辑管理员功能模块 个人信息 ​编辑员工管理 公寓户型管理 ​编辑公寓信息管理 系统结构设计 数据库设计 luwen参考 概述 源码获取 文末获取源…

bug总结(1)--变量取错

a c t i v i t y [ ′ t a g n a m e ′ ] 应为 activity[tag_name]应为 activity[′tagn​ame′]应为couponActivitList[0][‘name’] .隐藏的bug&#xff0c;在测试中竟然测不出来&#xff0c;而且上线了好久。为啥会出现这种低级错误呢&#xff1f;第一是写的时候不够仔细认…

C语言:基于单链表实现的泊车管理系统

一、需求 &#xff08;1&#xff09;管理员方账号登录&#xff1b; &#xff08;2&#xff09;车位管理显示&#xff1a;车位状态&#xff1b; &#xff08;3&#xff09;收费管理&#xff1a;小轿车 5元/小时&#xff0c;面包车6元/小时&#xff0c;大货车或客车7元/小时&a…

算法(6种思想、7种查找)、与数据结构(数组/链表/栈与队列/树)整理总结

算法 除了这里提到的算法思想和查找算法&#xff0c;算法还有别的类型&#xff1a; 排序算法&#xff1a; 对一组元素进行排序的算法。常见的排序算法包括冒泡排序、快速排序、归并排序等。 图算法&#xff1a; 解决图结构相关问题的算法&#xff0c;例如最短路径问题、最小…

Zookeeper详解

1.Zookeeper概述 1.Zookeeper概念 Zookeeper是 Apache Hadoop 项目下的一个子项目&#xff0c;是一个树形目录服务 Zookeeper 翻译过来就是动物园管理员&#xff0c;他是用来管 Hadoop&#xff08;大象&#xff09;、Hive(蜜蜂)、Pig(小猪)的管理员。简称zk Hadoop: 存储海…

【周总结周末日常】

周总结 完成任务开发并且与前端联调通过 完成已开发功能的冒烟测试 修复测试中出现的一些数据显示问题 2024/3/10 晴 温度适宜 这周天气比上周好多了&#xff0c;最起码见到好几次太阳 周六在世纪公园溜达一会儿&#xff0c;偶尔呼吸下大自然&#xff0c;挺棒的…

力扣hot100:152.乘积最大子数组(动态规划)

一个子数组问题&#xff0c;我们要使用线性dp&#xff0c;最好先考虑以i结尾&#xff0c;如果定义dp[i]为前i个数最大子数组乘积值 那么dp[i-1]就无法转移到dp[i]。因此我们先考虑dp[i]定义为以第i个数结尾的最大子数组乘积值。 53. 最大子数组和 最大子数组和是一个动态规划问…

重要通告 | 公司更名为“浙江实在智能科技有限公司”

更名公告 升级蜕变、砥砺前行 因业务快速发展和战略升级&#xff0c;经相关政府机构批准&#xff0c;自2024年3月1日起&#xff0c;原“杭州实在智能科技有限公司”正式更名为“浙江实在智能科技有限公司”。 更名后&#xff0c;公司统一社会信用代码不变&#xff0c;业务主体…

蓝桥杯单片机---第十二届省赛题目解析

文章目录 比赛题目一、代码相关定义、声明1.头文件声明2.变量声明 二、主要函数1.main函数2.按键扫描3.数码管显示4.电压模式1、2输出 & LED显示5.定时器中断6.消除85C显示 三、次要函数1.初始化函数Init2.按键函数Key3.LED函数Led4.数码管函数Seg5.iic函数中6.onewire函数…

python(5)之处理数组

上次代码结果如下&#xff1a; 1、处理数组的缺失值 1、isnan&#xff08;&#xff09;函数 isnan&#xff08;&#xff09;函数是Numpy模块里的一个可以标记数组中缺失值的位置 代码示例如下&#xff1a; import numpy as np ac np.array([1,2,3,2,3,4,5,9,np.nan,1]) p…

分布式CAP原理详解

引言 随着互联网的飞速发展&#xff0c;越来越多的应用开始采用分布式系统来提高系统的可用性和扩展性。在分布式系统中&#xff0c;CAP原理是一个非常重要的理论&#xff0c;它描述了分布式系统在面临网络分区时&#xff0c;如何在一致性、可用性和分区容错性之间进行权衡。本…