Java使用Tesseract进行OCR图片文字识别

news2024/9/21 4:37:59

前言

在当前的文字识别技术应用中,除了采用现有的API服务之外,常见的解决方案包括利用Tessdata、Canvas或OCRAD等工具。以下是对几种技术的简要分析:

  1. 百度API的使用体验表明,虽然其识别率令人满意,但并非完美无误。此外,该服务对使用次数有所限制,尽管对于一般需求而言足够,但存在超额使用导致服务受限的风险。

  2. Canvas技术要求对图像执行预处理步骤,如旋转、灰度化以及调整字符间距等,这些处理能显著提升识别成功率。然而,由于公司产品中的验证码类型多样,难以通过统一方法处理,因此该方案被暂时搁置。

  3. OCRAD的JavaScript版本已进行尝试,但识别准确率相对较低。有关此工具的具体应用将在未来的文章中进一步探讨。

尽管互联网上关于Tessdata技术的介绍文章众多,但实际应用过程中仍面临一定挑战。操作流程概述如下:首先截取全屏图像,接着提取特定元素图片,然后进行图像预处理,最后执行文字识别并输出结果。

通过这一流程,可以有效地实现对图像中文字的准确识别和解读。

注意:图片截取格式统一为.jpg,用png会出问题。 

Tessdata介绍

Tessdata是用于光学字符识别(OCR)的软件包,专为与Tesseract OCR引擎配合使用,提供必要的语言数据文件以支持文本识别的多种语言。它包含了预先训练好的模型,这些模型帮助Tesseract识别和转换不同语言的文本图像为可编辑和可搜索的文件格式

在Tesseract中,Tessdata的作用不可小觑,它是让Tesseract能够识别特定语言文本的关键。Tessdata文件夹通常存放在Tesseract安装目录下,每个语言模型都以“.traineddata”为扩展名的文件形式存在。例如,英语的模型文件是“eng.traineddata”,中文简体是“chi_sim.traineddata”。这些文件包含了每种语言特定的字符集和相关的训练信息,这些信息使得Tesseract能够准确地将图像中的文本转换为文本文件。

Tessdata不仅提供了官方支持的语言包,还允许用户生成自定义的traineddata文件,从而训练出适应特定需求的OCR模型。例如,如果现有的语言包无法满足某些特殊场景的需求,用户可以自行收集数据并按照Tesseract的训练流程创建新的语言模型。这一过程可能包括图像预处理、地面实况标注、模型训练和测试等步骤。通过这种方式,Tesseract可以不断扩展其应用范围,适应更多样的应用场景。

总的来说,Tessdata是Tesseract OCR引擎的核心部分,提供了使Tesseract能够识别并处理多种语言文本的能力。通过合理地使用和配置Tessdata文件,用户可以显著提高文字识别的准确率和效率。同时,Tesseract社区持续对Tessdata进行更新和优化,以适应不断变化的应用需求和提升用户体验。

实践案例 

 1、添加项目依赖 在项目的pom.xml文件中,添加以下依赖

<!--<tess4j图片识别>-->
<dependency>
	<groupId>net.java.dev.jna</groupId>
	<artifactId>jna</artifactId>
	<version>4.1.0</version>
</dependency>
<dependency>
	<groupId>net.sourceforge.tess4j</groupId>
	<artifactId>tess4j</artifactId>
	<version>2.0.1</version>
	<exclusions>
		<exclusion>
			<groupId>com.sun.jna</groupId>
			<artifactId>jna</artifactId>
		</exclusion>
	</exclusions>
</dependency>

2、从全图中截取元素图片

该部分路径存了两个,用来将处理后的图片覆盖原图片。

// 元素截图

