2023/8/16 华为云OCR识别驾驶证、行驶证

news2025/1/27 12:40:23

目录

一、 注册华为云账号开通识别驾驶证、行驶证服务

二、编写配置文件

        2.1、配置秘钥

        2.2、 编写配置工具类

三、接口测试

        3.1、测试接口

        3.2、结果

 四、实际工作中遇到的问题

        4.1、前端传值问题

        4.2、后端获取数据问题

        4.3、使用openfeign调用接口报错

        4.3、前端显示问题


hello大家好,好久没写博客了,你们找到工作了吗?博主在去年11月成功找到工作,到现在上班大半年了,最近需求用到华为云OCR文字识别,这里就详细记录一下!

一、 注册华为云账号开通识别驾驶证、行驶证服务

华为云官网:特惠专区_云服务器_云主机_企业上云-华为云

 如上图所示,华为云还有很多文字识别服务,这个看个人需求了解即可。

 开放api接口地址体验:https://console.huaweicloud.com/apiexplorer/#/openapi/OCR/debug?api=RecognizeDriverLicense

二、编写配置文件

        2.1、配置秘钥

ocr:
  projectId: xxxxxxxxxxxxxx   // 项目id:华为云个人凭证获取
  area: cn-north-4        // 区域:北京4区,目前好像只有北京4区支持这两个证件的识别服务
  ak: xxxxxxxxxxxxx        //AK:华为云个人凭证获取
  sk: xxxxxxxxxxxxx        //SK:华为云个人凭证获取

        2.2、 编写配置工具类

