优化红外图像性能,改回double存储

This commit is contained in:
Tian jianyong 2025-06-06 17:22:18 +08:00
parent eb3647a8f6
commit 3eab373226
4 changed files with 68 additions and 140 deletions

View File

@ -170,8 +170,8 @@ namespace ThreatSource.Tests.Simulation
//string[] missileTypes = ["lsgm_001"];
//string[] missileTypes = ["lbr_001"];
//string[] missileTypes = ["irc_001"];
//string[] missileTypes = ["itg_001"];
string[] missileTypes = ["mmw_001"];
string[] missileTypes = ["itg_001"];
//string[] missileTypes = ["mmw_001"];
//string[] missileTypes = ["tsm_001"];
string missileType = missileTypes[Random.Shared.Next(missileTypes.Length)];

View File

@ -9,7 +9,7 @@ namespace ThreatSource.Guidance
/// 该类存储红外图像的基本信息:
/// - 图像尺寸
/// - 像素物理大小
/// - 红外强度矩阵使用byte存储对数缩放
/// - 红外强度矩阵
/// 用于目标探测和识别
/// </remarks>
/// <remarks>
@ -17,79 +17,6 @@ namespace ThreatSource.Guidance
/// </remarks>
public class InfraredImage
{
// === 对数缩放参数 ===
/// <summary>
/// 强度值的最小值单位W/sr
/// 默认值1e-6 W/sr对应约273K0°C的物体在合理距离下的辐射强度
/// </summary>
private const double MIN_INTENSITY = 1e-6;
/// <summary>
/// 强度值的最大值单位W/sr
/// 默认值1e3 W/sr 对应高温物体在近距离的辐射强度上限
/// </summary>
private const double MAX_INTENSITY = 1e3;
/// <summary>
/// 最小强度值的对数log10
/// </summary>
private static readonly double MIN_LOG = Math.Log10(MIN_INTENSITY);
/// <summary>
/// 最大强度值的对数log10
/// </summary>
private static readonly double MAX_LOG = Math.Log10(MAX_INTENSITY);
/// <summary>
/// 对数范围
/// </summary>
private static readonly double LOG_RANGE = MAX_LOG - MIN_LOG;
/// <summary>
/// 预计算的强度值查找表,避免重复的对数运算
/// 索引0-255对应byte值值为对应的强度值W/sr
/// </summary>
private static readonly double[] INTENSITY_LOOKUP_TABLE = new double[256];
/// <summary>
/// 反向查找表强度值到byte的快速映射
/// 使用分段线性插值优化SetIntensity性能
/// </summary>
private static readonly double[] SORTED_INTENSITY_VALUES = new double[256];
/// <summary>
/// 静态构造函数,初始化查找表
/// </summary>
static InfraredImage()
{
// 预计算所有可能的byte值对应的强度值
for (int i = 0; i < 256; i++)
{
INTENSITY_LOOKUP_TABLE[i] = ComputeIntensityFromByte((byte)i);
SORTED_INTENSITY_VALUES[i] = INTENSITY_LOOKUP_TABLE[i];
}
}
/// <summary>
/// 计算byte值对应的强度值仅在静态构造函数中使用
/// </summary>
/// <param name="byteValue">byte值</param>
/// <returns>强度值单位W/sr</returns>
private static double ComputeIntensityFromByte(byte byteValue)
{
// 处理零值
if (byteValue == 0)
return 0.0;
// 反向对数缩放
double normalizedLog = (byteValue - 1) / 254.0;
double logIntensity = MIN_LOG + normalizedLog * LOG_RANGE;
return Math.Pow(10, logIntensity);
}
// === 基本属性 ===
/// <summary>
/// 图像宽度,单位:像素
/// </summary>
@ -106,10 +33,10 @@ namespace ThreatSource.Guidance
public double PixelSize { get; private set; }
/// <summary>
/// 红外强度矩阵使用byte存储对数缩放
/// 0 = 零强度1-255 = 对数缩放的强度值
/// 红外强度矩阵
/// 单位W/sr
/// </summary>
private byte[,] intensityData;
private double[,] intensityData;
/// <summary>
/// 图像中心视线方向
@ -135,7 +62,7 @@ namespace ThreatSource.Guidance
Height = height;
PixelSize = pixelSize;
LineOfSight = lineOfSight;
intensityData = new byte[height, width];
intensityData = new double[height, width];
SmokeCoverageMask = smokeCoverageMask ?? new bool[height, width];
}
@ -158,7 +85,7 @@ namespace ThreatSource.Guidance
// 重新分配强度数据数组(如果尺寸不匹配)
if (intensityData == null || intensityData.GetLength(0) != height || intensityData.GetLength(1) != width)
{
intensityData = new byte[height, width];
intensityData = new double[height, width];
}
else
{
@ -177,12 +104,12 @@ namespace ThreatSource.Guidance
{
if (row >= 0 && row < Height && col >= 0 && col < Width)
{
intensityData[row, col] = ConvertToByte(value);
intensityData[row, col] = value;
}
}
/// <summary>
/// 获取像素强度值(使用预计算查找表,高性能)
/// 获取像素强度值
/// </summary>
/// <param name="row">行索引</param>
/// <param name="col">列索引</param>
@ -191,74 +118,29 @@ namespace ThreatSource.Guidance
{
if (row >= 0 && row < Height && col >= 0 && col < Width)
{
return INTENSITY_LOOKUP_TABLE[intensityData[row, col]];
return intensityData[row, col];
}
return 0.0;
}
/// <summary>
/// 将强度值转换为byte简化版本高性能
/// </summary>
/// <param name="intensity">强度值单位W/sr</param>
/// <returns>缩放后的byte值</returns>
private static byte ConvertToByte(double intensity)
{
// 处理零值和负值
if (intensity <= 0)
return 0;
// 处理超出范围的值
if (intensity <= SORTED_INTENSITY_VALUES[1])
return 1;
if (intensity >= SORTED_INTENSITY_VALUES[255])
return 255;
// 使用简化的二分查找
return SimpleBinarySearch(intensity);
}
/// <summary>
/// 简化的二分查找,直接返回最接近的索引(移除距离计算)
/// </summary>
private static byte SimpleBinarySearch(double intensity)
{
int left = 1;
int right = 255;
// 标准二分查找
while (left < right)
{
int mid = (left + right) >> 1; // 使用位移代替除法
if (SORTED_INTENSITY_VALUES[mid] < intensity)
left = mid + 1;
else
right = mid;
}
return (byte)left;
}
/// <summary>
/// 获取内存占用信息(用于性能监控)
/// </summary>
/// <returns>内存占用字节数</returns>
public long GetMemoryUsage()
{
return sizeof(byte) * Width * Height; // byte数组
return sizeof(double) * Width * Height; // double数组
}
/// <summary>
/// 获取缩放参数信息(用于调试)
/// 获取图像信息(用于调试)
/// </summary>
/// <returns>缩放参数的调试信息</returns>
public string GetScalingInfo()
/// <returns>图像的调试信息</returns>
public string GetImageInfo()
{
return $"强度范围: [{MIN_INTENSITY:E3}, {MAX_INTENSITY:E3}] W/sr, " +
$"对数范围: [{MIN_LOG:F1}, {MAX_LOG:F1}], " +
$"相对精度: ~4.3%, " +
$"内存占用: {GetMemoryUsage():N0} bytes, " +
$"查找表: {INTENSITY_LOOKUP_TABLE.Length * sizeof(double):N0} bytes, " +
$"算法: 简化二分查找";
return $"图像尺寸: {Width}x{Height}, " +
$"像素大小: {PixelSize:E3} 弧度/像素, " +
$"内存占用: {GetMemoryUsage():N0} bytes";
}
}
}

