浏览代码

refactor: 删除无用脚本并添加性能分析模块

删除move_files.py、reorganize.py和evaluation.txt等无用脚本,添加performance_analyzer.py模块用于分析模型性能。更新README.md以包含性能指标说明和使用方法。
Hannnk 3 周之前
父节点
当前提交
3b4b918804

+ 16 - 0
Output/output_20250329_130338_results/performance_stats.txt

@@ -0,0 +1,16 @@
+检测性能统计报告
+==================================================
+
+详细统计信息:
+总样本数(CSV中唯一图像数): 34562
+检测到的目标总数: 644
+真实目标总数(TP): 177
+误报目标数(FP): 467
+真阴性数量(TN): 33918
+
+性能指标:
+准确率: 0.9865
+精确率: 0.2748
+召回率: 1.0000
+F1分数: 0.4312
+误报率(虚警率): 0.0136

+ 16 - 0
Output/output_20250329_140816_results/performance_stats.txt

@@ -0,0 +1,16 @@
+检测性能统计报告
+==================================================
+
+详细统计信息:
+总样本数(CSV中唯一图像数): 31086
+检测到的目标总数: 361
+真实目标总数(TP): 196
+误报目标数(FP): 165
+真阴性数量(TN): 30725
+
+性能指标:
+准确率: 0.9947
+精确率: 0.5429
+召回率: 1.0000
+F1分数: 0.7038
+误报率(虚警率): 0.0053

+ 62 - 1
README.md

@@ -108,4 +108,65 @@ pytest --cov=src tests/
 3. 文档
    - 使用Google风格文档字符串
    - 保持README.md更新
-   - 重要功能添加使用示例
+   - 重要功能添加使用示例
+
+## 性能指标说明
+
+### 1. 基础统计指标
+
+- **总样本数**:CSV文件中所有唯一的图像文件数量
+- **检测到的目标总数**:模型检测到的所有目标数量
+- **真实目标总数(TP)**:确认的真实无人机目标数量
+- **误报目标数(FP)**:错误检测为非无人机目标的数量
+- **真阴性数量(TN)**:正确识别为非无人机目标的数量
+
+### 2. 性能评估指标
+
+- **准确率(Accuracy)**
+  - 计算公式:`(TP + TN) / (TP + FP + TN)`
+  - 说明:反映模型整体正确分类的能力,即正确预测的样本占总样本的比例
+  - 取值范围:0-1,越接近1表示模型整体性能越好
+
+- **精确率(Precision)**
+  - 计算公式:`TP / (TP + FP)`
+  - 说明:反映模型在预测为正样本(无人机)时的准确程度
+  - 取值范围:0-1,越接近1表示模型在预测无人机时越准确
+
+- **召回率(Recall)**
+  - 计算公式:`TP / (TP + FN)`
+  - 说明:反映模型发现所有真实无人机目标的能力
+  - 取值范围:0-1,越接近1表示模型发现真实无人机的能力越强
+
+- **F1分数(F1 Score)**
+  - 计算公式:`2 * (Precision * Recall) / (Precision + Recall)`
+  - 说明:精确率和召回率的调和平均数,用于平衡精确率和召回率
+  - 取值范围:0-1,越接近1表示模型在精确率和召回率之间取得更好的平衡
+
+- **误报率/虚警率(False Alarm Rate)**
+  - 计算公式:`FP / (TN + FP)`
+  - 说明:反映模型将非无人机目标错误识别为无人机的比例
+  - 取值范围:0-1,越接近0表示模型在避免误报方面表现越好
+
+## 使用方法
+
+1. 运行推理:
+```bash
+python src/core/inference.py
+```
+
+2. 分析性能:
+```bash
+python src/analysis/performance_analyzer.py
+```
+
+## 输出说明
+
+运行性能分析后,将在结果目录下生成`performance_stats.txt`文件,包含:
+1. 详细统计信息(总样本数、检测目标数等)
+2. 性能指标(准确率、精确率、召回率等)
+
+## 注意事项
+
+1. 确保模型文件路径正确
+2. 确保输入图像格式正确
+3. 性能分析前需要将确认的真实目标放入`targets_all_True`目录

+ 0 - 61
evaluation.txt

