From c8240a075d841aacde550f70d46c4debe35b2dc2 Mon Sep 17 00:00:00 2001 From: Tian jianyong <11429339@qq.com> Date: Fri, 18 Apr 2025 18:58:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BA=A2=E5=A4=96=E7=9B=AE?= =?UTF-8?q?=E6=A0=87=E8=AF=86=E5=88=AB=E7=AE=97=E6=B3=95=E9=83=A8=E5=88=86?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E8=AE=B0=E5=BD=95=E7=90=86=E8=AE=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Guidance/InfraredImageGenerator.cs | 105 +++++++++++++++++- .../src/Guidance/InfraredTargetRecognizer.cs | 12 +- docs/project/theory.md | 63 +++++++++++ tools/ComprehensiveMissileSimulator.cs | 2 +- 4 files changed, 171 insertions(+), 11 deletions(-) diff --git a/ThreatSource/src/Guidance/InfraredImageGenerator.cs b/ThreatSource/src/Guidance/InfraredImageGenerator.cs index 22f7e3a..8477d35 100644 --- a/ThreatSource/src/Guidance/InfraredImageGenerator.cs +++ b/ThreatSource/src/Guidance/InfraredImageGenerator.cs @@ -53,7 +53,13 @@ namespace ThreatSource.Guidance /// /// 烟幕温度转换为强度的比例因子 (简化 T^4 关系) /// - private const double SMOKE_TEMPERATURE_FACTOR = 1e-11; + private const double SMOKE_TEMPERATURE_FACTOR = 1e-11; + + /// + /// 目标温度(K)转换为强度(W/sr)的比例因子 (基于简化 T^4) - **需要调整** + /// + private const double TEMPERATURE_TO_INTENSITY_FACTOR = 1e-6; // Initial guess 1e-11, changed to 1e-7, now 1e-6 + private const double KELVIN_OFFSET = 273.15; // 视线坐标系 private Vector3D forward; // 视线方向 @@ -359,6 +365,98 @@ namespace ThreatSource.Guidance double distance, double transmittance) { + // --- 开始: 使用 ThermalPattern 重构 --- + + // 获取目标当前的 3x3 热成像模式 (摄氏度) + double[,] thermalPattern = target.GetCurrentThermalPattern(); + if (thermalPattern == null) + { + Console.WriteLine($"警告: 目标 {target.Id} 未提供 ThermalPattern,无法生成基于模式的强度。"); + // Fallback or return? For now, let's just log and potentially result in a black target area. + // Alternatively, could fallback to the old Gaussian model here. + return; + } + + int halfLength = pixelLength / 2; + int halfWidth = pixelWidth / 2; + int pixelsSet = 0; + double maxSetIntensity = 0; + + // 确保映射的分母不为零 + double patternPixelWidth = Math.Max(1.0, (double)pixelWidth / 3.0); + double patternPixelHeight = Math.Max(1.0, (double)pixelLength / 3.0); // Assuming Length maps to Cols (Height of pattern grid) + + // 遍历目标在图像中的包围盒 + for (int dy = -halfWidth; dy <= halfWidth; dy++) + { + int y = centerY + dy; + if (y < 0 || y < 0 || y >= image.Height) continue; // Corrected y boundary check + + for (int dx = -halfLength; dx <= halfLength; dx++) + { + int x = centerX + dx; + if (x < 0 || x >= image.Width) continue; + + double finalIntensity; + double smokeIntensity = smokeIntensityLayer[y, x]; + + if (smokeIntensity >= 0) // 检查此像素是否被遮蔽烟幕覆盖 + { + finalIntensity = smokeIntensity; + } + else // 未被烟幕覆盖,基于 ThermalPattern 计算强度 + { + // 1. 将像素坐标映射到 3x3 热成像模式的索引 + // Map offset relative to top-left of bbox to [0, width/height-1] then divide + // Map dy from [-halfWidth, +halfWidth] to [0, pixelWidth-1] + // Map dx from [-halfLength, +halfLength] to [0, pixelLength-1] + int pixelYInBox = dy + halfWidth; + int pixelXInBox = dx + halfLength; + + // Map to pattern indices [0, 2] + int patternRow = (int)Math.Floor(pixelYInBox / patternPixelWidth); + int patternCol = (int)Math.Floor(pixelXInBox / patternPixelHeight); // X maps to Col + + // Clamp indices to [0, 2] + patternRow = Math.Max(0, Math.Min(2, patternRow)); + patternCol = Math.Max(0, Math.Min(2, patternCol)); + + // 2. 获取对应模式单元的温度 (摄氏度) + double tempCelsius = thermalPattern[patternRow, patternCol]; + + // 3. 转换为开尔文 + double tempKelvin = tempCelsius + KELVIN_OFFSET; + + // 4. 使用简化的 T^4 定律计算基础强度 (W/sr) + // Ensure tempKelvin is positive before power calculation + double pixelBaseIntensity = tempKelvin > 0 ? TEMPERATURE_TO_INTENSITY_FACTOR * Math.Pow(tempKelvin, 4) : 0; + + + // 5. 应用大气透过率和距离衰减 (使用 distance^2) + // Avoid division by zero distance + finalIntensity = (distance > 1e-6) ? (pixelBaseIntensity * transmittance / (distance * distance)) : pixelBaseIntensity * transmittance; + + + } + + // 设置最终计算出的强度到图像 + // 确保强度非负 + finalIntensity = Math.Max(0, finalIntensity); + image.SetIntensity(y, x, finalIntensity); + + if (smokeIntensity < 0) // 只统计非烟幕覆盖的像素 + { + pixelsSet++; + maxSetIntensity = Math.Max(maxSetIntensity, finalIntensity); + } + } + } + + Console.WriteLine($"目标基于ThermalPattern强度分布: 像素设置: {pixelsSet}, 最大强度: {maxSetIntensity:F6} W/sr"); + + // --- 结束: 使用 ThermalPattern 重构 --- + + /* --- 保留旧的高斯模型代码以供参考 --- // 计算目标自身应有的辐射强度(未被遮挡时) double targetBaseIntensity = target.Properties.InfraredRadiationIntensity * transmittance / Math.Pow(distance, 1.8); @@ -416,6 +514,7 @@ namespace ThreatSource.Guidance } Console.WriteLine($"目标/烟幕强度分布: 像素设置: {pixelsSet}, 最大强度: {maxSetIntensity:F6} W/sr"); + */ } /// @@ -464,9 +563,7 @@ namespace ThreatSource.Guidance } // 添加高斯噪声 (降低噪声水平) - double noiseReductionFactor = 0.0001; // 从 0.001 改为 0.0001 - double reducedNoiseLevel = noiseLevel * noiseReductionFactor; - double noise = (random.NextDouble() - 0.5) * bgIntensity * reducedNoiseLevel; + double noise = (random.NextDouble() - 0.5) * bgIntensity * noiseLevel; currentIntensity += noise; // 确保非负 diff --git a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs index 517ef35..1b50632 100644 --- a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs +++ b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs @@ -90,20 +90,20 @@ namespace ThreatSource.Guidance { EquipmentType.Tank, new TargetFeature( aspectRatio: 2.9, // 典型主战坦克长宽比 size: 1.0, // 基准尺寸 - intensityPattern: 0.9, // 热量集中分布 - temperatureGradient: 0.8 // 高温度梯度 + intensityPattern: 0.8, // 热量集中分布 + temperatureGradient: 0.7 // 高温度梯度 )}, { EquipmentType.APC, new TargetFeature( aspectRatio: 2.1, // 较短的车身 size: 0.7, // 相对坦克尺寸 intensityPattern: 0.7, // 均匀热分布 - temperatureGradient: 0.5 // 中等温度梯度 + temperatureGradient: 0.6 // 中等温度梯度 )}, { EquipmentType.Helicopter, new TargetFeature( aspectRatio: 4.8, // 考虑旋翼长度 size: 1.4, // 较大的整体尺寸 - intensityPattern: 0.5, // 发动机热量集中 - temperatureGradient: 0.9 // 极高温度梯度 + intensityPattern: 0.8, // 发动机热量集中 + temperatureGradient: 0.2 // 较低的温度梯度 )} }; } @@ -324,7 +324,7 @@ namespace ThreatSource.Guidance double mean = sum / count; // --- 修改为基于动态范围的阈值计算 --- - double thresholdFactor = 0.001; // 基于动态范围的因子 (初始值设为0.15, 从 0.05 改为 0.01) + double thresholdFactor = 0.05; // 基于动态范围的因子 (初始值设为0.15, 从 0.05 改为 0.01) double dynamicRange = maxIntensity - minIntensity; double threshold = minIntensity + dynamicRange * thresholdFactor; diff --git a/docs/project/theory.md b/docs/project/theory.md index a1ec553..99e3848 100644 --- a/docs/project/theory.md +++ b/docs/project/theory.md @@ -197,3 +197,66 @@ P_r \propto \rho \cdot A_{target} - 金属表面:0.2-0.9 - 涂装表面:0.1-0.3 - 植被背景:0.1-0.2 + +# 红外成像制导识别原理 + +## 1. 图像生成 (`InfraredImageGenerator`) + +### 1.1 基本原理 +图像生成器的目标是模拟红外传感器接收到的图像,综合考虑目标自身辐射、大气衰减、距离效应以及背景和噪声。 + +### 1.2 目标强度计算 +核心步骤是计算目标区域每个像素的红外辐射强度: + +1. **获取热分布模式 (`thermalPattern`)**: 从目标配置文件(如 `mbt_001.json`)中读取预定义的3x3温度矩阵 (`thermalPattern`)。系统会根据目标当前速度自动选择 `static` 或 `moving` 状态下的模式。 +2. **模式映射**: 将3x3的温度模式映射到图像中目标所占的像素区域 (`pixelWidth` x `pixelLength`)。采用简单的区域映射,将目标像素区域划分为3x3子区域,每个子区域内的所有像素使用对应的模式单元温度。 +3. **温度转强度**: 将模式单元的温度值(摄氏度°C)转换为绝对温度(开尔文K = °C + 273.15)。然后,使用简化的斯特藩-玻尔兹曼定律(T⁴定律)将温度转换为基础辐射强度(W/sr): + \[ Intensity_{base} = C_{factor} \times T_{Kelvin}^4 \] + 其中,`C_{factor}` 是温度到强度的转换系数 (`TEMPERATURE_TO_INTENSITY_FACTOR`)。 +4. **衰减应用**: 将计算出的基础强度应用大气/烟幕透过率 (`transmittance`) 和距离平方反比定律进行衰减: + \[ Intensity_{pixel} = \frac{Intensity_{base} \times transmittance}{distance^2} \] + +### 1.3 背景与噪声添加 +1. **背景**: 在非目标像素区域,如果其当前强度低于设定的基础背景强度 (`backgroundIntensity`),则将其设置为该背景强度。 +2. **噪声**: 在所有像素上叠加一个高斯分布的随机噪声。噪声的幅度基于基础背景强度和天气条件调整,并可以通过 `noiseReductionFactor` 控制。 + +### 1.4 关键参数 +- `backgroundIntensity` (构造函数默认值): `1e-4` W/sr (已手动调整) +- `TEMPERATURE_TO_INTENSITY_FACTOR`: `1e-6` (需要根据物理模型或实验数据调整) +- `noiseReductionFactor` (在`AddBackgroundAndNoise`中): `0.0001` (已调整降低噪声) +- 距离衰减模型: `1 / distance^2` + +## 2. 目标识别 (`InfraredTargetRecognizer`) + +### 2.1 图像分割 +目标是从包含背景和噪声的红外图像中准确地分离出目标区域。 + +1. **阈值计算**: 采用动态阈值方法,基于图像像素强度的实际动态范围计算阈值: + \[ Threshold = minIntensity + (maxIntensity - minIntensity) \times thresholdFactor \] + 这有助于适应不同光照和对比度条件。 +2. **连通区域分析 (Blob Detection)**: 使用计算出的阈值对图像进行二值化,然后查找所有像素强度高于阈值的连通像素区域(Blobs)。 +3. **Blob 过滤与选择**: 对找到的 Blobs 进行过滤,去除面积过小(可能是噪声)或过大(可能是背景或干扰)的区域。同时,检查 Blob 被烟幕覆盖的像素比例,过滤掉被严重遮挡的区域。最终选择剩余 Blobs 中面积最大的一个作为识别目标 (`ImageSegment`)。 + +### 2.2 特征提取 +从分割出的目标区域 (`ImageSegment`) 中提取一组用于分类的特征: + +1. **长宽比 (`AspectRatio`)**: 计算考虑了目标主方向(通过二阶矩计算)的旋转边界框的长宽比。这使得特征对目标旋转不敏感。 +2. **相对尺寸 (`Size`)**: 计算目标分割区域的最大维度(宽度或高度)与图像宽度的一个固定比例(如10%)的比值。*注意:此特征在目标距离非常近时可能不准确。* +3. **强度模式 (`IntensityPattern`)**: 量化目标热量分布的集中程度。结合了强度最高的像素(如最亮的30%)在目标区域内的占比,以及目标中心区域(中间1/3)相对于整体的平均亮度。得分高表示热量集中或中心亮。 +4. **温度梯度 (`TemperatureGradient`)**: 分析目标区域内的强度梯度分布。将目标区域划分为3x3网格,计算每个网格的平均梯度,然后重点分析假设的"后部"(发动机热点区域,当前实现假设在右侧)相对于"前部"和"中部"的梯度差异和对比度。*注意:此特征的有效性高度依赖于图像生成阶段是否包含了真实的内部热点细节。* + +### 2.3 目标分类 +将提取出的特征向量与预定义的模板库 (`targetFeatures`) 进行比较,以确定目标类型。 + +1. **特征模板库 (`targetFeatures`)**: 存储了已知目标类型(Tank, APC, Helicopter)的典型特征值(长宽比、尺寸、强度模式、温度梯度)。这些值需要根据目标的物理特性和仿真测试进行校准。 +2. **特征匹配**: 计算提取出的特征与每个模板特征之间的匹配得分(通常基于归一化的相对误差,得分范围0-1,1表示完美匹配)。 +3. **加权评分**: 使用一组预设的权重 (`CalculateFeatureWeights`) 对每个特征的匹配得分进行加权求和,得到每个模板类型的总匹配分数。 +4. **分类决策**: 选择总匹配分数最高的模板类型作为初步识别结果。同时,计算一个自适应阈值 (`CalculateAdaptiveThreshold`),该阈值基于提取特征的整体"质量"。只有当最高得分超过此自适应阈值时,才确认识别结果;否则,将目标分类为未知 (`Unknown`)。 + +### 2.4 关键参数与数据 +- **分割阈值因子 (`thresholdFactor`)**: `0.05` +- **特征权重 (`CalculateFeatureWeights`)**: `[0.30, 0.25, 0.15, 0.30]` (分别对应长宽比, 尺寸, 强度模式, 温度梯度) +- **特征模板库 (`targetFeatures`)**: + - Tank: `{ AR: 2.9, Size: 1.0, IP: 0.8, TG: 0.7 }` + - APC: `{ AR: 2.1, Size: 0.7, IP: 0.7, TG: 0.6 }` + - Helicopter: `{ AR: 4.8, Size: 1.4, IP: 0.8, TG: 0.2 }` diff --git a/tools/ComprehensiveMissileSimulator.cs b/tools/ComprehensiveMissileSimulator.cs index ed1add7..dfcc38e 100644 --- a/tools/ComprehensiveMissileSimulator.cs +++ b/tools/ComprehensiveMissileSimulator.cs @@ -250,7 +250,7 @@ namespace ThreatSource.Tools.MissileSimulation { var motionParameters = new MotionParameters { - Position = new Vector3D(2000, 1, 0), + Position = new Vector3D(2000, 1, 50), Orientation = new Orientation(Math.PI, 0.02, 0), InitialSpeed = 300 };