python实现xml标注数据正矩形框的目标检测数据增强并保存新的xml

本文介绍了如何使用Python和OpenCV库读取XML标注文件,提取图像中的边界框信息,然后对图像进行多种图像增强操作,如翻转、锐化、模糊等,并同步更新XML文件中对应的边界框坐标。该方法可用于数据集扩充,提高机器学习模型的泛化能力。
摘要由CSDN通过智能技术生成
# -*- coding:utf-8 -*-

import xml.etree.ElementTree as ET
import pickle
import os
from os import getcwd
import numpy as np
from PIL import Image
import shutil
import matplotlib.pyplot as plt

import imgaug as ia
from imgaug import augmenters as iaa
import  itertools

def read_xml_annotation(root, image_id):
    in_file = open(os.path.join(root, image_id),encoding='utf-8', errors='ignore')
    tree = ET.parse(in_file)
    root = tree.getroot()
    in_file.close()
    bndboxlist = []

    for object in root.findall('object'):  # 找到root节点下的所有country节点
        bndbox = object.find('bndbox')     # 子节点下节点rank的值

        xmin = int(bndbox.find('xmin').text)
        xmax = int(bndbox.find('xmax').text)
        ymin = int(bndbox.find('ymin').text)
        ymax = int(bndbox.find('ymax').text)
        # print(xmin,ymin,xmax,ymax)
        bndboxlist.append([xmin, ymin, xmax, ymax])
        # print(bndboxlist)

    bndbox = root.find('object').find('bndbox')
    return bndboxlist
    
def change_xml_list_annotation(root, image_id, new_target, saveroot, id):
    in_file = open(os.path.join(root, str(image_id) + '.xml'),encoding='utf-8', errors='ignore')  # 这里root分别由两个意思
    tree = ET.parse(in_file)
    elem = tree.find('filename')
    elem.text = id
    xmlroot = tree.getroot()
    index = 0

    for object in xmlroot.findall('object'):  # 找到root节点下的所有country节点
        bndbox = object.find('bndbox')  # 子节点下节点rank的值

        # xmin = int(bndbox.find('xmin').text)
        # xmax = int(bndbox.find('xmax').text)
        # ymin = int(bndbox.find('ymin').text)
        # ymax = int(bndbox.find('ymax').text)

        new_xmin = new_target[index][0]
        new_ymin = new_target[index][1]
        new_xmax = new_target[index][2]
        new_ymax = new_target[index][3]

        xmin = bndbox.find('xmin')
        xmin.text = str(new_xmin)
        ymin = bndbox.find('ymin')
        ymin.text = str(new_ymin)
        xmax = bndbox.find('xmax')
        xmax.text = str(new_xmax)
        ymax = bndbox.find('ymax')
        ymax.text = str(new_ymax)

        index = index + 1

    tree.write(os.path.join(saveroot, id[:-4] + '.xml'))

def mkdir(path):
    # 去除首位空格
    path = path.strip()
    # 去除尾部 \ 符号
    path = path.rstrip("\\")
    # 判断路径是否存在
    # 存在     True
    # 不存在   False
    isExists = os.path.exists(path)
    # 判断结果
    if not isExists:
        # 如果不存在则创建目录
        # 创建目录操作函数
        os.makedirs(path)
        print(path + ' Success')
        return True
    else:
        # 如果目录存在则不创建,并提示目录已存在
        print(path + ' Dir exist')
        return False

