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

目录

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

二、编写配置文件

        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;
        }
      }
    },

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Abcdzzr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值