python实现labelme样本自动标注

本文介绍了一种基于LabelMe的自动标注模块,适用于标签数量、类别固定,且形态、大小无显著变化的场景。通过图像处理技术定位固定特征点,计算偏移量调整标注框,大幅提高标注效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

公司前段时间做一个项目,需要用到语义分割,样本很多,但是都没有标注,也没有让标注公司弄,只好自己标注,平均两分半一张,一天标200多张人都要疯了,而且项目进度也比较着急。所以自己实现了一个基于labelme的自动标注模块,在了解正文之前,请先看下一段的说明,选择性绕道,以免耽误个人宝贵的时间。

说明

一、模块适用场景应满足以下条件:
1、 样本的标签数量、标签类别不变的场景(但也可以基于图像处理做标签检测,有标签出现时,可以实现自动标注,这就要看具体场景了)
2、 标签形态,大小,无明显变化,只存在相对位置的平移和旋转
3、 可利用图像处理技术,匹配到样本中一个或多个固定的位置(且该位置相对于样本的像素位置不变)
二、实现模块需要具备的相应技能:
1、 了解json文件的结构;
2、 了解图片的I/O操作及相应的类型转换;
3、 了解基础的图像处理技术,能实现图像突出特征点或区域的检测;
4、 python基础
三、模块效果:
1、模块标注准确率在90%以上,只需要调整小部分样本即可;
2、效果图如下(第一张为未标注状态)
第一张为未标注状态

正文

一、 json文件简介及相关API:

json结构简介:

{
  "imageHeight": 178,#图片的高(rows)
  "imageData": "/9j/4AAQSkZJRgABAQA.............gAooooA//2Q==",#图片编码成的str类型数据,可以再次解码成图片
  "flags": {},#分类样本标注时用到,是样本的类别(整个图片属于什么类别)
  "version": "4.2.10",
  "imageWidth": 1236,#图片宽(cols)
  "imagePath": "001194.jpg",#图片的名称
  "shapes": [#shepe里面以字典的形式存放标注的标签个数(类别个数)
    {
      "shape_type": "polygon",#标注形式,默认为多边形,还可以有矩形等其他形状
      "flags": {},#分类标签
      "label": "2",#这个框所属的类别
      "points": [#围成框的所有点,标注时第一个点存放在这里index为0的位置。
        [
          172.89719626168224,#第一个点的宽(cols)
          39.77881619937695#第一个点的高(rows)
        ],
        [
          141.1214953271028,
          53.17445482866043
        ],
        ......
        [
          144.23676012461058,
          86.81931464174455
        ]
      ],
      "group_id": null#组别
    },
    {
      "shape_type": "polygon",
      "flags": {},
      "label": "0",
      "points": [
        [
          170.09345794392522,
          47.255451713395644
        ],
        ......
        [
          186.91588785046727,
          74.3582554517134
        ]
      ],
      "group_id": null
    },
    {
      "shape_type": "polygon",
      "flags": {},
      "label": "1",
      "points": [
        [
          184.11214953271028,
          36.35202492211838
        ],
       ......
        [
          185.0467289719626,
          55.97819314641744
        ]
      ],
      "group_id": null
    },
    {
      "shape_type": "polygon",
      "flags": {},
      "label": "0",
      "points": [
        [
          1063.2398753894083,
          37.90965732087227
        ],
        ......
        [
          1080.9968847352025,
          64.0778816199377
        ]
      ],
      "group_id": null
    },
    {
      "shape_type": "polygon",
      "flags": {},
      "label": "3",
      "points": [
        [
          1061.0591900311526,
          30.121495327102807
        ],
       ......
        [
          1092.2118380062304,
          79.96573208722741
        ]
      ],
      "group_id": null
    }
  ]
}

综上,实现自动标注,第一步便是能让json文件和需要标注的样本一一对应起来,直接修改"imageData"的值便可。
代码如下:

