目录
🍸前言
小伙伴们大家好,最近在公众号上刷到如何在 java 中实现图片的识别和信息提取,巧了,鄙人毕设是有关人脸识别的,其中有一步骤就是图片的处理加信息提取,只不过是在 python 中使用的;闲暇无事,本地测试下在 Java 中要怎么实现从证件图片中提取身份信息
Ps:毕设中用的 python 实现可以参考下这篇文章(想想自己的论文,有点水了(bushi):
《Python人脸识别实现指南》_python人脸识别训练代码-CSDN博客
🍻一、工具选择
图片处理通常会使用光学字符识别(OCR)技术,查了下,比较常用的 OCR 工具有 Tesseract,可以帮助从指定图片中提取文本信息。
该工具的使用也比较简单,首先要安装 Tesseract OCR,然后引入相关的库即可;下载地址如下,选择好版本之后,可以自行下载,本地选择的是下载 exe 文件,本地安装一路 next 就行。但是要记住安装位置,因为代码中要引用安装包中的部分文件
Release 5.5.0 · tesseract-ocr/tesseract · GitHub
🍹二、代码实现
2.1 依赖引入
可以使用 Tess4J
这个 Java 的 Tesseract 包装库来集成 Tesseract OCR。
<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>4.5.0</version> <!-- 自行选择版本 -->
</dependency>
2.2 方法实现
这里可以直接写成工具类,但是为了方便拓展,可以结合策略模式,具体就是,针对不同的证件图片,都有对应的处理方式,如果有新增的类型,可以不用过多改动原有代码,而是不断扩展(开闭原则);整体的思路就是通过策略工厂和不同的策略类实现;
2.2.1 考虑到图片类型的增加,为了方便用枚举类来进行管理,目前就放了一种卡类型,后面要增加的话依次填写枚举值即可
public enum CardTypeEnum {
IDCARD;
}
2.2.2 创建一个具体的识别结果类,用来统一管理每种策略的处理结果
@Data
public class OcrResp {
//姓名
private String name;
//证件号码
private String idNum;
//出生日期
private String birth;
//有效时间
private String usefulPeriod;
//到期时间
private String validPeriod;
}
2.2.3 用抽象方法来定义图片识别提取的策略,这里另外提供了一个获取卡类型枚举的方法,主要是为了区分每个策略类针对的卡类型,每个策略类都要重写该方法,并返回自己对应的卡类型枚举值。
public abstract class AbstractOcrStrategy {
public abstract CardTypeEnum getCardEnum();
public abstract OcrResp ocr(String imagePath);
}
2.2.4 策略实现类,目前就只有一中卡类型,对应一个策略类;
整体比较简单,继承策略类之后,重写获取枚举值方法,和ocr方法的具体实现;这里要注意 tessDataPath 常量的取值,是一个文件的路径,对应的就是我们下载的tess ocr 安装的地址,需要使用其中的文件;
还有一个就是 result 是我们识别图片得到的文本信息,后端面的操作是使用正则去提取每一个我们想要的文本信息。
import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
import org.springframework.stereotype.Component;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author HuangBenben
*/
@Component
public class IdCardStrategy extends AbstractOcrStrategy{
@Override
public CardTypeEnum getCardEnum() {
return CardTypeEnum.IDCARD;
}
private final String tessDataPath = "C:/SoftWares/ocr_tool/tessdata"; // Tesseract 数据路径(如 tessdata)
@Override
public OcrResp ocr(String imagePath) {
OcrResp ocrResp = new OcrResp();
try {
File imageFile = new File(imagePath);
ITesseract instance = new Tesseract();
// 设置 Tesseract 数据路径
instance.setDatapath(tessDataPath);
instance.setLanguage("eng"); // 设置语言
// 读取图像并进行 OCR 识别
String result = instance.doOCR(imageFile);
// 假设身份证号为18位数字:xxxxxx xxxxxxx xxxxx
Pattern idPattern = Pattern.compile("\\d{17}[\\dXx]"); // 匹配身份证号
Matcher idMatcher = idPattern.matcher(result);
if (idMatcher.find()) {
String idNumber = idMatcher.group();
ocrResp.setIdNum(idNumber);
}
// 1. 提取 Name
Pattern namePattern = Pattern.compile("Name\\s*(.*)");
Matcher nameMatcher = namePattern.matcher(result);
if (nameMatcher.find()) {
ocrResp.setName(nameMatcher.group(1));
}
// 2. 提取出生日期
Pattern datePattern = Pattern.compile("(\\d{4}\\.\\d{2}\\.\\d{2})");
Matcher dateMatcher = datePattern.matcher(result);
if (dateMatcher.find()) {
ocrResp.setBirth(dateMatcher.group(1));
}
// 4. 提取签发日期和到期日期
Pattern validityPattern = Pattern.compile("(\\d{4}\\.\\d{2}\\.\\d{2})\\s*-\\s*(\\d{4}\\.\\d{2}\\.\\d{2})");
Matcher validityMatcher = validityPattern.matcher(result);
if (validityMatcher.find()) {
ocrResp.setUsefulPeriod(validityMatcher.group(1));
ocrResp.setValidPeriod(validityMatcher.group(2));
}
return ocrResp;
} catch (Exception e) {
System.err.println("OCR识别失败: " + e.getMessage());
}
return null;
}
}
2.2.5 策略工厂
@Component 注解标注是由 Spring 管理的组件
使用静态容器在 bean 初始化之后存储每种策略实现类;先扫描出策略类的所有实现,然后根据每个实现类返回的枚举值进行存储,key 对应的就是卡类型枚举, value 就是对应的策略类实例;这里有用到 EnumMap 详细用法可以参考这篇文章
【数据结构】⭐️基于枚举类型容器的使用-EnumMap-CSDN博客
@Component
public class StrategyFactory implements InitializingBean, ApplicationContextAware {
private ApplicationContext applicationContext;
public static Map<CardTypeEnum,AbstractOcrStrategy> OCR_STRATEGY_MAP = new EnumMap<>(CardTypeEnum.class);
@Override
public void afterPropertiesSet() {
Map<String, AbstractOcrStrategy> ocrStrategyMap = applicationContext.getBeansOfType(AbstractOcrStrategy.class);
ocrStrategyMap.values().forEach(e-> OCR_STRATEGY_MAP.put(e.getCardEnum(),e));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext= applicationContext;
}
}
💞️三、测试
本地测试的话就直接传一个需要识别的图片地址即可(也可以改动下代码,支持传入图片链接,通过 url 获取图片),这里在网上找了一个证件图片(小伙伴们要注意保护好隐私),测试下:
传入两个参数,一个是图片地址,另一个是该图片对应的卡类型,通过策略工厂获取对应的策略类处理任务,对比下,提取的信息都正确
🍻四、章末
这里只是简单实现了图片的信息提取,当然因为本地测试可直接获取到图片文件;也可以改造下支持传递图片,比如url链接或者其他方式,都很方便;另外也可以加入一些新的卡类型,但是要注意新增卡类型后对识别出的结果要做信息提取,用正则提取的时候注意调试。
文章到这里就结束了~