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

文章目录

  • 简介
  • 文件下载
  • 引入依赖
  • 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服务

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mysql的索引、事务、分库分表问题

1.了解MySQL的索引吗&#xff1f;它为什么使用Btree作为底层&#xff0c;而不是其他呢&#xff1f; 这里我们要谈的是其他数据结构的缺点&#xff0c;然后说说Btree的优点&#xff0c;也就看你对MySQL的Btree与其他数据结构熟不熟悉。 Hash &#xff08;1&#xff09;Hash 索引…

第五十五回 吴用使时迁偷甲 汤隆赚徐宁上山-以102flowers数据集为例训练ResNet50模型

汤隆说我家世代打造兵器&#xff0c;破连环马需要用钩镰枪&#xff0c;我会打造。还需要我的姑表哥&#xff0c;金枪手徐宁&#xff0c;因为他会钩镰枪法。汤隆和吴用商议了请徐宁上山的法子&#xff0c;派石迁去偷徐宁的宝贝雁翎锁子甲。 石迁到了东京&#xff0c;打听到徐宁住…

R语言:多值提取到点

ArcGIS中有相关工具实现多值提取到点的功能&#xff0c;在这里&#xff0c;我将使用R语言进行操作&#xff1a; library(dplyr) library(readxl) library(sf) library(raster)setwd("D:/Datasets") Bio <- stack(paste0("D:/Datasets/Data/worldclim2_1km/…

