OCR:文字识别

使用场景:

远程身份认证

自动识别录入用户身份/企业资质信息,应用于金融、政务、保险、电商、直播等场景,对用户、商家、主播进行实名身份认证,有效降低用户输入成本,控制业务风险

文档电子化

识别提取各类办公文档、合同文件、企业年报、法律卷宗等纸质文档中的文字信息,并基于位置信息进行比对、结构化处理,提高信息录入、存档、检索效率

交通出行

实现卡证、车辆信息的快速录入,提升比对效率,适用于司机身份核验、车主信息管理、智慧停车、卡口通行、车辆维修保养等场景

快递物流

实现快递分发全链路智能化升级,满足身份核验、智能寄件下单,运输车辆管理、快递单识别等不同场景需求。同时助力大宗货运物流过磅提效

财税报销

对10 余种常见税务发票、差旅票据自动分类、识别、录入,可快速对接国税平台进行增值税发票验真,适用于企业税务核算及内部报销场景,释放企业人力,简化业务流程

医疗保险

识别患者身份信息/各类医疗票据/医疗仪器盘数据,提升信息录入效率,助力提高保险理赔整体时效,并辅助病患管理、健康监测、处方单电子化等

识别实战

身份证验证

使用百度智能云的OCR身份证识别

鉴权认证机制

获取到access_token

通过API Key和Secret Key获取的access_token,参考"Access Token获取"

鉴权的主要目的是获取Access_token。Access_token是用户的访问令牌,承载了用户的身份、权限等信息。

1.获取AK/SK

创建应用

2.添加到nacos配置中

3.在业务层使用@Value获取

4.获取Access_token

使用下面编写好的工具类BaiduOcrApi 。

5.controller层

java 复制代码
    @Operation(summary = "识别身份证")
    @Parameters({
            @Parameter(name = "type", description = "back:国徽面;front:照片面", required = true, in = ParameterIn.QUERY)
    })
    @PostMapping("/idCard")
    public SimpleResponse<OCRIdCardResponse> recognizeIdCardBack(@RequestPart(name = "file") MultipartFile file,
                                                                 @RequestParam("type") String type) {

        return SimpleResponse.success(ocrService.recognizeIdCard(file, type));
    }

6.service层

java 复制代码
 
    @Value("${ocr.apiKey}")
    private String apiKey;

    @Value("${ocr.secretKey}")
    private String secretKey;

    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private RedissonClientTemplate redissonClientTemplate;

 /**
     * 识别身份证
     *
     * @param file 文件
     * @param type 类型
     * @return {@link OCRIdCardResponse}
     */
    @Override
    @SneakyThrows
    public OCRIdCardResponse recognizeIdCard(MultipartFile file, String type) {
        if (file == null || file.isEmpty()) {
            log.info("---------- 文件内容为空 ----------");
            throw new AppRuntimeException(ResponseCode.OPERATION_FAILED);
        }

        InputStream inputStream = file.getInputStream();

        // 获取access_token
        String accessToken = redissonClientTemplate.get(RedisKeyConstants.OCR_ACCESS_TOKEN);
        if (StringUtils.isEmpty(accessToken)) {
            accessToken = BaiduOcrApi.getAccessToken(apiKey, secretKey);
            // 保存accessToken到redis,有效时间为29天
            redissonClientTemplate.setex(RedisKeyConstants.OCR_ACCESS_TOKEN, accessToken, 29L, TimeUnit.DAYS);
        }

        // ocr识别
        String result = BaiduOcrApi.recognizeIDCardResult(inputStream, accessToken, type);
        OCRResult orcIdCardResult = objectMapper.readValue(result, OCRResult.class);
        if (orcIdCardResult == null || !"normal".equals(orcIdCardResult.getImage_status()) || orcIdCardResult.getWords_result_num() <= 0) {
            throw new AppRuntimeException(ResponseCode.OCR_API_ERROR);
        }
        OCRIdCardResponse orcIdCardResponse = new OCRIdCardResponse();

        Map<String, OCRResult.wordsModel> wordsResult = orcIdCardResult.getWords_result();
        // 获取结果
        if ("back".equals(type)) {
            // 身份证国徽面
            OCRResult.wordsModel wordsModel = wordsResult.get(OcrConstant.EXPIRATION_DATE);
            if (wordsModel == null) {
                throw new AppRuntimeException(ResponseCode.OCR_API_ERROR);
            }
            orcIdCardResponse.setExpirationDate(wordsModel.getWords());
        } else {
            // 身份证头像面
            OCRResult.wordsModel wordsModel1 = wordsResult.get(OcrConstant.NAME);
            if (wordsModel1 == null) {
                throw new AppRuntimeException(ResponseCode.OCR_API_ERROR);
            }
            orcIdCardResponse.setName(wordsModel1.getWords());

            OCRResult.wordsModel wordsModel2 = wordsResult.get(OcrConstant.ID_NUMBER);
            if (wordsModel2 == null) {
                throw new AppRuntimeException(ResponseCode.OCR_API_ERROR);
            }
            orcIdCardResponse.setIdNumber(wordsModel2.getWords());
        }
        // TODO 保存照片到OSS

        return orcIdCardResponse;

6.百度ocr请求工具类

java 复制代码
import cn.hutool.json.JSONObject;
import okhttp3.*;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * @ClassName: BaiduOcrApi
 * @Author: wujiada
 * @Date: 2024/12/16 10:21
 * @Description: 使用API Key和Secret Key获取Access Token,获取识别结果
 */
public class BaiduOcrApi {

    private static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();

    /**
     * 从用户的AK,SK生成鉴权签名(Access Token)
     *
     * @return 鉴权签名(Access Token)
     * @throws IOException IO异常
     */
    public static String getAccessToken(String apiKey, String secretKey) throws Exception {
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + apiKey
                + "&client_secret=" + secretKey);
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/oauth/2.0/token")
                .method("POST", body)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .build();
        Response response = HTTP_CLIENT.newCall(request).execute();
        assert response.body() != null;
        return new JSONObject(response.body().string()).get("access_token", String.class);
    }

    /**
     * <p>请求百度OCR识别身份证</p>
     *
     * @param inputStream 文件输入流
     * @param accessToken 访问百度云API的token
     * @param type: back:国徽面;front:照片面
     * @return {@link String}
     * @author wujiada
     * @since 2024/12/16 11:35
     */
    public static String recognizeIDCardResult(InputStream inputStream, String accessToken, String type) throws Exception {

        // 读取图片文件并转换为Base64编码
        // 将输入流转换为字节数组
        byte[] imageBytes = readInputStream(inputStream);

        // 使用Base64编码字节数组
        String base64EncodedImage = Base64.getEncoder().encodeToString(imageBytes);

        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        // front:身份证含照片的一面
        // back:身份证带国徽的一面
        RequestBody body = RequestBody.create(mediaType, "image=" + URLEncoder.encode(base64EncodedImage, StandardCharsets.UTF_8)
                + "&id_card_side=" + type + "&detect_ps=false&detect_risk=false&detect_quality=false&detect_photo=false&detect_card=false&detect_direction=false");
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token=" + accessToken)
                .method("POST", body)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .addHeader("Accept", "application/json")
                .build();
        Response response = HTTP_CLIENT.newCall(request).execute();
        assert response.body() != null;
        return response.body().string();
    }

    /**
     * <p>请求百度OCR识别营业执照</p>
     *
     * @param inputStream 文件输入流
     * @param accessToken 访问百度云API的token
     * @return {@link String}
     * @author wujiada
     * @since 2024/12/16 11:35
     */
    public static String recognizeBusinessLicenseResult(InputStream inputStream, String accessToken) throws Exception {

        // 读取图片文件并转换为Base64编码
        // 将输入流转换为字节数组
        byte[] imageBytes = readInputStream(inputStream);

        // 使用Base64编码字节数组
        String base64EncodedImage = Base64.getEncoder().encodeToString(imageBytes);

        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");

        RequestBody body = RequestBody.create(mediaType, "image=" + URLEncoder.encode(base64EncodedImage, StandardCharsets.UTF_8));
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rest/2.0/ocr/v1/business_license?access_token=" + accessToken)
                .method("POST", body)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .addHeader("Accept", "application/json")
                .build();
        Response response = HTTP_CLIENT.newCall(request).execute();
        assert response.body() != null;
        return response.body().string();
    }

    /**
     * <p>从输入流中读取所有字节并将它们存储在ByteArrayOutputStream</p>
     *
     * @param inputStream  文件输入流
     * @return {@link byte[]}
     * @author wujiada
     * @since 2024/12/16 11:37
     */
    private static byte[] readInputStream(InputStream inputStream) throws IOException {
        // 使用ByteArrayOutputStream收集字节
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int bytesRead;

        // 从输入流中读取数据直到EOF
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            byteArrayOutputStream.write(buffer, 0, bytesRead);
        }

        // 将收集的字节转换为字节数组
        return byteArrayOutputStream.toByteArray();
    }


}