@@ -1,61 +0,0 @@
-阈值:0.7 
-模型: UAV-250321.onnx
-模型评估结果:
-真阳性(TP): 34
-假阳性(FP): 1
-真阴性(TN): 610
-假阴性(FN): 144
-误报率(FPR): 0.16%
-漏报率(FNR): 80.90%
-
-0.6
-模型评估结果:
-真阳性(TP): 68
-假阳性(FP): 1
-真阴性(TN): 610
-假阴性(FN): 110
-误报率(FPR): 0.16%
-漏报率(FNR): 61.80%
-
-阈值:0.5 
-模型: UAV-250321.onnx
-模型评估结果:
-真阳性(TP): 96
-假阳性(FP): 25
-真阴性(TN): 586
-假阴性(FN): 82
-误报率(FPR): 4.09%
-漏报率(FNR): 46.07%
-
-阈值:0.45
-模型: UAV-250321.onnx
-模型评估结果:
-真阳性(TP): 111
-假阳性(FP): 61
-真阴性(TN): 550
-假阴性(FN): 67
-误报率(FPR): 9.98%
-漏报率(FNR): 37.64%
-
-
-阈值:0.3
-模型: UAV-250321.onnx
-模型评估结果:
-真阳性(TP): 147
-假阳性(FP): 246
-真阴性(TN): 365
-假阴性(FN): 31
-误报率(FPR): 40.26%
-漏报率(FNR): 17.42%
-
-
-1. 分开复杂背景和简单背景
-2. 漏报和误报率的计算方式
-3. 响应时间,多久能画面当中测出无人机(响应时间)
-  + 白天、黄昏、多云、阴天
-  + 位置标定的方式
-  + 电机定位精度
-  + 告警
-  + 热成像版本
-  + 飞机型号、方向、远近、姿态 
-  + 垂直起降飞行

+ 0 - 21
move_files.py

@@ -1,21 +0,0 @@
-import os
-import shutil
-
-# 创建目标目录
-os.makedirs('data/false_positive', exist_ok=True)
-
-# 移动特征库文件
-if os.path.exists('false_positive_features.pkl'):
-    shutil.move('false_positive_features.pkl', 'data/false_positive/')
-    print('已移动特征库文件')
-
-# 移动误报样本
-if os.path.exists('false_positive'):
-    for item in os.listdir('false_positive'):
-        src = os.path.join('false_positive', item)
-        dst = os.path.join('data/false_positive', item)
-        if os.path.isfile(src):
-            shutil.move(src, dst)
-    print('已移动误报样本')
-
-print('文件移动完成!') 

+ 0 - 28
reorganize.py

@@ -1,28 +0,0 @@
-import os
-import shutil
-
-# 定义目录结构
-dirs = {
-    'src/core': ['inference.py', 'feature_extractor.py', 'image_validation.py', 'ali_image_validation.py'],
-    'src/utils': ['bbox_visualizer.py', 'detection_visualizer.py', 'split_dataset.py', 'update_labels.py'],
-    'src/analysis': ['hotspot_analyzer.py', 'report_generator.py', 'analysis_report.py'],
-    'data/models': ['UAV-250321.onnx'],
-    'data/false_positive': [],
-    'tests': [],
-    'outputs/archive': []
-}
-
-# 创建目录结构
-for dir_path in dirs.keys():
-    os.makedirs(dir_path, exist_ok=True)
-
-# 移动文件
-for target_dir, files in dirs.items():
-    for file in files:
-        if os.path.exists(file):
-            shutil.move(file, os.path.join(target_dir, file))
-            print(f'Moved {file} to {target_dir}/')
-        else:
-            print(f'Warning: {file} not found')
-
-print('Project reorganization completed!') 

+ 128 - 0
src/analysis/performance_analyzer.py