@Component
public class OcrUtil {
    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);

    @Value("${ocr.projectId}")
    private String projectId;
    @Value("${ocr.area}")
    private String area;
    @Value("${ocr.ak}")
    private String AK;
    @Value("${ocr.sk}")
    private String SK;
    private static CloseableHttpClient httpClient;
    static {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(100);
        cm.setDefaultMaxPerRoute(20);
        cm.setDefaultMaxPerRoute(50);
        httpClient = HttpClients.custom().setConnectionManager(cm).build();
    }

    public String getTokenByAKSK (){
        String url = "https://iam."+area+".myhuaweicloud.com/v3/auth/tokens";
        Map<String,String> p1 = new HashMap<>();
        Map<String,Object> p2 = new HashMap<>();
        Map<String,Object> p3 = new HashMap<>();
        Map<String,Object> p4 = new HashMap<>();
        Map<String,Object> p5 = new HashMap<>();
        Map<String,Object> p6 = new HashMap<>();
        Map<String,Object> p7 = new HashMap<>();
        Map<String,Object> p8 = new HashMap<>();
        p1.put("key",AK);
        p2.put("key",SK);
        p3.put("access",p1);
        p3.put("secret",p2);
        p4.put("hw_ak_sk",p3);
        String[] str = new String[1];
        str[0] = "hw_ak_sk";
        p4.put("methods",str);
        p5.put("identity",p4);
        p6.put("name",area);
        p7.put("project",p6);
        p5.put("scope",p7);
        p8.put("auth",p5);
        String result = postJson(url, JSON.toJSONString(p8));
        return result;
    }

    public static String postJson(String url, String jsonString) {
        CloseableHttpResponse response = null;
        String result = "";
        try {
            HttpPost httpPost = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build();
            httpPost.setConfig(requestConfig);
            httpPost.setConfig(requestConfig);
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
            httpPost.setHeader("Accept", "application/json");
            httpPost.setEntity(new StringEntity(jsonString, StandardCharsets.UTF_8));
            response = httpClient.execute(httpPost);
            Header[] h = response.getAllHeaders();
            for(Header header : h){
                if(header.getName().equals("X-Subject-Token")){
                    result = header.getValue();
                }
            }
        } catch (IOException e) {
            log.error("调用HttpUtils.Post IOException, url=" + url + ",param=" + jsonString, e);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                log.error("调用HttpUtils.Post IOException, url=" + url + ",param=" + jsonString, e);
            }
        }
        return result;
    }

    public static Result postJson(String url, String token, String jsonString) {
        CloseableHttpResponse response = null;
        BufferedReader in;
        String result = "";
        boolean err = false;
        try {
            HttpPost httpPost = new HttpPost(url);
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(30000).setConnectionRequestTimeout(30000).setSocketTimeout(30000).build();
            httpPost.setConfig(requestConfig);
            httpPost.setConfig(requestConfig);
            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
            httpPost.setHeader("Accept", "application/json");
            httpPost.setHeader("X-Auth-Token", token);
            httpPost.setEntity(new StringEntity(jsonString, StandardCharsets.UTF_8));
            response = httpClient.execute(httpPost);
            in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            StringBuilder sb = new StringBuilder();
            String line;
            String NL = System.getProperty("line.separator");
            while ((line = in.readLine()) != null) {
                sb.append(line).append(NL);
            }
            in.close();
            result = sb.toString();
            err = response.getStatusLine().getStatusCode() == 400;
        } catch (IOException e) {
            log.error("调用HttpUtils.Post IOException, url=" + url + ",param=" + jsonString, e);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                log.error("调用HttpUtils.Post IOException, url=" + url + ",param=" + jsonString, e);
            }
        }
        if (err) {
            return Result.error().data("data", result);
        } else {
            return Result.ok().data("data", result);
        }
    }
    /**
     * 功能描述:
     * 华为云驾驶证识别
     * @Param: [token, imageUrl]
     * @Return: com.ruoyi.phaseone.common.utils.R
     * @Author: Mr.Huang
     * @Date: 2023/8/10 10:21
     **/
    public Result driverLicense(String token, String imageUrl) {
        String url = "https://ocr."+area+".myhuaweicloud.com/v2/"+projectId+"/ocr/driver-license";
        Map<String, Object> p = new HashMap<>();
        // url:图片地址  image:图片的base64数据 两个参数二选一,详情见官网API
        p.put("url", imageUrl);
        p.put("side", "front");
        log.info("ocr驾驶证识别请求路径:{},请求参数:{}",url,p);
        return postJson(url, token, JSON.toJSONString(p));
    }
    /**
     * 功能描述:
     * 华为云行驶证识别
     * @Param: [token, imageUrl]
     * @Return: com.sy.milkteasyservice.response.Result
     * @Author: Mr.Huang
     * @Date: 2023/8/14 10:52
     **/
    public Result vehicleLicense(String token, String imageUrl) {
        String url = "https://ocr."+area+".myhuaweicloud.com/v2/"+projectId+"/ocr/vehicle-license";
        Map<String, Object> p = new HashMap<>();
        // url:图片地址  image:图片的base64数据 两个参数二选一,详情见官网API
        p.put("url", imageUrl);
        // front:行驶证主页  back:行驶证副页
        p.put("side", "front");
        log.info("ocr行驶证识别请求路径:{},请求参数:{}",url,p);
        return postJson(url, token, JSON.toJSONString(p));
    }
}

调用此接口的流程就是:获取token后设置请求头,发起请求获得结果

三、接口测试

        3.1、测试接口

@RestController
public class HuaWeiObsController {
    @Autowired
    private ObsService ObsService;

    @Autowired
    private OcrUtil ocrUtil;

