Faster R-CNN pytorch源码血细胞检测实战(二)数据增强

news2024/12/24 9:20:34

Faster R-CNN pytorch源码血细胞检测实战(二)数据增强

文章目录

  • Faster R-CNN pytorch源码血细胞检测实战(二)数据增强
    • 1. 资源&参考
    • 2. 数据增强
      • 2.1 代码运行
      • 2.2 文件存放
    • 3 数据集划分
    • 4. 训练&测试
    • 5. 总结

1. 资源&参考

Faster R-CNN pytorch版源码调试过程参考:Faster R-CNN pytorch源码血细胞检测实战(详细版)
数据增强源码参考:voc数据集对有标签的数据集数据增强
其它参考:
imgaug使用文档

2. 数据增强

在Faster R-CNN pytorch源码血细胞检测实战(详细版)的基础上,我们完成了对Faster RCNN pytorch版代码的运行,并且基于公共血细胞数据集实现了对多血细胞的检测。现在,在前文的基础上,我们对数据进行增强,并基于增强后的数据对Faster RCNN进行训练,进而测试应用数据增强技术后的训练模型的检测精度。

2.1 代码运行

数据增强源码参考了这篇voc数据集对有标签的数据集数据增强,如下所示:

'''
Author: CodingWZP
Email: codingwzp@gmail.com
Date: 2021-08-06 10:51:35
LastEditTime: 2021-08-09 10:53:43
Description: Image augmentation with label.
'''
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 = "./JPEGImages/"
    XML_DIR = "./Annotations/"

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

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

    AUGLOOP = 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!')

建一个新的python文件,命名为img_augmentation.py,放在faster-rcnn.pytorch-pytorch-1.0\data\VOCdevkit2007\VOC2007目录下即可。
用命令python img_augmentation.py运行上述代码,会在VOC2007目录下生成一个AUG文件夹,里面存放好了JPEGImagesAnnotations文件夹,如下图所示:
在这里插入图片描述
而这两个文件夹则分别存放了包括原图和增强图像在内的2184张图像(384+384×5=2184),具体生成多少张,应用怎么样的增强,可以修改上述代码来实现,这里是对每张原图生成5张增强图像。

2.2 文件存放

正常来说,应该是将增强后的图像单独存放在faster-rcnn.pytorch-pytorch-1.0\data\目录下,并写一个读取该目录的类,但是,最近没啥时间来专门coding了,所以这里为了求快,直接按照以下懒人版方法修改文件即可。
2.1中生成的AUG文件夹,直接用该文件夹下的JPEGImagesAnnotations文件夹替换faster-rcnn.pytorch-pytorch-1.0\data\VOCdevkit2007\VOC2007JPEGImagesAnnotations

3 数据集划分

建一个新的python文件,命名为img_split.py,放在faster-rcnn.pytorch-pytorch-1.0\data\VOCdevkit2007\VOC2007目录下,代码内容如下所示:

import os
import random

path = './'  # 设置path为VOC2007文件夹即可,也就是当前文件夹
trainval_percent = 0.8  # 训练+验证占80%
train_percent = 0.75  # 训练集占训练+验证的75%,也就是0.8×0.75=0.6

xmlfilepath = os.path.join(path, 'Annotations')  # xml文件保存地址
txtsavepath = os.path.join(path, 'ImageSets/Main')  # txt文件保存地址
total_xml = os.listdir(xmlfilepath)  # 解析
original_xml = [f for f in total_xml if f.endswith('.xml') and len(os.path.splitext(f)[0].split('_')) == 2]
# print(original_xml)

num = len(original_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)

ftrainval = open(os.path.join(txtsavepath, 'trainval.txt'), 'w')
ftest = open(os.path.join(txtsavepath, 'test.txt'), 'w')
ftrain = open(os.path.join(txtsavepath, 'train.txt'), 'w')
fval = open(os.path.join(txtsavepath, 'val.txt'), 'w')

# 获取所有图像文件(原始和增强)
image_files = [f.replace('.xml', '') for f in os.listdir(os.path.join(path, 'JPEGImages')) if f.endswith('.jpg')]

# 用于记录已经写入的图像名
written_images = set()

for i in list:
    name = original_xml[i][:-4]  # 获取原始图像的文件名,不包括扩展名
    # print(name)

    if i in trainval:
        ftrainval.write(name + '\n')
        if i in train:
            ftrain.write(name + '\n')
            # 找到对应的增强图像并写入训练集
            for k in range(0, 5):  # 假设每张图像有5次增强
                augmented_name = f"{name}_{k}"
                if augmented_name not in written_images:
                    ftrain.write(augmented_name + '\n')
                    written_images.add(augmented_name)
        else:
            fval.write(name + '\n')

    else:
        ftest.write(name + '\n')

