计算DOTA文件的IOU

背景

在目标检测任务中,评估不同对象之间的重叠情况是至关重要的,而IOU(Intersection Over Union)是衡量这种重叠程度的重要指标。本文将介绍如何编写一个Python脚本,通过并行化处理DOTA格式的标注文件,统计同类别对象之间的IOU超过某个阈值的对数。

代码功能

本文代码的核心功能包括:

  1. 解析DOTA格式标注文件,提取对象类别和多边形坐标。
  2. 计算同类对象之间的IOU,并统计超过设定阈值的情况。
  3. 使用多进程并行化处理,提高对大规模数据的处理效率。
  4. 将最终的结果保存为CSV格式,方便后续分析。

完整代码

import os
import logging
from shapely.geometry import Polygon
import numpy as np
from itertools import combinations
from concurrent.futures import ProcessPoolExecutor, as_completed
import argparse
import pandas as pd# 配置日志
logging.basicConfig(level=logging.INFO,format='%(asctime)s [%(levelname)s] %(message)s',handlers=[logging.StreamHandler()]
)def parse_args():"""解析命令行参数。"""parser = argparse.ArgumentParser(description='进行标注文件的IOU分析,统计同类别对象之间的重叠数量。')parser.add_argument('--anno_folder', type=str, required=True, help='标注文件夹路径')parser.add_argument('--output_csv', type=str, default='iou_overlap_results.csv', help='输出CSV文件路径')parser.add_argument('--iou_threshold', type=float, default=0.01, help='IOU阈值,超过此值视为重叠')parser.add_argument('--num_workers', type=int, default=None, help='并行处理的进程数,默认为CPU核心数')parser.add_argument('--by_class', action='store_true', help='是否按类别统计重叠数量')return parser.parse_args()def parse_annotation_file(file_path, class_map=None):"""解析标注文件,提取对象的类别和多边形坐标。参数:file_path (str): 标注文件的路径。class_map (set, optional): 需要筛选的类别集合。默认为None,表示不筛选。返回:list of tuples: 每个元组包含类别和对应的Shapely多边形。"""objects = []try:with open(file_path, 'r') as file:for line_num, line in enumerate(file, 1):parts = line.strip().split()if len(parts) < 9:logging.warning(f"{file_path} 第{line_num}行格式不正确,跳过。")continuetry:# 假设坐标为前8个元素,类别为第9个元素coords = list(map(float, parts[:8]))dota_type = parts[8]if class_map and dota_type not in class_map:continue# 将坐标转换为Shapely多边形polygon = Polygon(np.array(coords).reshape(-1, 2))if not polygon.is_valid:logging.warning(f"{file_path} 第{line_num}行的多边形无效,跳过。")continueobjects.append((dota_type, polygon))except ValueError as ve:logging.error(f"{file_path} 第{line_num}行坐标转换错误: {ve}")except Exception as e:logging.error(f"读取文件 {file_path} 时发生错误: {e}")return objectsdef compute_iou(poly1, poly2):"""计算两个多边形的IOU。参数:poly1 (Polygon): 第一个多边形。poly2 (Polygon): 第二个多边形。返回:float: 两个多边形的IOU值。"""intersection = poly1.intersection(poly2).areaunion = poly1.union(poly2).areaif union == 0:return 0return intersection / uniondef analyze_file(file_path, by_class=False, class_map=None, iou_threshold=0.01):"""分析单个标注文件,统计同类别对象之间的IOU超过阈值的对数。参数:file_path (str): 标注文件的路径。by_class (bool, optional): 是否按类别统计。默认为False。class_map (set, optional): 需要筛选的类别集合。默认为None,表示所有类别。iou_threshold (float, optional): IOU阈值。默认为0.01。返回:list of dicts: 每个字典包含文件名、类别(如果按类别统计)和重叠对数。"""filename = os.path.basename(file_path)objects = parse_annotation_file(file_path, class_map)results = []if by_class:# 按类别分组class_dict = {}for dota_type, polygon in objects:class_dict.setdefault(dota_type, []).append(polygon)for dota_type, polygons in class_dict.items():overlap_count = 0num_objects = len(polygons)if num_objects < 2:# 少于两个对象,无需比较results.append({'filename': filename,'class': dota_type,'overlap_count': 0})continue# 使用组合生成所有可能的对象对for poly1, poly2 in combinations(polygons, 2):iou = compute_iou(poly1, poly2)if iou > iou_threshold:overlap_count += 1results.append({'filename': filename,'class': dota_type,'overlap_count': overlap_count})else:# 不按类别,统计所有对象之间的重叠polygons = [polygon for _, polygon in objects]overlap_count = 0num_objects = len(polygons)if num_objects >= 2:for poly1, poly2 in combinations(polygons, 2):iou = compute_iou(poly1, poly2)if iou > iou_threshold:overlap_count += 1results.append({'filename': filename,'overlap_count': overlap_count})return resultsdef main():args = parse_args()anno_folder = args.anno_folderoutput_csv = args.output_csviou_threshold = args.iou_thresholdnum_workers = args.num_workersby_class = args.by_class# 定义类别映射,如果需要筛选特定类别,可以在这里修改# 例如:class_map = {'embankment_dota', 'gravity_dota'}class_map = None  # 设置为None表示分析所有类别# class_map = {'embankment_dota'}  # 只分析 'embankment_dota' 类别# 获取所有标注文件all_files = [os.path.join(anno_folder, f) for f in os.listdir(anno_folder) if os.path.isfile(os.path.join(anno_folder, f))]logging.info(f"找到 {len(all_files)} 个标注文件。")# 准备并行处理results = []with ProcessPoolExecutor(max_workers=num_workers) as executor:future_to_file = {executor.submit(analyze_file, file_path, by_class, class_map, iou_threshold): file_path for file_path in all_files}for future in as_completed(future_to_file):file_path = future_to_file[future]try:file_results = future.result()results.extend(file_results)logging.info(f"完成分析文件: {os.path.basename(file_path)}")except Exception as exc:logging.error(f"分析文件 {os.path.basename(file_path)} 时发生异常: {exc}")# 将结果写入CSVif results:df = pd.DataFrame(results)df.to_csv(output_csv, index=False)logging.info(f"分析结果已保存到 {output_csv}")else:logging.warning("没有生成任何分析结果。")if __name__ == '__main__':main()

