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代理将会呈现以下发展趋势和新兴应用场景。 一、发展趋势 安全性更高:随着网络安全问题的日益突出,用户对代理服务器的安全性要求也越来越高…

AcWing 3425:小白鼠排队 ← 北京大学考研机试题

【题目来源】https://www.acwing.com/problem/content/3428/【题目描述】 N 只小白鼠,每只鼠头上戴着一顶有颜色的帽子。 现在称出每只白鼠的重量,要求按照白鼠重量从大到小的顺序输出它们头上帽子的颜色。 帽子的颜色用 red,blue 等字符串来…

c#下载微信跟支付宝交易账单

下载微信交易账单 //账单日期只能下载前一天的string datetime DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd");string body "";string URL "/v3/bill/fundflowbill" "?bill_date" datetime;//生成签名认证var auth BuildAu…

nodejs 异步函数加 await 和不加 await 的区别

在 nodejs 中,异步函数加上 await 和不加 await 的区别在于函数的返回值。 当一个异步函数加上 await 时,它会暂停当前函数的执行,直到异步操作完成并返回结果。这意味着可以直接使用异步操作的结果,而不需要使用 .then() 方法或…

什么是私有云和私有云计算?

私有云也被称为本地云架构,部署在企业的内部数据中心。如今,越来越多的提供商提供自己的私有云服务,以增强甚至取代企业自己的私有云环境。 美国国家标准与技术研究所 (NIST) 对私有云的定义是:“云基础架构为单一组织置备并为其…

【华为鸿蒙系统学习】- 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内核系统提供的一种可…

CSP-202309-2 坐标变换(其二)(模拟,c++,vector建二叉树)

计算机软件能力认证考试系统 问题描述 试题编号:202309-3试题名称:梯度求解时间限制:1.0s内存限制:512.0MB问题描述: 背景 西西艾弗岛运营公司近期在大力推广智能化市政管理系统。这套系统是由西西艾弗岛信息中心研发…

DAPP开发【11】IPFS星际文件管理系统【简介,实践看12】

IPFS(InterPlanetary File System)是一个点对点的分布式文件系统,旨在创建一个更快速、更安全和更开放的 Web。它不同于传统的 HTTP 协议,因为它不需要使用一个固定的地址来访问文件,而是通过一个基于内容寻址的系统&a…

HeartBeat监控Mysql状态

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

S32K324 UDS Bootloader开发-下位机篇-App软件开发

文章目录 前言ld文件修改增加编译文件CAN发送与接收发送接收函数调用UDS协议增加校验算法Hex文件合并总结前言 本文参考NXP官网的S32K3 Bootloader,移植实现UDS刷写功能。本文是APP软件的修改 本文参考NXP官网的S32K324 UBL,其中有一些Bug,也有一些和上位机不兼容的地方,在本…

每日一博 - 图解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 的值。 输入数据保证…