Fork me on GitHub

JackLin的博客

当前位置:首页 > 标签

SpringBoot 14 Spring 2 SpringMVC 3 MyBatis 2 Linux 4 阿里云 13 宝塔 1 Docker 3 ElasticSearch 2 Redis 4 Shiro 0 Dubbo 0 Swagger 0 Thymeleaf 6 数据库 11 MySQL 11 外键 2 Gradle 1 Test 0 Tomcat 1 JavaWeb 7 Ajax 1 注解 3 css 2 报错 3 多数据源 1 Java基础 1 源码 2 Servlet 1 JSP 1 环境搭建 8 RabbitMQ 1 七牛云 1 Edit.md 1 图像识别 4 英语 2 Zookeeper 1

阿里云AI训练营_Day05_创意日_图片识别文字

  • 2020-06-08
  • 176
  • SpringBoot
## 项目介绍 参加阿里云AI训练营的第5天,也是最后一天了。今天是创意日,想做什么就做什么,没有题目约束。 那么我打算做一个简单的识别图片中的文字的应用,并部署上线,以后也可能经常会用到。 ## 项目用到的文档地址 阿里云达摩院视觉开放平台:https://vision.aliyun.com/ 阿里云视觉开放平台 “通用识别” 地址:https://help.aliyun.com/document_detail/151896.html?spm=a2c4g.11186623.6.620.44da1ded5yuZbF ## 项目开始 ### (1)说明 经过前面几天的训练,自我感觉良好。已经对阿里云的视觉开放平台比较熟悉了,也熟悉使用提供的API的一些基础的步骤,感觉就是这些套路。 那么就不啰嗦了,直接上代码。由于只用到了一个场景,所以代码也比较简单,记得测试前要到阿里云开启 “文字识别服务” 哦! ![](http://image.linkaiblog.top/image-20200608223154211.png) ### (2)导入Maven依赖 ```xml <dependency> <groupId>com.aliyun</groupId> <artifactId>ocr</artifactId> <version>1.0.3</version> </dependency> <!-- 阿里巴巴的 fstjson ,和 jackson 的功能类似,用来处理 json字符串--> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency> ``` ### (3)创建Client,Config类 > AIService.java ```java private Client ocrClient; private RuntimeOptions runtimeOptions; @Value("${accessKeyId}") private String accessKeyId; @Value("${accessKeySecret}") private String accessKeySecret; @PostConstruct private void init() throws Exception { Config config = new Config(); config.type = "access_key"; config.regionId = "cn-shanghai"; config.accessKeyId = accessKeyId; config.accessKeySecret = accessKeySecret; config.endpoint = "ocr.cn-shanghai.aliyuncs.com"; ocrClient = new Client(config); runtimeOptions = new RuntimeOptions(); } ``` ### (4)关键代码,调用API函数 这里由于我们需要上传图片,所以参数选择了一个 InputStream,直接从文件中获取输入流。 看文档我们知道,从图片中识别的文字会被封装在一个 data 里面,我们从这里面获取数据即可。 ![](http://image.linkaiblog.top/image-20200608223740407.png) 同时,经过测试,文字识别的过程是一行一行识别的,每行识别出来的文字都成为封装在数组的一个元素里面,所以我们定义一个 StringBuffer 对象,用来拼接这些生成的文字。 > AiService.java ```java public String myRecognizeCharacter(InputStream is) throws Exception { RecognizeCharacterAdvanceRequest request = new RecognizeCharacterAdvanceRequest(); request.imageURLObject = is; request.minHeight = 10; request.outputProbability = true; RecognizeCharacterResponse response = ocrClient.recognizeCharacterAdvance(request, runtimeOptions); StringBuffer result = new StringBuffer(); for (RecognizeCharacterResponse.RecognizeCharacterResponseDataResults item:response.data.results ) { result.append(item.text + "\n"); } return result.toString(); } ``` ### (5)文件上传逻辑 我们在 Service 层实现文件上传的逻辑,然后在 Controller 层调用,并返回上传之后的文件名。 > AiService.java ```java public String uploadImage(MultipartFile file, HttpServletRequest request) { //获取文件名 : file.getOriginalFilename(); String uploadFileName = file.getOriginalFilename(); System.out.println("上传文件名 : "+uploadFileName); String uuid = UUID.randomUUID().toString().replaceAll("-", ""); System.out.println(uuid); String newFileName = "AI-Word-" + uuid + "-" + uploadFileName; //上传路径保存设置 UUID String path = request.getServletContext().getRealPath("/upload"); // String path = "src/main/resources/static/upload"; //如果路径不存在,创建一个 File realPath = new File(path); if (!realPath.exists()){ realPath.mkdir(); } System.out.println("上传文件保存地址:"+realPath); InputStream is = null; //文件输入流 OutputStream os = null; try { is = file.getInputStream(); os = new FileOutputStream(new File(realPath, newFileName)); //文件输出流 //读取写出 int len=0; byte[] buffer = new byte[1024]; while ((len=is.read(buffer))!=-1){ os.write(buffer,0,len); os.flush(); } } catch (IOException e) { e.printStackTrace(); } finally { try { os.close(); } catch (IOException e) { e.printStackTrace(); } try { is.close(); } catch (IOException e) { e.printStackTrace(); } } return newFileName; } ``` ### (6)Controller 层的逻辑 下面我们来看一下 Controller 层的代码,主要就是实现视图的跳转。然后调用 Service 层,获得数据并放在 Model 中并返回给前端 > AiController.jva ```java @Controller public class AIController { @Autowired private AIService aiService; @RequestMapping("/") public String toMain() { return "main"; } @RequestMapping("/fileupload") public String fileUpload(@RequestParam("file") MultipartFile file , HttpServletRequest request, Model model) throws IOException { // 1. 文件上传,返回上传之后新的文件名称 String newFileName = aiService.uploadImage(file, request); // 2. 图片中文字内容识别 InputStream is = file.getInputStream(); String resultWord = null; try { resultWord = aiService.myRecognizeCharacter(is); } catch (Exception e) { e.printStackTrace(); } model.addAttribute("result", "/upload/" + newFileName); model.addAttribute("word", resultWord); return "result"; } } ``` ### (7) 前端部分 最后再来看一下前端部分代码: > Result.html ```html <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> <style> div { width: 400px; border: 1px solid #ff5037; margin-top: 70px; } img { height: 400px; } </style> </head> <body> <div th:text="${word}"></div> <img th:src="@{${result}}" alt=""> </body> </html> ``` ## 测试 先进入主页面,选择图片并点击上传按钮: ![](http://image.linkaiblog.top/image-20200608224523080.png) 识别出来的结果: ![](http://image.linkaiblog.top/_2020060822581958SS.png) ## 阿里云高校计划 最后在贴一张阿里云的广告:”阿里云高校计划“,快来加入我们吧! ![](http://image.linkaiblog.top/image-20200606222043666.png)