if __name__ == "__main__":

    IMG_DIR = "C:\\Users\\Desktop\\temp\\test"
    XML_DIR = "C:\\Users\\Desktop\\temp\\test1"

    AUG_XML_DIR = "./Augxml/"  # 存储增强后的xml文件夹路径
    try:
        shutil.rmtree(AUG_XML_DIR)
    except FileNotFoundError as e:
        a = 1
    mkdir(AUG_XML_DIR)

    AUG_IMG_DIR = "./AugImg/"  # 存储增强后?bmp文件夹路径
    try:
        shutil.rmtree(AUG_IMG_DIR)
    except FileNotFoundError as e:
        a = 1
    mkdir(AUG_IMG_DIR)

    AUGLOOP = 100      # 每张影像增强的数量,可自行设置

    boxes_img_aug_list = []
    new_bndbox = []
    new_bndbox_list = []

    # 影像增强
    sometimes = lambda aug: iaa.Sometimes(0.5, aug) #建立lambda表达式
    seq = iaa.Sequential([
        #iaa.Flipud(0.5),  # 50%的概率上下翻转
        #iaa.Fliplr(0.5),  # 50%的概率镜像翻转
        iaa.Sharpen(alpha=(0, 1.0), lightness=(0.75, 1.5)), # 锐化处理
        iaa.Emboss(alpha=(0, 1.0), strength=(0, 2.0)), #浮雕效果
        sometimes(iaa.OneOf([
                    iaa.EdgeDetect(alpha=(0, 0.7)),
                    iaa.DirectedEdgeDetect(
                        alpha=(0, 0.7), direction=(0.0, 1.0)
                    ),
                ])),#边缘检测,将检测到的赋值0或者255然后叠在原图上
        iaa.ContrastNormalization((0.5, 2.0), per_channel=0.5),# 将整个图像的对比度变为原来的一半或者二倍
        iaa.Multiply((0.5, 1.5), per_channel=0.5),
        iaa.Add((-10, 10), per_channel=0.5), # 每个像素随机加减-10到10之间的数
        #iaa.AverageBlur(k=(2, 5)), # 核大小2~7之间,k=((5, 7), (1, 3))时,核高度5~7,宽度1~3
        #iaa.MedianBlur(k=(3, 5)),
        #iaa.Multiply((0.8, 1.5)),  # 像素乘上0.8到1.5之间的数字.
        #iaa.Superpixels(p_replace=(0, 1.0),n_segments=(20, 200)), #超像素增强
        #iaa.GaussianBlur(sigma=(0.5, 0.8)),  # iaa.GaussianBlur(0.5),参数 sigma 表示高斯模糊的强度,一般 sigma = 0 表示没有高斯模糊,sigma = 3.0 表示很强的模糊。采用 tripe 输入,表示 sigma 值在 (0, 0.03) 之间随机取。
        iaa.Affine(translate_px={"x": 0, "y": 0},scale=(1.0, 1.0),rotate=(-90, 90)),     # 旋转角度
        #iaa.CropAndPad(px=(-10, 0), percent=None, pad_mode='constant', pad_cval=0, keep_size=False),
        #iaa.PiecewiseAffine(scale=(0, 0.05), nb_rows=4, nb_cols=4, cval=0)
        #iaa.ElasticTransformation(alpha=(0, 50), sigma=(4.0, 6.0))
    ],
    random_order=True # 随机的顺序把这些操作用在图像上
    )
    suffix = '.jpg'
    # mylist=("".join(x) for  x in  itertools.product("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",repeat=16))
    for root, sub_folders, files in os.walk(IMG_DIR):

        for name in files:
            suffix = name[-5:]
            bndbox = read_xml_annotation(XML_DIR, name[:-4] + '.xml')
            shutil.copy(os.path.join(XML_DIR, name[:-4] + '.xml'), AUG_XML_DIR)
            shutil.copy(os.path.join(IMG_DIR, name), AUG_IMG_DIR)

            for epoch in range(AUGLOOP):
                seq_det = seq.to_deterministic()  # 保持坐标和图像同步改变,而不是随机
                # 读取图片
                img = Image.open(os.path.join(IMG_DIR, name))
                # sp = img.size
                img = np.asarray(img)
                # bndbox 坐标增强
                for i in range(len(bndbox)):
                    bbs = ia.BoundingBoxesOnImage([
                        ia.BoundingBox(x1=bndbox[i][0], y1=bndbox[i][1], x2=bndbox[i][2], y2=bndbox[i][3]),
                    ], shape=img.shape)

                    bbs_aug = seq_det.augment_bounding_boxes([bbs])[0]
                    boxes_img_aug_list.append(bbs_aug)

                    # new_bndbox_list:[[x1,y1,x2,y2],...[],[]]
                    n_x1 = int(max(1, min(img.shape[1], bbs_aug.bounding_boxes[0].x1)))
                    n_y1 = int(max(1, min(img.shape[0], bbs_aug.bounding_boxes[0].y1)))
                    n_x2 = int(max(1, min(img.shape[1], bbs_aug.bounding_boxes[0].x2)))
                    n_y2 = int(max(1, min(img.shape[0], bbs_aug.bounding_boxes[0].y2)))
                    if n_x1 == 1 and n_x1 == n_x2:
                        n_x2 += 1
                    if n_y1 == 1 and n_y2 == n_y1:
                        n_y2 += 1
                    if n_x1 >= n_x2 or n_y1 >= n_y2:
                        print('error', name)
                    new_bndbox_list.append([n_x1, n_y1, n_x2, n_y2])
                # 存储变化后的图片
                addname = str(epoch)
                image_aug = seq_det.augment_images([img])[0]
                path = os.path.join(AUG_IMG_DIR, name[:-4] + "_" + addname + suffix)
                print(path)
                image_auged = bbs.draw_on_image(image_aug, thickness=0)
                Image.fromarray(image_auged).save(path)

                # 存储变化后的XML
                change_xml_list_annotation(XML_DIR, name[:-4], new_bndbox_list, AUG_XML_DIR, name[:-4] + "_" + addname + suffix)
                print(name[:-4] + "_" + addname + suffix)
                new_bndbox_list = []

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要将 labelme 中的多边形标注转为 YOLOv5 的矩形标注,你可以按照以下步骤进行: 1. 首先,使用 labelme 打开需要转换的图片,并使用多边形标注工具对感兴趣的目标进行标注。 2. 然后,将标注好的图片导出为 JSON 文件。 3. 接着,使用 Python 代码读取 JSON 文件,并将多边形标注转换为矩形标注。具体实现可以参考以下代码: ```python import json def polygon_to_yolo(polygon, image_width, image_height): # 将多边形坐标转换为矩形坐标 x_values = [point[0] for point in polygon] y_values = [point[1] for point in polygon] x_min = min(x_values) x_max = max(x_values) y_min = min(y_values) y_max = max(y_values) # 计算矩形中心点坐标和宽高 center_x = (x_min + x_max) / 2 center_y = (y_min + y_max) / 2 width = x_max - x_min height = y_max - y_min # 计算 YOLOv5 格式的坐标和尺寸 x_center = center_x / image_width y_center = center_y / image_height box_width = width / image_width box_height = height / image_height return x_center, y_center, box_width, box_height with open('labelme_annotation.json', 'r') as f: data = json.load(f) image_width = data['imageWidth'] image_height = data['imageHeight'] shapes = data['shapes'] for shape in shapes: polygon = shape['points'] label = shape['label'] x_center, y_center, box_width, box_height = polygon_to_yolo(polygon, image_width, image_height) print(f"{label} {x_center} {y_center} {box_width} {box_height}") ``` 这段代码将读取名为 `labelme_annotation.json` 的 JSON 文件,并将其中的多边形标注转换为 YOLOv5 的矩形标注。最终输出的格式为:`label x_center y_center box_width box_height`。 4. 最后,将输出的矩形标注写入到 YOLOv5 格式的标注文件中即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

誓天断发

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

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

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

打赏作者

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

抵扣说明:

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

余额充值