with open(json_path, "r", encoding='utf-8') as jsonFile:#读取json文件
    json_data = json.load(jsonFile)#json.load()用于读取json文件函数
    with open(image_path,'rb') as image_file:#读取图片文件
	    image_text_data = image_file.read()
	    image_text_bytes = base64.b64encode(image_text_data)#用base64API编码
	    image_text_tring = image_text_bytes.decode('utf-8')#再解码成str类型,注意,如果直接将图片以二进制读入然后用str()函数转成str类型则不行
	
	    json_data_tra['imageData'] = image_text_tring#json是一个字典,所以,以字典的形式索引,修改对应key的值。
	  		with open(json_data_path, "w") as jsonFile:
            	json.dump(json_data_tra, jsonFile,ensure_ascii=False)#将修改好的json文件写入本地,json.dump()函数,用于json文件的output。

二、 特征区域检测及相应API

有如上修改后,只需要加上标注框微调便可以了。实现这个功能,需要基于一个或多个始终能检测到的特征点,利用特征点的移动距离来调整标注框的形状和相对图片的距离。
特征点检测代码如下(我选取了5个点,因为相机标定问题,导致图片有些部位存在形变,每一个框对应一个点减小了图片形变的影响):

def tamplate_match(image_data,template_path):#传入待标注图片,以及制作的特征区域模板图片

    point = []
    image = cv2.cvtColor(image_data, cv2.COLOR_BGR2GRAY)#转换成单通道
    image[int(image.shape[0] / 2.3):-1, int(image.shape[1] / 6):int(image.shape[1] - image.shape[1] / 6)] = 0#将多余特征覆盖,虑去杂质背景,增大检测准确率,此处可视情况改成图像相关的处理技术。
    for _,_,tamplate_name in os.walk(template_path):#读取模板路径下的模板图片名称
        break
    for name in tamplate_name:
        template_data_path = template_path + name
        template_data = cv2.imread(template_data_path,0)
        high,wide = template_data.shape

        template_image_result = cv2.matchTemplate(image, template_data, cv2.TM_SQDIFF_NORMED)  # 归一化相关系数匹配法
        cv2.normalize(template_image_result, template_image_result, 0, 1, cv2.NORM_MINMAX, -1)#归一化至0到1
        # 寻找矩阵(一维数组当做向量,用Mat定义)中的最大值和最小值的匹配结果及其索引位置(像素坐标)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(template_image_result)#用最小值
        point.append([min_loc,high,wide])

    return point#该列表下面每一个元素里面又都包含了一个2维元祖

def center_point_coordinate(point):#将返回的点,转换成区域中心点

    point_coor = []
    for info in point:
        min_loc = info[0]
        high = info[1]
        wide = info[2]
        point_coor.append((int(min_loc[0] + wide / 2), int(min_loc[1] + high / 2)))

    return point_coor#以元祖的形式返回结果

三、 计算偏移量以及标注框的新的点集

有了基础点,就可以基于这个点,先计算每个框的所有点基于其对应基础点的基础距离,然后再利用每次检测到的每一张图片上的特征点减去这个基础距离,就是每一张图片上不同框的所有的新的点集了。
代码如下:

def basic_json_point_offset(json_data,basic_point):#每个标签下面的所有点相对于基础检测点的偏移量,传入json数据,基本点的信息

    json_point_offset = []
    json_data_initial = copy.deepcopy(json_data)#深拷贝json文件,以防误修改
    info = json_data_initial["shapes"]#找到json文件的所有标注框
    if len(info) == len(basic_point):#假如使用的模板和标签数量一致
        for reference_point,info_point in zip(basic_point,info):#返回一个基础点,一个标注框的所有点
            point_set = []
            for point in info_point["points"]:
                offset_x = reference_point[0] - point[0]#基础点col-标注框的每一个点的col
                offset_y = reference_point[1] - point[1]
                point_set.append([offset_x,offset_y])#将这对偏移量添加进列表
            json_point_offset.append(point_set)#将这个框的所有点的偏移量添加到列表
    else:
        basic_point = np.array(basic_point)
        hight,wide = float(np.mean(basic_point[:,0])),float(np.mean(basic_point[:,1]))
        for info_point in info:
            point_set = []
            for point in info_point["points"]:
                offset_x = hight - point[0]#后面使用offset需要减 -=
                offset_y = wide - point[1]
                point_set.append([offset_x,offset_y])
            json_point_offset.append(point_set)

    return json_point_offset#返回偏移量列表