阿里云AI训练营_Day04_车辆检测系统

  • 2020-06-08
  • 171
  • 阿里巴巴
## 项目介绍 参加阿里云AI训练营的第4天,完成一个车辆检测系统 主要思路:用户上传身份证和受损车辆图片,识别结果返回前端,同时将数据存入数据库。 ## 项目用到文档地址 阿里云达摩院视觉开放平台:https://vision.aliyun.com/ 阿里云视觉开放平台 “车辆损伤识别” 地址:https://help.aliyun.com/document_detail/155002.html?spm=a2c4g.11174283.6.755.77e06bdfN9iMtt ## 项目模块1-各种识别服务 ### (1)说明 一开始的设想是用到身份证识别和车辆识别2个服务,但是发现同时导入 2 个依赖之后,有一些 jar 包会冲突,导致身份证识别的部分由于缺少一些 jar 包而不能正常运行。最后只用到了机动车识别和车辆损伤识别2个服务。 ### (2)导入项目依赖 这里的依赖我们使用较早的版本 ```xml <!-- 内容识别对应依赖 --> <!-- https://mvnrepository.com/artifact/com.aliyun/objectdet --> <dependency> <groupId>com.aliyun</groupId> <artifactId>objectdet</artifactId> <version>0.0.5</version> </dependency> <!-- 图片识别 --> <dependency> <groupId>com.aliyun</groupId> <artifactId>ocr</artifactId> <version>1.0.3</version> </dependency> ``` 之后同样要开通 “目标检测服务” 才能正常运行。 ### (3)创建 Client,Config类 虽然身份证识别部分会报错,但是这里依旧吧身份证识别部分的代码贴出来 > CraService.java ```java @Value("${accessKeyId}") private String accessKeyId; @Value("${accessKeySecret}") private String accessKeySecret; // "内容识别" --> 导入这个类:import com.aliyun.objectdet20191230.Client; private com.aliyun.objectdet.Client objectClient; private com.aliyun.ocr.Client ocrClient; private RuntimeObject runtimeObject; private RuntimeOptions runTimeOperations; @PostConstruct public void initClient() throws Exception { Config objectConfig = new Config(); objectConfig.type = "access_key"; objectConfig.regionId = "cn-shanghai"; objectConfig.accessKeyId = accessKeyId; objectConfig.accessKeySecret = accessKeySecret; // 注意这里的域名,我们是 “内容识别” 服务,所以开头是 objectdet= objectConfig.endpoint = "objectdet.cn-shanghai.aliyuncs.com"; objectClient = new com.aliyun.objectdet.Client(objectConfig); runtimeObject = new RuntimeObject(); com.aliyun.ocr.models.Config ocrConfig = new com.aliyun.ocr.models.Config(); ocrConfig.type = "access_key"; ocrConfig.regionId = "cn-shanghai"; ocrConfig.accessKeyId = accessKeyId; ocrConfig.accessKeySecret = accessKeySecret; // 注意这里的域名,我们是 “内容识别” 服务,所以开头是 objectdet= ocrConfig.endpoint = "ocr.cn-shanghai.aliyuncs.com"; ocrClient = new com.aliyun.ocr.Client(ocrConfig); runTimeOperations = new RuntimeOptions(); } ``` 需要注意的是两个 Client 是不同的包下面的 Client 类,一个是 “内容识别” 的,另一个是 “图像识别” 的。 ### (4)调用关键 API 这里原本调用了3个服务,分别是 “身份证识别”,“机动车识别”,“车辆受损识别”,关键代码如下: ```java // “机动车识别” public String myDetectVehicle(String filePath) throws Exception { DetectVehicleAdvanceRequest request = new DetectVehicleAdvanceRequest(); request.imageURLObject = new FileInputStream(filePath); DetectVehicleResponse response = objectClient.detectVehicleAdvance(request, runtimeObject); String result = null; // 发现这是一个内部类 for (DetectVehicleResponse.DetectVehicleResponseDataDetectObjectInfoList item:response.data.detectObjectInfoList ) { System.out.println(item.type); System.out.println(item.score); if ("vehicle".equals(item.type)) { System.out.println("检测成功!是机动车"); } else { System.out.println("该图片不是机动车!"); } result = item.type; } return result; } // “车辆损伤识别” public String myRecognizeVehicle(String filePath) throws Exception { // 使用 xxxAdvanceRequest,支持本地图片上传 RecognizeVehicleDamageAdvanceRequest request = new RecognizeVehicleDamageAdvanceRequest(); request.imageURLObject = new FileInputStream(filePath); // 识别 “车辆损伤” RecognizeVehicleDamageResponse response = objectClient.recognizeVehicleDamageAdvance(request, runtimeObject); return getHurtResult(response.data.elements); } // “身份证识别” --------> public String MyRecognizeIdCard(String filePath, String side) throws Exception { RecognizeIdentityCardAdvanceRequest request = new RecognizeIdentityCardAdvanceRequest(); request.imageURLObject = Files.newInputStream(Paths.get(filePath)); request.side = side; RecognizeIdentityCardResponse response = ocrClient.recognizeIdentityCardAdvance(request, runTimeOperations); if ("face".equals(side)) { return JSON.toJSONString(response.data.frontResult); } else { return ""; } } ``` ### (5) 车辆损伤补充代码 看文档我们知道,由于车辆损伤有很多种情况,所以我们需要对数据进行一定的处理,思路是通过一个 switch~case 语句区分各种损伤的具体情况。 ![](http://image.linkaiblog.top/image-20200608180242183.png) > 具体代码: ```java // 对 “车辆损伤” 识别出来的数据进行一定的处理,方便前台展示 public String getHurtResult(RecognizeVehicleDamageResponse.RecognizeVehicleDamageResponseDataElements[] items) { StringBuffer type = new StringBuffer("检测到的车辆损伤为:"); for (RecognizeVehicleDamageResponse.RecognizeVehicleDamageResponseDataElements item:items ) { switch (item.type) { case "1": type.append("轻微刮擦 "); break; case "2": type.append("重度刮擦 "); break; case "3": type.append("轻度变形 "); break; case "4": type.append("中度变形 "); break; case "5": type.append("重度变形 "); break; case "6": type.append("crack破损孔洞 "); break; case "7": type.append("翼子板和大灯缝隙 "); break; case "8": type.append("翼子板保险杠缝隙 "); break; case "9": type.append("大灯轻微刮擦 "); break; case "10": type.append("大灯重度刮擦 "); break; case "11": type.append("大灯破损 "); break; case "12": type.append("后视镜轻微刮擦 "); break; case "13": type.append("后视镜玻璃破损 "); break; case "14": type.append("后视镜脱落 "); break; case "15": type.append("挡风玻璃破损 "); break; } } return type.toString(); } ``` ## 项目模块2-图片上传服务,及数据库操作 这部分做的比较简易,没有美化样式,能看就行~就是一个简单的 from 表单 > test.html ```html <form th:action="@{/upload}" enctype="multipart/form-data" method="post"> 身份证:<input type="file" name="identityfile"> 受损车辆:<input type="file" name="carfile"> <input type="submit" value="upload"> </form> ``` ---- 图片上传对应的 Controller,上传完成之后,同时进行识别,然后在将识别输入存入数据库中 > CarController.java ```java @RequestMapping("/upload") public String fileUpload(@RequestParam("carfile") MultipartFile carFile, @RequestParam("identityfile") MultipartFile identityFile, Model model) throws IOException { // 1. 上传图片 ----》 “身份证” String identityPath = aiCarService.fileUpload(identityFile); // 2. 上传图片 -----》 “受损车辆” String carPath = aiCarService.fileUpload(carFile); // 3. 调用 Service 层分析图片 String face = null; String carStr = null; String carStr2 = null; try { // 3.1 身份证识别 ---> 只需要识别正面 // face = carService.MyRecognizeIdCard(identityPath , "face"); // 3.2 机动车检查 carStr = aiCarService.myDetectVehicle(carPath); // 3.3 车辆损伤识别 carStr2 = aiCarService.myRecognizeVehicle(carPath); } catch (Exception e) { e.printStackTrace(); } // 4. 保存数据到数据库中 Car car = new Car(null, carStr, carStr2); carService.insert(car); // 4. 将图片路径放入 Model 中 String carFileName = carFile.getOriginalFilename(); String identityFileName = identityFile.getOriginalFilename(); model.addAttribute("carfilename", "/upload/" + carFileName); model.addAttribute("identityfilename", "/upload/" + identityFileName); model.addAttribute("face", face); if ("vehicle".equals(carStr)) { model.addAttribute("carStr", "检测成功!是机动车"); } else { model.addAttribute("carStr", "您上传的图片不是机动车,请重新上传!!"); } model.addAttribute("carStr2", carStr2); return "result"; } ``` 对应的 Service > CarService.java ```java /** * @Description: 图片上传服务 * @Param: [file] * @return: void * @Author: 林凯 * @Date: 2020/6/8 */ public String fileUpload(MultipartFile file) { // 1. 获取文件名 String uploadFileName = file.getOriginalFilename(); // 2. 上传路径保存设置 UUID String path = "src/main/resources/static/upload"; // 2.1 如果路径不存在,创建一个 File realPath = new File(path); if (!realPath.exists()){ realPath.mkdir(); } // 3. 上传文件,并保存 InputStream is = null; //文件输入流 OutputStream os = null; try { is = file.getInputStream(); os = new FileOutputStream(new File(realPath, uploadFileName)); int len = 0; byte[] buffer = new byte[1024]; while ((len = is.read(buffer)) != -1) { os.write(buffer, 0, len); os.flush(); } } catch (IOException e) { e.printStackTrace(); } finally { try { os.close(); } catch (IOException e) { e.printStackTrace(); } try { is.close(); } catch (IOException e) { e.printStackTrace(); } } return path + "\\" + uploadFileName; } ``` 返回结果给前端,前端的处理部分 > result.html ```html <img th:src="${carfilename}" alt=""> <img th:src="${identityfilename}" alt=""> <p th:text="${carStr}"></p> <p th:text="${carStr2}"></p> ``` ## 测试效果 首先进入上传图片页面,并上传2张图片 ![](http://image.linkaiblog.top/image-20200608185634408.png) 然后点击 upload 上传并查看结果: ![](http://image.linkaiblog.top/image-20200608190502181.png) 数据库里面的结果: ![](http://image.linkaiblog.top/image-20200608190901927.png) ## 阿里云高校计划 最后在贴一张阿里云的广告:”阿里云高校计划“,快来加入我们吧! ![](http://image.linkaiblog.top/image-20200606222043666.png)

