OCR:文字识别

news2025/1/23 18:02:52

使用场景:

远程身份认证

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

文档电子化

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

交通出行

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

快递物流

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

财税报销

对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层

    @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层 

 
    @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请求工具类

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接收结果实体类

/**
 * @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,识别校验身份证。

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

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

相关文章

亚信安全春节14天双倍假期通告

亚信安全14天双倍假期来袭 “网安福利王”再次实至名归 2024年 8773小时&#xff0c;31582680秒 亚信安全一直驰骋于云网安世界 奋战在“安全 数智化”的壮阔征途上 如今&#xff0c;新春的脚步渐近 长达14天的春节长假 能让我们暂且放下忙碌的工作 去除班味&#xff0c…

使用Python打开资源管理器并选择文件

from PySide6.QtWidgets import QFileDialogdef openSelectFile(Path):filename, _ QFileDialog.getOpenFileName(Path, "打开文件", "", "所有文件 (*)")if filename:print(f"选择的文件: {filename}")return filename 代码解释 &a…

uniapp blob格式转换为video .mp4文件使用ffmpeg工具

前言 介绍一下这三种对象使用场景 您前端一旦涉及到文件或图片上传Q到服务器&#xff0c;就势必离不了 Blob/File /base64 三种主流的类型它们之间 互转 也成了常态 Blob - FileBlob -Base64Base64 - BlobFile-Base64Base64 _ File uniapp 上传文件 现在已获取到了blob格式的…

五、windows上vscode构建c/c++环境

1、安装vscode 官网下载界面&#xff1a;https://code.visualstudio.com/Download 请根据电脑系统安装所需版本点击下载链接&#xff08;一般情况下点击windows按钮即可&#xff09;鼠标左键双击&#xff0c;即可运行安装程序&#xff0c;点击【确认】&#xff1b;选择安装路径…

ElasticSearch中的模糊搜索:为什么输入错误还能搜索出来?

引言 在日常搜索中&#xff0c;用户经常会因为拼写错误或输入笔误导致搜索结果不准确。然而&#xff0c;ElasticSearch 提供了一种非常智能的模糊搜索&#xff08;Fuzzy Search&#xff09;功能&#xff0c;使得即使关键词输入错误&#xff0c;依然能够返回准确或接近的结果。…

prober.php探针

raw.githubusercontent.com/kmvan/x-prober/master/dist/prober.php

DIY-ESP8266移动PM2.5传感器-带屏幕-APP

本教程将指导您制作一台专业级的空气质量检测仪。这个项目使用经济实惠的ESP8266和PMS5003传感器&#xff0c;配合OLED显示屏&#xff0c;不仅能实时显示PM2.5数值&#xff0c;还能通过手机APP随时查看数据。总成本70元&#xff0c;相比几百的用的便宜&#xff0c;用的心理踏实…

怎么将pdf中的某一个提取出来?介绍几种提取PDF中页面的方法

怎么将pdf中的某一个提取出来&#xff1f;传统上&#xff0c;我们可能通过手动截取屏幕或使用PDF阅读器的复制功能来提取信息&#xff0c;但这种方法往往不够精确&#xff0c;且无法保留原文档的排版和格式。此外&#xff0c;很多时候我们需要提取的内容可能涉及多个页面、多个…

2024微博用户消费趋势报告:七成城市用户更爱用微博

文 | 魏力 发布 | 大力财经 站在岁末回首这一年&#xff0c;在信息浪潮的汹涌翻涌之下&#xff0c;社交媒体平台犹如社会经济的晴雨表&#xff0c;精准地折射出大众生活与消费的万千景象。近日&#xff0c;大力财经看到一份报告&#xff0c;微博发布了《2024微博用户消费趋势…

#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

【数据安全】如何保证其安全

数据安全风险 数字经济时代&#xff0c;数据已成为重要的生产要素。智慧城市、智慧政务的建设&#xff0c;正以数据为核心&#xff0c;推动城市管理的智能化和公共服务的优化。然而&#xff0c;公共数据开放共享与隐私保护之间的矛盾日益凸显&#xff0c;如何在确保数据安全的…

武汉市电子信息与通信工程职称公示了

2024年武汉市电子信息与通信工程专业职称公示了&#xff0c;本次公示通过人员有109人。 基本这已经是今年武汉市工程相关职称最后公示了&#xff0c;等待出证即可。 为什么有人好奇&#xff0c;一样的资料&#xff0c;都是业绩、论文等&#xff0c;有的人可以过&#xff0c;有的…

勤研低代码平台:高效数据集成助力企业数字化转型

在数字化转型的浪潮中&#xff0c;企业对高效开发工具的需求日益增长。勤研低代码平台强大的开发能力和灵活的数据集成方案&#xff0c;是企业提升效率、降低成本的理想选择。数据集成作为勤研低代码平台的核心功能之一&#xff0c;为企业提供了高效整合和利用数据的能力&#…

【毕业设计】A079-基于Java的影院订票系统的设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看项目链接获取⬇️&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600个选题ex…

大腾智能受邀出席南京工业软件云工程应用创新中心工业软件生态应用推广大会并领奖

12月18日&#xff0c;南京工业软件云工程应用创新中心工业软件生态应用推广大会在南京江北新区圆满召开。本次大会由南京江北新区管委会主办&#xff0c;南京工业软件云工程应用创新中心、南京江北新区智能制造产业发展管理办公室联合承办&#xff0c;华为云计算技术有限公司支…

EasyPlayer.js播放器Web播放H.265要兼顾哪些方面?

在数字化时代&#xff0c;流媒体技术已经成为信息传播和娱乐消费的重要方式。随着互联网技术的飞速发展和移动设备的普及&#xff0c;流媒体服务正在重塑我们的生活和工作方式。从视频点播、在线直播到音乐流媒体&#xff0c;流媒体技术的广泛应用不仅改变了内容的分发和消费模…

fabric.js

目录 一、在canvas上画简单的图形 二、在canvas上用路径(Path)画不规则图形 三、在canvas上插入图片并设置旋转属性(angle) 四、让元素动起来(animate) 五、图像过滤器(filters)让图片多姿多彩 六、颜色模式(Color)和相互转换(toRgb、toHex) 七、对图形的渐变填充(Gradi…

白话AI大模型(LLM)原理

大模型&#xff08;例如 GPT-4或类似的深度学习模型&#xff09;是基于神经网络的系统&#xff0c;用于理解、生成文本、图像或其他数据类型。其工作原理可以分为以下几个核心步骤&#xff0c;我将通过易于理解的例子逐一解释。 1. 神经网络的基本概念 大模型背后有一个非常庞…

基于海思soc的智能产品开发(巧用mcu芯片)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 对于开发车规级嵌入式软件的同学来说&#xff0c;socmcu这样的组合&#xff0c;他们并不陌生。但是传统的工业领域&#xff0c;比如发动机、医疗或…

力扣438-找到字符串中所有字母异位词

力扣438-找到字符串中所有字母异位词 力扣438-找到字符串中所有字母异位词原题地址&#xff1a;https://leetcode.cn/problems/find-all-anagrams-in-a-string/description/ 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词的子串&#x…