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远程调用。但是调用的过程中报错了。报错信息:\Bad Message 414\\reason: URI Too Long\

解决办法:此问题是因为图片数据转换成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;
        }
      }
    },
相关推荐
晨间晓4 小时前
图片里的阴影能不能减弱?用华为云码道开发 OpenCV 光照校正工具
人工智能·opencv·华为云
熊猫钓鱼>_>4 小时前
Kotlin Multiplatform for OpenHarmony 实战:kotlinx-serialization JSON 适配
开发语言·华为·kotlin·华为云·json·harmonyos·code
开开心心就好16 小时前
多份文档怎么批量打印?支持多种格式
java·服务器·开发语言·pdf·ocr·散列表·启发式算法
开开心心就好18 小时前
文件被占用删不掉?解锁工具强制删除
java·运维·服务器·开发语言·前端·pdf·ocr
晨间晓18 小时前
图片里的细小噪点怎么平滑?用华为云码道开发 OpenCV 图像滤波对比工具
人工智能·opencv·华为云
偷吃米饭1 天前
图片特征怎么描述?用华为云码道开发 OpenCV ORB 特征提取工具
人工智能·opencv·华为云
晨间晓1 天前
图片里的关键点怎么找?用华为云码道开发 OpenCV FAST 特征点检测工具
人工智能·opencv·华为云
晨间晓1 天前
二值图里的噪点怎么去掉?用华为云码道开发 OpenCV 形态学操作工具
人工智能·opencv·华为云
晨间晓1 天前
图片里的角点在哪里?用华为云码道开发 OpenCV Harris 角点检测工具
人工智能·opencv·华为云
晨间晓2 天前
图片细节丰富不丰富?用华为云码道开发 OpenCV 纹理复杂度分析工具
人工智能·opencv·华为云