代码详解

接下来我们将详细解释该脚本的每个部分。

1. 配置日志和命令行参数解析

我们首先配置了日志系统,以便记录运行时的相关信息。日志系统可以帮助我们实时跟踪程序的执行状态和潜在问题。

import logginglogging.basicConfig(level=logging.INFO,format='%(asctime)s [%(levelname)s] %(message)s',handlers=[logging.StreamHandler()]
)

然后,定义了命令行参数解析函数 parse_args(),用于接收用户输入的文件夹路径、IOU阈值、输出文件路径、并行进程数等参数:

def parse_args():parser = argparse.ArgumentParser(description='进行标注文件的IOU分析,统计同类别对象之间的重叠数量。')parser.add_argument('--anno_folder', type=str, required=True, help='标注文件夹路径')parser.add_argument('--output_csv', type=str, default='iou_overlap_results.csv', help='输出CSV文件路径')parser.add_argument('--iou_threshold', type=float, default=0.01, help='IOU阈值,超过此值视为重叠')parser.add_argument('--num_workers', type=int, default=None, help='并行处理的进程数,默认为CPU核心数')parser.add_argument('--by_class', action='store_true', help='是否按类别统计重叠数量')return parser.parse_args()

2. 解析DOTA格式文件

DOTA标注文件包含多个对象的坐标和类别,通常以文本行的形式存储。我们通过 parse_annotation_file() 函数读取文件内容,并提取每个对象的类别和多边形坐标。

