【目标检测实用脚本系列】标注图片裁切成boundingbox的小图

【目标检测实用脚本系列】将labelImg标注的xml标签,按标签名建立文件夹,并将对应的裁切小图保存到文件夹中

目标检测中数据是至关重要的一个环节,使用当前脚本可以快捷的将已经标注好的xml标签,按标签名切分成图像以便查验,切出来的标签图片如下:

在这里插入图片描述
脚本如下,只需要将第46、48、50行路径改为自己的路径即可:

import cv2
import xml.etree.ElementTree as ET
import os
import glob
from tqdm import tqdm
import shutil

def count_num(indir):
    label_list = []
    # 提取xml文件列表
    os.chdir(indir)
    annotations = os.listdir('.')
    annotations = glob.glob(str(annotations) + '*.xml')
    # 新建字典,用于存放各类标签名及其对应的数目
    dict = {}
    # 遍历xml文件
    for i, file in enumerate(annotations):

        # actual parsing
        in_file = open(file, encoding='utf-8')
        tree = ET.parse(in_file)
        root = tree.getroot()

        # 遍历文件的所有标签
        for obj in root.iter('object'):
            name = obj.find('name').text
            if (name in dict.keys()):
                # 如果标签不是第一次出现,则+1
                dict[name] += 1
            else:
                # 如果标签是第一次出现,则将该标签名对应的value初始化为1
                dict[name] = 1

    # 打印结果
    print("各类标签的数量分别为:")
    for key in dict.keys():
        print(key + ': ' + str(dict[key]))
        label_list.append(key)
    print("标签类别如下:")
    print(label_list)
    return label_list


if __name__ == '__main__':
    # 原始图片路径
    img_path = '/home/lzj/fall_dataset/JPEGImages'
    # 原始标签路径
    xml_path = '/home/lzj/fall_dataset/Annotations'
    # 待存放新图片的路径
    obj_img_path = '/home/lzj/fall_dataset/cut_xml'

    # 调用函数统计各类标签数目
    label_list = count_num(xml_path)
    # 判断所在目录下是否有该文件名的文件夹
    if not os.path.exists(obj_img_path):
        os.makedirs(obj_img_path)
        print(f"已经创建文件夹{obj_img_path}")
    # 新建以标签名字命名的文件夹
    for label in label_list:
        new_label_path = os.path.join(obj_img_path, label)
        if not os.path.exists(new_label_path):
            os.makedirs(new_label_path)
            print(f"已经创建文件夹{new_label_path}")

    # 遍历图片文件夹
    for img_file in tqdm(os.listdir(img_path)):
        # 判断文件是否为图片格式
        if img_file[-4:] in ['.png', '.jpg', '.bmp', '.jpeg']:
            # 将图片路径与图片名进行拼接
            img_filename = os.path.join(img_path, img_file)
            # 读取图片
            img_cv = cv2.imread(img_filename)

            # 分割出图片名,如“000.png” 图片名为“000”
            img_name = (os.path.splitext(img_file)[0])
            # 利用标签路径、图片名、xml后缀拼接出完整的标签路径名
            xml_name = os.path.join(xml_path, ('%s.xml' % img_name))

            # 判断与图片同名的标签是否存在,因为图片不一定每张都打标
            if os.path.exists(xml_name):
                # 利用ET读取xml文件
                root = ET.parse(xml_name).getroot()
                # 目标框个数统计,防止目标文件覆盖
                count = 0
                # 遍历所有目标框
                for obj in root.iter('object'):
                    # 获取目标框名称,即label名
                    name = obj.find('name').text
                    # 找到框目标
                    xmlbox = obj.find('bndbox')
                    # 将框目标的四个顶点坐标取出
                    x0 = xmlbox.find('xmin').text
                    y0 = xmlbox.find('ymin').text
                    x1 = xmlbox.find('xmax').text
                    y1 = xmlbox.find('ymax').text

                    # 把对应标签存放到指定的目录下
                    now_path = os.path.join(obj_img_path, name)
                    # cv2裁剪出目标框中的图片
                    obj_img = img_cv[int(y0):int(y1), int(x0):int(x1)]
                    # 保存裁剪图片
                    cv2.imwrite(os.path.join(now_path, ('%s_%s' % (img_name, count) + '.jpg')), obj_img)
                    count += 1  # 目标框统计值自增1