ftrainval.close()
ftrain.close()
fval.close()
ftest.close()

用命令python img_split.py运行上述代码,会在faster-rcnn.pytorch-pytorch-1.0\data\VOCdevkit2007\VOC2007\ImageSets\Main\生成划分数据集的txt文件。
注意img_split.pyimg_augmentation.py是对应的,可以看到我在img_augmentation.py中对每张图片都增强了5次,所以在img_split.py中也是每次读取原始图像的5个增强图像文件
为了防止数据泄露,所以在img_split.py中,只用增强后的数据来对模型进行训练,而不用于验证和测试,可以看到在img_split.py中的这几行:

# 只有训练集中添加了增强后的图像
if i in trainval:
    ftrainval.write(name + '\n')
    if i in train:
        ftrain.write(name + '\n')
        # 找到对应的增强图像并写入训练集
        for k in range(0, 5):  # 假设每张图像有5次增强
            augmented_name = f"{name}_{k}"
            if augmented_name not in written_images:
                ftrain.write(augmented_name + '\n')
                written_images.add(augmented_name)
    else:
        fval.write(name + '\n')

else:
    ftest.write(name + '\n')

4. 训练&测试

在开始训练之前,还需要把之前训练产生的模型以及cache删除掉,分别在下面三个路径下:
faster-rcnn.pytorch-pytorch-1.0\output\res101\voc_2007_test\faster_rcnn_10\
faster-rcnn.pytorch-pytorch-1.0\data\cache\
faster-rcnn.pytorch-pytorch-1.0\data\VOCdevkit2007\annotations_cache\
之后,参照Faster R-CNN pytorch源码血细胞检测实战(详细版)中即可。

5. 总结

这次代码调试过程还是让我学到了很多的,由于pytorch版Faster RCNN源码的实现和运行比较复杂,因此点到为止,只要求能成功复现实验,并且了解了怎么调参即可,代码的实现细节可以参考其它的开源仓库,据我所知好像mmdetection对Faster RCNN的实现就比较简洁,且易于运行。

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

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

相关文章

kafka windows版本的下载安装,并且本地使用(亲测有效)

目录 1 问题2 下载 1 问题 本地启动一个kafka ,然后可以实现生产者 消费者 2 下载 https://downloads.apache.org/kafka/ 选择一个版本下载 下载之后解压 修改配置 修改好之后,就保存,之后先启动zookper ,之后再启动 ka…

Mybatis-Plus 3.3.2 发布,新增优雅的数据安全保护姿势[MyBatis-Plus系列]

Hi,大家好,我是悟纤。过着爱谁谁的生活,活出不设限的人生。 存在数据库中的数据对于普通用户而言是不可见的,好像是藏起来了一样,但对于开发者,只要知道数据库的连接地址、用户名、密码,则数据不再安全;这也意味着,一旦连接数据库的配置文件暴露出去,则数据不再安全…

聚焦中国—东盟大健康产业峰会 点靓广西“长寿福地”品牌

12月8-10日2023中国—东盟大健康产业峰会暨大健康产业博览会在南宁国际会展中心成功举办,本次峰会由国家中医药管理局、广西壮族自治区人民政府联合主办,中国老年学和老年医学学会、自治区党委宣传部、自治区民政厅、广西壮族自治区外事办公室、广西壮族…

SQL窗口函数OVER用法整理