    @ApiOperation(value = "上传图片文件",notes = "xxxxx")
    @PostMapping("/uploadImgFile")
    public Result upload(MultipartFile file){
        String url = ObsService.upload(file);
        // 行驶证识别

/*        Result result = ocrUtil.vehicleLicense(ocrUtil.getTokenByAKSK(), url);
        System.out.println("调用华为云行驶证识别结果:"+result.toString());
        Map<String, Object> data = result.getData();
        Object data1 = data.get("data");
        JSONObject jsonObject = JSON.parseObject(data1.toString());
        String result1 = jsonObject.get("result").toString();
        System.out.println(result1);
        vehicleLicense vehicleLicense = JSON.parseObject(result1, vehicleLicense.class);
        System.out.println("orc识别结果是:"+vehicleLicense.toString());
        return Result.ok().data("result",vehicleLicense).data("url",url);*/
        // 驾驶证识别
        Result result = ocrUtil.driverLicense(ocrUtil.getTokenByAKSK(), url);
        System.out.println("调度接口获取的结果集:"+result);
        Map<String, Object> data = result.getData();
        Object data1 = data.get("data");
        JSONObject jsonObject = JSON.parseObject(data1.toString());
        String result1 = jsonObject.get("result").toString();
        System.out.println(result1);
        drivingLicence drivingLicence = JSON.parseObject(result1, drivingLicence.class);
        System.out.println("orc识别结果是:"+drivingLicence.toString());
        return Result.ok().data("result",drivingLicence).data("url",url);
    }
}

这里的文件上传用的是华为云的OBS服务,上传图片后拿到该图片对应的地址,注意:此图片地址必须要可以访问,如设置访问权限则会调用接口失败!

        3.2、结果

 

 

 四、实际工作中遇到的问题

        4.1、前端传值问题

问题描述:由于前端使用的是根据el-upload封装后的组件,我发现驾驶证和行驶证上传到的是同一个接口,那这样就分不清上传的驾驶证还是行驶证。

解决办法:在调用后端接口传入图片类型字段,判断是驾驶证还是行驶证

:action="this.$http.adornUrl(`/proxyKpiApi/${config.uploadUrl}?${config.id ? `id=${config.id}&` : ''}token=${$cookie.get('token')}&${config.type ? `type=${config.type}` : ''}`)"

 

        4.2、后端获取数据问题

问题描述:项目中使用的华为云obs文件上传服务,但是上传后获得的图片地址因为安全性考虑,不能直接访问,导致调用接口失败。

 

    // openfeign驾驶证服务
    @PostMapping(value = "/performance/driverLicense", params = "{url={url}}")
    R driverLicense(@RequestParam("url") String url);
    // openfeign行驶证服务
    @PostMapping(value = "/performance/vehicleLicense", params = "{url={url}}")
    R vehicleLicense(@RequestParam("url") String url);

解决办法:将上传的文件转换成base64格式,调用接口时改成使用image参数,图片的base64数据。

                if(StringUtils.isNotBlank(type)){
                    byte[] fileBytes = file.getBytes();
                    // 将上传的文件转换成base64格式
                    String base64String = Base64.getEncoder().encodeToString(fileBytes);
                    if(type.equals("driverLicense")){
                        // 远程调用识别驾驶证服务
                        com.ruoyi.phaseone.common.utils.R r = carrierPerformanceService.driverLicense(base64String);
                        log.info("ocr驾驶证识别请求结果:{}",r);
                        if(String.valueOf(r.get("code")).equals("0")){
                            Object data = r.get("data");
                            JSONObject jsonObject = JSON.parseObject(data.toString());
                            String result1 = jsonObject.get("result").toString();
                            DrivingLicenceEntity drivingLicenceEntity = JSON.parseObject(result1, DrivingLicenceEntity.class);
                            map.put("ocrResult",drivingLicenceEntity);
                        }
                    }else if(type.equals("vehicleLicense")){
                        // 远程调用识别行驶证服务
                        com.ruoyi.phaseone.common.utils.R r = carrierPerformanceService.vehicleLicense(base64String);
                        log.info("ocr行驶证识别请求结果:{}",r);
                        if(String.valueOf(r.get("code")).equals("0")){
                            Object data = r.get("data");
                            JSONObject jsonObject = JSON.parseObject(data.toString());
                            String result1 = jsonObject.get("result").toString();
                            VehicleLicenseEntity vehicleLicenseEntity = JSON.parseObject(result1, VehicleLicenseEntity.class);
                            map.put("ocrResult",vehicleLicenseEntity);
                        }
                    }
                }

        4.3、使用openfeign调用接口报错

