使用YOLO系列txt目标检测标签的滑窗切割:批量处理图像和标签的实用工具
使用YOLO系列txt目标检测标签的滑窗切割:批量处理图像和标签的实用工具
- 使用YOLO的TXT目标检测标签的滑窗切割:批量处理图像和标签的实用工具
- 背景
- 1. 代码概述
- 2. 滑窗切割算法原理
- 滑窗切割步骤:
- 示例:
- 3. **代码实现**
- 1. **加载标签**
- 2. **切割标签**
- 3. **主函数**
- 4. **如何使用该工具**
- 4. **完整代码**
使用YOLO的TXT目标检测标签的滑窗切割:批量处理图像和标签的实用工具
背景
在计算机视觉领域,目标检测(Object Detection)是一个非常重要的任务。随着 YOLO(You Only Look Once)系列模型的普及,目标检测模型已经被广泛应用于各种实际场景中。对于目标检测任务,训练模型所需的标注数据至关重要。
当我们处理大规模图像数据集时,尤其是在图像的尺寸远大于模型输入尺寸时,往往需要使用 滑窗切割(Sliding Window)技术,将大图像分割成多个小块进行处理。这一过程不仅可以减小每次训练所需的计算资源,还能增强模型的鲁棒性。
本博客将介绍如何使用 YOLO 的TXT目标检测标签格式 对大图像进行滑窗切割,并确保标签的正确性。我们将逐步阐述该代码的工作原理、使用方法及其在目标检测中的实际意义。
1. 代码概述
该代码实现了对大图像及其对应标签的 滑窗切割,并确保切割后的标签正确地被裁剪并保存。它通过对图像和标签的逐块切割,将大图像分割成多个较小的图像块,同时调整标签的位置和大小,以符合新的图像尺寸。
主要步骤如下:
- 加载图像和标签:读取图片和标签文件,确保标签与图像对应。
- 滑窗切割:以给定的窗口大小和步长,对图像进行滑窗切割。
- 裁剪标签:对于每个切割窗口,检查标签是否位于窗口内,如果位于窗口内,调整标签坐标,并确保标签归一化。
- 保存切割后的图像和标签:将切割后的图像和标签保存到新的文件夹中。
2. 滑窗切割算法原理
滑窗切割是计算机视觉中常用的技术,通常用于:
- 大图像分块:当图像尺寸过大时,模型输入尺寸无法处理整个图像,可以将其切割成小块进行逐块处理。
- 多尺度检测:不同尺度的物体需要不同大小的窗口来检测。通过滑窗切割,能够在多个尺度上执行目标检测任务。
滑窗切割步骤:
-
指定窗口大小和步长:窗口大小和步长决定了滑窗的密集程度。步长越小,生成的窗口越多,计算量越大。窗口大小决定了每个块的输入尺寸。
-
标签裁剪:标签的裁剪是根据目标与滑窗的交集来进行的。每个标签会被裁剪到窗口内,并且坐标会被重新归一化到窗口的尺寸。
示例:
- 窗口大小:640x640像素。
- 横向步长:301像素。
- 纵向步长:180像素。
对于每个标签,代码会检查它是否位于当前滑窗内,如果是,标签的位置和尺寸会被重新计算并保存。
3. 代码实现
1. 加载标签
def load_labels(label_file):"""加载YOLO的标签文件"""labels = []with open(label_file, 'r') as f:for line in f:parts = line.strip().split()cls = int(parts[0]) # 类别x_center, y_center, w, h = map(float, parts[1:])labels.append((cls, x_center, y_center, w, h))return labels
这段代码用于读取每个标签文件,并将其转换为包含类别和坐标的格式,方便后续处理。
2. 切割标签
def save_cut_labels(window_x, window_y, window_size, img_width, img_height, labels):"""根据滑窗切割标签,并确保标签正确裁剪"""new_labels = []for cls, x_center, y_center, w, h in labels:# 将归一化坐标转换为像素坐标x_center_px = x_center * img_widthy_center_px = y_center * img_heightw_px = w * img_widthh_px = h * img_height# 计算标签与当前窗口的交集区域intersection_x1 = max(x_center_px - w_px / 2, window_x)intersection_y1 = max(y_center_px - h_px / 2, window_y)intersection_x2 = min(x_center_px + w_px / 2, window_x + window_size)intersection_y2 = min(y_center_px + h_px / 2, window_y + window_size)# 如果标签和窗口相交if intersection_x1 < intersection_x2 and intersection_y1 < intersection_y2:# 计算交集区域的宽高和中心坐标intersection_w = intersection_x2 - intersection_x1intersection_h = intersection_y2 - intersection_y1intersection_x_center = (intersection_x1 + intersection_x2) / 2intersection_y_center = (intersection_y1 + intersection_y2) / 2# 将交集区域的坐标归一化normalized_x_center = (intersection_x_center - window_x) / window_sizenormalized_y_center = (intersection_y_center - window_y) / window_sizenormalized_w = intersection_w / window_sizenormalized_h = intersection_h / window_size# 生成新的标签new_labels.append(f"{cls} {normalized_x_center} {normalized_y_center} {normalized_w} {normalized_h}")return new_labels
该函数根据当前窗口的位置,裁剪标签,并将裁剪后的标签归一化到当前窗口大小。
3. 主函数
def main():image_folder = 'images' # 输入图片文件夹label_folder = 'labels' # 输入标签文件夹output_image_folder = 'output_images'output_label_folder = 'output_labels'if not os.path.exists(output_image_folder):os.makedirs(output_image_folder)if not os.path.exists(output_label_folder):os.makedirs(output_label_folder)image_files = sorted(os.listdir(image_folder))label_files = sorted(os.listdir(label_folder))window_size = 640 # 滑窗大小step_x = 301 # 横向步长step_y = 180 # 纵向步长# 遍历所有图片和标签文件for image_file, label_file in zip(image_files, label_files):# 读取图片image_path = os.path.join(image_folder, image_file)image = cv2.imread(image_path)img_height, img_width, _ = image.shape# 读取对应的标签label_path = os.path.join(label_folder, label_file)labels = load_labels(label_path)# 计算横向和纵向可以切割的窗口数量num_windows_x = (img_width - window_size) // step_x + 1num_windows_y = (img_height - window_size) // step_y + 1# 遍历所有切割窗口for i in range(num_windows_x):for j in range(num_windows_y):window_x = i * step_xwindow_y = j * step_y# 获取当前窗口内的标签windowed_labels = save_cut_labels(window_x, window_y, window_size, img_width, img_height, labels)if windowed_labels: # 如果窗口内有标签# 保存切割后的图片windowed_image = image[window_y:window_y + window_size, window_x:window_x + window_size]output_image_path = os.path.join(output_image_folder, f"{os.path.splitext(image_file)[0]}_window_{i}_{j}.jpg")cv2.imwrite(output_image_path, windowed_image)# 保存切割后的标签output_label_path = os.path.join(output_label_folder, f"{os.path.splitext(label_file)[0]}_window_{i}_{j}.txt")with open(output_label_path, 'w') as f:for label in windowed_labels:f.write(label + '\n')
4. 如何使用该工具
-
准备工作:
- 将你的图片和标签放在
images/
和labels/
文件夹中。 - 确保标签格式为 YOLOv5 格式,即每行包含
class_id x_center y_center width height
(所有值均为归一化形式)。
- 将你的图片和标签放在
-
运行脚本:
- 运行上述代码,程序将自动读取图片和标签,进行滑窗切割,并将每个切割后的图像和标签保存到新的文件夹中。
-
输出结果:
- 切割后的图像会保存在
output_images/
文件夹中。 - 切割后的标签会保存在
output_labels/
文件夹中,标签内容与原标签一致,只是经过裁
- 切割后的图像会保存在
4. 完整代码
import os
import cv2def load_labels(label_path):"""加载YOLOv5标签文件"""labels = []with open(label_path, 'r') as f:for line in f.readlines():parts = line.strip().split()cls = int(parts[0]) # 类别x_center = float(parts[1]) # x中心y_center = float(parts[2]) # y中心w = float(parts[3]) # 宽度h = float(parts[4]) # 高度labels.append([cls, x_center, y_center, w, h])return labelsdef save_cut_labels(window_x, window_y, window_size, img_width, img_height, labels):"""根据滑窗切割标签,并确保标签正确裁剪"""new_labels = []for cls, x_center, y_center, w, h in labels:# 将归一化坐标转换为像素坐标x_center_px = x_center * img_widthy_center_px = y_center * img_heightw_px = w * img_widthh_px = h * img_height# 计算标签与当前窗口的交集区域intersection_x1 = max(x_center_px - w_px / 2, window_x)intersection_y1 = max(y_center_px - h_px / 2, window_y)intersection_x2 = min(x_center_px + w_px / 2, window_x + window_size)intersection_y2 = min(y_center_px + h_px / 2, window_y + window_size)# 如果标签和窗口相交if intersection_x1 < intersection_x2 and intersection_y1 < intersection_y2:# 计算交集区域的宽高和中心坐标intersection_w = intersection_x2 - intersection_x1intersection_h = intersection_y2 - intersection_y1intersection_x_center = (intersection_x1 + intersection_x2) / 2intersection_y_center = (intersection_y1 + intersection_y2) / 2# 将交集区域的坐标归一化normalized_x_center = (intersection_x_center - window_x) / window_sizenormalized_y_center = (intersection_y_center - window_y) / window_sizenormalized_w = intersection_w / window_sizenormalized_h = intersection_h / window_size# 生成新的标签new_labels.append(f"{cls} {normalized_x_center} {normalized_y_center} {normalized_w} {normalized_h}")# 如果没有标签,返回空列表return new_labelsdef main():image_folder = 'images' # 输入图片文件夹label_folder = 'labels' # 输入标签文件夹output_image_folder = 'output_images'output_label_folder = 'output_labels'if not os.path.exists(output_image_folder):os.makedirs(output_image_folder)if not os.path.exists(output_label_folder):os.makedirs(output_label_folder)image_files = sorted(os.listdir(image_folder))label_files = sorted(os.listdir(label_folder))window_size = 640 # 滑窗大小step_x = 301 # 横向步长step_y = 180 # 纵向步长# 遍历所有图片和标签文件for image_file, label_file in zip(image_files, label_files):# 读取图片image_path = os.path.join(image_folder, image_file)image = cv2.imread(image_path)img_height, img_width, _ = image.shape# 读取对应的标签label_path = os.path.join(label_folder, label_file)labels = load_labels(label_path)# 计算横向和纵向可以切割的窗口数量num_windows_x = (img_width - window_size) // step_x + 1num_windows_y = (img_height - window_size) // step_y + 1# 遍历所有切割窗口for i in range(num_windows_x):for j in range(num_windows_y):window_x = i * step_xwindow_y = j * step_y# 获取当前窗口内的标签windowed_labels = save_cut_labels(window_x, window_y, window_size, img_width, img_height, labels)# 如果标签列表为空,说明此窗口没有标签,跳过该窗口if not windowed_labels:continue# 保存切割后的图片windowed_image = image[window_y:window_y + window_size, window_x:window_x + window_size]output_image_path = os.path.join(output_image_folder, f"{os.path.splitext(image_file)[0]}_window_{i}_{j}.jpg")cv2.imwrite(output_image_path, windowed_image)# 保存切割后的标签output_label_path = os.path.join(output_label_folder, f"{os.path.splitext(label_file)[0]}_window_{i}_{j}.txt")with open(output_label_path, 'w') as f:for label in windowed_labels:f.write(label + '\n')if __name__ == "__main__":main()
相关文章:
使用YOLO系列txt目标检测标签的滑窗切割:批量处理图像和标签的实用工具
使用YOLO系列txt目标检测标签的滑窗切割:批量处理图像和标签的实用工具 使用YOLO的TXT目标检测标签的滑窗切割:批量处理图像和标签的实用工具背景1. 代码概述2. 滑窗切割算法原理滑窗切割步骤:示例: 3. **代码实现**1. **加载标签…...

