VOC数据增强与调整大小

news2024/9/29 0:55:53

数据增强是针对数据集图像数量太少所采取的一种方法。
博主在实验过程中,使用自己的数据集时发现其数据量过少,只有280张,因此便想到使用数据增强的方式来获取更多的图像信息。对于图像数据,我们可以采用旋转等操作来获取更多的图像。
对于已经标注好的图片,则可以通过imgaug实现对图片和标签中的boundingbox同时变换。
首先,安装依赖库。我们首先创建conda环境,然后下载对应的工具包,这里需要提示一下,里面有个工具包imgaug只能在python2.7,3.4以及3.6使用,并且其需要很多依赖包,我们在直接执行安装imgaug命令时会默认安装opencv-python,但博主却总是安装失败,后来发现可以安装opencv来代替。即:

conda install opencv

考虑到下载速度,可以使用以下命令按照imgaug依赖包:

pip install six numpy scipy matplotlib scikit-image opencv-python imageio tqdm -i https://pypi.tuna.tsinghua.edu.cn/simple

随后也可以直接安装imgaug

conda  install imgaug

接下来是相关功能介绍。

读取原影像bounding boxes坐标

读取xml文件并使用ElementTree对xml文件进行解析,找到每个object的坐标值。

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')

    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, str(id + '.xml')))

生成变换序列

产生一个处理图片的Sequential。

# 影像增强
    seq = iaa.Sequential([
        iaa.Invert(0.5),
        iaa.Fliplr(0.5),  # 镜像
        iaa.Multiply((1.2, 1.5)),  # change brightness, doesn't affect BBs
        iaa.GaussianBlur(sigma=(0, 3.0)),  # iaa.GaussianBlur(0.5),
        iaa.Affine(
            translate_px={"x": 15, "y": 15},
            scale=(0.8, 0.95),
        )  # translate by 40/60px on x/y axis, and scale to 50-70%, affects BBs
    ])

bounding box 变化后坐标计算
先读取该影像对应xml文件,获取所有目标的bounding boxes,然后依次计算每个box变化后的坐标。

seq_det = seq.to_deterministic()  # 保持坐标和图像同步改变,而不是随机
# 读取图片
img = Image.open(os.path.join(IMG_DIR, name[:-4] + '.jpg'))
# 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])
# 存储变化后的图片
image_aug = seq_det.augment_images([img])[0]
path = os.path.join(AUG_IMG_DIR,
                    str(str(name[:-4]) + '_' + str(epoch)) + '.jpg')
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,
                           str(name[:-4]) + '_' + str(epoch))
# print(str(str(name[:-4]) + '_' + str(epoch)) + '.jpg')
new_bndbox_list = []

开始增强

数据准备
输入数据为两个文件夹一个是需要增强的图像数据(JPEGImages),一个是对应的xml文件(Annotations)。注意:图像文件名需和xml文件名相对应!

在这里插入图片描述
在这里插入图片描述

之后执行即可,得到文件如下:

在这里插入图片描述
在这里插入图片描述

完整代码

import xml.etree.ElementTree as ET
import os
import imgaug as ia
import numpy as np
import shutil
from tqdm import tqdm
from PIL import Image
from imgaug import augmenters as iaa

ia.seed(1)


