当前位置: 首页 > news >正文

使用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. 代码概述

该代码实现了对大图像及其对应标签的 滑窗切割,并确保切割后的标签正确地被裁剪并保存。它通过对图像和标签的逐块切割,将大图像分割成多个较小的图像块,同时调整标签的位置和大小,以符合新的图像尺寸。

主要步骤如下:

  1. 加载图像和标签:读取图片和标签文件,确保标签与图像对应。
  2. 滑窗切割:以给定的窗口大小和步长,对图像进行滑窗切割。
  3. 裁剪标签:对于每个切割窗口,检查标签是否位于窗口内,如果位于窗口内,调整标签坐标,并确保标签归一化。
  4. 保存切割后的图像和标签:将切割后的图像和标签保存到新的文件夹中。

2. 滑窗切割算法原理

滑窗切割是计算机视觉中常用的技术,通常用于:

  • 大图像分块:当图像尺寸过大时,模型输入尺寸无法处理整个图像,可以将其切割成小块进行逐块处理。
  • 多尺度检测:不同尺度的物体需要不同大小的窗口来检测。通过滑窗切割,能够在多个尺度上执行目标检测任务。
滑窗切割步骤:
  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. 如何使用该工具

  1. 准备工作

    • 将你的图片和标签放在 images/labels/ 文件夹中。
    • 确保标签格式为 YOLOv5 格式,即每行包含 class_id x_center y_center width height(所有值均为归一化形式)。
  2. 运行脚本

    • 运行上述代码,程序将自动读取图片和标签,进行滑窗切割,并将每个切割后的图像和标签保存到新的文件夹中。
  3. 输出结果

    • 切割后的图像会保存在 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目标检测标签的滑窗切割&#xff1a;批量处理图像和标签的实用工具 使用YOLO的TXT目标检测标签的滑窗切割&#xff1a;批量处理图像和标签的实用工具背景1. 代码概述2. 滑窗切割算法原理滑窗切割步骤&#xff1a;示例&#xff1a; 3. **代码实现**1. **加载标签…...

架构10-可观测性

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

git管理Unity项目的正确方式

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

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自带公式编辑器编辑的公式格式&#xff1a; MathType编辑的格式&a…...

校园失物招领系统基于 SpringBoot:点亮校园归还遗失物之光

2系统开发环境 2.1vue技术 Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。 [5] 与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第…...

dhcpd服务器的配置与管理(超详细!!!)

前提条件&#xff1a; &#xff08;1&#xff09;虚拟机能够联网&#xff08;如果nat模式不能联网的看另一期&#xff09; CentOS7 NAT模式不能联网-CSDN博客 &#xff08;2&#xff09;系统是Centos8&#xff0c;因为下载的dhcp-server软件包版本和Centos7不匹配,如果你能成…...

Qml之基本控件

一.Qml常用控件 1.Text(显示普通文本和富文本) 1.1显示普通文本&#xff1a; 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的主要目的&#xff0c;一个是可以支持更好的并…...

Ruby On Rails 笔记1——Rails 入门

突然想跟着官方文档把Ruby On Rails过一遍&#xff0c;把一些有用的记下来就可以一直看了&#xff0c;do它! https://guides.rubyonrails.org/v7.2/ 注&#xff1a;官网是英文文档&#xff0c;我自己翻译了一下&#xff0c;不确保完全准确&#xff0c;只供自己学习开发使用。 …...

高效开发 Python Web 应用:FastAPI 数据验证与响应体设计

高效开发 Python Web 应用&#xff1a;FastAPI 数据验证与响应体设计 目录 &#x1f9d1;‍&#x1f4bb; FastAPI 的数据验证系统与 Pydantic 模型&#x1f4e6; 响应体与模型&#xff1a;定义响应数据的最佳实践&#x1f504; 响应模型与查询参数的结合&#xff1a;增强灵活…...

基于“开源 2+1 链动 O2O 商城小程序”的门店拉新策略与流程设计

摘要&#xff1a;在数字化商业浪潮席卷之下&#xff0c;实体门店面临着激烈的市场竞争&#xff0c;如何高效拉新成为关乎门店生存与发展的关键问题。本文聚焦于“开源 21 链动 O2O 商城小程序”&#xff0c;深入探讨结合多种手段的门店拉新策略及详细流程设计。通过剖析到店扫码…...

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&#xff1f; 3.第一个SpringBoot程序 4.配置参数优先级 5.springboot自动装配原理 6.SpringBootApplication&SpringApplication.run 7.ConfigurationProperties(prefix "") 8.Validated数据校验 29、聊聊该如何写一…...

深入探讨Go语言中的双向链表

简介 双向链表是链表家族中的一种高级结构&#xff0c;每个节点不仅指向下一个节点&#xff0c;还指向上一个节点。今天&#xff0c;我们将学习如何在Go语言中实现和操作这种灵活的数据结构。 双向链表的优缺点 优点&#xff1a; 可以从任一方向遍历链表&#xff0c;灵活性高…...

Fastapi + vue3 自动化测试平台---移动端App自动化篇

概述 好久写文章了&#xff0c;专注于新框架&#xff0c;新UI界面的实践&#xff0c;废话不多说&#xff0c;开搞 技术架构 后端&#xff1a; Fastapi Airtest multiprocessing 前端&#xff1a; 基于 Vue3、Vite、TypeScript、Pinia、Pinia持久化插件、Unocss 和 Elemen…...

