Java实现数据标注功能

发布时间:2023年12月20日

需求描述

又是奇葩需求的一天,产品给了一张原图
在这里插入图片描述
需要实现效果
在这里插入图片描述
这个其实应该用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识别接口。

文章来源:https://blog.csdn.net/qq_48959845/article/details/135105750
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。