Java实现数据标注功能

需求描述

又是奇葩需求的一天,产品给了一张原图
在这里插入图片描述
需要实现效果
在这里插入图片描述
这个其实应该用python实现会容易一些,不过不影响Java也可以

使用腾讯OCR接口

官方文档
在这里插入图片描述
温馨提示:使用他们的接口不是免费的喔,厉害的大神可以自己去训练一个这样的模型
引入腾讯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());
        }
    }
}

生成base64编码

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识别接口。

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
0.0013021 0.0078125 0.0013021 0.0013021 0.0026042 0.0026042 0.0078125 0.0091146 0.0039063 0.0039063 0.0013021 0.0052083 0.014323 0.010417 0.0078125 0.0013021 0.0039063 0 0.0065104 0.0026042 0.0065104 0.0078125 0.0065104 0.0013021 0.010417 0.0039063 0.011719 0.0052083 0.0013021 0.019531 0.0052083 0.0013021 0.0052083 0.0039063 0.0039063 0.0013021 0.0052083 0.022135 0.0039063 0.0065104 0.0078125 0.0039063 0.0013021 0.0026042 0.0039063 0.0052083 0.0078125 0.0039063 0.0052083 0.0013021 0 0.0052083 0.0052083 0.0065104 0.0039063 0.0026042 0.0052083 0.0026042 0.0026042 0.0039063 0.0026042 0.0039063 0.0013021 0.0052083 0.0039063 0.0039063 0 0.0052083 0 0.0065104 0.0026042 0.0065104 0 0.0052083 0 0.0013021 0.0026042 0.0052083 0.0065104 0.0078125 0.0052083 0 0.010417 0.0091146 0.0052083 0.0052083 0.0065104 0.0013021 0.0078125 0.0052083 0.0052083 0.0091146 0.0065104 0.0052083 0.011719 0.0026042 0.0078125 0.0078125 0.0039063 0 0.0052083 0.0039063 0.0039063 0.0026042 0.0091146 0.0039063 0.011719 0.0026042 0.0091146 0.0039063 0.0013021 0.016927 0.0013021 0.0013021 0.0013021 0.0052083 0.0013021 0.0013021 0.0013021 0.0026042 0.0026042 0.0065104 0.0065104 0.0039063 0.0091146 0.0026042 0.0039063 0.0039063 0.011719 0.0078125 0.010417 0 0.0039063 0 0.0013021 0.0013021 0.0026042 0.0091146 0.0052083 0.0039063 0.0013021 0.0039063 0.0039063 0.013021 0.0026042 0.058594 0.0052083 0.0078125 0.0065104 0.0039063 0.0026042 0.0026042 0.0078125 0.0052083 0.0078125 0.0039063 0.0013021 0.0026042 0.0026042 0.0052083 0.0013021 0.010417 0.0026042 0.0052083 0.0013021 0 0.0065104 0.0091146 0.0065104 0.0013021 0.013021 0.0065104 0.0052083 0.0026042 0.0013021 0.0052083 0.0013021 0.0039063 0.0052083 0.0052083 0.0013021 0.0026042 0.0052083 0.0013021 0.0013021 0.010417 0.016927 0.0039063 0.0078125 0.0039063 0 0.0013021 0.0013021 0.0052083 0.0065104 0 0 0.0039063 0.0026042 0.0013021 0.0040323 0.0080645 0.0013441 0.0053763 0.0053763 0.0067204 0.0094086 0.0013441 0.0013441 0.010753 0.012097 0.0040323 0.0026882 0
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

炸鸡叔老白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值