def parse_annotation_file(file_path, class_map=None):"""解析标注文件,提取对象的类别和多边形坐标。参数:file_path (str): 标注文件的路径。class_map (set, optional): 需要筛选的类别集合。默认为None,表示不筛选。返回:list of tuples: 每个元组包含类别和对应的Shapely多边形。"""objects = []try:with open(file_path, 'r') as file:for line_num, line in enumerate(file, 1):parts = line.strip().split()if len(parts) < 9:logging.warning(f"{file_path} 第{line_num}行格式不正确,跳过。")continuetry:# 假设坐标为前8个元素,类别为第9个元素coords = list(map(float, parts[:8]))dota_type = parts[8]if class_map and dota_type not in class_map:continue# 将坐标转换为Shapely多边形polygon = Polygon(np.array(coords).reshape(-1, 2))if not polygon.is_valid:logging.warning(f"{file_path} 第{line_num}行的多边形无效,跳过。")continueobjects.append((dota_type, polygon))except ValueError as ve:logging.error(f"{file_path} 第{line_num}行坐标转换错误: {ve}")except Exception as e:logging.error(f"读取文件 {file_path} 时发生错误: {e}")return objects

通过这个函数,我们可以将文件中的每个对象转化为一个Shapely库支持的多边形对象,方便后续计算IOU。

3. 计算IOU

IOU(交并比)的计算公式如下:

IOU = \frac{\text{Intersection Area}}{\text{Union Area}}

我们利用Shapely库中的 intersection()union() 方法来计算两个多边形的交集和并集面积。

def compute_iou(poly1, poly2):intersection = poly1.intersection(poly2).areaunion = poly1.union(poly2).areaif union == 0:return 0return intersection / union

4. 文件分析与并行化处理

analyze_file() 函数用于分析单个标注文件,统计同类别对象之间的IOU超过设定阈值的对数。支持按类别统计或整体统计。

def analyze_file(file_path, by_class=False, class_map=None, iou_threshold=0.01):"""分析单个标注文件,统计同类别对象之间的IOU超过阈值的对数。参数:file_path (str): 标注文件的路径。by_class (bool, optional): 是否按类别统计。默认为False。class_map (set, optional): 需要筛选的类别集合。默认为None,表示所有类别。iou_threshold (float, optional): IOU阈值。默认为0.01。返回:list of dicts: 每个字典包含文件名、类别(如果按类别统计)和重叠对数。"""filename = os.path.basename(file_path)objects = parse_annotation_file(file_path, class_map)results = []if by_class:# 按类别分组class_dict = {}for dota_type, polygon in objects:class_dict.setdefault(dota_type, []).append(polygon)for dota_type, polygons in class_dict.items():overlap_count = 0num_objects = len(polygons)if num_objects < 2:# 少于两个对象,无需比较results.append({'filename': filename,'class': dota_type,'overlap_count': 0})continue# 使用组合生成所有可能的对象对for poly1, poly2 in combinations(polygons, 2):iou = compute_iou(poly1, poly2)if iou > iou_threshold:overlap_count += 1results.append({'filename': filename,'class': dota_type,'overlap_count': overlap_count})else:# 不按类别,统计所有对象之间的重叠polygons = [polygon for _, polygon in objects]overlap_count = 0num_objects = len(polygons)if num_objects >= 2:for poly1, poly2 in combinations(polygons, 2):iou = compute_iou(poly1, poly2)if iou > iou_threshold:overlap_count += 1results.append({'filename': filename,'overlap_count': overlap_count})return results

推荐工具

在本文代码中,我们使用了以下Python库,它们在处理几何计算、多进程处理、文件解析等方面发挥了重要作用。如果你对这些库不太熟悉,可以通过以下链接获取更多信息和文档。

  1. Shapely - 进行几何对象的构造和操作,比如多边形的交集、并集等计算。

    • 官方文档:Shapely Documentation
    • 安装方法:pip install shapely
  2. NumPy - 科学计算库,用于处理数值数组。在这里,我们用它来将多边形的坐标转换为二维数组。

    • 官方文档:NumPy Documentation
    • 安装方法:pip install numpy
  3. itertools - Python标准库中的组合工具,用于生成多边形配对,计算它们之间的IOU。

    • 官方文档:itertools Documentation
  4. concurrent.futures - Python标准库中的并发工具,用于多进程并行处理标注文件。

    • 官方文档:concurrent.futures Documentation

结论

通过这篇博客,我们详细介绍了如何使用Python并行化处理DOTA格式的标注文件,并统计对象之间的IOU重叠情况。该脚本不仅具有较强的灵活性(支持按类别或整体统计),还充分利用多进程加速大数据量的处理。希望这篇博客能够帮助你在实际项目中更高效地处理和分析目标检测任务中的标注文件。