def read_xml_annotation(root, image_id):
    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)
        # 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'))  # 这里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')

    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, str(id + '.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 + ' 创建成功')
        return True
    else:
        # 如果目录存在则不创建,并提示目录已存在
        print(path + ' 目录已存在')
        return False


if __name__ == "__main__":

    IMG_DIR = "E:/KITTI/jiamusi/VOC/JPEGImage/"#图像原路径
    XML_DIR = "E:/KITTI/jiamusi/VOC/VOC_Annotation/"

    AUG_XML_DIR = "E:/KITTI/jiamusi/VOC/VOC/Annotations/"  # 存储增强后的XML文件夹路径
    try:
        shutil.rmtree(AUG_XML_DIR)
    except FileNotFoundError as e:
        a = 1
    mkdir(AUG_XML_DIR)

    AUG_IMG_DIR = "E:/KITTI/jiamusi/VOC/VOC/JPEGImages/"  # 存储增强后的影像文件夹路径
    try:
        shutil.rmtree(AUG_IMG_DIR)
    except FileNotFoundError as e:
        a = 1
    mkdir(AUG_IMG_DIR)

    AUGLOOP = 5  # 每张影像增强的数量,博主有近260张,增强5次即可

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

    # 影像增强
    seq = iaa.Sequential([
        iaa.Invert(0.5),
        iaa.Fliplr(0.5),  # 镜像
        iaa.Multiply((1.2, 1.5)),  # change brightness, doesn't affect BBs
        iaa.GaussianBlur(sigma=(0, 3.0)),  # iaa.GaussianBlur(0.5),
        iaa.Affine(
            translate_px={"x": 15, "y": 15},
            scale=(0.8, 0.95),
        )  # translate by 40/60px on x/y axis, and scale to 50-70%, affects BBs
    ])

    for name in tqdm(os.listdir(XML_DIR), desc='Processing'):

        bndbox = read_xml_annotation(XML_DIR, name)

        # 保存原xml文件
        shutil.copy(os.path.join(XML_DIR, name), AUG_XML_DIR)
        # 保存原图
        og_img = Image.open(IMG_DIR + '/' + name[:-4] + '.jpg')
        og_img.convert('RGB').save(AUG_IMG_DIR + name[:-4] + '.jpg', 'JPEG')
        og_xml = open(os.path.join(XML_DIR, name))
        tree = ET.parse(og_xml)
        # 修改增强后的xml文件中的filename
        elem = tree.find('filename')
        elem.text = (name[:-4] + '.jpg')
        tree.write(os.path.join(AUG_XML_DIR, name))

        for epoch in range(AUGLOOP):
            seq_det = seq.to_deterministic()  # 保持坐标和图像同步改变,而不是随机
            # 读取图片
            img = Image.open(os.path.join(IMG_DIR, name[:-4] + '.jpg'))
            # 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])
            # 存储变化后的图片
            image_aug = seq_det.augment_images([img])[0]
            path = os.path.join(AUG_IMG_DIR,
                                str(str(name[:-4]) + '_' + str(epoch)) + '.jpg')
            image_auged = bbs.draw_on_image(image_aug, size=0)
            Image.fromarray(image_auged).convert('RGB').save(path)

            # 存储变化后的XML
            change_xml_list_annotation(XML_DIR, name[:-4], new_bndbox_list, AUG_XML_DIR,
                                       str(name[:-4]) + '_' + str(epoch))
            # print(str(str(name[:-4]) + '_' + str(epoch)) + '.jpg')
            new_bndbox_list = []
    print('Finish!')

但运行后发现问题,图片太大,所有我们需要进行修改。
原图为6960x46460,其不但图片较大,且6960不能整除32,造成错误。因此需要将图片进行修改。并要在resize的同时还要将标注信息一并转换。

import glob
import xml.dom.minidom
import cv2
from PIL import Image
import matplotlib.pyplot as plt
import os

# 定义待批量裁剪图像的路径地址
IMAGE_INPUT_PATH = r'E:\KITTI\jiamusi\VOC\VOC2023\JPEGImages'
XML_INPUT_PATH = r'E:\KITTI\jiamusi\VOC\VOC2023\Annotations'
# 定义裁剪后的图像存放地址
IMAGE_OUTPUT_PATH = r'E:\KITTI\jiamusi\VOC\VOC2023\VOC2023\JPEGImages'
XML_OUTPUT_PATH = r'E:\KITTI\jiamusi\VOC\VOC2023\VOC2023\Annotations'
imglist = os.listdir(IMAGE_INPUT_PATH)
xmllist = os.listdir(XML_INPUT_PATH)

for i in range(len(imglist)):
    # 每个图像全路径
    image_input_fullname = IMAGE_INPUT_PATH + '/' + imglist[i]
    xml_input_fullname = XML_INPUT_PATH + '/' + xmllist[i]
    image_output_fullname = IMAGE_OUTPUT_PATH + '/' + imglist[i]
    xml_output_fullname = XML_OUTPUT_PATH + '/' + xmllist[i]

    img = cv2.imread(image_input_fullname)
    height, width = img.shape[:2]

    # 定义缩放信息 以等比例缩放到416为例
    scale1 = 720/ height #y
    scale2 = 1280 / width#x
    height = 720
    width = 1280

    dom = xml.dom.minidom.parse(xml_input_fullname)
    root = dom.documentElement

    # 读取标注目标框
    objects = root.getElementsByTagName("bndbox")

    for object in objects:
        xmin = object.getElementsByTagName("xmin")
        xmin_data = int(float(xmin[0].firstChild.data))
        # xmin[0].firstChild.data =str(int(xmin1 * x))
        ymin = object.getElementsByTagName("ymin")
        ymin_data = int(float(ymin[0].firstChild.data))
        xmax = object.getElementsByTagName("xmax")
        xmax_data = int(float(xmax[0].firstChild.data))
        ymax = object.getElementsByTagName("ymax")
        ymax_data = int(float(ymax[0].firstChild.data))

        # 更新xml
        width_xml = root.getElementsByTagName("width")
        width_xml[0].firstChild.data = width
        height_xml = root.getElementsByTagName("height")
        height_xml[0].firstChild.data = height

        xmin[0].firstChild.data = int(xmin_data * scale2)
        ymin[0].firstChild.data = int(ymin_data * scale1)
        xmax[0].firstChild.data = int(xmax_data * scale2)
        ymax[0].firstChild.data = int(ymax_data * scale1)

        # 另存更新后的文件
        with open(xml_output_fullname, 'w') as f:
            dom.writexml(f, addindent='  ', encoding='utf-8')
        # 测试缩放效果
        img = cv2.resize(img, (width, height))
        '''
        # xmin, ymin, xmax, ymax分别为xml读取的坐标信息
        left_top = (int(xmin_data*scale), int(ymin_data*scale))
        right_down= (int(xmax_data*scale), int(ymax_data*scale))
        cv2.rectangle(img, left_top, right_down, (255, 0, 0), 1)
        '''

    cv2.imwrite(image_output_fullname, img)

将其转换为1280x720的格式,就可以使用了。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/338953.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android Dalvik虚拟机 堆初始化流程

前言 上篇文章介绍了dalvik虚拟机启动流程,在dalvik虚拟机启动时调用了dvmGcStartup来启动堆。 本文介绍我们在日常开发使用Java时的堆创建流程。 Dalvik堆介绍 Dalvik虚拟机中,堆是由heap[0] Active堆和heap[1] Zygote堆两部分组成的。其中&#xff…

13 Day:实现内核线程

前言:我们昨天完成了内核的内存池以及内存管理程序,今天我们要揭开操作系统多任务执行的神秘面纱,来了解并实现一个多任务的操作系统。 一,实现内核线程 在聊线程之间我们先聊聊处理器吧,众所周之现在我们的CPU动不动…

心跳太快对身体带来影响?4种方法来减速!

心脏每时每刻都在跳动,跳动时遵循一定的节律。正常情况下成年人每分钟心跳达到60~120下,若心跳每分钟大于120下,被判断为心动过速;若心跳每分钟不足50下,被判断为心动过缓,无论是哪种因素均会影响身体健康。…

详解Redisson分布式限流的实现原理

我们目前在工作中遇到一个性能问题,我们有个定时任务需要处理大量的数据,为了提升吞吐量,所以部署了很多台机器,但这个任务在运行前需要从别的服务那拉取大量的数据,随着数据量的增大,如果同时多台机器并发…

如何用Python打包好exe文件,并替换图标

前言 Python打包?打包exe文件?怎么操作? ok,今天我来分享分享,教你们如何打包号文件,顺便还来展示一下,如何替换好图标 首先把你的代码准备好,尽量不要中文路径,容易报…

flex 布局

设为 Flex 布局以后&#xff0c;子元素的float、clear和vertical-align属性将失效。 flex 和 inline-flexflex&#xff1a; 将对象作为弹性伸缩盒显示inline-flex&#xff1a;将对象作为内联块级弹性伸缩盒显示<style>.main {background-color: #0f0;display: flex; /*父…

【VictoriaMetrics】VictoriaMetrics启停脚本

先看结果,启动VictoriaMetrics UI界面可访问

有趣的Hack-A-Sat黑掉卫星挑战赛——定位卫星Jackson

国家太空安全是国家安全在空间领域的表现。随着太空技术在政治、经济、军事、文化等各个领域的应用不断增加&#xff0c;太空已经成为国家赖以生存与发展的命脉之一&#xff0c;凝聚着巨大的国家利益&#xff0c;太空安全的重要性日益凸显[1]。而在信息化时代&#xff0c;太空安…

图解LeetCode——剑指 Offer 53 - I. 在排序数组中查找数字 I

一、题目 统计一个数字在排序数组中出现的次数。 二、示例 示例 1 【输入】nums [5,7,7,8,8,10], target 8 【输出】2 示例 2: 【输入】nums [5,7,7,8,8,10], target 6 【输出】0 提示&#xff1a; 0 < nums.length < 10^5-10^9 < nums[i] < 10^9nums 是一…

基于Java+SpringBoot+SpringCloud+Vue前后端分离医院管理系统设计与实现

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建、毕业项目实战、项目定制✌ 博主作品&#xff1a;《微服务实战》专栏是本人的实战经验总结&#xff0c;《S…

一文总结 JUC 并发编程

文章目录一、JUC 并发编程二、协调锁1. Synchronized2. Synchronized 锁下线程通信3. Lock 锁4. Lock 锁实例 - ReentrantLock5. 读写锁 - ReadWriteLock三、CAS & 原子类1. CAS2. 原子类2.1 基础原子类2.2 数组类型原子类2.3 引用型原子类四、线程1. Callable 和 Future2.…

Filter防火墙(8)

实验目的 1、了解个人防火墙的基本工作原理&#xff1b; 2、掌握Filter防火墙的配置。 预备知识防火墙 防火墙&#xff08;Firewall&#xff09;是一项协助确保信息安全的设备&#xff0c;会依照特定的规则&#xff0c;允许或是限制传输的数据通过。防火墙可以是一台专属的硬…

Linux防火墙(7)

实验目的 通过该实验了解Linux防火墙iptables实现原理&#xff0c;掌握iptables基本使用方法&#xff0c;能够利用iptables对操作系统进行加固。预备知识基本原理 netfilter/iptables&#xff08;简称为iptables&#xff09;组成Linux平台下的包过滤防火墙&#xff0c;具有完成…

拉普拉斯矩阵的定义,常见的几种形式以及代码实现?

拉普拉斯矩阵 拉普拉斯矩阵(Laplacian matrix) 也叫做导纳矩阵、基尔霍夫矩阵或离散拉普拉斯算子,主要应用在图论中,作为一个图的矩阵表示。对于图 G=(V,E),其Laplacian 矩阵的定义为 L=D-A,其中 L 是Laplacian 矩阵, D=diag(d)是顶点的度矩阵(对角矩阵),d=rowSum(A),…

【Java 面试合集】简述下Java的三个特性 以及项目中的应用

简述下Java的特征 以及项目中的应用 1. 概述 上述截图中就是Java的三大特性&#xff0c;以及特性的实现方案。接下来就每个点展开来说说 2. 封装 满足&#xff1a;隐藏实现细节&#xff0c;公开使用方法 的都可以理解为是封装 而实现封装的有利手段就是权限修饰符了。可以根据…

【MT7628】开发环境搭建-安装Fedora12

1.下载Fedora安装镜像 1.1链接地址 http://dl.fedoraproject.org/pub/archive/fedora/linux/releases/12/Fedora/i386/iso/ 1.2选择如下截图的软件包下载 1.3下载完成的软件包名称

06分支限界法

文章目录八数码难题普通BFS算法全局择优算法&#xff08;A算法&#xff0c;启发式搜索算法&#xff09;单源最短路径问题装载问题算法思想&#xff1a;队列式分支限界法优先队列式分支限界法布线问题最大团问题批处理作业调度问题分支限界法与回溯法的区别&#xff1a; &#x…

已解决sc delete MongoDB卸载MongoDB拒绝访问。

已解决sc delete MongoDB卸载MongoDB拒绝访问。 文章目录报错问题报错翻译报错原因解决方法联系博主免费帮忙解决报错报错问题 粉丝群里面的一个小伙伴遇到问题跑来私信我&#xff0c;想卸载MongoDB数据库&#xff0c;但是发生了报错&#xff08;当时他心里瞬间凉了一大截&…

select 与 where、order by、limit 子句执行优先级比较

当 select 和 其他三种语句的一者或者多者同时出现时&#xff0c;他们之间是存在执行先后顺序的。 他们的优先级顺序是&#xff1a;where > select > order by > limit 目录 1、select 与 where 2、select 与 order by 3、order by 与 limit 4、优先级证明 1、s…

低噪声与功放选型购买

低噪声与功率放大器的区别&#xff1f;购买时怎么区分&#xff1f; 低噪放 低噪放&#xff0c;低噪声射频放大器。作用就是要求噪声系数很低&#xff0c;放大电压信号。一般放在系统第一级&#xff0c;因为噪声系数低&#xff0c;接收放大的信号有很好的的信噪比。如天线的接…