问题描述:按照上面步骤修改后,由于项目是微服务架构,文件上传服务和前端调用的接口不在同一个服务上,所以要使用openfeign远程调用。但是调用的过程中报错了。报错信息:[<h1>Bad Message 414</h1><pre>reason: URI Too Long</pre>]

解决办法:此问题是因为图片数据转换成base64后,通过远程调用传的值URI太长了,因此我们将接口改造一下,将参数改成对象。

@Data
public class ImageEntity implements Serializable {
    private String imageUrl;
    private String imageBase64;
}
    // openfeign驾驶证服务
    @PostMapping( "/performance/driverLicense")
    R driverLicense(@RequestBody ImageEntity image);
    // openfeign行驶证服务
    @PostMapping("/performance/vehicleLicense")
    R vehicleLicense(@RequestBody ImageEntity image);
                if(StringUtils.isNotBlank(type)){
                    byte[] fileBytes = file.getBytes();
                    // 将上传的文件转换成base64格式
                    String base64String = Base64.getEncoder().encodeToString(fileBytes);
                    ImageEntity image =new ImageEntity();
                    image.setImageBase64(base64String);
                    if(type.equals("driverLicense")){
                        // 远程调用识别驾驶证服务
                        com.ruoyi.phaseone.common.utils.R r = carrierPerformanceService.driverLicense(image);
                        log.info("ocr驾驶证识别请求结果:{}",r);
                        if(String.valueOf(r.get("code")).equals("0")){
                            Object data = r.get("data");
                            JSONObject jsonObject = JSON.parseObject(data.toString());
                            String result1 = jsonObject.get("result").toString();
                            DrivingLicenceEntity drivingLicenceEntity = JSON.parseObject(result1, DrivingLicenceEntity.class);
                            map.put("ocrResult",drivingLicenceEntity);
                        }
                    }else if(type.equals("vehicleLicense")){
                        // 远程调用识别行驶证服务
                        com.ruoyi.phaseone.common.utils.R r = carrierPerformanceService.vehicleLicense(image);
                        log.info("ocr行驶证识别请求结果:{}",r);
                        if(String.valueOf(r.get("code")).equals("0")){
                            Object data = r.get("data");
                            JSONObject jsonObject = JSON.parseObject(data.toString());
                            String result1 = jsonObject.get("result").toString();
                            VehicleLicenseEntity vehicleLicenseEntity = JSON.parseObject(result1, VehicleLicenseEntity.class);
                            map.put("ocrResult",vehicleLicenseEntity);
                        }
                    }
                }

        4.3、前端显示问题