架构10-可观测性
零、文章目录 架构10-可观测性 1、可观测性 (1)可观测性的背景 **历史沿革:**可观测性最初由匈牙利数学家鲁道夫卡尔曼提出,用于线性动态控制系统。后来,该概念被引入到计算机科学中。**现代意义:**在分…...

git管理Unity项目的正确方式
git管理Unity项目的正确打开方式 前言:对于刚开始git进行unity项目管理的时候,我采取的方式是全部文件上传,文件数量太多以及上传太大,我尝试过一下几个方法: 利用git的LFS大文件进行传方式,可行但比较麻…...

openssl使用哈希算法生成随机密钥
文章目录 一、openssl中随机数函数**OpenSSL 随机数函数概览**1. **核心随机数函数** **常用函数详解**1. RAND_bytes2. RAND_priv_bytes3. RAND_seed 和 RAND_add4. RAND_status **随机数生成器的熵池****常见用例****注意事项** 二、使用哈希算法生成随机的密钥 一、openssl中…...

将word里自带公式编辑器编辑的公式转换成用mathtype编辑的格式
文章目录 将word里自带公式编辑器编辑的公式转换成用mathtype编辑的格式MathType安装问题MathType30天试用延期MathPage.wll文件找不到问题 将word里自带公式编辑器编辑的公式转换成用mathtype编辑的格式 word自带公式编辑器编辑的公式格式: MathType编辑的格式&a…...