View File

@ -32,7 +32,7 @@ dotnet test --filter "Category!=Performance"
6. 仅运行性能测试:
```bash
dotnet test --filter "Category=Performance"
dotnet test --filter "Category=Performance" --logger "console;verbosity=detailed"
```
7. 按类名排除:
@ -45,6 +45,11 @@ dotnet test --filter "FullyQualifiedName!~PerformanceTest"
dotnet test --filter "Category!=Performance&FullyQualifiedName!~Performance"
```
9. 运行 Release 模式下的性能测试:
```bash
dotnet test --configuration Release --filter "RunPerformanceTest" --verbosity minimal --nologo --logger "console;verbosity=normal"
```
### 测试报告
时间2025-05-16
测试目的:测试 Vector3D 作为类和结构体的性能差异

View File

@ -200,7 +200,7 @@ dotnet test --configuration Release --filter "RunPerformanceTest" --verbosity mi
- 优化效果:
- GC次数减少 60%,效果不错,但帧时间有所上升
- 是否采用:
- 是否采用:否,考虑提高了程序复杂度,提高了帧时间
=== 详细性能测试结果 ===
@ -284,7 +284,7 @@ dotnet test --configuration Release --filter "RunPerformanceTest" --verbosity mi
- 优化效果:
- 没有什么变化
- 是否采用:考虑将Intensity从对数运算改为查找表
- 是否采用:否,考虑提高了程序复杂度,提高了帧时间
=== 详细性能测试结果 ===
@ -407,4 +407,45 @@ Gen2 GC次数: 0 (0.0 次/秒)
帧时间表现: 优秀 ✅
内存管理: 优秀 ✅
GC频率: 优秀 ✅
【潜在问题分析】
【潜在问题分析】
### 第八次优化
时间2025-06-05 12:00:00
- 优化内容:
- 将 InfraredImage 的 Intensity 数组从 byte 改回 double去掉对数计算和查找表
- 优化效果:
- 帧时间减小GC次数增加但影响不大
- 是否采用:是
=== 详细性能测试结果 ===
【基本统计】
测试时长: 30.0 秒
总更新次数: 1416
平均FPS: 47.2
平均帧时间: 1.10 ms
【帧时间分析】
最小帧时间: 0.00 ms
最大帧时间: 19.10 ms
95%分位数: 5.03 ms
99%分位数: 7.89 ms
【内存使用分析】
起始内存: 2.93 MB
结束内存: 8.54 MB
峰值内存: 9.52 MB
内存增长: 5.61 MB
平均内存增长率: 0.19 MB/s
【垃圾回收分析】
Gen0 GC次数: 93 (3.1 次/秒)
Gen1 GC次数: 79 (2.6 次/秒)
Gen2 GC次数: 69 (2.3 次/秒)
总GC次数: 241
【性能评级】
帧时间表现: 优秀 ✅
内存管理: 优秀 ✅
GC频率: 一般 ⚠️
【潜在问题分析】
⚠️ Gen0 GC频率过高存在内存分配风暴