public static String[] elementscreenShot(WebElement element )
		throws Exception {
	WrapsDriver wrapsDriver = (WrapsDriver) element;
	long time = System.currentTimeMillis();

	// 截图整个页面
	File screen = ((TakesScreenshot) wrapsDriver.getWrappedDriver())
			.getScreenshotAs(OutputType.FILE);
	BufferedImage img = ImageIO.read(screen);
	// 获得元素的高度和宽度
	int width = element.getSize().getWidth();
	int height = element.getSize().getHeight();
	// 创建一个矩形使用上面的高度,和宽度
	Rectangle rect = new Rectangle(width, height);
	// 得到元素的坐标
	Point p = element.getLocation();
	BufferedImage dest = img.getSubimage(p.getX(), p.getY(),
			(int) rect.getWidth(), (int) rect.getHeight());
	// 存为png格式
	ImageIO.write(dest, "png", screen);
	DateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
	FileSystemView fsv = FileSystemView.getFileSystemView();
	File com = fsv.getHomeDirectory(); // 这便是读取桌面路径的方法了
	String url = com.getPath() + "/test";
	File location = new File(url);
	if (!location.exists()) {
		location.mkdirs();
	}

	String imgPath = location.getAbsolutePath() + File.separator + "pic_"
			+ time + ".jpg";
	String cleanPath = location.getAbsolutePath();
	//存了原图片和清楚后图片的地址
	String[] imgpath = { imgPath, cleanPath };
	File targetFile = new File(imgPath);
	try {
		FileUtils.copyFile(screen, targetFile);
	} catch (IOException e1) {
		e1.printStackTrace();
	}
	//元素图片路径
	return imgpath;
}

3、对截取图片进行处理:灰度化、二值化、去除干扰线等

以下是图像处理的类,其中对于去除干扰线的操作还是慎用,可能会把文字也剔除掉。

public class CleanElementImage {
    /**
     *
     * @param sfile
     *            需要去噪的图像
     * @param destDir
     *            去噪后的图像保存地址
     * @throws IOException
     */
    public static void handlImage(File sfile, String destDir)  throws IOException {
        File destF = new File(destDir);
        if (!destF.exists())
        {
            destF.mkdirs();
        }

        BufferedImage bufferedImage = ImageIO.read(sfile);
        int h = bufferedImage.getHeight();
        int w = bufferedImage.getWidth();

        // 灰度化
        int[][] gray = new int[w][h];
        for (int x = 0; x < w; x++)
        {
            for (int y = 0; y < h; y++)
            {
                int argb = bufferedImage.getRGB(x, y);
                // 图像加亮(调整亮度识别率非常高)
                int r = (int) (((argb >> 16) & 0xFF) * 1.1 + 30);
                int g = (int) (((argb >> 8) & 0xFF) * 1.1 + 30);
                int b = (int) (((argb >> 0) & 0xFF) * 1.1 + 30);
                if (r >= 255)
                {
                    r = 255;
                }
                if (g >= 255)
                {
                    g = 255;
                }
                if (b >= 255)
                {
                    b = 255;
                }
                gray[x][y] = (int) Math
                        .pow((Math.pow(r, 2.2) * 0.2973 + Math.pow(g, 2.2)
                                * 0.6274 + Math.pow(b, 2.2) * 0.0753), 1 / 2.2);
            }
        }

        // 二值化
        int threshold = ostu(gray, w, h);
        BufferedImage binaryBufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_BINARY);
        for (int x = 0; x < w; x++)
        {
            for (int y = 0; y < h; y++)
            {
                if (gray[x][y] > threshold)
            {
                gray[x][y] |= 0x00FFFF;
            } else
            {
                gray[x][y] &= 0xFF0000;
            }
            binaryBufferedImage.setRGB(x, y, gray[x][y]);
        }
    }


    ImageIO.write(binaryBufferedImage, "jpg", new File(destDir, sfile
            .getName()));

}

public static boolean isBlack(int colorInt)
{
    Color color = new Color(colorInt);
    if (color.getRed() + color.getGreen() + color.getBlue() <= 300)
    {
        return true;
    }
    return false;
}

public static boolean isWhite(int colorInt)
{
    Color color = new Color(colorInt);
    if (color.getRed() + color.getGreen() + color.getBlue() > 300)
    {
        return true;
    }
    return false;
}

