python批量数据处理脚本——目标检测数据标签的labelme格式转yolo格式

在训练yolov5(yolo系列中yolov5用的比较多,就拿yolov5来举例好了)前首先需要标定数据集,可能标完几千张时发现自己标的竟然是labelme格式(而yolov5训练需要的是yolo格式),此时你的心情会不会气得吐血,想着又要重新标定了?
又或者你在网上找了非常久终于找到类一批很满意的数据集以及还有好心人给你标定好了开源使用,但是却发现也只有labelme格式,此时你的心情会不会犹如坐过山车一般看到了希望到达顶端,有忽然希望破灭跌倒了底端?
不用怕,可以使用python脚本转化一下即可使用了!

import json
import os
import shutil
import cv2
import os
from numpy.lib.twodim_base import triu_indices_from
import pandas as pd
from glob import glob
import codecs

print(cv2.__version__)


def getBoundingBox(points):              # 找到两个点的x最大最小值,y最大最小值
    xmin = points[0][0]
    xmax = points[0][0]
    ymin = points[0][1]
    ymax = points[0][1]
    for p in points:
        if p[0] > xmax:
            xmax = p[0]
        elif p[0] < xmin:
            xmin = p[0]

        if p[1] > ymax:
            ymax = p[1]
        elif p[1] < ymin:
            ymin = p[1]
    return [int(xmin), int(xmax), int(ymin), int(ymax)]


def json2txt(json_path, midTxt_path):
    json_data = json.load(open(json_path))         # 读取并加载json文件
    img_h = json_data["imageHeight"]
    img_w = json_data["imageWidth"]
    shape_data = json_data["shapes"]
    shape_data_len = len(shape_data)
    img_name = os.path.split(json_path)[-1].split(".json")[0]    # 以“PATH”中最后一个‘/’作为分隔符
    name = img_name + '.jpg'                            # 找到json文件对应的图片
    data = ''
    for i in range(shape_data_len):
        lable_name = shape_data[i]["label"]             # 获取一个json文件里的每个标签的名称
        points = shape_data[i]["points"]                # 获取一个json文件里的每个标签的坐标位置
        [xmin, xmax, ymin, ymax] = getBoundingBox(points)
        if xmin <= 0:
            xmin = 0
        if ymin <= 0:
            ymin = 0
        if xmax >= img_w:  
            xmax = img_w - 1
        if ymax >= img_h:
            ymax = img_h - 1
        b = name + ' ' + lable_name + ' ' + str(xmin) + ' ' + str(ymin) + ' ' + str(xmax) + ' ' + str(ymax)
        print(b)
        data += b + '\n'
    with open(midTxt_path + '/' + img_name + ".txt", 'w', encoding='utf-8') as f:    
        f.writelines(data)                                                   # 创建文件并写入相关数据
                                                   #写入数据:图片文件名,每个图片的标签名、xy最大最小值

def txt2darknet(midTxt_path, img_path):
    data = pd.DataFrame()
    filelist = os.listdir(midTxt_path) 
    for file in filelist:                                                   
        file_path = os.path.join(midTxt_path, file)
        filename = os.path.splitext(file)[0]
        imgName = filename + '.jpg'
        imgPath = os.path.join(img_path, imgName)
        img = cv2.imread(imgPath)
        [img_h, img_w, _] = img.shape
        data = ""
        with codecs.open(file_path, 'r', encoding='utf-8',errors='ignore') as f1:
            for line in f1.readlines():
                line = line.strip('\n')
                a = line.split(' ')
                if a[1] == 'other' or a[1] == 'mask' or a[1] == 'del': continue
                if a[1] == 'head': 
                    a[1] = '0'
                elif a[1] == 'hat':
                    a[1] = '1'
                elif a[1] == 'helmet':
                    a[1] = '2'
                # 这里是自己命名的类别及对应的数字

                x1 = float(a[2])
                y1 = float(a[3])
                w = float(a[4]) - float(a[2])
                h = float(a[5]) - float(a[3])

                if w <= 15 and h <= 15: continue

                center_x = float(a[2]) + w / 2
                center_y = float(a[3]) + h / 2
                a[2] = str(center_x / img_w)
                a[3] = str(center_y / img_h)
                a[4] = str(w / img_w)
                a[5] = str(h / img_h)
                b = a[1] + ' ' + a[2] + ' ' + a[3] + ' ' + a[4] + ' ' + a[5]
                print(b)
                data += b + '\n'
        with open(saved_path + '/' + filename + ".txt", 'w', encoding='utf-8') as f2:    
            f2.writelines(data)

json_path = "json文件的文件夹路径"
midTxt_path = "中间存放的tmp文件夹会自动删除"
img_path = '图片文件夹路径'
saved_path = '存放darknet格式文件的文件夹路径'

if not os.path.exists(midTxt_path):
    os.mkdir(midTxt_path)

filelist = os.listdir(json_path)                    # 取文件夹下的所有文件或文件夹
for file in filelist:
    old_dir = os.path.join(json_path, file)         # 路径与每个文件(夹)拼接
    if os.path.isdir(old_dir):
        continue                                    # 如果是文件夹跳过,只要文件
    filetype = os.path.splitext(file)[1]            
    if(filetype != ".json"): continue               #取文件后缀,只要json格式的
    json2txt(old_dir, midTxt_path)

txt2darknet(midTxt_path, img_path)
shutil.rmtree(midTxt_path)

下一节讲yolo转labelme。
有不懂的欢迎私聊或者交流,欢迎大神指正。

Python中,将LabelMe标注的数据换为YOLO所需的格式,通常需要几个步骤。LabelMe是一个图像标注工具,而YOLO是一种目标检测算法,它们的数据结构有所不同。这里提供一个简化版的示例,假设你已经有一个包含LabelMe JSON文件的目录: ```python import os import json from PIL import Image from pascal_voc_writer import Writer def labelme_to_yolo(labelme_json_dir, output_yolo_dir): # 创建YOLO所需的文件结构 if not os.path.exists(output_yolo_dir): os.makedirs(output_yolo_dir) for filename in os.listdir(labelme_json_dir): if filename.endswith(".json"): with open(os.path.join(labelme_json_dir, filename), "r") as f: data = json.load(f) img_path = os.path.join(labelme_json_dir, data["imagePath"]) im = Image.open(img_path) width, height = im.size annotations = [] for shape in data["shapes"]: label = shape["label"] points = [(x, y) for x, y, w, h in shape["points"]] x_min, y_min = min(points, key=lambda xy: xy[0])[0], min(points, key=lambda xy: xy[1])[1] x_max, y_max = max(points, key=lambda xy: xy[0])[0] + w, max(points, key=lambda xy: xy[1])[1] + h box_w, box_h = x_max - x_min, y_max - y_min object_name = f"{label}_box" annotations.append({ "class": object_name, "xmin": x_min, "ymin": y_min, "xmax": x_max, "ymax": y_max, "obj": 1 }) # 写入YOLO所需的txt文件 txt_file = os.path.join(output_yolo_dir, filename[:-5] + ".txt") with open(txt_file, "w") as txt_f: Writer(txt_file).write(annotations, names=[f"{i}_box" for i in range(len(annotations))], image_size=(width, height)) # 使用函数数据 labelme_to_yolo("path/to/labelme/json", "path/to/output/yolo") ``` 这个脚本读取每个LabelMe JSON,提取出边界框信息并换为YOLO所需的格式(每行一个对象,包含类别名、坐标)。注意实际使用时可能需要根据LabelMe JSON的具体结构进行调整。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值