---

希望这篇博客对您有所帮助,如果您喜欢这篇文章,请点赞或关注,我会持续分享更多实用的 Python 技术内容!

---

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/882488.shtml

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

相关文章

JDK17下,使用SHA1算法报Certificates do not conform to algorithm constraints错误

JDK17从17.0.5开始&#xff0c;默认不再允许使用SHA1算法&#xff0c;如果引用的jar包或代码里使用了SHA1算法&#xff0c;会报以下错误。 Caused by: javax.net.ssl.SSLHandshakeException: Certificates do not conform to algorithm constraintsat java.base/sun.security.…

演示:基于WPF的DrawingVisual开发的高刷新率示波器

一、目的&#xff1a;分享一个基于WPF的DrawingVisual开发的高刷新率示波器 二、效果演示 特此说明&#xff1a;由于Gif录制工具帧率不够&#xff0c;渲染60帧用了4.6秒&#xff0c;平均帧率在12Hz左右&#xff0c;所以展示效果不好&#xff0c;想要看好些的效果可以看文章下面…

python中堆的用法

Python 堆&#xff08;Headp&#xff09; Python中堆是一种基于二叉树存储的数据结构。 主要应用场景&#xff1a; 对一个序列数据的操作基于排序的操作场景&#xff0c;例如序列数据基于最大值最小值进行的操作。 堆的数据结构&#xff1a; Python 中堆是一颗平衡二叉树&am…

每日OJ题_牛客_集合_排序_C++_Java

目录 牛客_集合_排序 题目解析 C代码 Java代码 牛客_集合_排序 集合_牛客题霸_牛客网 (nowcoder.com) 题目解析 笔试题可直接用set排序&#xff0c;面试可询问是否要手写排序函数&#xff0c;如果要手写排序&#xff0c;推荐写快排。 C代码 #include <iostream> …

Redis中String类型数据扩容原理分析

大家好&#xff0c;我是 V 哥。在 Java 中&#xff0c;我们有动态数组ArrayList&#xff0c;当插入新元素空间不足时&#xff0c;会进行扩容&#xff0c;好奇 Redis 中的 String 类型&#xff0c;C 语言又是怎样的实现策略&#xff0c;带着疑问&#xff0c;咱们来了解一下。 最…

SOD-YOLOv8 - 增强YOLOv8以在交通场景中检测小目标

原文链接:中英文对照阅读 摘要 计算机视觉中的目标检测对于交通管理,紧急响应,自动驾驶车辆和智能城市至关重要。 尽管在目标检测上有重大进步,但在远程摄像头获取的图像中检测小目标仍具有挑战性,这主要是由于它们的大小、与摄像头的距离、形状的多样性和杂乱的背景所造…

集合框架07:LinkedList使用

1.视频链接&#xff1a;13.14 LinkedList使用_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1zD4y1Q7Fw?spm_id_from333.788.videopod.episodes&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5&p142.LinkedList集合的增删改查操作 package com.yundait.Demo01;im…

【判断推理】逻辑论证之归因论证

2.1 归因论证概述 归因&#xff1a;指人们对 他人或自己行为的原因的推论过程。具体而言&#xff0c;就是观察者对他人的行为过程或自己的行为过程所进行的因果解释和推论。&#xff08;通俗而言&#xff0c;归因就是对已经发生的事实&#xff0c;在众多可能的原因中找出一个原…

【大模型问答测试】大模型问答测试脚本实现(第二版)——接入pytest与代码解耦

背景 接上一篇&#xff0c;【大模型问答测试】大模型问答测试脚本实现&#xff08;第一版&#xff09;。 在实现自动化的时候&#xff0c;原先把很多方法与request请求写在一块了&#xff0c;趁着目前实现接口数量较少&#xff0c;决定对代码进行解耦&#xff0c;并且清晰目录…

Qt获取磁盘信息+表格显示

效果展示 主要代码 获取磁盘相关数据 获取磁盘数据 Qt 没有提供相关的接口&#xff0c;需要使用 Windows API。接口解释如下&#xff1a; BOOL GetDiskFreeSpaceExW([in, optional] LPCWSTR lpDirectoryName,[out, optional] PULARGE_INTEGER lpFreeBytesAvailable…