public static int isBlackOrWhite(int colorInt)
{
    if (getColorBright(colorInt) < 30 || getColorBright(colorInt) > 730)
    {
        return 1;
    }
    return 0;
}

public static int getColorBright(int colorInt)
{
    Color color = new Color(colorInt);
    return color.getRed() + color.getGreen() + color.getBlue();
}

public static int ostu(int[][] gray, int w, int h)
{
    int[] histData = new int[w * h];
    // Calculate histogram
    for (int x = 0; x < w; x++)
    {
        for (int y = 0; y < h; y++)
        {
            int red = 0xFF & gray[x][y];
            histData[red]++;
        }
    }

    // Total number of pixels
    int total = w * h;

    float sum = 0;
    for (int t = 0; t < 256; t++){
        sum += t * histData[t];}

    float sumB = 0;
    int wB = 0;
    int wF = 0;

    float varMax = 0;
    int threshold = 0;

    for (int t = 0; t < 256; t++)
    {
        wB += histData[t]; // Weight Background
        if (wB == 0) {
            continue;
        }

        wF = total - wB; // Weight Foreground
        if (wF == 0) {
            break;
        }

        sumB += (float) (t * histData[t]);

        float mB = sumB / wB; // Mean Background
        float mF = (sum - sumB) / wF; // Mean Foreground

        // Calculate Between Class Variance
        float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);

        // Check if new maximum found
        if (varBetween > varMax)
        {
            varMax = varBetween;
            threshold = t;
        }
    }

    return threshold;
}
}

4、准备识别的语言包

默认是英文(识别字母和数字),如果要识别中文(数字 + 中文),需要制定语言包。\
语言包可以指定一个路径,有就可以了。
源码下载地址
可以下载源码,然后到下面这个路径找到语言包,把语言包放到一个路径:\
例如:XXX/tessdata/下面。

tesseract.js-master.zip\tesseract.js-master\tests\assets\traineddata 

 

 5、对图片进行识别