HTML静态网页成品作业(HTML+CSS)——家乡漳州介绍设计制作(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

爬虫入门到精通_框架篇16(Scrapy框架基本使用_名人名言的抓取

1 目标站点分析 抓取网站&#xff1a;http://quotes.toscrape.com/ 主要显示了一些名人名言&#xff0c;以及作者、标签等等信息&#xff1a; 点击next&#xff0c;page变为2&#xff1a; 2 流程框架 抓取第一页&#xff1a;请求第一页的URL并得到源代码&#xff0c;进行下…

学校Java的第七天

目录 一、什么是数组 二、作用 三、如何使用数组 1、声明数组变量 2、创建数组 示例&#xff1a; 3、数组的使用 示例&#xff1a; 4、数组的遍历 for循环示例&#xff08;不知道for循环的可以查看我之前发的文章&#xff09; for-each循环&#xff08;也就是增强for…

使用JDBC操作数据库

意志、工作和等待是成功的金字塔的基石。 Will, work and wait are the pyramidal cornerstones for success. 文章目录 JDBC简介&#xff1a;JDBC访问数据库步骤StatementPreparedStatement JDBC简介&#xff1a; 在Java应用程序中&#xff0c;JDBC&#xff08;Java Database…

【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现

&#x1f31e;前言 这里我们会实现一个项目&#xff1a;在linux操作系统下基于OpenCV和Socket的人脸识别系统。 目录 &#x1f31e;前言 &#x1f31e;一、项目介绍 &#x1f31e;二、项目分工 &#x1f31e;三、项目难题 &#x1f31e;四、实现细节 &#x1f33c;4.1 关…

腾讯云服务器99元一年厉害了,老用户可以买,续费也是99元

良心腾讯云推出99元一年服务器&#xff0c;新用户和老用户均可以购买&#xff0c;续费不涨价&#xff0c;续费也是99元&#xff0c;配置为轻量2核2G4M、50GB SSD盘、300GB月流量、4M带宽&#xff1a;优惠价格99元一年&#xff0c;续费99元&#xff0c;官方活动页面 txybk.com/g…

java继承,接口,抽象类

目录 目录 1 继承的含义 2 继承的好处 3使类与类之间产生了关系。 看这里继承-------我的理解 代码部分 接口 代码 抽象类 代码 各位友友们大家好呀&#x1f60a;&#xff01; 今天让我们继续回顾java&#xff0c;看看java中的抽象类以及接口继承是什么&#x1f914…

LeetCode Python - 46.全排列

目录 题目答案运行结果 题目 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 示例 2&#x…

MybatisPlus分页失效不起作用问题剖析

【问题描述】 在使用MybatisPlus的selectPage时发现分页不起作用&#xff0c;每次返回的都是全部的数据&#xff0c;同时getPages()和getTotal()返回的都是0。 【相关代码】 mybatisPlus的版本&#xff1a; <dependency><groupId>com.baomidou</groupId>&…

排序算法之选择排序|c++实现

引言 排序算法学习第二弹之选择排序&#xff0c;这也是入门的一个基础算法。 算法描述 从序列中选择最大&#xff08;小&#xff09;的元素&#xff0c;放在序列的结束位置&#xff08;下标为n-1&#xff09; 从剩下的未排序序列中继续选择最大&#xff08;小&#xff09;的…

IDEA打开项目文件目录不见了

偶尔发生新拉下来的代码&#xff0c;或者旧代码修改了包名&#xff0c;项目名称等&#xff0c;idea左侧project一栏不显示代码的文件目录。例如下面此时不要慌张&#xff0c;不用删除项目重新拉取&#xff0c;通过以下方式解决&#xff1a; 本人尝试能够解决&#xff0c;如果无…

蓝牙系列第九:协议链路层(LL)分析

到这里,我们开始分析具体的协议栈每一层的数据处理,首先从底下的LL数据链路层开始。依然是根据韦东上老师的视频进行解析分析。 结合书籍《低功耗蓝牙开发权威指南,Robin Heydon著》第7章,实际上这书只是对蓝牙原版协议的简化、摘要。回顾以前学过的《BLE协议各层的形象化…

OpenText Availability——适用于 Windows 和 Linux 服务器的高可用性和灾难恢复解决方案

OpenText Availability——适用于 Windows 和 Linux 服务器的高可用性和灾难恢复解决方案 连续复制&#xff0c;最大限度地减少数据丢失快速故障转移&#xff0c;最大限度地减少停机时间可忽略的性能影响支持物理、虚拟和基于云的系统平台 停机从多种途径侵扰 IT 企业。 从相…

2.模拟问题——7.九宫格键盘输入时间

输入 bob www 输出 7 7 【提交地址】 题目分析 九宫格键盘如图所示&#xff1a; 注意&#xff0c;题目中有两个对应关系需要注意&#xff1a; 第一&#xff0c;字母与按键次数的对应第二&#xff0c;字母与按键的对应&#xff0c;如果连续两次是不同的按键则不需要等待&…

超越DragGAN和DragDiffusion!StableDrag:基于点的图像编辑新框架(南大腾讯) 原创 Yutao Cui等 AI生成未来

超越DragGAN和DragDiffusion&#xff01;StableDrag:基于点的图像编辑新框架(南大&腾讯) 原创 Yutao Cui等 AI生成未来 文章链接&#xff1a;https://arxiv.org/pdf/2403.04437 开源地址&#xff1a;https://stabledrag.github.io/ 基于点的图像编辑自DragGAN出现以来就引…

阿里云-零基础入门推荐系统 【Baseline】

文章目录 赛题介绍评价方式理解赛题理解代码实战导包df节省内存函数读取采样或全量数获取 用户 - 文章 - 点击时间字典获取点击最多的topk个文章itemcf的物品相似度计算itemcf 的文章推荐给每个用户根据物品的协同过滤推荐文章召回字典转换成df生成提交文件获取测试集从所有的召…

202003 青少年软件编程(Scratch)等级考试试卷(一级)

202003 青少年软件编程&#xff08;Scratch&#xff09;等级考试试卷&#xff08;一级&#xff09; 第1题&#xff1a;【 单选题】 在Scratch中&#xff0c;以下哪个区域可以展示编程效果&#xff1f; A:代码区 B:舞台区 C:角色区 D:积木区 【正确答案】: B 【试题解析】…