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

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 iaaia.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 bndboxlistdef 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文件中的filenameelem = tree.find('filename')elem.text = (str(id) + '.jpg')xmlroot = tree.getroot()# 修改增强后的xml文件中的pathelem = tree.find('path')if elem != None:elem.text = (saveroot + str(id) + '.jpg')index = 0for 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 + 1tree.write(os.path.join(saveroot, str(id + '.xml')))def mkdir(path):# 去除首位空格path = path.strip()# 去除尾部 \ 符号path = path.rstrip("\\")# 判断路径是否存在# 存在     True# 不存在   FalseisExists = os.path.exists(path)# 判断结果if not isExists:# 如果不存在则创建目录# 创建目录操作函数os.makedirs(path)print(path + ' 创建成功')return Trueelse:# 如果目录存在则不创建,并提示目录已存在print(path + ' 目录已存在')return Falseif __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 = 1mkdir(AUG_XML_DIR)AUG_IMG_DIR = "./AUG/JPEGImages/"  # 存储增强后的影像文件夹路径try:shutil.rmtree(AUG_IMG_DIR)except FileNotFoundError as e:a = 1mkdir(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 BBsiaa.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文件中的filenameelem = 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.sizeimg = 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 += 1if n_y1 == 1 and n_y2 == n_y1:n_y2 += 1if 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)# 存储变化后的XMLchange_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 randompath = './'  # 设置path为VOC2007文件夹即可,也就是当前文件夹
trainval_percent = 0.8  # 训练+验证占80%
train_percent = 0.75  # 训练集占训练+验证的75%,也就是0.8×0.75=0.6xmlfilepath = 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.mzph.cn/news/213691.shtml

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

相关文章

静态SOCKS5的未来发展趋势和新兴应用场景

随着网络技术的不断发展和进步,静态SOCKS5代理也在不断地完善和发展。未来,静态SOCKS5代理将会呈现以下发展趋势和新兴应用场景。 一、发展趋势 安全性更高:随着网络安全问题的日益突出,用户对代理服务器的安全性要求也越来越高…

【华为鸿蒙系统学习】- HarmonyOS4.0开发|自学篇

​ 🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 💫个人格言:"没有罗马,那就自己创造罗马~" 目录 HarmonyOS 4.0 技术介绍: HarmonyOS三大特征: 1.实现硬件互助&#…

Appium 并行测试多个设备

一、前置说明 在自动化测试中,经常需要验证多台设备的兼容性,Appium可以用同一套测试运例并行测试多个设备,以达到验证兼容性的目的。 解决思路: 查找已连接的所有设备;为每台设备启动相应的Appium Server&#xff1b…

docker的资源控制:

docker的资源控制: 对容器的使用宿主机的资源进行限制 cpu 内存 磁盘i/0 docker使用linux自带的功能cgroup control grouos是linux内核系统提供的一种可以限制,记录,隔离进程所使用的物理资源 control grouos是linux内核系统提供的一种可…

HeartBeat监控Mysql状态

目录 一、概述 二、 安装部署 三、配置 四、启动服务 五、查看数据 一、概述 使用heartbeat可以实现在kibana界面对 Mysql 服务存活状态进行观察,如有必要,也可在服务宕机后立即向相关人员发送邮件通知 二、 安装部署 参照章节:监控组件…

每日一博 - 图解5种Cache策略

文章目录 概述读策略Cache AsideRead Through 写策略Write ThroughWrite AroundWrite Back 使用场景举例 概述 缓存是在系统中存储数据的临时存储器,用于提高访问速度。缓存策略定义了如何在缓存和主存之间管理数据 读策略 Read data from the system: &#x1f5…

vue3原生方法滚动列表

效果图 代码 import { ref, onBeforeUnmount, onUnmounted } from "vue"; //定时器初始化 let timer ref(null); //ref绑定初始化 let roll ref(null); //等同于vue2中的beforeDestroy onBeforeUnmount(() > {//清除定时器clearTimeout(timer.value); }); //等同…

AGI时代探导开发的智能化落地之路:中国企业低代码及无代码应用价值报告V6