```
/**
	 * 图片识别
	 * @author wangy
	 * @date 2019-08-26
	 * @param parameter
	 */
	public static  String  ocrResult(WebElement element ) throws Exception {

		FileSystemView fsv = FileSystemView.getFileSystemView();
		File com=fsv.getHomeDirectory();    //这便是读取桌面路径的方法了
		String url = "";
		String os = System.getProperty("os.name");
		//识别系统,找不同的语言包路径
		if (os.indexOf("Windows") == -1) {
			url = "/opt/google/";
		} else {
			url = com.getPath();
		}
		//获取元素截图的路径
        String path[]=Screenshot.elementscreenShot(element);
        //获取未处理的截图路径
        String imgpath=path[0];
		String result = null;
		File imageFile = new File(imgpath);
		//要对图片处理
        CleanElementImage.handlImage(imageFile,path[1]);
		ITesseract instance = new Tesseract();
		//读取语言包的路径地址
		instance.setDatapath(url + File.separator + "test" + File.separator
				+ "tessdata");
		// 默认是英文(识别字母和数字),如果要识别中文(数字 + 中文),需要制定语言包,这里是数字,所以没用语言包
//        instance.setLanguage("chi_sim");
//为了防止没截完图片就识别,做了一个简单的循环
		try{
			String ocrResult=instance.doOCR(imageFile);
			if(imageFile.exists()&&ocrResult!=""){
				result=ocrResult;
			}else {
				while(true){
					Thread.sleep(1000);
					if(imageFile.exists()&&ocrResult!=""){
						result=ocrResult;
						break;
					}
				}
			}

		}catch(TesseractException e){
			System.out.println(e.getMessage());
		}
		return result;
	}

这一部分由于项目问题,贴在这里做了特殊处理,原码有一点点区别。大家使用,如果有什么问题,欢迎反馈!

6、成果

这里简单放个对照,图片将就看一下效果,识别结果大概90%以上吧:

 

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

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

相关文章

一个月狂撸5.8W,利用AI制作宝宝走秀视频,让宝宝“出海”捞美刀

今天给大家分享的项目是**AI宝宝走秀视频玩法&#xff0c;**在项目拆解之前&#xff0c;先看一下这个账号。这个账号是在Tiktok上的&#xff0c;也就是海外版的抖音。 基本上都是几千万的播放&#xff0c;按照海外版抖音的激励计划&#xff0c;每播放一万次&#xff0c;就能赚8…

紧跟大模型技术趋势,为更大更通用的大模型提供底层支撑!关于智能计算系统:从深度学习到大模型,全新版本,发布!

文章目录 &#x1f4cb;前言&#x1f3af; 关于智能计算系统&#x1f3af; 内容简介&#x1f3af; 作者简介&#x1f3af; 专家推荐&#x1f3af; 目录大纲&#x1f525; 参与方式 &#x1f4cb;前言 “只要你想把大模型做得更好、做得更大、做得更快、做得更省电&#xff0c;…

翻译软件 Fastrans 开发日志 #01

目录 预览前言功能技术待办 预览 Github 仓库链接&#xff1a;https://github.com/YaoqxCN/Fastrans Gitee 仓库链接&#xff1a;https://gitee.com/yaoqx/Fastrans 求求给我点个 star 叭 qaq 现在才是 v1.0.0&#xff0c;给我个 star 鼓励我继续开发下去&#xff01; 我相信…

AI如何帮助普通人实现自我成长和副业变现

前言 最近有没有发现身边的一切都变得越来越"智能"了&#xff1f;连家里的空调都学会了自己调整温度&#xff0c;害得我每天起床都觉得它比我聪明。这不禁让我想到&#xff0c;既然连空调都在进化&#xff0c;我们这些普通人是不是也该搭上AI的快车&#xff0c;来个华…

找出所有子集异或和的和 全排列2

1863.找出所有子集异或和的和 解释&#xff1a;做本题没思路的话&#xff0c;强烈建议看本专栏上一篇博文 class Solution { public:int sum 0;int path 0;int subsetXORSum(vector<int>& nums) {dfs(nums, 0);return sum;}void dfs(vector<int>& nums,…

大模型分布式训练技术(DP、DDP和FSDP)

目录 数据并行&#xff08;PyTorch DP&#xff09; 分布式数据并行&#xff08;PyTorch DDP&#xff09; DP 与 DDP 的区别 补充说明&#xff1a;DP与DDP数据传输过程 完全分片数据并行(PyTorch FSDP) 补充说明&#xff1a;ZeRO FSDP DDP 与 FSDP 的区别 DP、DDP和FSD…

ADW400环保监测模块,用于各省市环保平台对接

ADW400环保监测模块主要用于计量低压网络的三相有功电能&#xff0c;同时可选择四个回路的电流输入&#xff0c;具有RS485通讯和470MHz无线通讯功能&#xff0c;方便用户进行用电监测、集抄和管理。可灵活安装于配电箱内&#xff0c;实现对不同区域和不同负荷的分项电能计量&am…

构建智慧园区的全方位解决方案:技术、部署与挑战应对

在当今数字化转型的浪潮中,智慧园区作为城市智能化的重要组成部分,正在成为各地政府和企业关注的焦点。本文将围绕一套完整的智慧园区解决方案,详细阐述其技术架构、部署流程以及在实施过程中可能遇到的挑战及应对策略。 1. 智慧园区解决方案概述 智慧园区解决方案旨在通过先…

Qt 一个带数据压缩的加解密实现类,压缩率达到了1/3

一.加解密效果 1-1000字符串,所占大小2890(加密前) 1-1000字符串,所占大小1964(加密后) 二.加解密功能实现类 /* Copyright (c) 2011, Andre Somers All rights reserved.Redistribution and use in…

Windows上安装 nodejs,npm 和 yarn详细教程

1、下载Node.js 访问Node.js 官网下载&#xff0c;下载需要版本版本&#xff0c;具体操作如下 2、安装Node.js 具体安装可参考以下知乎教程 https://www.zhihu.com/question/591831850/answer/3423661990 3、配置淘宝镜像 npm config set registry https://registry.npmmirror…

Codeforces Round 925 (Div. 3) E. Anna and the Valentine‘s Day Gift (博弈论*1400)

根据题目条件&#xff0c;我们知道10的m次方就是1后面跟着m个0&#xff0c;也就是说这是个最小的m1位数。 那么只要是最终得来的数的尾数是m1位数就可以通过。 思考影响数位的因素&#xff1f; 在这道题里&#xff0c;安娜能够对数位进行的操作只有删去后导零&#xff0c;由此…

安卓刷机笔记

前置知识 双清— 清除data 、 cache 四清----清除 data 、 cache 、 dalvik分区 、 system分区 四清的好处&#xff1a;卡刷ZIP格式的刷机包都是使用第三方recovery刷入的&#xff0c;所以我们在刷机之前对上一个系统的数据&#xff0c;包括用户数据、系统残留都需要彻底清除&a…

dolphinscheduler 日志乱码

dolphinscheduler 日志乱码如下图所示&#xff0c;检查服务器编码为zh_CN.UTF-8 修改$dolphinscheduler/bin/env/dolphinscheduler_env.sh 增加 JAVA_OPTS"$JAVA_OPTS -Dfile.encodingUTF-8" 参数 重新安装启动 修改前 修改后

i.MX裸机开发(10):UART——串口通讯

本章参考资料&#xff1a;《IMX6ULRM》&#xff08;参考手册&#xff09;。 学习本章时&#xff0c;配合《IMX6ULRM》Chapter 53 Universal Asynchronous Receiver/Transmitter (UART)一起阅读&#xff0c;效果会更佳&#xff0c;特别是涉及到寄存器说明的部分。 本章主要内容…

一文读懂 LLM 如何进行微调?

​你知道吗&#xff0c;咱们用那些已经训练好的大型语言模型&#xff0c;其实有好多不同的玩法。最常见的有三种&#xff1a;一种是用模型提取的特征来训练新的小模型&#xff1b;另一种是直接给模型看新任务的例子&#xff0c;让它学着怎么回答&#xff0c;这招叫做提示&#…

深度探究|软件主宰世界,我们究竟错过了什么?

这乃是知乎 COO 张宁于近期针对国内过往十年创投环境展开的深度思索。 张宁觉得&#xff0c;在过去的十年当中&#xff0c;美国硅谷专注于 SaaS 领域&#xff0c;凭借软件的标准化来提升企业的效率与经济性&#xff0c;同时倡导开放性与多样性。 中国在过去的十年里&#xff…

Java之线程篇二

目录 Thread的常见构造方法 Thread的常见属性 代码示例1 代码示例2 示例代码3 代码示例4 代码示例5 小结 线程中断 代码示例1 代码示例2 代码示例3 代码示例4 小结 线程等待 获取当前线程的引用 Thread的常见构造方法 举例 Thread t1 new Thread(); Thread t2…

YOLOv8改进 | 融合改进 | C2f融合Faster模块提升检测速度【完整代码 + 主要代码解析】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…

conda环境安装与删除

安装 1.cmd安装 conda create -n xxxxx(名字) python3.8 进入虚拟环境 activate xxxxx(名字) 查看虚拟环境的库 pip list 退出虚拟环境 deactivate 2.pycharm直接创建 对一个项目右下角&#xff1a; 可以使用现有环境&#xff0c;也可以创建新环境 删除 在cmd中输入&…

大模型在安全领域的十大应用场景及实现路径

作为网络安全及AI的双重爱好者&#xff0c;笔者也一直在关注大模型在安全领域的相关应用&#xff0c;从目前市面上看到的产品来说&#xff0c;相关的结合还在一个较为早期的阶段&#xff0c;很多产品能力也是为了大模型而大模型&#xff0c;并未真正发挥其价值。 在去年上一篇相…