一、OCR的最终敲定
在上一次的开发中已经完成了图片预处理,单图、多图和pdf识别,在探索更多文件格式识别后,发现Tessertact OCR的能力确实有限,在进行很多处理时需要引入很多其他的库,增加了应用的负担,并且依赖与依赖间不好管理,所以我们决定采用百度的解决方案。
二、百度云的创建
打开百度智能云-云智一体深入产业,注册登录后打开用户中心。
在用户中心中搜索OCR:
点击进入文字识别,打开应用列表:
创建应用,勾选需要的领域:
创建成功后打开文字识别-百度智能云:
三、准备调用
先安装所需的依赖。
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20240205</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
写一个Utils类来专门服务百度的OCR,按照文档的指示,写一个从用户的AK,SK生成鉴权签名(Access Token)的函数,方便后续调用。(API_KEY和SECRET_KEY自行填写)
public static final String API_KEY = "6gLVxxxxxxxxxxxxxhNYPTj";
public static final String SECRET_KEY = "V7FPoxxxxxxxxxxxxxxxxWwyv1OiO";
public static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().readTimeout(300, TimeUnit.SECONDS).build();
/**
* 从用户的AK,SK生成鉴权签名(Access Token)
*
* @return 鉴权签名(Access Token)
* @throws IOException IO异常
*/
public static String getAccessToken() {
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + API_KEY
+ "&client_secret=" + SECRET_KEY);
Request request = new Request.Builder()
.url("https://aip.baidubce.com/oauth/2.0/token")
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
Response response = null;
try {
response = HTTP_CLIENT.newCall(request).execute();
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
return new JSONObject(response.body().string()).getString("access_token");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
拿到 Access Token后来写一个函数,试一下最简单的图片识别。
public static String getImgResponse(String imgBase64) throws IOException{
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
String bodystr ="image=" + imgBase64 + "&detect_direction=false¶graph=false&probability=false&multidirectional_recognize=false";
RequestBody body = RequestBody.create(mediaType, bodystr);
Request request = new Request.Builder()
.url("https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=" + getAccessToken())
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("Accept", "application/json")
.build();
Response response = HTTP_CLIENT.newCall(request).execute();
return response.body().string();
}
接下来写一个新的Service类来做调用,按照文档,图片需要转成base64编码进行传输,并且将字符串中的分别转换为为%2F,%3D,%2B,以符合百度的要求,所以要在工具类中写一个处理base64编码的函数。
package com.dpsk.dpsk_quiz_sys_java.service;
import com.dpsk.dpsk_quiz_sys_java.utils.BaiduUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Base64;
@Service
public class BaiduOcrService {
public String recognizeImg(MultipartFile image) throws IOException {
// 将图片文件转换为Base64字符串
byte[] imageBytes = image.getBytes();
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
//将字符串中的/,=,+
//分别转换为为%2F,%3D,%2B
//符合百度的要求
base64Image = BaiduUtils.replaceSpecialCharacters(base64Image);
return BaiduUtils.getImgResponse(base64Image);
}
}
工具类 ↓
//将字符串中的/=+,分别转换为为%2F,%3D,%2B
public static String replaceSpecialCharacters(String str) {
// 使用StringBuilder来构建新的字符串
StringBuilder sb = new StringBuilder();
// 遍历字符串的每个字符
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
switch (c) {
case '/':
sb.append("%2F");
break;
case '=':
sb.append("%3D");
break;
case '+':
sb.append("%2B");
break;
default:
sb.append(c);
}
}
return sb.toString();
}
至此,可以来写Controller来和前端对接了。
package com.dpsk.dpsk_quiz_sys_java.controller;
import com.dpsk.dpsk_quiz_sys_java.pojo.ResponseMessage;
import com.dpsk.dpsk_quiz_sys_java.service.BaiduOcrService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/baiduocr")
public class BaiduOcrController {
@Autowired
private BaiduOcrService ocrService;
@PostMapping("/recognize")
public ResponseMessage<String> recognizeImage(@RequestParam("image") MultipartFile image) {
if (image == null || image.isEmpty()) {
return ResponseMessage.error("照片为空");
}
try {
// 调用OCR服务
String ocrResult = ocrService.recognizeImg(image);
// 返回成功结果
return ResponseMessage.success(ocrResult);
} catch (Exception e) {
// 返回错误信息
return ResponseMessage.error("Error occurred during OCR processing: " + e.getMessage());
}
}
}
四 、简单测试与效果展示
使用postman,各项参数按照文档填写。
- 图片的base64编码是不包含图片头的,如
(data:image/jpg;base64,)
; - 使用 Postman 工具或 Python、PHP 等请求库会自动进行 urlencode,无需自行处理。
(请求格式支持:PNG、JPG、JPEG、BMP、TIFF、PNM、WebP)
可以看到整体是JSON格式,其中data是一个words数组,每个words是每一行的识别的内容,最后words_result_num为words数组的长度,需要后期整合为完整的一段话。