@@ -0,0 +1,128 @@
+import os
+import pandas as pd
+import numpy as np
+from typing import List, Dict
+import shutil
+
+class PerformanceAnalyzer:
+    def __init__(self, result_dir: str):
+        self.result_dir = result_dir
+        self.csv_path = os.path.join(result_dir, 'detection_report.csv')
+        self.targets_dir = os.path.join(result_dir, 'targets_all')
+        self.true_targets_dir = os.path.join(result_dir, 'targets_all_True')
+        
+        # 确保目录存在
+        os.makedirs(self.true_targets_dir, exist_ok=True)
+        
+    def analyze(self) -> Dict:
+        """分析检测性能"""
+        # 读取CSV文件
+        df = pd.read_csv(self.csv_path)
+        
+        # 获取所有检测到的目标
+        all_targets = set(os.listdir(self.targets_dir))
+        true_targets = set(os.listdir(self.true_targets_dir))
+        
+        # 获取总样本数(CSV中唯一的图像文件数)
+        total_samples = len(df['Image File'].unique())
+        
+        # 初始化统计
+        stats = {
+            'TP': 0,  # 真阳性
+            'FP': 0,  # 假阳性
+            'FN': 0,  # 假阴性
+            'TN': 0   # 真阴性
+        }
+        
+        # 计算真阳性(TP):targets_all_True文件夹中的所有文件
+        stats['TP'] = len(true_targets)
+        
+        # 计算假阳性(FP):在targets_all中但不在targets_all_True中的文件
+        stats['FP'] = len(all_targets - true_targets)
+        
+        # 计算真阴性(TN):总样本数减去TP和FP
+        stats['TN'] = total_samples - (stats['TP'] + stats['FP'])
+        
+        # 计算性能指标
+        total = stats['TP'] + stats['FP'] + stats['TN']
+        accuracy = (stats['TP'] + stats['TN']) / total if total > 0 else 0
+        precision = stats['TP'] / (stats['TP'] + stats['FP']) if (stats['TP'] + stats['FP']) > 0 else 0
+        recall = stats['TP'] / (stats['TP'] + stats['FN']) if (stats['TP'] + stats['FN']) > 0 else 0
+        f1_score = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0
+        # 计算误报率(虚警率):FP / (TN + FP)
+        false_alarm_rate = stats['FP'] / (stats['TN'] + stats['FP']) if (stats['TN'] + stats['FP']) > 0 else 0
+        
+        # 打印详细统计信息
+        print("\n详细统计信息:")
+        print(f"总样本数(CSV中唯一图像数): {total_samples}")
+        print(f"检测到的目标总数: {len(all_targets)}")
+        print(f"真实目标总数(TP): {len(true_targets)}")
+        print(f"误报目标数(FP): {len(all_targets - true_targets)}")
+        print(f"真阴性数量(TN): {stats['TN']}")
+        
+        # 保存统计结果到文件
+        stats_file = os.path.join(self.result_dir, 'performance_stats.txt')
+        with open(stats_file, 'w', encoding='utf-8') as f:
+            f.write("检测性能统计报告\n")
+            f.write("=" * 50 + "\n\n")
+            
+            f.write("详细统计信息:\n")
+            f.write(f"总样本数(CSV中唯一图像数): {total_samples}\n")
+            f.write(f"检测到的目标总数: {len(all_targets)}\n")
+            f.write(f"真实目标总数(TP): {len(true_targets)}\n")
+            f.write(f"误报目标数(FP): {len(all_targets - true_targets)}\n")
+            f.write(f"真阴性数量(TN): {stats['TN']}\n\n")
+            
+            f.write("性能指标:\n")
+            f.write(f"准确率: {accuracy:.4f}\n")
+            f.write(f"精确率: {precision:.4f}\n")
+            f.write(f"召回率: {recall:.4f}\n")
+            f.write(f"F1分数: {f1_score:.4f}\n")
+            f.write(f"误报率(虚警率): {false_alarm_rate:.4f}\n")
+        
+        print(f"\n统计结果已保存到: {stats_file}")
+        
+        return {
+            'stats': stats,
+            'metrics': {
+                'accuracy': accuracy,
+                'precision': precision,
+                'recall': recall,
+                'f1_score': f1_score,
+                'false_alarm_rate': false_alarm_rate
+            }
+        }
+    
+    def mark_true_targets(self, true_target_files: List[str]):
+        """标记真实目标"""
+        for target_file in true_target_files:
+            src = os.path.join(self.targets_dir, target_file)
+            dst = os.path.join(self.true_targets_dir, target_file)
+            if os.path.exists(src):
+                shutil.copy2(src, dst)
+                print(f'已标记真实目标: {target_file}')
+
+def main():
+    # 示例使用
+    result_dir = r"D:\PythonProject\Model\output_20250329_130338_results"
+    analyzer = PerformanceAnalyzer(result_dir)
+    
+    # 分析性能
+    results = analyzer.analyze()
+    
+    # 打印结果
+    print("\n检测性能统计:")
+    print(f"真阳性(TP): {results['stats']['TP']}")
+    print(f"假阳性(FP): {results['stats']['FP']}")
+    print(f"假阴性(FN): {results['stats']['FN']}")
+    print(f"真阴性(TN): {results['stats']['TN']}")
+    
+    print("\n性能指标:")
+    print(f"准确率: {results['metrics']['accuracy']:.4f}")
+    print(f"精确率: {results['metrics']['precision']:.4f}")
+    print(f"召回率: {results['metrics']['recall']:.4f}")
+    print(f"F1分数: {results['metrics']['f1_score']:.4f}")
+    print(f"误报率(虚警率): {results['metrics']['false_alarm_rate']:.4f}")
+
+if __name__ == '__main__':
+    main()