今天分享的AGI系列深度研究报告:《AGI时代探导开发的智能化落地之路:中国企业低代码及无代码应用价值报告V6》。 (报告出品方:甲子光年智库) 报告共计:47页 点击添加图片描述(最多60个字&…

机器学习与人工智能:一场革命性的变革

机器学习与人工智能:一场革命性的变革 人工智能的概述什么是机器学习定义解释 数据集结构机器学习应用场景 人工智能的概述 1956年8月,在美国汉诺斯小镇宁静的达特茅斯学院中,约翰麦卡锡(John McCarthy)、马文闵斯基&…

数据链路层的作用和三个基本问题

目录 一. 数据链路层的作用二. 数据链路层解决的三个问题2.1 数据链路和帧2.2 三个基本问题(重要)2.2.1 封装成帧2.2.2 透明传输2.2.3 差错检测 \quad 一. 数据链路层的作用 \quad \quad \quad 光有链路不能传输数据, 还要加上协议, 这样才是数据链路 数据链路层的作用就是负责…

RHEL8_Linux虚拟数据优化器VDO

本章主要介绍虚拟化数据优化器 什么是虚拟数据优化器VDO创建VDO设备以节约硬盘空间 1.了解什么是VDO VDO全称是Virtual Data Optimize(虚拟数据优化),主要是为了节省硬盘空间。 现在假设有两个文件file1和 file2,大小都是10G。file1和 fil…

.NET 材料检测系统崩溃分析

Windbg 分析 1. 到底是哪里的崩溃 一直跟踪我这个系列的朋友应该知道分析崩溃第一个命令就是 !analyze -v ,让windbg帮我们自动化异常分析。 0:033> !analyze -v CONTEXT: (.ecxr) rax00000039cccff2d7 rbx00000039c85fc2b0 rcx00000039cccff2d8 rdx000000000…

洛谷P3807 Lucas定理

传送门: P3807 【模板】卢卡斯定理/Lucas 定理 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P3807题干: 给定整数n,m,p 的值,求出C(nm,n)​mod p 的值。 输入数据保证…

5分钟搞懂K8S Pod Terminating/Unknown故障排查

Kubernetes集群中的Pod有时候会进入Terminating或Unknown状态,本文列举了6种可能的原因,帮助我们排查这种现象。原文: K8s Troubleshooting — Pod in Terminating or Unknown Status 有时我们会看到K8S集群中的pod进入"Terminating"或"U…

每日一练【查找总价格为目标值的两个商品】

一、题目描述 题目链接 购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况,返回任一结果即可。 示例 1: 输入:price [3, 9, 12, 15], target 18 输出:[3,15] …

成都工业学院Web技术基础(WEB)实验一:HTML5排版标签使用

写在前面 1、基于2022级计算机大类实验指导书 2、代码仅提供参考,前端变化比较大,按照要求,只能做到像,不能做到一模一样 3、图片和文字仅为示例,需要自行替换 4、如果代码不满足你的要求,请寻求其他的…

Gemini与GPT-4的巅峰对决:AI界的双壁之战

随着人工智能技术的飞速发展,AI领域的竞争越来越激烈。在这个充满挑战与机遇的时代,两个备受瞩目的AI巨头——Gemini Pro和GPT-4,成为了人们关注的焦点。这两者都以其强大的功能和卓越的性能,引领着AI领域的发展潮流。本文将详细介…

MyBatisX插件

MyBatisX插件 MyBatis-Plus为我们提供了强大的mapper和service模板,能够大大的提高开发效率。 但是在真正开发过程中,MyBatis-Plus并不能为我们解决所有问题,例如一些复杂的SQL,多表联查,我们就需要自己去编写代码和SQ…

connection error;reply-code=503;unknown exchange type ‘x-delayed-message‘

错误原因 这个错误表明你的 RabbitMQ 服务器不认识交换机类型 “x-delayed-message”,这通常是因为你的 RabbitMQ 服务器没有启用 rabbitmq_delayed_message_exchange 插件,或者插件版本与你的 RabbitMQ 服务器不兼容。 解决方法 启用 RabbitMQ 延迟队…

JAVA安全之Spring参数绑定漏洞CVE-2022-22965

前言 在介绍这个漏洞前,介绍下在spring下的参数绑定 在Spring框架中,参数绑定是一种常见的操作,用于将HTTP请求的参数值绑定到Controller方法的参数上。下面是一些示例,展示了如何在Spring中进行参数绑定: 示例1&am…