阿里云AI训练营_Day03_电子相册

  • 2020-06-06
  • 191
  • 阿里巴巴
## 项目介绍 参加阿里云AI训练营的第3天,完成一个电子相册。 电子相册需要用到 “人脸属性识别” 和 “场景识别” 2个服务,开通之后就开始我们的项目吧! ## 项目用到文档地址 阿里云达摩院视觉开放平台:https://vision.aliyun.com/ 阿里云视觉开放平台 “人脸属性识别” 地址:https://help.aliyun.com/document_detail/151968.html?spm=a2c4g.11186623.2.20.19714c68VRbnB9 阿里云视觉开放平台 “场景识别” 地址:https://help.aliyun.com/document_detail/152007.html?spm=a2c4g.11186623.6.670.19714c68sp5KFt github给出的示例代码地址:https://github.com/aliyun/alibabacloud-viapi-demo ## 项目开始 ### (1)引入项目依赖 依赖就按照示例代码中的依赖来吧,引入之后可以支持本地图片上传。 ```xml <!-- https://mvnrepository.com/artifact/com.aliyun/aliyun-java-sdk-core --> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.4.9</version> </dependency> <!-- https://mvnrepository.com/artifact/com.aliyun/facebody --> <dependency> <groupId>com.aliyun</groupId> <artifactId>facebody</artifactId> <version>0.0.7</version> </dependency> <!-- https://mvnrepository.com/artifact/com.aliyun/imagerecog --> <dependency> <groupId>com.aliyun</groupId> <artifactId>imagerecog</artifactId> <version>0.0.5</version> </dependency> ``` - 记得要开通对应场景的服务,否则就会报这样的错误 ![](http://image.linkaiblog.top/image-20200606212319897.png) ### (2)创建并初始化 Client,Config 和之前的套路一样,我们需要创建对应场景的 Client 和 Config 类,关于这部分的详细解释可以参照我的上一篇博客 【阿里云AI训练营-_Day02-身份证识别】。 关于 Config 的属性配置,文档中也详细说明了,我们要根据不同的场景赋予不同的值。 ![](http://image.linkaiblog.top/image-20200606213550538.png) ----- 由于我们用到了 2 个场景的服务,所以可以先定义2个关于场景的变量用来标识不同的场景 > 定义 2 个标识场景的变量 ```java // 我们自己的 accessKey 和 accessSecret,需要在配置文件中配置 @Value("${aliyun.accessKeyId}") private String accessKey; @Value("${aliyun.accessSecret}") private String accessSecret; // 人脸属性识别的场景标识 static String faceBodyEndpoint = "facebody"; // 图片场景识别的标识 static String imageRecogEndpoint = "imagerecog"; ``` ----- 下面分别贴出关于 2 个场景的 Client 和Config 类的配置 > Client 和 Config 配置 ```java // 创建人脸属性识别的 Client private com.aliyun.facebody.Client getFaceBodyClient(String endpoint) throws Exception { com.aliyun.facebody.models.Config config = new com.aliyun.facebody.models.Config(); config.accessKeyId = accessKey; config.accessKeySecret = accessSecret; config.type = "access_key"; config.regionId = "cn-shanghai"; config.endpointType = "internal"; // 这里的 config.enpoint 由外部传入,就是传入我们一开始定义的变量,格式化之后为: facebody.cn-shanghai.aliyuncs.com , 对应 人脸属性识别的域名 config.endpoint = String.format("%s.%s", endpoint, "cn-shanghai.aliyuncs.com"); config.protocol = "http"; return new com.aliyun.facebody.Client(config); } // 创建场景识别的 Client private com.aliyun.imagerecog.Client getImageRecogClient(String endpoint) throws Exception { com.aliyun.imagerecog.models.Config config = new com.aliyun.imagerecog.models.Config(); config.accessKeyId = accessKey; config.accessKeySecret = accessSecret; config.type = "access_key"; config.regionId = "cn-shanghai"; config.endpointType = "internal"; // 这里的 config.enpoint 由外部传入,就是传入我们一开始定义的变量,格式化之后为: imagerecog.cn-shanghai.aliyuncs.com , 对应场景识别的访问域名。 config.endpoint = String.format("%s.%s", endpoint, "cn-shanghai.aliyuncs.com"); config.protocol = "http"; return new com.aliyun.imagerecog.Client(config); } ``` ### (3)调用对应场景的 API 老规矩,看文档;示例代码永远只能是举了例子,关键部分的解释还是文档中更详细。 #### 1. 人脸属性识别场景 文档中说了,返回的数据有很多,List,Integer之类的,他们都封装在这个叫 Data 的属性里面,那么我们调用之后就可以直接从 xxxResponse 中获取数据了。 ![](http://image.linkaiblog.top/image-20200606214950120.png) 但是实际上并没有想象中的怎么美好,我看了一下示例代码,发现这个 Data 里面只有一个名字叫做 elements 的对象数组,数组里面的对象是 RecognizeExpressionResponseDataElements 类的对象;然后在这个 RecognizeExpressionResponseDataElements 类里面只能够获取够获取 3 个属性: ![](http://image.linkaiblog.top/image-20200606220000314.png) 这明显和文档中的不符合啊,我个人感觉可能是依赖版本的问题,示例代码中的版本可能太低了,而文档是6月3号更新的,所以使用新版本后,应该以文档为标准; 由于临近期末,时间有限,我就不再尝试了,有兴趣的小伙伴可以测试一下新版本的SDK。 那么按照示例中的代码,这部分的代码应该这样 > 人脸属性识别代码 ,传入的参数为从图片获取的输入流 ```java // 人脸属性识别主要有哪些表情 public List<String> recognizeExpression(InputStream inputStream) throws Exception { RecognizeExpressionAdvanceRequest request = new RecognizeExpressionAdvanceRequest(); request.imageURLObject = inputStream; List<String> labels = new ArrayList<>(); try { // 调用我们前面的方法,获取一个 Client 对象 Client client = getFaceBodyClient(faceBodyEndpoint); RecognizeExpressionResponse resp = client.recognizeExpressionAdvance(request, new RuntimeObject()); // 注意这里我们遍历的是 data 里面的 elements 对象数组,然后从对象中获取 expression 并放入 labels 中 for (RecognizeExpressionResponse.RecognizeExpressionResponseDataElements element : resp.data.elements) { labels.add(ExpressionEnum.getNameByNameEn(element.expression)); } } catch (ClientException e) { log.error("ErrCode:{}, ErrMsg:{}, RequestId:{}", e.getErrCode(), e.getErrMsg(), e.getRequestId()); } return labels; } ``` #### 2. 场景识别 文档关键部分截图,这次文档和代码的出入比较很少,可以跟着文档来走。从 Data 中获取 Tags 进一步获取 Value ![](http://image.linkaiblog.top/image-20200606220712373.png) > 场景识别关键代码,传入的参数为从图片获取的输入流 ```java // 场景识别部分代码 public List<String> recognizeScene(InputStream inputStream) throws Exception { RecognizeSceneAdvanceRequest request = new RecognizeSceneAdvanceRequest(); request.imageURLObject = inputStream; List<String> labels = new ArrayList<>(); try { // 调用之前的方法获取一个 Client 对象 com.aliyun.imagerecog.Client client = getImageRecogClient(imageRecogEndpoint); RecognizeSceneResponse resp = client.recognizeSceneAdvance(request, new RuntimeObject()); // 遍历 data 里面的 tags,从中获取 value 并放入 labels 中 for (RecognizeSceneResponse.RecognizeSceneResponseDataTags tag: resp.data.tags) { labels.add(tag.value); } } catch (ClientException e) { log.error("ErrCode:{}, ErrMsg:{}, RequestId:{}", e.getErrCode(), e.getErrMsg(), e.getRequestId()); } return labels; } ``` ### (4)测试 由于示例代码中的前端部分使用了 Vue + ElementUI,我对 Vue 不是很精通,所以我运行项目后拖入图片没有反应,F12控制里面的 Console 会报错。 所以这里直接使用本地的图片,直接调用 VisionService 类里面的方法(就是我们刚才写的那些方法)来测试 > 测试代码 ```java @Autowired VisionService visionService; @Test void contextLoads() { try { FileInputStream inputStream = new FileInputStream("D:\\Temp\\images\\5a4ca1f4ddd31.jpg"); List<String> expressions = visionService.recognizeExpression(inputStream); for (String expersion:expressions ) { System.out.println("人脸表情:" + expersion); } FileInputStream inputStream1 = new FileInputStream("D:\\Temp\\images\\5a4ca1f4ddd31.jpg"); List<String> recognizeScene = visionService.recognizeScene(inputStream1); for (String scene:recognizeScene ) { System.out.println("对应场景:" + scene); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } ``` > 本地图片 ![](http://image.linkaiblog.top/image-20200606221441905.png) 最中的识别结果: ![](http://image.linkaiblog.top/image-20200606212453730.png) ## 关于 **由于前端代码出现了Bug,所以只测试了后端调用服务API的关键代码,主要是结合代码和文档一起分析,这样才能一通百通。额,好吧,最主要的原因是时间不够,月底就期末考了,能抽出来的时间不是很多,所以不想把时间花费在解决前端的Bug上面。** ## 友情推广 贴一下阿里云的活动,有兴趣的小伙伴可以参加一下 ![](http://image.linkaiblog.top/image-20200606222043666.png)

