图像及对应xml文件切割

 原图像大小为1024*2048,输入网络中太大。便将其裁剪为两张1024*1024大小的图像,同时对其对应的xml(VOC格式)进行修改,代码参考了csdn其他博主的,具体是哪个,找不到了,未添加参考源,着实抱歉。

标签保留策略是如果一个标注框恰好在中间且被切分为了两块,均保留(后续还需要人工检核修改,因为有的标注框会很小很小)。

import cv2
import xml.etree.ElementTree as ET
import os
import numpy as np
from tqdm import tqdm
from PIL import Image


# 数据扩增
# 读xml文档返回每个目标边界框信息
def read_xml_annotation(root, image_id):  # (源xml文件夹地址和文件夹内所有图像名称)
    in_file = open(os.path.join(root, image_id))
    tree = ET.parse(in_file)
    root = tree.getroot()
    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)
        bndboxlist.append([xmin, ymin, xmax, ymax])

    bndbox = root.find('object').find('bndbox')
    return bndboxlist

# 更改xml信息将裁剪至每个小部分的对应目标边界框进行提取
def change_xml_list_annotation(root, image_id, new_target, saveroot, id):
    in_file = open(os.path.join(root, str(image_id) + '.xml'))  # 这里root分别由两个意思
    tree = ET.parse(in_file)

    # 修改xml文件中的filename
    elem = tree.find('filename')
    elem.text = (str(id) + '.jpg')
    xmlroot = tree.getroot()

    # 修改xml文件中的path
    elem = tree.find('path')
    if elem != None:
        elem.text = (saveroot + str(id) + '.jpg')

    #修改xml文件中的图像宽高
    tree.find('size').find('width').text = str(1024)
    tree.find('size').find('height').text = str(1024)


    index = 0

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

        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)
        if xmin.text == "0" and ymin.text == "0" and xmax.text == "0" and ymax.text == "0":
            xmlroot.remove(object)  # 由于在后续设置中将超出五个裁剪完成图像范围的目标边界框的四个参数全部设为0,此处将参数为0的object删除掉,剩余满足裁剪范围内的目标边界框
        index = index + 1
    tree.write(os.path.join(saveroot, str(id + '.xml')))
    
# 遍历指定目录,显示目录下的所有文件名
def CropImage4File(filepath, destpath):
    pathDir = os.listdir(filepath)  # 列出文件路径中的所有路径或文件
    for allDir in pathDir:
        child = os.path.join(filepath, allDir)
        dest = os.path.join(destpath, allDir)
        if os.path.isfile(child):
            image = cv2.imread(child)
        sp = image.shape  # 获取图像形状:返回【行数值,列数值】列表
        sz1 = sp[0]  # 图像的高度(行 范围)
        sz2 = sp[1]  # 图像的宽度(列 范围)
        #sz3 = sp[2]                #像素值由【RGB】三原色组成
        #你想对文件的操作
        n, s = os.path.splitext(dest)

        a1 = 0  # x start
        b1 = int(sz1)  # x end  列
        c1 = 0  # y start
        d1 = int(sz2/2)  # y end  行
        cropImg1 = image[a1:b1, c1:d1]  # 裁剪图像
        cv2.imwrite(n + '_1' + s, cropImg1)  # 写入图像路径

        a2 = 0  # x start
        b2 = int(sz1)  # x end
        c2 = int(sz2/2)  # y start
        d2 = int(sz2)  # y end
        cropImg2 = image[a2:b2, c2:d2]  # 裁剪图像
        cv2.imwrite(n + '_2' + s, cropImg2)  # 写入图像路径

if __name__ == '__main__':
    filepath = 'E:/yolov5-master/VOCData/9.15text/images/'  # 源图像
    XML_DIR = 'E:/yolov5-master/VOCData/Annotations/'  # 源xml
    destpath = 'E:/yolov5-master/qiege/image_qiege/'  # 保存裁剪图片的文件夹地址
    AUG_XML_DIR = 'E:/yolov5-master/qiege/labels_qiege/'  # 保存xml地址
    
    new_bndbox_list = []  # 提前清空存储anchor,否则anchor会重复覆盖
    CropImage4File(filepath,destpath)
    for name in tqdm(os.listdir(XML_DIR), desc='Processing'):
        bndbox = read_xml_annotation(XML_DIR, name)  # 一张图片的边界框信息
        og_xml = open(os.path.join(XML_DIR, name))
        tree = ET.parse(og_xml)
        elem = tree.find('filename')
        elem.text = (name[:-4] + '.jpg')  # 每一次将xml文件中的filename节点信息进行更改
        img = Image.open(os.path.join(filepath, name[:-4] + '.jpg'))
        img = np.asarray(img)
        i_h, i_w, _ = img.shape
        # 分别依据左上右上左下右下和中心位置对满足要求的目标边界框进行分别提取,并保存在各自对应的xml文件中,若目标边界框在裁剪图片边缘上,则舍弃
        for i in range(len(bndbox)):
            x1 = bndbox[i][0]
            y1 = bndbox[i][1]
            x2 = bndbox[i][2]
            y2 = bndbox[i][3]
            n_x1 = 0
            n_y1 = 0
            n_x2 = 0
            n_y2 = 0
            #anchor在左半部分,全保留
            if x1 < i_w / 2 and x2 < i_w / 2 and y1 < i_h  and y2 < i_h :
                n_x1 = x1
                n_y1 = y1
                n_x2 = x2
                n_y2 = y2
            #anchor被切割,将x的最大值赋值为1024(裁剪后的图像最大宽)
            if x1 <i_w / 2 and x2 >i_w / 2 and y1 < i_h  and y2 < i_h :
                n_x1 = x1
                n_y1 = y1
                n_x2 = 1024
                n_y2 = y2
            new_bndbox_list.append([n_x1, n_y1, n_x2, n_y2])
        epoch = 1
        # 存储变化后的XML
        change_xml_list_annotation(XML_DIR, name[:-4], new_bndbox_list, AUG_XML_DIR, str(name[:-4]) + '_' + str(epoch))
        # 将new_bndbox_list清零
        new_bndbox_list = []
        for i in range(len(bndbox)):
            x1 = bndbox[i][0]
            y1 = bndbox[i][1]
            x2 = bndbox[i][2]
            y2 = bndbox[i][3]
            n_x1 = 0
            n_y1 = 0
            n_x2 = 0
            n_y2 = 0
            #anchor全在右半部分,全保留
            if x1 > i_w / 2 and x2 > i_w / 2 and y1 < i_h  and y2 < i_h :
                n_x1 = x1 - 1024
                n_y1 = y1
                n_x2 = x2 - 1024
                n_y2 = y2
            #anchor被切割,将x最小值赋值为0,最大值减去1024
            if x1 <i_w / 2 and x2 >i_w / 2 and y1 < i_h  and y2 < i_h :
                n_x1 = 0
                n_y1 = y1
                n_x2 = x2 - 1024
                n_y2 = y2
            new_bndbox_list.append([n_x1, n_y1, n_x2, n_y2])
        epoch = 2
        # 存储变化后的XML
        change_xml_list_annotation(XML_DIR, name[:-4], new_bndbox_list, AUG_XML_DIR, str(name[:-4]) + '_' + str(epoch))

效果如下:

 

 

 

 

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值