推荐算法的学习

文章目录 前言1、模型1.1 从本领域模型的发展历史中学习1.1.1 在历史中总结发展规律和趋势1.1.2 发现模型之间的共性&#xff0c;方便记忆 1.2 从其他领域的发展中学习1.2.1 注意力机制1.2.2 残差网络 1.3 实践该怎么办&#xff1f; 2、 特征2.1 数据源的选择与建立2.2 特征构造…

Python生成随机密码脚本

引言 在数字化时代&#xff0c;密码已成为我们保护个人信息和数据安全的重要手段。然而&#xff0c;手动创建复杂且难以猜测的密码是一项既繁琐又容易出错的任务。幸运的是&#xff0c;Python编程语言为我们提供了一种高效且灵活的方法来自动生成随机密码。本文将详细介绍如何…

android app执行shell命令视频课程补充android 10/11适配-千里马android

(https://blog.csdn.net/learnframework/article/details/120103471) https://blog.csdn.net/learnframework/article/details/120103471 hi&#xff0c;有学员在学习跨进程通信专题课程时候&#xff0c;在实战app执行一个shell命令的项目时候&#xff0c;对课程本身的android …

【高等数学】无穷级数

0. 了解 无穷级数是指将无穷多个数按照一定的规律相加起来的表达式。 打个比方,就像你有一个无穷长的梯子,每一级梯子代表一个数。把这些数一个一个加起来,就形成了无穷级数。 比如常见的等比级数,这里是首项,是公比。如果,这个等比级数是收敛的,也就是它的和是一个有限…

Hackmyvm-Lookup

0x00信息收集 0x01端口扫描 PORT STATE SERVICE 22/tcp open ssh 80/tcp open http MAC Address: 08:00:27:0A:44:CF (Oracle VirtualBox virtual NIC)22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)80/tcp open http Apache ht…

数据权限的设计与实现系列13——前端筛选器组件Everright-filter集成多控制维度实现

‍ 数据权限多维度实现 上面的所有工作&#xff0c;实际都是基于业务实体属性这一数据权限控制维度展开的。 接下来&#xff0c;我们来设计与实现多维度&#xff0c;主要是用户组&#xff08;即角色&#xff09;、组织机构和用户。 ‍ 业务需求分析 用户控制维度 业务场景…

【MATLAB代码】指纹定位方法(KNN)介绍与例程(二维、轨迹定位),源代码可复制粘贴到MATLAB上运行

文章目录 指纹定位指纹定位技术简介基本原理位置估算公式1. 最近邻居算法(KNN)2. 加权最近邻居算法(W-KNN)3. 最小二乘法(LS)最终位置 P P P通过求解下面的方程获得:应用场景优缺点优点缺点总结源代码代码运行运行方法运行结果指纹定位 指纹定位技术简介 指纹定位是一…

SpringBoot日常:封装redission starter组件

文章目录 逻辑实现POM.xmlRedissionConfigRedissionPropertiesRedissionUtilsspring.factories 功能测试application.yml配置POM.xmlTestController运行测试 本章内容主要介绍如何通过封装相关的redission连接配置和工具类&#xff0c;最终完成一个通用的redission starter。并…

洛谷 P1038 [NOIP2003 提高组] 神经网络(拓扑排序)

题目传送门 感觉这道题需要我们高超的语文阅读水平…… 解题思路 我们发现要计算一个细胞的状态值&#xff08;&#xff09;&#xff0c;就需要先算出有边指向它的其他细胞对答案的贡献&#xff1b; 这是有拓扑序的&#xff0c;所以我们想到拓扑排序。 题目中说了&#xff0…

FastDFS单节点部署

FastDFS单节点部署 1、FastDFS入门1.1 分布式文件系统1.2 FastDFS 简介1.3 FastDFS 发展历史1.4 FastDFS 整体架构1.5 FastDFS 线上使用者 2、FastDFS 环境搭建2.1 FastDFS 安装2.1.1 安装前的准备2.1.2 安装 libfastcommon库2.1.3 安装 FastDFS 2.2FastDFS 配置2.2.1 去掉/etc…