阿里云AI训练营_Day02_文字识别_身份证识别

  • 2020-06-05
  • 151
  • 阿里巴巴
## 项目介绍 近期参加了阿里云的AI训练营,按照要求完成了一个 “身份证识别” 的 Web应用,特此记录一下。 **由于之前使用过百度AI的人脸识别SDK,而且对阿里云比较熟悉,所以这篇博客侧重于对官方文档阅读理解,以及对给出的视频和项目Demo的理解及运用。** ## 项目用到文档地址 阿里云达摩院视觉开放平台:https://vision.aliyun.com/ 阿里云视觉开放平台文档地址:https://help.aliyun.com/product/142958.html?spm=a2c4g.11186623.6.540.263e3c74d59JVh Aliyun Java SDK COCR 仓库地址:https://mvnrepository.com/artifact/com.aliyun/aliyun-java-sdk-core 新版文字识别 Ocr20191230 仓库地址:https://mvnrepository.com/artifact/com.aliyun/ocr20191230 阿里云的2个Demo的github项目地址:https://github.com/aliyun/alibabacloud-viapi-demo 文章中的代码都是参考的这2个Demo ### 说明 **经过多次尝试并仔细的阅读,发现官方提供的Demo中的引入和依赖和官方文档中引入的依赖有点区别。而且Demo中的 Config 类的配置和文档中的配置也存在一定的区别。** **我是2种依赖和配置都测试过了,觉得官方文档中的配置的确有问题,会导致报错,于是选择了 Demo 中的配置。(后面会有详细说明)** 这里只展示本地图片上传识别,没用到阿里云OOS对象存储服务;关于前端的一些代码逻辑也没有给出,只给出身份证识别关键部分的代码。 ## 开始项目(配置参照Demo中的配置) ### 开通服务 按照文档中的说明,开通服务,不出意外的话很容易就开通成功了,如下图所示: ![](http://image.linkaiblog.top/image-20200530101808285.png) ### 使用 Maven 导入SDK相关依赖 文档中说了提供2个版本的SDK,旧版需用阿里云OSS存储我们的图片,由于我用的是七牛云的图像存储,没用用阿里云,于是选择新版本SDK,支持本地图片上传。 这里我们选择使用官方提供的Demo中的依赖,而不是用官方文档中提供的依赖 我的导入的依赖 ``` <dependency> <groupId>com.aliyun</groupId> <artifactId>ocr</artifactId> <version>1.0.3</version> </dependency> ``` ### 创建 Config 类和 Client 类 参考文档中的说明,我们需要先创建一个 Config 类,将我们的 accessKeyId 和 accessKeySecret 以及一些其他的配置保存在 Config 类中,再通过 Config 类为参数创建 Client 类。 注意:Config 类和 Client 类都是位于 com.aliyun.ocr 包下面的类,导包的时候注意一下。 遇到的坑,文档中的配置存在 Bug,具体如下: ![](http://image.linkaiblog.top/image-20200605153228838.png) 改进之后,我们关于 Config 类的配置及初始化应该这样(和官方提供的Demo中一样) ``` private Client client; private RuntimeOptions runtime; @Value("${accessKeyId}") private String accessKeyId; @Value("${accessKeySecret}") private String accessKeySecret; @PostConstruct private void init() throws Exception { Config config = new Config(); config.type = "access_key"; config.regionId = "cn-shanghai"; config.accessKeyId = accessKeyId; config.accessKeySecret = accessKeySecret; config.endpoint = "ocr.cn-shanghai.aliyuncs.com"; ocrClient = new Client(config); // 需要注意的是,这里我们创建一个 RuntimeOptions 对象,之后会用到这个对象 runtime = new RuntimeOptions(); } ``` 之后继续看文档 ### 调用 Client 类的方法 #### (1)调用流程概述 文档中举了一个银行卡识别的例子,说白了就是创建一个 xxxRequest 对象,然后获取本地图片的数量流并赋值给 xxxRequest 对象的 imageURLObject 属性,以及将一些其他的配置放入 xxxRequest 对象中。 之后通过调用 Client 对象的 xxxAdvance() 方法,获得一个 xxxResponse 对象;然后我们只需要从这个 xxxResponse 对象中获取 JSON 字符串即可。 ------ 这个 xxx 代表了不同的场景,即不同的场景使用的类和方法都有所不同,不过名字都类似。具体的场景的参数也会有略微的不同,可以参看文档中关于该场景的详细描述。 ![](http://image.linkaiblog.top/image-20200530110245328.png) #### (2)具体的使用 下面以身份证识别为例,看下文档中是如何描述的: ![](http://image.linkaiblog.top/image-20200605154824944.png) 实际上在这里还可以进行调试,快速体验一下身份证识别: ![](http://image.linkaiblog.top/image-20200605163104006.png) 我们在IDEA中查看查找相关的类 ![](http://image.linkaiblog.top/image-20200530110518906.png) 实际上这些场景对应的类都可以在我们添加Maven依赖之后导入的jar包中看到: ![](http://image.linkaiblog.top/image-20200605155108707.png) 好了,看完了文档之后,我就使用身份证识别场景的类和方法对文档中的代码进行替换,效果如下 ``` public String MyRecognizeIdCard(String filePath, String side) throws Exception { // 注意我们的类的名称和方法的名称 RecognizeIdentityCardAdvanceRequest req = new RecognizeIdentityCardAdvanceRequest(); InputStream inputStream = new FileInputStream(new File(filePath)); req.imageURLObject = Files.newInputStream(Paths.get(filePath)); req.side = side; RecognizeIdentityCardResponse rep = client.recognizeIdentityCardAdvance(req, runtime); // 这个 face 不是凭空产生的,是我们看完文档中,文档中给出的值 if ("face".equals(side)) { // 正面识别,通过阿里巴巴的 fastjson 将这个 fromResult 类转换为 JSON 格式的字符串并返回 return JSON.toJSONString(rep.data.frontResult); } else { // 反面识别 return JSON.toJSONString(rep.data.backResult); } } ``` 之后我们在测试类中进行测试 ``` @Autowired private OcrService ocrService; @Test void contextLoads() { try { String face = ocrService.MyRecognizeIdCard("D:\\Temp\\images\\_2020053011373037SS.png", "face"); System.out.println("face = " + face); String backface = ocrService.MyRecognizeIdCard("D:\\Temp\\images\\IMG20200530112702.jpg", "back"); System.out.println("back = " + backface); } catch (TeaException e) { System.out.println(e.getData()); } catch (Exception e) { e.printStackTrace(); } } ``` 由于我的图片打了马赛克,所以只能识别出部分结果,结果如下所示 ![](http://image.linkaiblog.top/image-20200605155952932.png) ## 关于使用文档中的配置 我照着文档一步一步来,和文档一样的代码,依赖也是一样的,莫名其妙会报错。不知道是我自己的原因还是文档本来就有错,反正我的代码就是跑不起来,这里展示一下我的报错的代码,希望有小伙伴可以发现问题并解决。 > 初始化部分 ----> 关键就是没有将 config.endpointType="internal"; 注释掉 ![](http://image.linkaiblog.top/image-20200605161121027.png) > 我引入的Maven依赖 ``` <!-- https://mvnrepository.com/artifact/com.aliyun/aliyun-java-sdk-core --> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.1</version> </dependency> <!-- https://mvnrepository.com/artifact/com.aliyun/ocr20191230 --> <dependency> <groupId>com.aliyun</groupId> <artifactId>ocr20191230</artifactId> <version>0.0.3</version> </dependency> ``` > 报错 ![](http://image.linkaiblog.top/image-20200605161231544.png)