def json_offset_translational(json_data,json_point_offset,coor_point):#利用偏移量计算新的标注框的点集,传入json数据,偏移量,特征点的像素坐标

    json_data_initial = copy.deepcopy(json_data)
    info = json_data_initial["shapes"]
    if len(coor_point) == len(info):
        for num, info_point in enumerate(info):
            for offset_point,point in zip(json_point_offset[num],info_point["points"]):
                point[0] = coor_point[num][0] - offset_point[0]
                point[1] = coor_point[num][1] - offset_point[1]
    else:
        basic_point = np.array(coor_point)
        hight, wide = float(np.mean(basic_point[:, 0])), float(np.mean(basic_point[:, 1]))
        for e,info_point in  enumerate(info):
            for offset_point,point in zip(json_point_offset[e],info_point["points"]):
                point[0] = hight - offset_point[0]
                point[1] = wide - offset_point[1]

    return json_data_initial#返回的是修改了标注框的json文件

四、 json文件数据其他修改

如上,便基本实现了如题功能,只需要在完善下便可。
代码如下:

def image_json_adjustment(path,template_path,json_path):#传入待标注图片的路径,模板路径,模板json文件的路径(需要手动标注一张json文件做为模板)

    with open(json_path, "r", encoding='utf-8') as jsonFile:
        json_data = json.load(jsonFile)

    file_name,json_point_offset = [],[]
    for _,_,file_name in os.walk(path):
        break
    for i,name in enumerate(file_name):
        image_path = path + name
        json_data_path = path + name[:-4] + '.json'
        image = cv2.imread(image_path, 1)
        point = tamplate_match(image,template_path)
        coor_point = center_point_coordinate(point)

        if i == 0:
            json_point_offset = basic_json_point_offset(json_data,coor_point)
        else:
            json_data_tra = json_offset_translational(json_data, json_point_offset,coor_point)

            with open(image_path,'rb') as image_file:
                image_text_data = image_file.read()
                image_text_bytes = base64.b64encode(image_text_data)
                image_text_tring = image_text_bytes.decode('utf-8')

                json_data_tra['imageData'] = image_text_tring#修改json文件对应的图片
                json_data_tra["imagePath"] = name#修改名称
                json_data_tra["imageHeight"] =  image.shape[0]#修改高宽
                json_data_tra["imageWidth"] = image.shape[1]

                with open(json_data_path, "w") as jsonFile:
                    json.dump(json_data_tra, jsonFile,ensure_ascii=False)

感谢耐心查阅!