7.ocrAPI接收结果实体类

java 复制代码
/**
 * @ClassName: OCRResult
 * @Author: wujiada
 * @Date: 2024/12/16 11:45
 * @Description: 请求百度OCRAPI识别返回结果
 */
@Data
@Schema(description = "请求百度ORC识别API身份证返回结果")
public class OCRResult implements Serializable {

    @Schema(description = "唯一的log id,用于问题定位")
    private Long log_id;

    @Schema(description = "识别结果数,表示words_result的元素个数")
    private Long words_result_num;

    @Schema(description = "定位和识别结果数组")
    private Map<String, wordsModel> words_result;

    /*  normal-识别正常
        reversed_side-身份证正反面颠倒
        non_idcard-上传的图片中不包含身份证
        blurred-身份证模糊
        other_type_card-其他类型证照
        over_exposure-身份证关键字段反光或过曝
        over_dark-身份证欠曝(亮度过低)
        unknown-未知状态*/
    @Schema(description = "识别状态")
    private String image_status;

    @Data
    public static class wordsModel {
        private Object location;
        private String words;
    }
}

总结

通过以上操作,就可以实现前端上传身份证文件,然后发送到百度云OCR,识别校验身份证。

相关推荐
只恨天高11 分钟前
扩展SpringBoot中的SpringMVC的默认配置
java·spring boot·spring
CodeSheep程序羊13 分钟前
吴恩达官宣开源,yyds!
java·javascript·人工智能·python·深度学习·神经网络·github
乱世在摸鱼15 分钟前
代码随想录五刷day5
java·开发语言·数据结构·算法·leetcode
六月长安2 小时前
k8s kubernetes
java·容器·kubernetes
中安OCR人工智能3 小时前
车牌识别OCR授权:助力国产化升级,全面提升道路监控效率
人工智能·算法·ocr
西岭千秋雪_4 小时前
设计模式の建造者&适配器&桥接模式
java·设计模式·建造者模式·桥接模式·适配器模式
阿落ovo5 小时前
访问控制列表ACL
java·运维·服务器·网络·数据库·华为·智能路由器
cv2016_DL5 小时前
ocr中CTC解码相关
算法·ocr·transformer
莫名其妙小饼干6 小时前
社区生活超市系统|Java|SSM|JSP|
java·开发语言·maven·mssql