问题描述:调用接口成功后,由于前端使用的是el-upload封装后的组件,用的watch函数监听值的变化,每次打开该控件都会显示其结果。

    watch: {
      'dataForm.carLicence.attachments' (newVal, oldVal) {

      }

解决方案:判断newVal中的ocrResult是否为空,不为空在赋值,因为可以上传多个文件,所以每次更新选取集合中最后一个元素的数据

    watch: {
      'dataForm.carLicence.attachments' (newVal, oldVal) {
        if (newVal[newVal.length - 1] && newVal[newVal.length - 1].ocrResult !== undefined && newVal[newVal.length - 1].ocrResult !== null) {
          // 车牌号
          this.dataForm.carNumber = newVal[newVal.length - 1].ocrResult.number;
          // 发动机号
          this.dataForm.engineNumber = newVal[newVal.length - 1].ocrResult.engine_no;
          // 所有人
          this.dataForm.carLicence.person = newVal[newVal.length - 1].ocrResult.name;
          // 品牌型号
          this.dataForm.carLicence.brandModel = newVal[newVal.length - 1].ocrResult.model;
          // 注册日期
          this.dataForm.carLicence.registerTime = newVal[newVal.length - 1].ocrResult.register_date;
          // 发证日期
          this.dataForm.carLicence.certificationTime = newVal[newVal.length - 1].ocrResult.issue_date;
        }
      }
    },

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

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

相关文章

python bytes基本用法

目录 1 第一个字符变大写&#xff0c;其余字符变小写 capitalize() 2 生成指定长度内容&#xff0c;然后把指定的bytes放到中间 center() 3 计数 count() 4 解码 decode() 5 是否以指定的内容结尾 endswith() 6 将制表符调整到指定大小 expandtabs() 7 寻找指…

ref拿到组件的实例对象或者原生html标签

在组件中&#xff0c;或者html标签中写ref属性&#xff0c;就是在注册引用 可以通过ref拿到组件的实例对象 也可以通过ref拿到原生的html标签

Linux系统安装及使用HHDBCS

1 安装 1.1 下载HHDBCS 使用浏览器进入官方社区&#xff08;恒辉产品社区&#xff09;&#xff0c;选择HHDBCS子社区&#xff0c;首页点击下载&#xff0c;进入下载页面&#xff1b; 选择官网下载/云盘下载皆可。 在弹出框中选择如图所示选项&#xff0c;点击下载&#xff…

带着设计思维画版图——第一次和第二次

版图设计目标&#xff1a; 面积小&#xff0c;性能好&#xff08;少恶化&#xff09;&#xff0c;成本低 设计规则规定了同层与不同层之间的最小距离&#xff0c;因此限制了最小面积 模拟版图设计流程 第一步&#xff1a;设计原理图输入 常用快捷键如下&#xff1a; 介…

YOLO算法封装进入ros系统,识别结果供其他节点订阅

一,前期工作空间搭建 新建工作空间,第一级名称可以换,第二级src最好别换,这是ros系统的固定格式 mkdir -p workspace_yolo/src切换到工作空间 workspace_yolo,进行编译构建项目 cd workspace_yolo/catkin_make输出如下所示: 添加环境变量 cd devel/ 获取到devel文件路径…

模型预测笔记(一):数据清洗分析及可视化、模型搭建、模型训练和预测代码一体化和对应结果展示(可作为baseline)

模型预测 一、导入关键包二、如何载入、分析和保存文件三、修改缺失值3.1 众数3.2 平均值3.3 中位数3.4 0填充 四、修改异常值4.1 删除4.2 替换 五、数据绘图分析5.1 饼状图5.1.1 绘制某一特征的数值情况&#xff08;二分类&#xff09; 5.2 柱状图5.2.1 单特征与目标特征之间的…

花生十三 判断推理(三)分析类、推出类

分析类 题型 真假分析 定义&#xff1a;孰真孰假的真假话分析&#xff0c;命题真假无法确定&#xff0c;无法利用推出关系解题 解题思路 矛盾法&#xff08;三种矛盾&#xff09;&#xff1a;A和非A&#xff0c;“A或B” 与“非A且非B” 技巧&#xff1a;一“找”矛盾&am…

在ARM服务器上一键安装Proxmox VE(以在Oracle Cloud VPS上为例)(甲骨文)

前言 如题&#xff0c;具体用到的说明文档如下 virt.spiritlhl.net 具体流程 首先是按照说明&#xff0c;先得看看自己的服务器符不符合安装 Proxmox VE的条件 https://virt.spiritlhl.net/guide/pve_precheck.html#%E5%90%84%E7%A7%8D%E8%A6%81%E6%B1%82 有提到硬件和软…

C# 读取pcd、ply点云文件数据

最近研究了下用pcl读取点云数据&#xff0c;又做了个C#的dll&#xff0c;方便读取&#xff0c;同样这个dll基于pcl 最新版本1.13.1版本开发。 上次做的需要先得到点云长度&#xff0c;再获取数据。这次这个定义了一个PointCloudXYZ类来存数据。将下面的dll拷贝到可执行目录下&a…

边缘网络的作用及管理工具

自从引入软件即服务 &#xff08;SaaS&#xff09; 以来&#xff0c;它一直引领着全球按需软件部署创新的竞赛&#xff0c;它提供的灵活性以及其云计算架构带来的易于集成使其成为交付业务应用程序的标准。 在 SaaS 模型中&#xff0c;最佳用户体验的三重奏涉及无缝设置、低延…

20230818 数据库自整理部分

并发事务 脏读 一个事务读取到另一事务还没有提交的数据 事务B读取了事务A还没有提交的数据 不可重复读 一个事务先后读取同一条记录&#xff0c;但是两次读取的数据不同&#xff0c;称之为不可重复读 查询出来的数据不一样 1步骤b还没有提交 3步骤b已经提交 幻读 一个…

利用dayj转换查询时间获取当前周月年最后一天

利用dayj转换查询时间 queryForm 查询参数对象 switch 区分选择时间类型 日 周 月 年 计算结束时间 dayjs(element).endOf("week").format("YYYY-MM-DD") 当前周结束时间 日期时间查询框配置参数格式 {label: "",width: 220,key: "…

中期国际:MT4挂单和止损设置教程:善用限价和止损单来管理风险

在外汇交易中&#xff0c;合理设置挂单和止损是保护资金和管理风险的重要手段。MT4平台提供了便捷的挂单和止损功能&#xff0c;帮助交易者更好地控制交易风险。本文将为您介绍如何善用限价和止损单来管理风险&#xff0c;以及在MT4平台上的操作步骤。 一、设置限价挂单 限价挂…

ZooKeeper单机服务器启动

ZooKeeper服务器的启动&#xff0c;大体可以分为以下五个主要步骤&#xff1a;配置文件解析、初始化数据管理器、初始化网络I/O管理器、数据恢复和对外服务。下图所示是单机版ZooKeeper服务器的启动流程图。 预启动 预启动的步骤如下。 (1)统一由QuorumPeerMain作为启动类。 …

游乐场vr设备虚拟游乐园vr项目沉浸体验馆

在景区建设一个VR游乐场项目可以为游客提供一种新颖、刺激和沉浸式的游乐体验。提高游客的体验类型&#xff0c;以及景区的类目&#xff0c;从而可以吸引更多的人来体验。 1、市场调研&#xff1a;在决定建设VR游乐场项目之前&#xff0c;需要进行市场调研&#xff0c;了解当地…

YOLOv2和YOLOv3基础

目录 v2改进网络结构先验框感受野 V3多scale残差网络架构先验框softmax层代替 v2 改进 网络结构 先验框 感受野 V3 多scale 残差 网络架构 先验框 softmax层代替

项目管理系统是什么?能干什么?有什么功能?一文看懂

阅读本文您可以了解&#xff1a;1、项目任务管理系统是什么&#xff1b;2、项目任务管理系统的作用&#xff1b;3、项目任务管理系统的功能 一、什么是项目任务管理 项目任务管理是指运用系统的理论方法&#xff0c;在有限的条件和资源下&#xff0c;对项目从开始到结束的全流…

jvm-类加载子系统

1.内存结构概述 类加载子系统负责从文件系统或网络中加载class文件&#xff0c;class文件在文件开头有特定的文件标识 ClassLoader只负责class文件的加载&#xff0c;至于它是否运行&#xff0c;则由Execution Engine决定 加载的类信息存放于一块称为方法区的内存空间&#xff…

英特尔NUC12发烧友套件(蝰蛇峡谷)评测,适合设计者的迷你主机

英特尔的下一代计算单元&#xff08;NUC&#xff09;系列迷你个人电脑不断发展&#xff0c;现在已经拥有真正的英特尔Arc游戏硬件。NUC 12蝰蛇峡谷是第一款采用英特尔Arc专用图形处理器的NUC&#xff0c;具体来说&#xff0c;是搭载了Arc A770M移动GPU和16GB独立显存。配备Core…

【数据分享】1901-2022年1km分辨率逐年最低气温栅格数据(免费获取/全国/分省)

气温数据是我们在各项研究中最常用的气象指标之一&#xff01;之前我们给大家分享过1901-2022年1km分辨率逐月最低气温栅格数据&#xff08;可查看之前的文章获悉详情&#xff09;&#xff01;该数据来源于国家青藏高原科学数据中心&#xff0c;这儿的逐月最低气温是当月每日最…