目标检测数据集图片及标签同步裁剪
目录
前言
具体方法
使用介绍
完整代码
前言
在目标检测任务中,模型的训练依赖于大量高质量的标注数据。然而,获取足够多的标注数据集往往代价高昂,并且某些情况下,数据集中的样本分布不均衡,这会导致模型的泛化能力不足。为此,数据增强成为提升模型性能的常用方法之一。
在数据增强的各种方法中,裁剪是一种高效且常用的技术。通过对图片进行随机或特定区域的裁剪,能够生成更多的训练样本,提高模型对不同尺度和位置目标的鲁棒性。此外,裁剪还可以有效解决原始图片尺寸过大的问题,避免对训练性能造成影响。大尺寸图片会增加模型的计算开销,导致训练速度变慢、内存消耗增大。而通过裁剪,图片尺寸得以缩小,训练效率随之提升。
然而,裁剪不仅仅是简单地对图片进行操作,目标检测任务中,每个目标的边界框(标签)必须与图片裁剪过程同步更新,否则裁剪后的标签将失去准确性,影响模型的训练效果。本篇文章将重点介绍如何在进行目标检测数据集图片裁剪时,同时对目标的标签进行精确调整,确保裁剪后的图片和标签保持一致,从而构建高质量的增强数据集,助力模型的准确性与泛化能力提升。
具体方法
本文所使用的裁剪方式为图片的宽度和高度各自从中间切开,将一个图片分为左上,右上,左下,右下四个部分,其中保留含有标签的那部分图片,其余未含有标签的部分则不保留。
def crop_image(image, save_dir, name, suf, boxes):H, W, _ = image.shape# 左上区域if boxes[0] == 1:img_top_left = image[0:H // 2, 0:W // 2]save_path = os.path.join(save_dir, f"{name}_1{suf}")cv.imwrite(save_path, img_top_left)# 右上区域if boxes[1] == 1:img_top_right = image[0:H // 2, W // 2:W]save_path = os.path.join(save_dir, f"{name}_2{suf}")cv.imwrite(save_path, img_top_right)# 左下区域if boxes[2] == 1:img_bottom_left = image[H // 2:H, 0:W // 2]save_path = os.path.join(save_dir, f"{name}_3{suf}")cv.imwrite(save_path, img_bottom_left)# 右下区域if boxes[3] == 1:img_bottom_right = image[H // 2:H, W // 2:W]save_path = os.path.join(save_dir, f"{name}_4{suf}")cv.imwrite(save_path, img_bottom_right)
这部分为裁剪图片的函数定义,可以看到只保留含有标签的部分图像
def split_box(box, shape):W, H = shape[1], shape[0]n, xmin, ymin, xmax, ymax = boxregions = []# 左上区域if xmin < W / 2 and ymin < H / 2:xmin_new = max(0, xmin)ymin_new = max(0, ymin)xmax_new = min(W / 2, xmax)ymax_new = min(H / 2, ymax)regions.append((n, xmin_new, ymin_new, xmax_new, ymax_new, 'left_top'))# 右上区域if xmax > W / 2 and ymin < H / 2:xmin_new = max(W / 2, xmin) - W / 2ymin_new = max(0, ymin)xmax_new = min(W, xmax) - W / 2ymax_new = min(H / 2, ymax)regions.append((n, xmin_new, ymin_new, xmax_new, ymax_new, 'right_top'))# 左下区域if xmin < W / 2 and ymax > H / 2:xmin_new = max(0, xmin)ymin_new = max(H / 2, ymin) - H / 2xmax_new = min(W / 2, xmax)ymax_new = min(H, ymax) - H / 2regions.append((n, xmin_new, ymin_new, xmax_new, ymax_new, 'left_bottom'))# 右下区域if xmax > W / 2 and ymax > H / 2:xmin_new = max(W / 2, xmin) - W / 2ymin_new = max(H / 2, ymin) - H / 2xmax_new = min(W, xmax) - W / 2ymax_new = min(H, ymax) - H / 2regions.append((n, xmin_new, ymin_new, xmax_new, ymax_new, 'right_bottom'))normalized_regions = []for region in regions:box = region[1:5] # 获取 (xmin, ymin, xmax, ymax)normalized_box = xyxy2xywhn((W/2, H/2), box) # 归一化normalized_regions.append((region[0], *normalized_box, region[5])) # 保留标签return normalized_regions
这部分函数为标签裁剪,这里我将每个标签都完整的分割出来,避免因为标签在图片中间交界处而导致的标签发生丢失现象,同时每部分标签加入一定的标志,全部运行完之后返回这部分标志,经过处理后传入图片裁剪中就可以知道哪部分图片需要保留,避免了图片重复写入。
使用介绍
完整代码如下,修改其中路径部分即可使用,需要注意本文仅支持标签文件为yolo格式的txt文件,如果对于转换格式不熟悉的可以去看我下面这篇文章,里面有相关的介绍及方法
VOC格式转YOLO格式,xml文件转txt文件简单通用代码_voc转yolo-CSDN博客文章浏览阅读509次,点赞8次,收藏4次。很多人在进行目标检测训练时习惯将得到的数据标注为XML文件的VOC格式,或者在网上获取的数据集被标注为XML文件,但是不同的标注工具进行的标注会产生不同的标注xml文件,这里我写了一种通用的针对含有最基本图片和标注坐标信息的xml进行转换,在这里简单介绍并分享出来xml文件中最基本需要含有的信息为size,object下的name和bndbox,具体示例如下图(如果xml文件中没有size也就是图片的宽和高则需要单独对每个图片进行读取,感兴趣可以私聊,这里不展开介绍)_voc转yolohttps://blog.csdn.net/qq_67105081/article/details/140000193?spm=1001.2014.3001.5501转换过之后想要再次转换回voc格式的xml文件可以去查看我的下面这篇博客
yolov8等目标检测数据集YOLO格式转VOC格式,txt文件转xml文件,格式转换_yolo格式标签转voc格式-CSDN博客文章浏览阅读255次,点赞3次,收藏8次。YOLO格式的标注文件是归一化之后的数据,每一行有5个数值,从左到右分别是类别,中心坐标x,中心坐标y,宽度w,高度h,这些数据经过计算后即可得到xmin,ymin,xmax,ymax的值,将这些信息相应的填入xml文件中即可。还有一个关键部分是xml文件的构建,如下代码构建,变量确认后替换。_yolo格式标签转voc格式https://blog.csdn.net/qq_67105081/article/details/142915326?spm=1001.2014.3001.5501
完整代码
# 作者:CSDN-笑脸惹桃花 https://blog.csdn.net/qq_67105081?type=blog
# github:peng-xiaobai https://github.com/peng-xiaobai/Data-Augmentor
import os
import numpy as np
import cv2 as cvdef GetFileList(dir):l = []files = os.listdir(dir)for file in files:if file.endswith(('.png', '.jpg', '.jpeg', '.bmp', '.tif')):l.append(os.path.join(dir, file))return ldef xywhn2xyxy(x, w, h):y = np.copy(x) if isinstance(x, np.ndarray) else x.copy() if hasattr(x, 'copy') else xy[0] = w * (x[0] - 0.5 * x[2])y[1] = h * (x[1] - 0.5 * x[3])y[2] = w * (x[0] + 0.5 * x[2])y[3] = h * (x[1] + 0.5 * x[3])return ydef xyxy2xywhn(size, box):x_center = (box[0] + box[2]) / 2.0y_center = (box[1] + box[3]) / 2.0w = box[2] - box[0]h = box[3] - box[1]x = x_center / size[0]y = y_center / size[1]w = w / size[0]h = h / size[1]return x, y, w, hdef crop_image(image, save_dir, name, suf, boxes):H, W, _ = image.shape# 左上区域if boxes[0] == 1:img_top_left = image[0:H // 2, 0:W // 2]save_path = os.path.join(save_dir, f"{name}_1{suf}")cv.imwrite(save_path, img_top_left)# 右上区域if boxes[1] == 1:img_top_right = image[0:H // 2, W // 2:W]save_path = os.path.join(save_dir, f"{name}_2{suf}")cv.imwrite(save_path, img_top_right)# 左下区域if boxes[2] == 1:img_bottom_left = image[H // 2:H, 0:W // 2]save_path = os.path.join(save_dir, f"{name}_3{suf}")cv.imwrite(save_path, img_bottom_left)# 右下区域if boxes[3] == 1:img_bottom_right = image[H // 2:H, W // 2:W]save_path = os.path.join(save_dir, f"{name}_4{suf}")cv.imwrite(save_path, img_bottom_right)def split_box(box, shape):W, H = shape[1], shape[0]n, xmin, ymin, xmax, ymax = boxregions = []# 左上区域if xmin < W / 2 and ymin < H / 2:xmin_new = max(0, xmin)ymin_new = max(0, ymin)xmax_new = min(W / 2, xmax)ymax_new = min(H / 2, ymax)regions.append((n, xmin_new, ymin_new, xmax_new, ymax_new, 'left_top'))# 右上区域if xmax > W / 2 and ymin < H / 2:xmin_new = max(W / 2, xmin) - W / 2ymin_new = max(0, ymin)xmax_new = min(W, xmax) - W / 2ymax_new = min(H / 2, ymax)regions.append((n, xmin_new, ymin_new, xmax_new, ymax_new, 'right_top'))# 左下区域if xmin < W / 2 and ymax > H / 2:xmin_new = max(0, xmin)ymin_new = max(H / 2, ymin) - H / 2xmax_new = min(W / 2, xmax)ymax_new = min(H, ymax) - H / 2regions.append((n, xmin_new, ymin_new, xmax_new, ymax_new, 'left_bottom'))# 右下区域if xmax > W / 2 and ymax > H / 2:xmin_new = max(W / 2, xmin) - W / 2ymin_new = max(H / 2, ymin) - H / 2xmax_new = min(W, xmax) - W / 2ymax_new = min(H, ymax) - H / 2regions.append((n, xmin_new, ymin_new, xmax_new, ymax_new, 'right_bottom'))normalized_regions = []for region in regions:box = region[1:5] # 获取 (xmin, ymin, xmax, ymax)normalized_box = xyxy2xywhn((W/2, H/2), box) # 归一化normalized_regions.append((region[0], *normalized_box, region[5])) # 保留标签return normalized_regionsdef save_boxes(label_path, boxes):# 先获取标注文件的基本路径和扩展名base_label_path, ext = os.path.splitext(label_path)for box in boxes:# 获取区域标识(左上、右上、左下、右下)region = box[5]if region == 'left_top':suffix = '_1'elif region == 'right_top':suffix = '_2'elif region == 'left_bottom':suffix = '_3'elif region == 'right_bottom':suffix = '_4'else:continue # 如果区域标识不在预期范围内,跳过specific_label_path = f"{base_label_path}{suffix}{ext}"with open(specific_label_path, 'a') as f:f.write(f"{int(box[0])} " + " ".join(map(str, box[1:5])) + '\n')fileDir = r"E:\peanut_data\j" # 原图片路径
label_path = r"E:\peanut_data\txt" # 原label的路径
list1 = GetFileList(fileDir)image_save_path_head = r"E:\peanut_data\j1" # 分割后有标注图片储存路径
label_save_path_head = r"E:\peanut_data\txt1" # 标签储存路径if not os.path.exists(image_save_path_head):os.makedirs(image_save_path_head)
if not os.path.exists(label_save_path_head):os.makedirs(label_save_path_head)for i in list1:l = [0, 0, 0, 0]img = cv.imread(i)shape = img.shapeseq = 1name, suf = os.path.splitext(os.path.basename(i))labelname = os.path.join(label_path, name) + '.txt' # 找到对应图片的labelpos = []with open(labelname, 'r') as f1:#print(labelname)while True:lines = f1.readline()if lines == '\n':lines = Noneif not lines:breakp_tmp = [float(i) for i in lines.split()]pos.append(p_tmp)pos = np.array(pos)for k in pos:k[1:] = xywhn2xyxy(k[1:], shape[1], shape[0])regions = split_box(k, shape)labelname_new = os.path.join(label_save_path_head, name) + '.txt'save_boxes(labelname_new, regions)for region in regions:region_name = region[-1]if region_name == 'left_top':l[0] = 1print("The region is 'left_top'.")elif region_name == 'right_top':l[1] = 1print("The region is 'right_top'.")elif region_name == 'left_bottom':l[2] = 1print("The region is 'left_bottom'.")elif region_name == 'right_bottom':l[3] = 1print("The region is 'right_bottom'.")f1.close()crop_image(img, image_save_path_head, name, suf, l)
相关文章:
目标检测数据集图片及标签同步裁剪
目录 前言 具体方法 使用介绍 完整代码 前言 在目标检测任务中,模型的训练依赖于大量高质量的标注数据。然而,获取足够多的标注数据集往往代价高昂,并且某些情况下,数据集中的样本分布不均衡,这会导致模型的泛化能…...
【设计模式-简单工厂】
定义 简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,用于通过一个工厂类来创建某个产品类的实例,而不直接在客户端(调用方)中实例化对象。 这种模式的主要思想是将对象的创建逻辑集中在一个…...
多个版本的GCC(GNU编译器集合)可以同时安装并存
在Ubuntu系统中,多个版本的GCC(GNU编译器集合)可以同时安装并存。GCC是编译C、C以及其他编程语言程序的重要工具,不同的项目可能需要不同版本的GCC来确保兼容性。 为什么需要多个GCC版本 项目依赖:不同的软件项目可能…...
量子纠错--shor‘s 码
定理1 (量子纠错的条件) C是一组量子编码,P是映射到C上的投影算子。假设是一个算子元素描述的量子操作,那么基于量子编码C,存在一个能对抗描述的噪声的纠错操作R的充要条件是 对某个复元素厄米矩阵成立。 将算子元素称为导致的错误。如果这样…...
机器学习2
一、模型评估方法 1.1 K折交叉验证法(K-Fold Cross Validation) 1.1.1 定义 K折交叉验证法是一种用于评估模型性能的技术。它将数据集分为K个相等的子集,模型会轮流使用一个子集作为测试集,其余K-1个子集作为训练集。这个过程会…...
二分查找_ x 的平方根搜索插入位置山脉数组的峰顶索引
x 的平方根 在0~X中肯定有数的平方大于X,这是肯定的。我们需要从中找出一个数的平方最接近X且不大于X。0~X递增,它们的平方也是递增的,这样我们就可以用二分查找。 我们找出的数的平方是<或者恰好X,所以把0~X的平方分为<X …...
汽车建模用什么软件最好?汽车建模渲染建议!
在汽车建模和渲染领域,选择合适的软件对于实现精确的设计与高质量的视觉效果至关重要。那么不少的汽车设计师如何选择合适的建模软件与渲染方案呢,一起来简单看看吧! 一、汽车建模用软件推荐 1、Alias Autodesk旗下的Alias系列软件是汽车设…...
蘑菇分类识别数据集(猫脸码客 第222期)
蘑菇分类识别文本/图像数据集 蘑菇,作为一种广泛分布于全球的真菌,隶属于伞菌目伞菌亚门蘑菇科蘑菇属,拥有众多别名,如白蘑菇、洋蘑菇等。其不仅是世界上人工栽培最广泛、产量最高、消费量最大的食用菌品种之一,还在许…...
长短期记忆网络(Long Short-Term Memory,LSTM)
简介:个人学习分享,如有错误,欢迎批评指正。 长短期记忆网络(Long Short-Term Memory,简称LSTM)是一种特殊的循环神经网络(Recurrent Neural Network,简称RNN)架构&#…...
WHAT - 引入第三方组件或项目使用需要注意什么
目录 1. 功能匹配2. 社区与维护3. 兼容性4. 性能5. 易用性6. 安全性7. 授权和许可证8. 国际化支持9. 依赖性10. 未来维护 在前端开发过程中引入第三方组件或项目时,应该从以下几个方面进行考虑,以确保引入的组件能够有效解决问题并适合长期维护ÿ…...
原生鸿蒙操作系统HarmonyOS NEXT(HarmonyOS 5)正式发布
华为于10月22日19:00举办“原生鸿蒙之夜暨华为全场景新品发布会”。此次发布会推出全新的原生鸿蒙操作系统HarmonyOS NEXT(HarmonyOS 5)以及nova 13、WATCH Ultimate、MatePad Pro等新品。 据介绍,此前已经发布过的鸿蒙系统,由于系…...
WindTerm配置快捷键Ctrl+C和Ctrl+V
WindTerm配置快捷键CtrlC和CtrlV 平时使用ssh和sftp连接的时候,经常使用windterm, 但是windterm里面找不到相关的快捷键设置, 因为操作习惯,想把CtrlC和CtrlV分别配置为复制和粘贴,其他的快捷键操作可以按照该方法进…...
AOP学习
corol调用serverce不在是直接调用的是调用底层代理对象,由代理对象统一帮我们处理 AOP常见概念 通知类型 切面顺序...
【ubuntu18.04】ubuntu18.04升级cmake-3.29.8及还原系统自带cmake操作说明
参考链接 cmake升级、更新(ubuntu18.04)-CSDN博客 升级cmake操作说明 下载链接 Download CMake 下载版本 下载软件包 cmake-3.30.3-linux-x86_64.tar.gz 拷贝软件包到虚拟机 cp /var/run/vmblock-fuse/blockdir/jrY8KS/cmake-3.29.8-linux-x86_64…...
利用Docker搭建一套Mycat2+MySQL8一主一从、读写分离的最简单集群(保姆教程)
文章目录 1、Mycat介绍1.1、mycat简介1.2、mycat重要概念1.3、Mycat1.x与Mycat2功能对比1.2、主从复制原理 2、前提准备3、集群规划4、安装和配置mysql主从复制4.1、master节点安装mysql8容器4.2、slave节点安装mysql8容器4.2、配置主从复制4.3、测试主从复制配置 5、安装mycat…...
算法——python实现堆排序
文章目录 堆排序二叉树堆堆排序的过程:代码实现python中的heapq模块 堆排序 二叉树 关于二叉树的操作,其实核心就是 父节点找子节点,子节点找父节点 如果要将二叉树存储到队列中,就需要找出 父子节点之间的规律: 父…...
uniapp-components(封装组件)
<myitem></myitem> 在其他类里面这样调用。...
avue-crud组件,输入框回车搜索问题
crud组件,输入框回车搜索问题。 文档是并没有标注,实际上已经具备此功能。 需要在curd的option增加属性 searchEnter: true 即可实现输入内容后回车搜索。 avue的一些踩坑记录 - 前端小小菜 - 博客园...
STM32F407ZGT6定时器相关测试
结论: 20us以下的IO翻转操作,存在误差输出比较定时器使能与禁用功能正常输入捕获定时器使能与禁用功能正常单通道输出比较、输入捕获均正常多通道输出比较波形无干扰,但仍是存在20us以下的IO翻转操作存在误差多通道输入捕获正常 一、单一通…...
群晖通过 Docker 安装 GitLab
Docker 配置容器步骤都是大同小异的,可以参考: 群晖通过 Docker 安装 Gitea-CSDN博客 1. 在 Docker 文件夹中创建 GitLab,并创建子文件夹 2. 设置权限 3. 打开 Docker 应用,并在注册表搜索 gitlab-ce 4. 选择 gitlab-ce 映像运行…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