文章目录 SQL窗口函数OVER用法整理 SQL窗口函数OVER用法整理 OVER的定义 OVER用于为行定义一个窗口,它对一组值进行操作,不需要使用GROUP BY子句对数据进行分组,能够在同一行中同时返回基础行的列和聚合列。 语法 OVER ( [ PARTITION BY c…

核心大表7亿数据,查询性能快40倍!科大讯飞HTAP探索实践

科大讯飞在 2021 年关注原生分布式数据库,并于 2023 年 7 月在核心业务落地 OceanBase,实现了业务稳定运行、灵活扩缩容,以及一套系统处理 TP 和 AP 业务且互不影响。并带来了意外收获,即存储成本下降 50%、运维复杂度极大简化。科…

五年制专转本备考冲刺阶段,老师给你六点建议助你上岸

1、热衷的不是学习,而是思考 人与人之间最大的差别在于思维的差别,也可以说是思考的差别。专转本也是如此,有人思考得简单,有人思考得复杂;有人想得全面,有人想得肤浅。 只有善于思考,才会对问…

Springboot管理系统数据权限过滤——ruoyi实现方案

本文主要简述,Ruoyi框架使用的权限过滤实现方案,实现简单易懂。主要知识点有: 注解定义;面向切面编程,在执行有数据权限注解的方法之前获取用户组织权限,拼接到domain对象的params参数中; 1. …

函数的栈帧

我们每次在调用函数的时候,都说会进行传参。每次创建函数,或者进行递归的时候,也会说会进行压栈。 那么,今天我们就来具体看看函数到底是如何进行压栈,传参的操作。 什么是栈? 首先我们要知道,…

Python (五) 处理图像

程序员的公众号:源1024,获取更多资料,无加密无套路! 最近整理了一波电子书籍资料,包含《Effective Java中文版 第2版》《深入JAVA虚拟机》,《重构改善既有代码设计》,《MySQL高性能-第3版》&…

深度学习(生成式模型)——ADM:Diffusion Models Beat GANs on Image Synthesis

文章目录 前言基础模型结构UNet结构Timestep Embedding关于为什么需要timestep embedding global attention layer 如何提升diffusion model生成图像的质量Classifier guidance实验结果 前言 在前几篇博文中,我们已经介绍了DDPM、DDIM、Classifier guidance等相关的…

【Scala】Scala中的一些基本数据类型的特性 列表、元组、构造器、单例对象、伴生类、伴生对象、抽象类与特质

列表 使用List(“”,“”,“”)去声明 sliding 和 groued表示迭代器 val iter List("Hadoop", "Spark", "Scala") sliding 2// sliding 和 groued 是有区别的while (iter.hasNext){println(iter.next())}for (elem <- iter){println(elem)}…

11 月 NFT 动态:交易量增长,Layer 2 格局剧变

作者&#xff1a;stellafootprint.network 11 月份&#xff0c;随着比特币和以太坊价格的提升&#xff0c;加密货币市场活动频繁&#xff0c;市场呈现进一步复苏的迹象。NFT 领域中&#xff0c;Blur 的交易量飙升&#xff0c;进一步巩固地位&#xff1b;Blast 的亮相&#xff…

数字图像处理(实践篇)二十二 使用opencv进行人脸、眼睛、嘴的检测

目录 1 xml文件 2 涉及的函数 3 实践 使用opencv进行人脸、眼睛、嘴的检测。 1 xml文件 方法① 下载 地址&#xff1a;https://github.com/opencv/opencv/tree/master/data/haarcascades 点击haarcascade_frontalface_default.xml文件 对着Raw右键&#xff0c;选择“链接…

centos7 安装nnDetection环境

nnunet和nnDetection更新导致默认安装可能会出现无法调用GPU的问题&#xff0c;这里稍微细致的记录下安装nnDetection环境过程。 1.创建虚拟环境&#xff1a; Please note that nndetection requires Python 3.8. Please use PyTorch 1.X version for now and not 2.0 这里要…

Linux——Web网站服务(二)

一、httpd服务的访问控制 1、客户机地址限制 通过Require配置项&#xff0c;可以根据主机的主机名或P地址来决定是否允许客户端访问。在 httpd服务器的主配置文件的<Location>&#xff0c;<Directory>、<Files>、<Limit>配置段中均可以使用Require配置…

【SpringBoot教程】SpringBoot 实现前后端分离的跨域访问(CORS)

作者简介&#xff1a;大家好&#xff0c;我是撸代码的羊驼&#xff0c;前阿里巴巴架构师&#xff0c;现某互联网公司CTO 联系v&#xff1a;sulny_ann&#xff08;17362204968&#xff09;&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗…

分布式锁实现方案 - Lock4j 使用

一、Lock4j 分布式锁工具 你是不是在使用分布式锁的时候&#xff0c;还在自己用 AOP 封装框架&#xff1f;那么 Lock4j 你可以考虑一下。 Lock4j 是一个分布式锁组件&#xff0c;其提供了多种不同的支持以满足不同性能和环境的需求。 立志打造一个简单但富有内涵的分布式锁组…

云贝教育 | 分享课:12月12日周二晚Oracle分享课享来了

Oracle 19c OCM分享课分享主题: Introduction to Clusterware 讲师&#xff1a;郭一军 直播分享平台&#xff1a;云贝教育视频号 时间&#xff1a;12月12日 周二晚 19: 30

物联网平台:网络调试助手+HTTP+上传数据到onenet

目录 onenet设备初始化 获取设备id和密钥key 尝试上传数据&#xff0c;实例 onenet设备初始化 获取设备id和密钥key 进入官网 中移坤灵 - 中国移动物联网开放平台 (10086.cn)https://open.iot.10086.cn/ 创建登录账号后&#xff0c;点击左上角的开发者中心 点击左上角的全…

ARP协议:地址解析协议

目录 引言 什么是ARP协议&#xff1f; ARP协议的工作原理 1. ARP请求 2. ARP应答 3. ARP缓存 ARP协议的应用 结语 其他链接 引言 在计算机网络中&#xff0c;地址解析协议&#xff08;ARP&#xff0c;Address Resolution Protocol&#xff09;扮演着重要的角色。ARP协议…