ElasticSearch easy-es 聚合函数 group by 混合写法求Top N 词云 分词

1.将用户访问记录表数据同步到ES&#xff0c;并且分词&#xff0c;获取用户访问最多前十条词语。 Elasticsearch、Easy-es 快速入门 SearchAfterPage分页 若依前后端分离 Ruoyi-Vue SpringBoot 使用结巴分词器 <!-- 分词器--><dependency><groupId>com.hua…...

在 ASP.NET C# Web API 中实现 Serilog 以增强请求和响应的日志记录

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

2024年顶级小型语言模型前15名

本文&#xff0c;我们将深入了解2024年备受瞩目的十五款小型语言模型&#xff08;SLMs&#xff09;&#xff0c;它们分别是Llama 3.1 8B、Gemma2、Qwen 2、Mistral Nemo、Phi-3.5等。这些SLMs以其精巧的体积和高效率著称&#xff0c;它们不需要依赖庞大的服务器资源&#xff0c…...

精通 Python 网络安全(一)

前言 最近&#xff0c;Python 开始受到越来越多的关注&#xff0c;最新的 Python 更新添加了许多可用于执行关键任务的包。我们的主要目标是帮助您利用 Python 包来检测和利用漏洞&#xff0c;并解决网络挑战。 本书将首先带您了解与网络和安全相关的 Python 脚本和库。然后&…...

【python自动化二】pytest集成allure生成测试报告

pytest本身不会直接生成测试报告&#xff0c;而allure是一种生成测试报告的公共插件&#xff0c;可与多种测试框架配合生成测试报告&#xff0c;本文介绍下如何集成allure生成测试报告。 1.allure安装 1.安装allure-pytest 先安装allure的pytest插件&#xff0c;用于在pytes…...

网络版本的通讯录青春版(protobuf)

环境搭建 Protobuf 还常⽤于通讯协议、服务端数据交换场景。 因为我们主要目的只是为了学习protobuf&#xff0c;因此对于客户端&#xff0c;原本应该具备&#xff1a; 新增⼀个联系⼈ ◦ 删除⼀个联系⼈ ◦ 查询通讯录列表 ◦ 查询⼀个联系⼈的详细信息 这样四个功能。 …...

开源模型应用落地-安全合规篇-用户输入价值观判断(三)

一、前言 在深度合规功能中,对用户输入内容的价值观判断具有重要意义。这一功能不仅仅是对信息合法性和合规性的简单审核,更是对信息背后隐含的伦理道德和社会责任的深刻洞察。通过对价值观的判断,系统能够识别可能引发不当影响或冲突的内容,从而为用户提供更安全、更和谐的…...

神经网络入门实战:(十四)pytorch 官网内置的 CIFAR10 数据集,及其网络模型

(一) pytorch 官网内置的网络模型 图像处理&#xff1a; Models and pre-trained weights — Torchvision 0.20 documentation (二) CIFAR10数据集的分类网络模型&#xff08;仅前向传播&#xff09;&#xff1a; 下方的网络模型图片有误&#xff0c;已做修改&#xff0c;具…...

【Rust在WASM中实现pdf文件的生成】

Rust在WASM中实现pdf文件的生成 前言概念和依赖问题描述分步实现pdf转Blob生成URL两种方式利用localstorage传递参数处理图片Vec<u8>到pdf格式的Vec<u8>使用rust创建iframe显示pdf的Blob最后 前言 实现了一个通用的前端jpg转pdf的wasm,因为动态响应框架无法直接打…...

在MySQL中执行sum case when报错:SUM does not exist

1. 报错 在pgsql中能正常运行的一段SQL在MySQL中运行的时候报错了&#xff1a; SELECT DATE( hr.handle_time ) AS statsDate,SUM ( CASE WHEN hma.app_type IN ( 2, 5 ) THEN ch_money ELSE 0 END ) AS aliPayAmt,SUM ( CASE WHEN hma.app_type IN ( 1, 4 ) THEN ch_money EL…...

【openssl】相关指令

熟悉下相关概念 x509&#xff1a;证书标准pem和der&#xff1a;两种&#xff08;包括公私钥、证书签名请求、证书等内容的&#xff09;的格式&#xff0c;前者是文本形式&#xff0c;linux常用&#xff0c;后者是二进制形式&#xff0c;windows常用&#xff0c;仅仅是格式&…...

实例分割详解

实例分割详解 引言 实例分割是计算机视觉领域的一项复杂任务&#xff0c;它要求模型能够识别图像中不同类别的对象&#xff0c;并对每个单独的对象进行像素级别的分类。与语义分割不同的是&#xff0c;实例分割不仅要区分不同的类别&#xff0c;还要识别同一类别中的不同个体…...

D87【python 接口自动化学习】- pytest基础用法

day87 pytest运行参数 -m -k 学习日期&#xff1a;20241203 学习目标&#xff1a;pytest基础用法 -- pytest运行参数-m -k 学习笔记&#xff1a; 常用运行参数 pytest运行参数-m -k pytest -m 执行特定的测试用例&#xff0c;markers最好使用英文 [pytest] testpaths./te…...

浅谈MySQL路由

华子目录 mysql-router介绍下载mysql-router安装mysql-router实验 mysql-router介绍 mysql-router是一个对应用程序透明的InnoDB Cluster连接路由服务&#xff0c;提供负载均衡、应用连接故障转移和客户端路由利用路由器的连接路由特性&#xff0c;用户可以编写应用程序来连接到…...