校园失物招领系统基于 SpringBoot:点亮校园归还遗失物之光
2系统开发环境 2.1vue技术 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。 [5] 与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第…...

dhcpd服务器的配置与管理(超详细!!!)
前提条件: (1)虚拟机能够联网(如果nat模式不能联网的看另一期) CentOS7 NAT模式不能联网-CSDN博客 (2)系统是Centos8,因为下载的dhcp-server软件包版本和Centos7不匹配,如果你能成…...
Qml之基本控件
一.Qml常用控件 1.Text(显示普通文本和富文本) 1.1显示普通文本: Window { visible: true width: 320 height: 240 title: qsTr("Hello World") Text { text: "Hello World!" font.family: "Helvetica" font.pointSize: 24 color:…...
【Java从入门到放弃 之 Stream API】
Java Stream API Stream API行为参数化传递代码Lambda表达式Lambda 表达式的语法方法引用 Lambda 表达式的实际应用集合操作并发编程 Lambda 表达式的注意事项总结 Stream API Java8提供了一个全新的API - Stream。引入这个Stream的主要目的,一个是可以支持更好的并…...
Ruby On Rails 笔记1——Rails 入门
突然想跟着官方文档把Ruby On Rails过一遍,把一些有用的记下来就可以一直看了,do它! https://guides.rubyonrails.org/v7.2/ 注:官网是英文文档,我自己翻译了一下,不确保完全准确,只供自己学习开发使用。 …...
高效开发 Python Web 应用:FastAPI 数据验证与响应体设计
高效开发 Python Web 应用:FastAPI 数据验证与响应体设计 目录 🧑💻 FastAPI 的数据验证系统与 Pydantic 模型📦 响应体与模型:定义响应数据的最佳实践🔄 响应模型与查询参数的结合:增强灵活…...

基于“开源 2+1 链动 O2O 商城小程序”的门店拉新策略与流程设计
摘要:在数字化商业浪潮席卷之下,实体门店面临着激烈的市场竞争,如何高效拉新成为关乎门店生存与发展的关键问题。本文聚焦于“开源 21 链动 O2O 商城小程序”,深入探讨结合多种手段的门店拉新策略及详细流程设计。通过剖析到店扫码…...
33.5 remote实战项目之设计prometheus数据源的结构
本节重点介绍 : 项目要求 通过remote read读取prometheus中的数据通过remote write向prometheus中写入数据 准备工作 新建项目 prome_remote_read_write设计prometheus 数据源的结构初始化 项目要求 通过remote read读取prometheus中的数据通过remote write向prometheus中写…...

微服务springboot详细解析(一)
目录 1.Spring概述 2.什么是SpringBoot? 3.第一个SpringBoot程序 4.配置参数优先级 5.springboot自动装配原理 6.SpringBootApplication&SpringApplication.run 7.ConfigurationProperties(prefix "") 8.Validated数据校验 29、聊聊该如何写一…...
深入探讨Go语言中的双向链表
简介 双向链表是链表家族中的一种高级结构,每个节点不仅指向下一个节点,还指向上一个节点。今天,我们将学习如何在Go语言中实现和操作这种灵活的数据结构。 双向链表的优缺点 优点: 可以从任一方向遍历链表,灵活性高…...

Fastapi + vue3 自动化测试平台---移动端App自动化篇
概述 好久写文章了,专注于新框架,新UI界面的实践,废话不多说,开搞 技术架构 后端: Fastapi Airtest multiprocessing 前端: 基于 Vue3、Vite、TypeScript、Pinia、Pinia持久化插件、Unocss 和 Elemen…...
ElasticSearch easy-es 聚合函数 group by 混合写法求Top N 词云 分词
1.将用户访问记录表数据同步到ES,并且分词,获取用户访问最多前十条词语。 Elasticsearch、Easy-es 快速入门 SearchAfterPage分页 若依前后端分离 Ruoyi-Vue SpringBoot 使用结巴分词器 <!-- 分词器--><dependency><groupId>com.hua…...

在 ASP.NET C# Web API 中实现 Serilog 以增强请求和响应的日志记录
介绍 日志记录是任何 Web 应用程序的关键方面。它有助于调试、性能监控和了解用户交互。在 ASP.NET C# 中,集成 Serilog 作为记录请求和响应(包括传入和传出的数据)的中间件可以显著提高 Web API 的可观察性和故障排除能力。 在过去的几周里&…...

2024年顶级小型语言模型前15名
本文,我们将深入了解2024年备受瞩目的十五款小型语言模型(SLMs),它们分别是Llama 3.1 8B、Gemma2、Qwen 2、Mistral Nemo、Phi-3.5等。这些SLMs以其精巧的体积和高效率著称,它们不需要依赖庞大的服务器资源,…...
精通 Python 网络安全(一)
前言 最近,Python 开始受到越来越多的关注,最新的 Python 更新添加了许多可用于执行关键任务的包。我们的主要目标是帮助您利用 Python 包来检测和利用漏洞,并解决网络挑战。 本书将首先带您了解与网络和安全相关的 Python 脚本和库。然后&…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...