package com.ruoyi.system.utils;
|
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.tencentcloudapi.common.AbstractModel;
|
import com.tencentcloudapi.common.Credential;
|
import com.tencentcloudapi.common.profile.ClientProfile;
|
import com.tencentcloudapi.common.profile.HttpProfile;
|
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
import com.tencentcloudapi.ocr.v20181119.OcrClient;
|
import com.tencentcloudapi.ocr.v20181119.models.*;
|
|
import com.ruoyi.system.config.TencentOCRConfig;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Component;
|
|
import java.io.File;
|
import java.util.Base64;
|
import java.nio.file.Files;
|
import java.util.HashMap;
|
import java.util.Map;
|
|
/**
|
* 腾讯云OCR工具类
|
* 使用腾讯云OCR服务进行文字识别
|
* 支持通用文字识别、手写体识别等多种识别类型
|
*
|
* 使用示例:
|
* // 通用文字识别
|
* JSONObject result = TencentOCRUtil.generalRecognize("path/to/image.jpg");
|
*
|
* // 手写体识别
|
* JSONObject result = TencentOCRUtil.handwritingRecognize("path/to/image.jpg");
|
*/
|
@Component
|
public class TencentOCRUtil {
|
|
private static final Logger log = LoggerFactory.getLogger(TencentOCRUtil.class);
|
|
private static TencentOCRConfig staticTencentOcrConfig;
|
|
@Autowired
|
public void setTencentOcrConfig(TencentOCRConfig tencentOcrConfig) {
|
TencentOCRUtil.staticTencentOcrConfig = tencentOcrConfig;
|
}
|
|
/**
|
* 获取腾讯云OCR客户端实例
|
* @return OcrClient客户端实例
|
* @throws TencentCloudSDKException SDK异常
|
*/
|
private static OcrClient getClient() throws TencentCloudSDKException {
|
Credential cred = new Credential(
|
staticTencentOcrConfig.getSecretId(),
|
staticTencentOcrConfig.getSecretKey()
|
);
|
|
HttpProfile httpProfile = new HttpProfile();
|
httpProfile.setEndpoint(staticTencentOcrConfig.getEndpoint());
|
|
ClientProfile clientProfile = new ClientProfile();
|
clientProfile.setHttpProfile(httpProfile);
|
|
return new OcrClient(cred, "", clientProfile);
|
}
|
|
/**
|
* 通用文字识别(图片路径)
|
* @param imagePath 图片路径
|
* @return 识别结果
|
*/
|
public static JSONObject generalRecognize(String imagePath) {
|
try {
|
byte[] imageBytes = Files.readAllBytes(new File(imagePath).toPath());
|
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
|
|
OcrClient client = getClient();
|
GeneralBasicOCRRequest req = new GeneralBasicOCRRequest();
|
req.setImageBase64(base64Image);
|
|
GeneralBasicOCRResponse resp = client.GeneralBasicOCR(req);
|
|
log.info("腾讯云OCR通用文字识别成功,图片路径: {}", imagePath);
|
|
JSONObject result = new JSONObject();
|
result.put("success", true);
|
result.put("data", JSON.parseObject(AbstractModel.toJsonString(resp)));
|
result.put("content", extractContentFromTencentResult(JSON.parseObject(AbstractModel.toJsonString(resp))));
|
|
return result;
|
|
} catch (Exception e) {
|
log.error("腾讯云OCR通用文字识别失败: {}", e.getMessage(), e);
|
|
JSONObject errorResult = new JSONObject();
|
errorResult.put("success", false);
|
errorResult.put("error", e.getMessage());
|
|
return errorResult;
|
}
|
}
|
|
/**
|
* 通用文字识别(文件对象)
|
* @param imageFile 图片文件对象
|
* @return 识别结果
|
*/
|
public static JSONObject generalRecognize(File imageFile) {
|
try {
|
byte[] imageBytes = Files.readAllBytes(imageFile.toPath());
|
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
|
|
OcrClient client = getClient();
|
GeneralBasicOCRRequest req = new GeneralBasicOCRRequest();
|
req.setImageBase64(base64Image);
|
|
GeneralBasicOCRResponse resp = client.GeneralBasicOCR(req);
|
|
log.info("腾讯云OCR通用文字识别成功,文件名: {}", imageFile.getName());
|
|
JSONObject result = new JSONObject();
|
result.put("success", true);
|
result.put("data", JSON.parseObject(AbstractModel.toJsonString(resp)));
|
result.put("content", extractContentFromTencentResult(JSON.parseObject(AbstractModel.toJsonString(resp))));
|
|
return result;
|
|
} catch (Exception e) {
|
log.error("腾讯云OCR通用文字识别失败: {}", e.getMessage(), e);
|
|
JSONObject errorResult = new JSONObject();
|
errorResult.put("success", false);
|
errorResult.put("error", e.getMessage());
|
|
return errorResult;
|
}
|
}
|
|
/**
|
* 通用文字识别(图片字节数组)
|
* @param imageBytes 图片字节数组
|
* @return 识别结果
|
*/
|
public static JSONObject generalRecognize(byte[] imageBytes) {
|
try {
|
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
|
|
OcrClient client = getClient();
|
GeneralBasicOCRRequest req = new GeneralBasicOCRRequest();
|
req.setImageBase64(base64Image);
|
|
GeneralBasicOCRResponse resp = client.GeneralBasicOCR(req);
|
|
log.info("腾讯云OCR通用文字识别成功,字节数组长度: {}", imageBytes.length);
|
|
JSONObject result = new JSONObject();
|
result.put("success", true);
|
result.put("data", JSON.parseObject(AbstractModel.toJsonString(resp)));
|
result.put("content", extractContentFromTencentResult(JSON.parseObject(AbstractModel.toJsonString(resp))));
|
|
return result;
|
|
} catch (Exception e) {
|
log.error("腾讯云OCR通用文字识别失败: {}", e.getMessage(), e);
|
|
JSONObject errorResult = new JSONObject();
|
errorResult.put("success", false);
|
errorResult.put("error", e.getMessage());
|
|
return errorResult;
|
}
|
}
|
|
/**
|
* 高精度文字识别
|
* @param imagePath 图片路径
|
* @return 识别结果
|
*/
|
public static JSONObject accurateRecognize(String imagePath) {
|
try {
|
byte[] imageBytes = Files.readAllBytes(new File(imagePath).toPath());
|
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
|
|
OcrClient client = getClient();
|
GeneralAccurateOCRRequest req = new GeneralAccurateOCRRequest();
|
req.setImageBase64(base64Image);
|
|
GeneralAccurateOCRResponse resp = client.GeneralAccurateOCR(req);
|
|
log.info("腾讯云OCR高精度文字识别成功,图片路径: {}", imagePath);
|
|
JSONObject result = new JSONObject();
|
result.put("success", true);
|
result.put("data", JSON.parseObject(AbstractModel.toJsonString(resp)));
|
result.put("content", extractContentFromTencentResult(JSON.parseObject(AbstractModel.toJsonString(resp))));
|
|
return result;
|
|
} catch (Exception e) {
|
log.error("腾讯云OCR高精度文字识别失败: {}", e.getMessage(), e);
|
|
JSONObject errorResult = new JSONObject();
|
errorResult.put("success", false);
|
errorResult.put("error", e.getMessage());
|
|
return errorResult;
|
}
|
}
|
|
public static JSONObject handwritingRecognize(String imagePath, String[] itemNames) {
|
try {
|
byte[] imageBytes = Files.readAllBytes(new File(imagePath).toPath());
|
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
|
|
OcrClient client = getClient();
|
|
ExtractDocMultiRequest req = new ExtractDocMultiRequest();
|
req.setImageBase64(base64Image);
|
// {"患者签名(手印)", "签字人身份证号码", "日期", "联系电话", "本人", "签字人与患者关系"}
|
req.setItemNames(itemNames != null ? itemNames : new String[]{"患者姓名", "性别", "年龄", "身份证号", "诊断", "需支付转运费用", "行程", "开始时间", "结束时间", "家属签名"});
|
req.setOutputLanguage("cn");
|
req.setReturnFullText(false);
|
req.setItemNamesShowMode(false);
|
ExtractDocMultiResponse resp = client.ExtractDocMulti(req);
|
|
log.info("腾讯云OCR手写体识别成功,图片路径: {}", imagePath);
|
|
// 解析响应数据
|
JSONObject responseData = JSON.parseObject(AbstractModel.toJsonString(resp));
|
|
|
log.info("手写体识别提取到 {} 个字段", responseData.size());
|
return responseData;
|
|
} catch (Exception e) {
|
log.error("腾讯云OCR手写体识别失败: {}", e.getMessage(), e);
|
JSONObject errorResult = new JSONObject();
|
errorResult.put("error", e.getMessage());
|
return errorResult;
|
}
|
}
|
/**
|
* 手写体识别
|
* @param imagePath 图片路径
|
* @param itemNames 需要提取的字段名称数组
|
* @return 识别结果 Map,key为AutoName的值,value为AutoContent的值
|
*/
|
public static Map<String, String> handwritingRecognizeWith(String imagePath, String[] itemNames) {
|
Map<String, String> resultMap = new HashMap<>();
|
try {
|
JSONObject responseData = handwritingRecognize(imagePath, itemNames);
|
|
// 从StructuralList中提取数据
|
if (responseData.containsKey("StructuralList") && responseData.getJSONArray("StructuralList") != null) {
|
JSONArray structuralList = responseData.getJSONArray("StructuralList");
|
for (int i = 0; i < structuralList.size(); i++) {
|
JSONObject structural = structuralList.getJSONObject(i);
|
if (structural.containsKey("Groups") && structural.getJSONArray("Groups") != null) {
|
JSONArray groups = structural.getJSONArray("Groups");
|
for (int j = 0; j < groups.size(); j++) {
|
JSONObject group = groups.getJSONObject(j);
|
if (group.containsKey("Lines") && group.getJSONArray("Lines") != null) {
|
JSONArray lines = group.getJSONArray("Lines");
|
for (int k = 0; k < lines.size(); k++) {
|
JSONObject line = lines.getJSONObject(k);
|
String autoName = null;
|
String autoContent = null;
|
|
// 提取AutoName
|
if (line.containsKey("Key") && line.getJSONObject("Key") != null) {
|
JSONObject key = line.getJSONObject("Key");
|
if (key.containsKey("AutoName")) {
|
autoName = key.getString("AutoName");
|
}
|
}
|
|
// 提取AutoContent
|
if (line.containsKey("Value") && line.getJSONObject("Value") != null) {
|
JSONObject value = line.getJSONObject("Value");
|
if (value.containsKey("AutoContent")) {
|
autoContent = value.getString("AutoContent");
|
}
|
}
|
|
// 将键值对放入结果Map
|
if (autoName != null && autoContent != null) {
|
resultMap.put(autoName, autoContent);
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
log.info("手写体识别提取到 {} 个字段", resultMap.size());
|
return resultMap;
|
|
} catch (Exception e) {
|
log.error("腾讯云OCR手写体识别失败: {}", e.getMessage(), e);
|
resultMap.put("error", e.getMessage());
|
return resultMap;
|
}
|
}
|
|
/**
|
* 身份证识别
|
* @param imagePath 图片路径
|
* @param cardSide 身份证正反面,"FRONT"表示正面,"BACK"表示反面
|
* @return 识别结果
|
*/
|
public static JSONObject idCardRecognize(String imagePath, String cardSide) {
|
try {
|
byte[] imageBytes = Files.readAllBytes(new File(imagePath).toPath());
|
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
|
|
OcrClient client = getClient();
|
IDCardOCRRequest req = new IDCardOCRRequest();
|
req.setImageBase64(base64Image);
|
req.setCardSide(cardSide);
|
|
IDCardOCRResponse resp = client.IDCardOCR(req);
|
|
log.info("腾讯云OCR身份证识别成功,图片路径: {},方向: {}", imagePath, cardSide);
|
|
JSONObject result = new JSONObject();
|
result.put("success", true);
|
result.put("data", JSON.parseObject(AbstractModel.toJsonString(resp)));
|
result.put("content", extractContentFromTencentResult(JSON.parseObject(AbstractModel.toJsonString(resp))));
|
|
return result;
|
|
} catch (Exception e) {
|
log.error("腾讯云OCR身份证识别失败: {}", e.getMessage(), e);
|
|
JSONObject errorResult = new JSONObject();
|
errorResult.put("success", false);
|
errorResult.put("error", e.getMessage());
|
|
return errorResult;
|
}
|
}
|
|
/**
|
* 银行卡识别
|
* @param imagePath 图片路径
|
* @return 识别结果
|
*/
|
public static JSONObject bankCardRecognize(String imagePath) {
|
try {
|
byte[] imageBytes = Files.readAllBytes(new File(imagePath).toPath());
|
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
|
|
OcrClient client = getClient();
|
BankCardOCRRequest req = new BankCardOCRRequest();
|
req.setImageBase64(base64Image);
|
|
BankCardOCRResponse resp = client.BankCardOCR(req);
|
|
log.info("腾讯云OCR银行卡识别成功,图片路径: {}", imagePath);
|
|
JSONObject result = new JSONObject();
|
result.put("success", true);
|
result.put("data", JSON.parseObject(AbstractModel.toJsonString(resp)));
|
result.put("content", extractContentFromTencentResult(JSON.parseObject(AbstractModel.toJsonString(resp))));
|
|
return result;
|
|
} catch (Exception e) {
|
log.error("腾讯云OCR银行卡识别失败: {}", e.getMessage(), e);
|
|
JSONObject errorResult = new JSONObject();
|
errorResult.put("success", false);
|
errorResult.put("error", e.getMessage());
|
|
return errorResult;
|
}
|
}
|
|
/**
|
* 从腾讯云OCR结果中提取纯文本内容
|
* @param result OCR识别结果
|
* @return 提取的文本内容
|
*/
|
private static String extractContentFromTencentResult(JSONObject result) {
|
StringBuilder content = new StringBuilder();
|
|
// 处理通用OCR结果
|
if (result.containsKey("TextDetections") && result.getJSONArray("TextDetections") != null) {
|
JSONArray textDetections = result.getJSONArray("TextDetections");
|
for (int i = 0; i < textDetections.size(); i++) {
|
JSONObject detection = textDetections.getJSONObject(i);
|
if (detection.containsKey("DetectedText")) {
|
content.append(detection.getString("DetectedText")).append("\n");
|
}
|
}
|
}
|
// 处理手写体OCR结果
|
else if (result.containsKey("Items") && result.getJSONArray("Items") != null) {
|
JSONArray items = result.getJSONArray("Items");
|
for (int i = 0; i < items.size(); i++) {
|
JSONObject item = items.getJSONObject(i);
|
if (item.containsKey("Itemstring")) {
|
content.append(item.getString("Itemstring")).append("\n");
|
}
|
}
|
}
|
// 处理身份证OCR结果
|
else if (result.containsKey("Name") || result.containsKey("Sex") || result.containsKey("Nation") ||
|
result.containsKey("Birth") || result.containsKey("Address") || result.containsKey("IdNum")) {
|
if (result.containsKey("Name") && result.getString("Name") != null) {
|
content.append("姓名: ").append(result.getString("Name")).append("\n");
|
}
|
if (result.containsKey("Sex") && result.getString("Sex") != null) {
|
content.append("性别: ").append(result.getString("Sex")).append("\n");
|
}
|
if (result.containsKey("Nation") && result.getString("Nation") != null) {
|
content.append("民族: ").append(result.getString("Nation")).append("\n");
|
}
|
if (result.containsKey("Birth") && result.getString("Birth") != null) {
|
content.append("出生: ").append(result.getString("Birth")).append("\n");
|
}
|
if (result.containsKey("Address") && result.getString("Address") != null) {
|
content.append("地址: ").append(result.getString("Address")).append("\n");
|
}
|
if (result.containsKey("IdNum") && result.getString("IdNum") != null) {
|
content.append("身份证号: ").append(result.getString("IdNum")).append("\n");
|
}
|
}
|
// 处理银行卡OCR结果
|
else if (result.containsKey("CardNo") && result.getString("CardNo") != null) {
|
content.append("银行卡号: ").append(result.getString("CardNo")).append("\n");
|
}
|
|
return content.toString().trim();
|
}
|
|
/**
|
* 从识别结果中提取目标字段(金额、日期、备注等)
|
* @param ocrResult OCR识别的原始结果
|
* @return 提取后的目标字段
|
*/
|
public static Map<String, String> extractTargetFields(JSONObject ocrResult) {
|
Map<String, String> extracted = new HashMap<>();
|
|
// 校验OCR结果是否有效
|
if (!ocrResult.containsKey("success") || !ocrResult.getBooleanValue("success")) {
|
extracted.put("error", ocrResult.getString("error"));
|
return extracted;
|
}
|
|
// 获取识别的文字内容
|
String content = ocrResult.getString("content");
|
if (content == null || content.isEmpty()) {
|
extracted.put("error", "OCR识别结果为空");
|
return extracted;
|
}
|
|
// 在内容中查找特定关键词
|
String[] lines = content.split("\n");
|
for (String line : lines) {
|
line = line.trim();
|
|
// 查找金额相关信息
|
if (line.contains("金额") || line.contains("合计") || line.contains("总计") || line.matches(".*\\d+\\.\\d{2}.*")) {
|
if (!extracted.containsKey("totalAmount")) {
|
extracted.put("totalAmount", line);
|
}
|
}
|
|
// 查找日期相关信息
|
if (line.contains("日期") || line.matches(".*\\d{4}[-/年]\\d{1,2}[-/月]\\d{1,2}.*")) {
|
if (!extracted.containsKey("date")) {
|
extracted.put("date", line);
|
}
|
}
|
|
// 查找备注相关信息
|
if (line.contains("备注") || line.contains("说明")) {
|
if (!extracted.containsKey("remark")) {
|
extracted.put("remark", line);
|
}
|
}
|
}
|
|
// 如果没有找到特定字段,返回全文
|
if (extracted.isEmpty()) {
|
extracted.put("fullText", content);
|
}
|
|
return extracted;
|
}
|
|
/**
|
* 手写体识别(使用默认字段)
|
* @param imagePath 图片路径
|
* @return 识别结果 Map,key为AutoName的值,value为AutoContent的值
|
*/
|
public static Map<String, String> handwritingRecognize(String imagePath) {
|
String[] defaultItemNames = {"患者姓名", "性别", "年龄", "身份证号", "诊断", "需支付转运费用", "行程", "开始时间", "结束时间", "家属签名"};
|
return handwritingRecognizeWith(imagePath, defaultItemNames);
|
}
|
}
|