又是奇葩需求的一天,产品给了一张原图
需要实现效果
这个其实应该用python实现会容易一些,不过不影响Java也可以
官方文档
温馨提示:使用他们的接口不是免费的喔,厉害的大神可以自己去训练一个这样的模型
引入腾讯SDK
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-ocr</artifactId>
<version>3.1.923</version>
</dependency>
复制示例代码
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.*;
public class SmartStructuralOCRV2
{
public static JSONObject getImgXYInfo(String filePath,String sux) {
try{
// 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
// 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
// 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
Credential cred = new Credential("SecretId", "SecretKey");
// 实例化一个http选项,可选的,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("ocr.tencentcloudapi.com");
// 实例化一个client选项,可选的,没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
OcrClient client = new OcrClient(cred, "", clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
SmartStructuralOCRV2Request req = new SmartStructuralOCRV2Request();
// 返回的resp是一个SmartStructuralOCRV2Response的实例,与请求对象对应
SmartStructuralOCRV2Response resp = client.SmartStructuralOCRV2(req);
String imageBinary = getImageBinary(filePath, sux);
// String imageBinary = getImageBinary("D:\\code\\jsonFile\\src\\main\\java\\org\\example\\img\\dd.jpg", "jpg");
req.setImageBase64(imageBinary);
// 输出json格式的字符串回包
System.out.println(SmartStructuralOCRV2Response.toJsonString(resp));
} catch (TencentCloudSDKException e) {
System.out.println(e.toString());
}
}
}
public static String getImageBinary(String imageFileName, String suffix) {
BASE64Encoder encoder = new BASE64Encoder();
File imageFile = new File(imageFileName);
try {
BufferedImage bufferedImage = ImageIO.read(imageFile);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, suffix, baos);
byte[] bytes = baos.toByteArray();
return encoder.encodeBuffer(bytes).trim();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void imt(String path ,String sux) {
// 返回时示例
// String str = "{\"Angle\":-0.26950273,\"RequestId\":\"feb20204-d78e-445b-94e8-8808a2570f6b\",\"StructuralList\":[{\"Groups\":[{\"Lines\":[{\"Key\":{\"AutoName\":\"姓名\"},\"Value\":{\"AutoContent\":\"奥巴马\",\"Coord\":{\"LeftBottom\":{\"X\":1181,\"Y\":855},\"LeftTop\":{\"X\":1181,\"Y\":740},\"RightBottom\":{\"X\":1483,\"Y\":855},\"RightTop\":{\"X\":1483,\"Y\":740}}}}]}]},{\"Groups\":[{\"Lines\":[{\"Key\":{\"AutoName\":\"性别\"},\"Value\":{\"AutoContent\":\"男\",\"Coord\":{\"LeftBottom\":{\"X\":1178,\"Y\":1087},\"LeftTop\":{\"X\":1178,\"Y\":975},\"RightBottom\":{\"X\":1293,\"Y\":1087},\"RightTop\":{\"X\":1293,\"Y\":975}}}}]}]},{\"Groups\":[{\"Lines\":[{\"Key\":{\"AutoName\":\"民族\"},\"Value\":{\"AutoContent\":\"肯尼亚\",\"Coord\":{\"LeftBottom\":{\"X\":1741,\"Y\":1076},\"LeftTop\":{\"X\":1741,\"Y\":964},\"RightBottom\":{\"X\":2060,\"Y\":1076},\"RightTop\":{\"X\":2060,\"Y\":964}}}}]}]},{\"Groups\":[{\"Lines\":[{\"Key\":{\"AutoName\":\"出生\"},\"Value\":{\"AutoContent\":\"1961年8月4日\",\"Coord\":{\"LeftBottom\":{\"X\":1186,\"Y\":1297},\"LeftTop\":{\"X\":1186,\"Y\":1205},\"RightBottom\":{\"X\":2127,\"Y\":1297},\"RightTop\":{\"X\":2127,\"Y\":1205}}}}]}]},{\"Groups\":[{\"Lines\":[{\"Key\":{\"AutoName\":\"住址\"},\"Value\":{\"AutoContent\":\"华盛顿特区宜宾法尼亚大道1600号白宫\",\"Coord\":{\"LeftBottom\":{\"X\":1133,\"Y\":1759},\"LeftTop\":{\"X\":1133,\"Y\":1437},\"RightBottom\":{\"X\":1945,\"Y\":1759},\"RightTop\":{\"X\":1945,\"Y\":1437}}}}]}]},{\"Groups\":[{\"Lines\":[{\"Key\":{\"AutoName\":\"公民身份号码\"},\"Value\":{\"AutoContent\":\"123456196108047890\",\"Coord\":{\"LeftBottom\":{\"X\":1668,\"Y\":2148},\"LeftTop\":{\"X\":1668,\"Y\":2036},\"RightBottom\":{\"X\":3116,\"Y\":2148},\"RightTop\":{\"X\":3116,\"Y\":2036}}}}]}]}],\"WordList\":[]}";
JSONObject imgXYInfo = getImgXYInfo(path,sux);
// JSONObject imgXYInfo = getImgXYInfo("D:\\code\\jsonFile\\src\\main\\java\\org\\example\\img\\dd.jpg","jpg");
// JSONObject imgXYInfo = JSONObject.parseObject(str);
JSONArray structuralList = imgXYInfo.getJSONArray("StructuralList");
for (Object a : structuralList) {
JSONObject jsonObject = JSONObject.parseObject(String.valueOf(a));
JSONArray groups = jsonObject.getJSONArray("Groups");
for (Object group : groups) {
JSONObject jsonObjectG = JSONObject.parseObject(String.valueOf(group));
JSONArray lines = jsonObjectG.getJSONArray("Lines");
for (Object line : lines) {
JSONObject jsonObjectL = JSONObject.parseObject(String.valueOf(line));
JSONObject objectLJSONObject = jsonObjectL.getJSONObject("Value");
JSONObject coord = objectLJSONObject.getJSONObject("Coord");
JSONObject leftTop = coord.getJSONObject("LeftTop");
JSONObject rightTop = coord.getJSONObject("RightTop");
JSONObject rightBottom = coord.getJSONObject("RightBottom");
// JSONObject leftBottom = coord.getJSONObject("LeftBottom");
Integer x = leftTop.getInteger("X");
Integer y = leftTop.getInteger("Y");
Integer rx = rightTop.getInteger("X");
Integer ry = rightBottom.getInteger("Y");
Integer width = rx - x;
Integer height = ry - y;
// System.out.println(x);
// System.out.println(y);
// System.out.println(rx);
// System.out.println(ry);
// System.out.println(width);
// System.out.println(height);
drawAndGetPictureUrl(path,sux, x,y,width,height,Color.RED);
}
}
}
}
/**
*
* @param originalPicture 原始图片地址
* @param x:该参数用于返回检测框左上角位置的横坐标(x)所在的像素位置,结合剩余参数可唯一确定检测框的大小和位置。
* @param y:该参数用于返回检测框左上角位置的纵坐标(y)所在的像素位置,结合剩余参数可唯一确定检测框的大小和位置。
* @param width: 该参数用于返回检测框的宽度(由左上角出发在x轴向右延伸的长度),结合剩余参数可唯一确定检测框的大小和位置。
* @param height:该参数用于返回检测框的高度(由左上角出发在y轴向下延伸的长度),结合剩余参数可唯一确定检测框的大小和位置。
* @param drawColor:画框的颜色
* @return
* @throws Exception
*/
private static void drawAndGetPictureUrl(String originalPicture, String sux, int x, int y, int width, int height, Color drawColor) {
BufferedImage bufferedImage = null;
//读取图片文件,得到BufferedImage对象
try {
if (StringUtils.isEmpty(originalPicture)) {
System.out.println("绘制图片失败:原始图片地址为空");
return;
}
InputStream inputStream = new FileInputStream(originalPicture);
// HttpURLConnection connection = (HttpURLConnection) new URL(originalPicture).openConnection();
// connection.setRequestMethod("GET");
// if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
// inputStream = connection.getInputStream();
// }
bufferedImage = ImageIO.read(inputStream);
//得到Graphics2D 对象
Graphics2D g2D = (Graphics2D) bufferedImage.getGraphics();
//设置颜色、画笔粗细
g2D.setColor(drawColor);
g2D.setStroke(new BasicStroke(5));
//绘制矩形
g2D.drawRect(x, y, width, height);
g2D.setFont(new Font("", Font.BOLD, 40));
//绘制文字
g2D.drawString("(" + x + "," + y + ")", x-50, y);
g2D.drawString("(" + x + "," + (y + height) + ")", x-100, y+ height +50);
g2D.drawString("(" + (x + width) + "," + y + ")", x + width -50, y);
g2D.drawString("(" + (x + width) + "," + (y + height) + ")", x + width -100, y+ height + 50);
// g2D.drawString(x+ "", x-50, y);
// g2D.drawString((y + height) + "", x, y+ height +50);
// g2D.drawString("" + (x + width), x + width -50, y);
// g2D.drawString( (y + height) + "", x + width, y+ height + 50);
ByteArrayOutputStream os = new ByteArrayOutputStream();
String savePath = originalPicture;
ImageIO.write(bufferedImage, sux, new FileOutputStream(savePath));
} catch (Exception e) {
e.printStackTrace();
// System.out.println("绘制图片失败:,原图片:{},error:{}", originalPicture, e);
}
}
public static void main(String[] args) throws Exception {
File file = new File("D:\\code\\jsonFile\\src\\main\\java\\org\\example\\img");
File[] files = file.listFiles();
Integer i = 0;
Integer er = 0;
for (File f : files) {
if (f.isDirectory()) {
File typeFile = new File(f.toString());
File[] listFiles = typeFile.listFiles();
for (File listFile : listFiles) {
String imgPath = listFile.toString();
String[] split = imgPath.split("\\.");
try {
imt(imgPath,split[1]);
System.out.println("标注完成" + ++ i);
} catch (Exception e) {
System.out.println("标注失败" + ++ er);
}
}
}
if (f.isFile()) {
String imgPath = f.toString();
String[] split = imgPath.split("\\.");
try {
imt(imgPath,split[1]);
System.out.println("标注完成" + ++ i);
} catch (Exception e) {
System.out.println("标注失败" + ++ er);
}
}
}
System.out.println("OK");
// drawAndGetPictureUrl("asa",200,600,500,100,Color.RED);
// System.out.println(imgXYInfo);
// JSONObject imgXY = getImgXY("");
// System.out.println(imgXY);
// int width = 283;
// int height = 355;
// int y = 20;//top
// int x = 149;//left
// drawAndGetPictureUrl("https://tse2-mm.cn.bing.net/th/id/OIP-C.duz6S7Fvygrqd6Yj_DcXAQHaF7?rs=1&pid=ImgDetMain",x, y, width, height, Color.RED);
}
只能做好相对比较好的图片,对于图片被旋转 或是图片不规则的标注出来还是有一定误差和缺陷的,而且严重依赖第三方ocr识别接口。