当前位置:首页 > 标签
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
- 217
- SpringBoot
## 项目介绍
参加阿里云AI训练营的第5天,也是最后一天了。今天是创意日,想做什么就做什么,没有题目约束。
那么我打算做一个简单的识别图片中的文字的应用,并部署上线,以后也可能经常会用到。
## 项目用到的文档地址
阿里云达摩院视觉开放平台:https://vision.aliyun.com/
阿里云视觉开放平台 “通用识别” 地址:https://help.aliyun.com/document_detail/151896.html?spm=a2c4g.11186623.6.620.44da1ded5yuZbF
## 项目开始
### (1)说明
经过前面几天的训练,自我感觉良好。已经对阿里云的视觉开放平台比较熟悉了,也熟悉使用提供的API的一些基础的步骤,感觉就是这些套路。
那么就不啰嗦了,直接上代码。由于只用到了一个场景,所以代码也比较简单,记得测试前要到阿里云开启 “文字识别服务” 哦!

### (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 里面,我们从这里面获取数据即可。

同时,经过测试,文字识别的过程是一行一行识别的,每行识别出来的文字都成为封装在数组的一个元素里面,所以我们定义一个 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>
```
## 测试
先进入主页面,选择图片并点击上传按钮:

识别出来的结果:

## 阿里云高校计划
最后在贴一张阿里云的广告:”阿里云高校计划“,快来加入我们吧!

阿里云AI训练营_Day04_车辆检测系统
- 2020-06-08
- 203
- 阿里巴巴
## 项目介绍
参加阿里云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 语句区分各种损伤的具体情况。

> 具体代码:
```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张图片

然后点击 upload 上传并查看结果:

数据库里面的结果:

## 阿里云高校计划
最后在贴一张阿里云的广告:”阿里云高校计划“,快来加入我们吧!

阿里云AI训练营_Day03_电子相册
- 2020-06-06
- 272
- 阿里巴巴
## 项目介绍
参加阿里云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>
```
- 记得要开通对应场景的服务,否则就会报这样的错误

### (2)创建并初始化 Client,Config
和之前的套路一样,我们需要创建对应场景的 Client 和 Config 类,关于这部分的详细解释可以参照我的上一篇博客 【阿里云AI训练营-_Day02-身份证识别】。
关于 Config 的属性配置,文档中也详细说明了,我们要根据不同的场景赋予不同的值。

-----
由于我们用到了 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 中获取数据了。

但是实际上并没有想象中的怎么美好,我看了一下示例代码,发现这个 Data 里面只有一个名字叫做 elements 的对象数组,数组里面的对象是 RecognizeExpressionResponseDataElements 类的对象;然后在这个 RecognizeExpressionResponseDataElements 类里面只能够获取够获取 3 个属性:

这明显和文档中的不符合啊,我个人感觉可能是依赖版本的问题,示例代码中的版本可能太低了,而文档是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

> 场景识别关键代码,传入的参数为从图片获取的输入流
```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();
}
}
```
> 本地图片

最中的识别结果:

## 关于
**由于前端代码出现了Bug,所以只测试了后端调用服务API的关键代码,主要是结合代码和文档一起分析,这样才能一通百通。额,好吧,最主要的原因是时间不够,月底就期末考了,能抽出来的时间不是很多,所以不想把时间花费在解决前端的Bug上面。**
## 友情推广
贴一下阿里云的活动,有兴趣的小伙伴可以参加一下

阿里云AI训练营_Day02_文字识别_身份证识别
- 2020-06-05
- 182
- 阿里巴巴
## 项目介绍
近期参加了阿里云的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中的配置)
### 开通服务
按照文档中的说明,开通服务,不出意外的话很容易就开通成功了,如下图所示:

### 使用 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,具体如下:

改进之后,我们关于 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 代表了不同的场景,即不同的场景使用的类和方法都有所不同,不过名字都类似。具体的场景的参数也会有略微的不同,可以参看文档中关于该场景的详细描述。

#### (2)具体的使用
下面以身份证识别为例,看下文档中是如何描述的:

实际上在这里还可以进行调试,快速体验一下身份证识别:

我们在IDEA中查看查找相关的类

实际上这些场景对应的类都可以在我们添加Maven依赖之后导入的jar包中看到:

好了,看完了文档之后,我就使用身份证识别场景的类和方法对文档中的代码进行替换,效果如下
```
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();
}
}
```
由于我的图片打了马赛克,所以只能识别出部分结果,结果如下所示

## 关于使用文档中的配置
我照着文档一步一步来,和文档一样的代码,依赖也是一样的,莫名其妙会报错。不知道是我自己的原因还是文档本来就有错,反正我的代码就是跑不起来,这里展示一下我的报错的代码,希望有小伙伴可以发现问题并解决。
> 初始化部分 ----> 关键就是没有将 config.endpointType="internal"; 注释掉

> 我引入的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>
```
> 报错
