Java通过百度OCR实现图片文字识别、身份证识别与车牌识别
百度智能云开通免费服务
1、先注册一个百度智能云账号
2、领取免费资源(每天固定免费多少次的使用次数,如果想用更多,可以花钱开通)
选择对应的服务和资源
左下角点击0元领取就可以了
返回概览界面
服务列表出现,表示免费资源领取成功
3、创建应用
创建成功后会在应用列表显示,从这个界面我们可以获取到AppID、API Key和Secret Key,代码中没有这三个是无法使用的
代码实现
导入依赖
//百度OCR
implementation 'com.baidu.aip:java-sdk:4.16.16'
我用的是gradle
Maven如下:
//百度OCR
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.16.17</version>
</dependency>
Controller
由于不涉及到数据库,我就直接用的controller
package com.example.studydemo.OCR;
import com.baidu.aip.ocr.AipOcr;
import com.example.studydemo.common.ReturnResult;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@RestController
@RequestMapping("/ocr")
public class OcrController {
//设置APPID/AK/SK
private static String APP_ID = "";
private static String API_KEY ="";
private static String SECRET_KEY = "";
@PostMapping("/imageToFont")
public ReturnResult imageToFont(MultipartFile image) throws IOException {
// 初始化一个AipOcr
AipOcr aipOcr = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
if (isImage(image.getInputStream())){
image.transferTo(Path.of("./",image.getOriginalFilename()));
String path = "./" + image.getOriginalFilename();
System.out.println(path);
ArrayList<String> re = basicGeneral(aipOcr,path);
File f = new File(path);
if (f.exists()){
f.delete();
}
return ReturnResult.buildSuccessResult(re);
}else {
return ReturnResult.buildSuccessResult("文件格式必须为图片格式");
}
}
@PostMapping("/checkIdCord")
public ReturnResult checkIdCord (MultipartFile image) throws IOException {
// 初始化一个AipOcr
AipOcr aipOcr = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
if (isImage(image.getInputStream())){
image.transferTo(Path.of("./",image.getOriginalFilename()));
String path = "./" + image.getOriginalFilename();
System.out.println(path);
Map<String,Object> re = idCord(aipOcr,path);
File f = new File(path);
if (f.exists()){
f.delete();
}
return ReturnResult.buildSuccessResult(re);
}else {
return ReturnResult.buildSuccessResult("文件格式必须为图片格式");
}
}
@PostMapping("/checkLicencePlateNumber")
public ReturnResult checkLicencePlateNumber (MultipartFile image) throws IOException {
// 初始化一个AipOcr
AipOcr aipOcr = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
if (isImage(image.getInputStream())){
image.transferTo(Path.of("./",image.getOriginalFilename()));
String path = "./" + image.getOriginalFilename();
System.out.println(path);
Map<String,Object> re = licencePlateNumber(aipOcr,path);
File f = new File(path);
if (f.exists()){
f.delete();
}
return ReturnResult.buildSuccessResult(re);
}else {
return ReturnResult.buildSuccessResult("文件格式必须为图片格式");
}
}
public static boolean isImage(InputStream inputStream) {
if (inputStream == null) {
return false;
}
Image img;
try {
img = ImageIO.read(inputStream);
return !(img == null || img.getWidth(null) <= 0 || img.getHeight(null) <= 0);
} catch (Exception e) {
return false;
}
}
/*
* 通用文字识别
* */
public static ArrayList<String> basicGeneral(AipOcr aipOcr,String path){
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<String, String>();
options.put("language_type", "CHN_ENG");//识别语言类型,默认为中英文混合
options.put("detect_direction", "true");//是否检查图片朝向,默认false不检查
options.put("detect_language", "true");//是否检查语言,默认false不检查
options.put("probability", "true");//是否返回识别结果中每一行的置信度
// 调用接口,返回JSON格式数据
JSONObject jsonObject = aipOcr.basicGeneral(path, options);
//获取JSON对象里提取图片文字信息数组
JSONArray jsonArray = jsonObject.getJSONArray("words_result");
//循环打印信息
ArrayList<String> result = new ArrayList<>();
for(int i = 0;i<jsonArray.length();i++){
System.out.println(jsonArray.getJSONObject(i).get("words"));
result.add((String) jsonArray.getJSONObject(i).get("words"));
}
return result;
}
/*
* 身份证文字识别
* */
public static Map<String,Object> idCord(AipOcr aipOcr,String path){
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<String, String>();
options.put("detect_direction", "true");//检查图片朝向。默认false不检测
options.put("detect_risk", "false");//是否开启身份证类型检测功能(类型为身份证复印件、临时身份证、身份证翻拍、修改过的身份证),默认false不开启
String idCardSide = "front";//身份证含照片一面
// String idCardSide = "back";//身份证含国徽一面
//本地图片识别,返回JSON对象
JSONObject jsonObject = aipOcr.idcard(path, idCardSide, options);
//获取到我们需要的信息
JSONObject result = jsonObject.getJSONObject("words_result");
Map<String,Object> map = new HashMap<>();
//获取迭代器,
Iterator<String> iterator = result.keys();
while (iterator.hasNext()){
//获取键和值
String key = iterator.next();
String value = result.getJSONObject(key).getString("words");
//打印识别结果
System.out.println(key+" : "+value);
map.put(key,value);
}
return map;
}
/*
* 车牌号识别
* */
public Map<String,Object> licencePlateNumber(AipOcr aipOcr,String path){
// 传入可选参数调用接口
HashMap<String, String> options = new HashMap<String, String>();
options.put("multi_detect", "false");//是否检测多张图片,默认false
//本地图片识别,返回JSON对象
JSONObject jsonObject = aipOcr.plateLicense(path, options);
System.out.println(jsonObject);
//获取需要的信息
JSONObject result = jsonObject.getJSONObject("words_result");
Map<String,Object> map = new HashMap<>();
map.put("车牌颜色:",result.getString("color"));
map.put("车牌号:",result.getString("number"));
return map;
}
}
注:上述中AppID、API Key和Secret Key要换成自己百度智能云应用列表中复制的
上述中后面的方法应该放进工具类的,时间有限,就放在一起了
涉及的返回类:
package com.example.studydemo.common;
import lombok.Data;
@Data
public class ReturnResult {
private int code;
private String msg;
private Object data;
private ReturnResult(){
}
private static ReturnResult buildResult(int code, String msg, Object data){
ReturnResult result = new ReturnResult();
result.code = code;
result.msg = msg;
result.data = data;
return result;
}
public static ReturnResult buildSuccessResult(String msg, Object data) {
return buildResult(200, msg, data);
}
public static ReturnResult buildSuccessResult(Object data) {
return buildSuccessResult("success", data);
}
public static ReturnResult buildFailureResult(int code, String msg, Object data) {
return buildResult(code, msg, data);
}
public static ReturnResult buildFailureResult(String msg, Object data) {
return buildFailureResult(500, msg, data);
}
public static ReturnResult buildFailureResult(String msg) {
return buildFailureResult(500, msg, null);
}
}
如果不想用返回类,直接将Controller中接口的返回值改成自己想要的就行了
身份证识别升级版
@PostMapping("/checkIdCord")
public ReturnResult checkIdCord (MultipartFile image) throws IOException {
// 初始化一个AipOcr
AipOcr aipOcr = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
if (isImage(image.getInputStream())){
image.transferTo(Path.of("./",image.getOriginalFilename()));
String path = "./" + image.getOriginalFilename();
System.out.println(path);
Map<String,Object> re = idCord(aipOcr,path);
File f = new File(path);
if (f.exists()){
f.delete();
}
String idcode = (String) re.get("公民身份号码");
System.out.println(idcode);
if (!Objects.equals(idcode,null) && !Objects.equals(idcode,"")) {
boolean valid = IdcardUtil.isValidCard(idcode);
re.put("是否有效:", valid);
//转换
// String convert15To18 = IdcardUtil.convert15To18(idcord);
// map.put("18位:",convert15To18);
//年龄
java.util.Date day = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
DateTime date = DateUtil.parse(sdf.format(day));
int age = IdcardUtil.getAgeByIdCard(idcode, date);
re.put("年龄:", age);
//生日
String birth = IdcardUtil.getBirthByIdCard(idcode);
re.put("生日:", birth);
//省份
String province = IdcardUtil.getProvinceByIdCard(idcode);
re.put("省份:", province);
return ReturnResult.buildSuccessResult(re);
}else {
return ReturnResult.buildFailureResult("身份证号码不能为空");
}
}else {
return ReturnResult.buildSuccessResult("文件格式必须为图片格式");
}
}
这个身份证识别多加了是否有效,识别所在省份、生日、年龄等功能,如果用的话只需要将这个替换上述checkIdCord方法即可
参考:https://blog.csdn.net/m0_51527921/article/details/123419775
https://blog.csdn.net/m0_53434091/article/details/127826119
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通