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

目录

[一、 注册华为云账号开通识别驾驶证、行驶证服务](#一、 注册华为云账号开通识别驾驶证、行驶证服务)

二、编写配置文件

2.1、配置秘钥

[2.2、 编写配置工具类](#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、 编写配置工具类

java 复制代码
@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、测试接口

java 复制代码
@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文件上传服务,但是上传后获得的图片地址因为安全性考虑,不能直接访问,导致调用接口失败。

java 复制代码
    // 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数据。

java 复制代码
                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太长了,因此我们将接口改造一下,将参数改成对象。

java 复制代码
@Data
public class ImageEntity implements Serializable {
    private String imageUrl;
    private String imageBase64;
}
java 复制代码
    // openfeign驾驶证服务
    @PostMapping( "/performance/driverLicense")
    R driverLicense(@RequestBody ImageEntity image);
    // openfeign行驶证服务
    @PostMapping("/performance/vehicleLicense")
    R vehicleLicense(@RequestBody ImageEntity image);
java 复制代码
                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函数监听值的变化,每次打开该控件都会显示其结果。

html 复制代码
    watch: {
      'dataForm.carLicence.attachments' (newVal, oldVal) {

      }

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

html 复制代码
    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;
        }
      }
    },
相关推荐
我的运维人生2 小时前
华为云技术深度解析:以系统性创新加速智能化升级
华为云·运维开发·技术共享
菜就多练_08288 小时前
《深度学习》OpenCV 摄像头OCR 过程及案例解析
人工智能·深度学习·opencv·ocr
OCR_wintone4211 天前
中安未来 OCR—— 开启高效驾驶证识别新时代
人工智能·汽车·ocr
OCR_wintone4211 天前
中安未来 OCR—— 开启文字识别新时代
人工智能·深度学习·ocr
OCR_wintone4211 天前
翔云 OCR:发票识别与验真
人工智能·深度学习·ocr
linlinlove22 天前
828华为云征文|华为云Flexus云服务器X实例部署 即时通讯IM聊天交友软件——高性能服务器实现120W并发连接
服务器·华为云·交友
acc82262 天前
828华为云征文|华为云 Flexus X 实例之家庭娱乐中心搭建
华为云
OCR_wintone4212 天前
中安未来 OCR:引领智能报关新时代
ocr
会洗碗的CV工程师3 天前
828华为云征文|使用Flexus X实例创建FDS+Nginx服务实现图片上传功能
java·服务器·spring boot·nginx·华为云
FHYAAAX3 天前
云服务架构与华为云架构
架构·华为云·云服务架构