运行后的结果如下:
在这里插入图片描述

### 实现方法 对于处理 DOTA 数据集中的像,可以采用 MATLAB 进行像放大、切割以及重新标注的操作。具体操作如下: #### 像放大部分 为了将原始图片尺寸扩大两倍,可利用 `imresize` 函数来调整像大小。 ```matlab img = imread('path_to_image'); % 读取原 resized_img = imresize(img, 2); % 放大两倍 ``` 此部分代码实现了对输入像按比例缩放的功能[^1]。 #### 切割512x512子部分 完像放大之后,下一步是对像进行裁剪得到固定大小 (512×512像素) 的片段(chips),这可以通过循环遍历整张像的不同区域实现。 ```matlab chipSize = [512, 512]; % 定义芯片尺寸 [rows, cols, ~] = size(resized_img); for i = 1:chipSize(1):cols-chipSize(1)+1 for j = 1:chipSize(2):rows-chipSize(2)+1 chip = resized_img(j:j+chipSize(2)-1,i:i+chipSize(1)-1,:); subplot(ceil((cols-chipSize(1)+1)/chipSize(1)), ceil((rows-chipSize(2)+1)/chipSize(2)), ... ((i/chipSize(1))+(j/chipSize(2))-1)); imshow(chip); title(['Chip at position (' num2str(i) ', ' num2str(j) ')']); imwrite(chip,['output_folder/' num2str(i) '_' num2str(j) '.png']); % 存储每个碎片到指定文件夹下 end end ``` 上述脚本会创建一系列重叠或不重叠的小窗口,并从中提取相应位置处的子像作为新的样本保存下来。 #### 重新标注目标框部分 当生这些 chips 后,则需更新原有标签信息以适应新坐标系下的物体边界框。假设已知某对象在全上的真实边框为 `[xmin ymin xmax ymax]` 形式的向量形式表示法,那么针对每一个被分割出来的局部视窗而言,其内部所含有的同一实体应当具有相对应变换后的坐标值。 设当前正在处理第 `(m,n)` 块 chip ,即位于整个宽高方向上分别偏移了 m*stride 和 n*stride 单位长度的位置;此时若要计算该区域内某个特定实例的新矩形框参数,则可通过下面的方式获得: ```matlab function new_bbox = transform_bboxes(bbox, stride, m, n) % 输入参数说明: % bbox - 原始全局坐标的 bounding box 数组 [N x 4], N 表示数量; % stride - 步长(这里等于 chip 大小) % m,n - 当前 chip 所属行列索引号 new_bbox = zeros(size(bbox)); for k=1:size(bbox,1) xmin_global = bbox(k,1); ymin_global = bbox(k,2); xmax_global = bbox(k,3); ymax_global = bbox(k,4); % 计算相对于当前 chip 左上角点的偏移量 offset_xmin = max(xmin_global-(n-1)*stride,0); offset_ymin = max(ymin_global-(m-1)*stride,0); offset_xmax = min(xmax_global-n*stride,chipSize(1)); offset_ymax = min(ymax_global-m*stride,chipSize(2)); % 更新 bounding boxes new_bbox(k,:)=[offset_xmin,offset_ymin,... offset_xmin+offset_xmax-xmin_global,... offset_ymin+offset_ymax-ymin_global]; end end ``` 这段函数接受一组或多组 global coordinate 下定义的对象包围盒描述,并返回它们转换至局部视角后对应的版本。注意这里的逻辑考虑到了越界情况的发生——如果原本完整的 object 落入两个相邻 patches 中间的话,则只保留可见的那一部分。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Zhijun.li@Studio

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

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

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

打赏作者

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

抵扣说明:

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

余额充值