<think>好的,我现在需要帮助用户了解如何使用LabelMe工具自动标注矩形框。用户提到了教程、使用方法和示例代码,所以我要确保回答涵盖这些方面。首先,我需要回忆LabelMe的功能和相关引用内容。根据提供的引用,特别是引用[2]和引用[3],LabelMe支持多种标注类型,包括矩形框,并且可以通过扩展或脚本进行自动化处理。 用户的问题是关于自动标注,而通常LabelMe的界面是手动操作的,所以自动标注可能需要借助脚本或插件。引用[3]提到可以扩展和定制,比如添加新的工具或导出格式,这可能涉及到编写代码。因此,我需要考虑如何通过编写Python脚本与LabelMe的API交互,或者使用现有的命令行工具来实现自动标注。 接下来,我需要检查是否有现成的示例代码或方法。根据引用[1],LabelMe标注文件是JSON格式,包含形状信息,如矩形框的坐标。自动生成这些JSON文件可能是一个方法。此外,引用[4]提到了LabelImg使用XML和文本格式,但LabelMe使用JSON,所以需要确保生成正确的格式。 可能的步骤包括: 1. 安装LabelMe。 2. 准备图像数据集。 3. 编写脚本生成带有矩形框标注JSON文件。 4. 使用LabelMe进行验证或后续处理。 需要确保示例代码正确,比如使用LabelMePython API(如果有的话),或者直接构建符合其JSON结构的文件。同时,要引用相关的资料,比如引用[2]和[3]来支持方法的可行性。 用户可能需要具体的代码示例,比如如何生成一个包含矩形框的JSON文件。这里需要参考LabelMeJSON结构,通常包括version、flags、shapes(包含label、points、shape_type等)。因此,示例代码应该构造这样的结构,并保存为.json文件。 还需要考虑路径问题,确保图像路径正确,以及如何批量处理。此外,可能提到使用命令行工具来自动化,比如labelme_json_to_dataset命令,但不确定是否适用于自动生成标注。 最后,验证生成的JSON文件是否能在LabelMe中正确加载,确保矩形框显示正确。可能还需要说明如何修改脚本以适应不同的标签或坐标。</think>以下是使用LabelMe自动标注矩形框的详细教程,结合脚本实现批量处理: ### 一、LabelMe自动标注矩形框方法 LabelMe本身是交互式标注工具,但可通过以下两种方式实现自动标注: 1. **脚本生成JSON标注文件**(推荐):直接生成符合LabelMe格式的JSON文件[^2] 2. **API调用扩展功能**:通过Python API控制标注流程(需二次开发) ### 二、自动标注实现步骤(脚本方式) #### 1. 安装LabelMe ```bash pip install labelme ``` #### 2. 准备图像文件 建议将图像存放在`./images`目录,结构示例: ``` dataset/ ├── images/ │ ├── img1.jpg │ └── img2.png └── labels/ # 自动生成 ``` #### 3. 自动标注脚本示例 ```python import json import os from glob import glob def auto_bbox(image_dir, output_dir): os.makedirs(output_dir, exist_ok=True) for img_path in glob(os.path.join(image_dir, "*.*")): # 构造基础信息 base_name = os.path.basename(img_path) json_data = { "version": "5.2.1", "flags": {}, "shapes": [ { "label": "object", # 修改为实际类别 "points": [[100, 150], [300, 400]], # 自动检测坐标填入 "group_id": None, "shape_type": "rectangle", "flags": {} } ], "imagePath": base_name, "imageData": None, # 实际使用需用base64编码 "imageHeight": 600, # 替换为实际尺寸 "imageWidth": 800 } # 保存JSON文件 with open(os.path.join(output_dir, base_name+'.json'), 'w') as f: json.dump(json_data, f, indent=2) # 使用示例 auto_bbox("./dataset/images", "./dataset/labels") ``` #### 4. 关键参数说明 - `points`字段应为矩形对角坐标,格式:`[[x1,y1], [x2,y2]]` - 实际应用需集成目标检测模型,将预测框填入`points`字段[^3] - 图像尺寸需与实际图片一致 ### 三、标注验证 1. 打开LabelMe界面 ```bash labelme ./dataset/images --autosave ``` 2. 加载生成的JSON文件,将自动显示矩形标注框 ### 四、批量转换示例 将自动生成的JSON转换为YOLO格式: ```python import json import os def labelme2yolo(json_dir, class_map): for json_file in os.listdir(json_dir): with open(os.path.join(json_dir, json_file)) as f: data = json.load(f) yolo_lines = [] for shape in data['shapes']: if shape['shape_type'] == 'rectangle': x1, y1 = shape['points'][0] x2, y2 = shape['points'][1] # 转换坐标 dw = 1./data['imageWidth'] dh = 1./data['imageHeight'] x_center = ((x1 + x2)/2) * dw y_center = ((y1 + y2)/2) * dh width = abs(x2 - x1) * dw height = abs(y2 - y1) * dh # 写入行 yolo_lines.append(f"{class_map[shape['label']]} {x_center} {y_center} {width} {height}") # 保存YOLO格式 txt_path = os.path.splitext(json_file)[0] + '.txt' with open(txt_path, 'w') as f: f.write('\n'.join(yolo_lines)) # 使用示例 class_map = {"object": 0} # 类别映射 labelme2yolo("./dataset/labels", class_map) ```
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值