- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
今天给大家分享一个 SpringBoot 整合 Tess4j 库实现图片文字识别的小案例,希望xdm喜欢.
文末有案例代码的Git地址,可以自己下载了去玩玩儿或继续扩展也行.
话不多说,开整吧.
先简单给没听过的xdm解释下,这里要分清楚 Tesseract 和 Tess4j 的区别.
Tesseract 是一个开源的光学字符识别(OCR)引擎,它可以将图像中的文字转换为计算机可读的文本。支持多种语言和书面语言,并且可以在命令行中执行。它是一个流行的开源OCR工具,可以在许多不同的操作系统上运行.
Tess4J 是一个基于 Tesseract OCR引擎 的Java接口,可以用来识别图像中的文本,说白了,就是封装了它的API,让Java可以直接调用.
搞清楚这俩东西,就足够了.
既然是SpringBoot,基础依赖我就不赘述了,这里贴下Tess4J的依赖,是可以用maven下载的.
<!-- tess4j -->
<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>4.5.4</version>
</dependency>
这里,我特地把训练数据的目录路径配置在yml里,后续可以扩展到配置中心.
server:
port: 8888
# 训练数据文件夹的路径
tess4j:
datapath: D:/tessdata
然后我解释下什么是训练数据 。
Tesseract OCR库通过训练数据来学习不同语言和字体的特征,以便更好地识别图片中的文字.
在安装Tesseract OCR库时,通常会生成一个包含多个子文件夹的训练数据文件夹,其中每个子文件夹都包含了特定语言或字体的训练数据.
比如我这里是下载后放到了D盘的tessdata目录下,如图所示,其实就是一个 .traineddata 为后缀的文件,大小约2M多.
如果你没有特定的训练数据需求,使用默认的训练数据文件即可,我这里就是直接下载默认的来用的.
还有一点要注意的是, 直接读resource目录下的路径是读不到的哈 ,所以我放到了D盘,训练数据本身也是更推荐放到独立的位置,方便后续训练数据.
我们新建一个配置类,初始化一下Tesseract类,交给Spring管理,这样借用了Spring的单例模式.
package com.example.tesseractocr.config;
import net.sourceforge.tess4j.Tesseract;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @作者: 公众号【Java分享客栈】
* @日期: 2023/10/12 22:58
* @描述:
*/
@Configuration
public class TesseractOcrConfiguration {
@Value("${tess4j.datapath}")
private String dataPath;
@Bean
public Tesseract tesseract() {
Tesseract tesseract = new Tesseract();
// 设置训练数据文件夹路径
tesseract.setDatapath(dataPath);
// 设置为中文简体
tesseract.setLanguage("chi_sim");
return tesseract;
}
}
就几行代码,非常简单.
package com.example.tesseractocr.service;
import lombok.AllArgsConstructor;
import net.sourceforge.tess4j.*;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Service
@AllArgsConstructor
public class OcrService {
private final Tesseract tesseract;
/**
* 识别图片中的文字
* @param imageFile 图片文件
* @return 文字信息
*/
public String recognizeText(MultipartFile imageFile) throws TesseractException, IOException {
// 转换
InputStream sbs = new ByteArrayInputStream(imageFile.getBytes());
BufferedImage bufferedImage = ImageIO.read(sbs);
// 对图片进行文字识别
return tesseract.doOCR(bufferedImage);
}
}
我们新建一个rest接口,用来测试效果,使用上传图片文件的方式.
package com.example.tesseractocr.controller;
import com.example.tesseractocr.service.OcrService;
import lombok.AllArgsConstructor;
import net.sourceforge.tess4j.TesseractException;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@RequestMapping("/api")
@RestController
@AllArgsConstructor
public class OcrController {
private final OcrService ocrService;
@PostMapping(value = "/recognize", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String recognizeImage(@RequestParam("file") MultipartFile file) throws TesseractException, IOException {
// 调用OcrService中的方法进行文字识别
return ocrService.recognizeText(file);
}
}
这里我用ApiPost工具来测试下最终效果 。
我准备的一张图片如下,是从知乎上随便截取的一张.
我们调接口试一下,这里要设置Header的Content-Type,别忘了哈.
这里是body中的参数,我们选择form-data中的File属性,表示以上传文件形式来调接口.
看下效果,其实还是挺不错的,我和图片比对了一下,基本上都识别出来了.
1)、Tesseract-ocr官方Github地址: https://github.com/tesseract-ocr/tesseract 。
2)、Tesseract-ocr安装下载: https://digi.bib.uni-mannheim.de/tesseract/ 。
PS:这里我没有用官方Github文档中给的地址,因为太慢了,找了一个下载比较快的,你们可以往下拉找到win64位的安装即可,如果没有训练需求,不用下也可以) 。
3)、训练文件: https://digi.bib.uni-mannheim.de/tesseract/tessdata_fast/ 。
PS:在2)的路径下,有一个tessdata_fast目录,点进去就能直接下载到默认训练文件,这种比较简便,省去了前面安装下载的过程.
4)、案例代码: https://gitee.com/fangfuji/java-share 。
PS:代码放在Gitee上,在同名博文目录里面,包含代码+安装文件+训练文件.
是不是非常简单xdm,反正我觉得挺有意思的,后面抽空再试试训练数据.
好了,今天的小知识,你学会了吗?
如果喜欢,请点赞+关注↓↓↓,持续分享干货哦! 。
最后此篇关于Java也能做OCR!SpringBoot整合Tess4J实现图片文字识别的文章就讲到这里了,如果你想了解更多关于Java也能做OCR!SpringBoot整合Tess4J实现图片文字识别的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!