Commit 9f52eb0d authored by 尹洪福's avatar 尹洪福

update

parent cbee0c5d
# AIPD 算子开发计划
> 更新日期:2026-03-19
---
## 1. 各场景准确度优化
### 当前进展
**模型版本**: LightStereo_HS (M variant), epoch 1199, 清理异常数据后测试集 222 场景 / 1319 样本。
| 指标 | 值 |
|------|----|
| 整体 EPE | **0.0768** |
| 整体偏差 (pred-gt) | +0.0328 |
**按批次准确度**:
| 批次 | 场景数 | 平均误差 |
|------|--------|---------|
| 1224 | 60 | 0.0580 |
| 1225 | 60 | 0.0742 |
| 多层次300 | 82 | 0.0728 |
| 同平面 | 20 | 0.1546 |
**按 pd 绝对值范围**:
| pd 范围 | 样本数 | 平均误差 |
|---------|--------|---------|
| [0, 0.5) | 526 | 0.0434 |
| [0.5, 1.0) | 289 | 0.0634 |
| [1.0, 2.0) | 229 | 0.0976 |
| [2.0, 3.0) | 53 | 0.0510 |
| [3.0, 6.0) | 222 | 0.1580 |
**已识别的典型问题场景与根因**:
| 根因 | 典型场景 | 误差特征 |
|------|---------|---------|
| 极暗/低SNR | 1225/399 (亮度21, 左右差异0.68) | 全程偏向0, p=800误差3.06 |
| 弱纹理/单平面 | 同平面/112 (亮度37) | 系统性正偏差, 远距离误差2.5+ |
| 竖条纹匹配歧义 | 多层次300/178 (亮度67) | 中间pd范围(p=577)误差最大1.24, 两端反而准确 |
| 近距离(100mm) | 多数场景 | pd>3时EPE=0.158, 模型向0回归 |
**数据集清理**: 已检测并移除 19 个异常场景(清晰度多峰/GT标注异常),占比1.2%。
**各场景已采集 20 组数据**,后续训练优化方向:
- 暗光场景:数据增强(亮度/对比度 jitter + 噪声注入),降权极暗样本
- 竖条纹:特征预处理水平平滑 / Group-wise Correlation
- 近距离:加大 |pd| 权重的 loss,或增加 COST_VOLUME_STEPS
### 开发计划
| 任务 | 时间 | 状态 |
|------|------|------|
| 新采集 各场景20 组数据整合到训练集 | 3.20 - 3.22 | 待实现 |
| 数据增强(ColorJitter + RandomErase)| 3.22 - 3.24 | 待实现 |
| 暗光/竖条纹场景针对性训练与验证 | 3.24 - 3.28 | 待实现 |
| 近距离(100mm) loss 加权优化 | 3.28 - 4.01 | 待实现 |
---
## 2. 置信度
### 当前进展
已实现基于**纹理覆盖率**的二值置信度方案,集成在 `HPdProcessor.cpp` 中:
- **纹理掩码**: 对左图做 Sobel 梯度,阈值 `TEXTURE_THRESH=6`,生成二值纹理掩码
- **置信度计算**: 每个 block 统计纹理像素占比,`texRatio > 0.05` → confidence=1.0,否则 confidence=0.0
- **时域滤波**: `PdTemporalFilter` 对 pd 和 confidence 做帧间平滑
Python 仿真脚本 `sim_foregroundPd.py` 已对齐 C++ 实现,支持可视化验证。
**局限**: 当前为简单二值置信度(0/1),缺乏连续置信度评分。弱纹理但非完全无纹理的场景(如同平面/112,texRatio > 5% 但误差仍大)无法区分。
### 开发计划
| 任务 | 时间 | 状态 |
|------|------|------|
| 基于纹理覆盖率的二值置信度 | 已完成 | **已完成** |
| Python 仿真对齐 C++ 验证 | 已完成 | **已完成** |
| 连续置信度(纹理率 + 左右差异 + pd方差综合评分)| 4.01 - 4.07 | 待实现 |
---
## 3. 前景 ROI
### 当前进展
已实现完整的**前景提取 pipeline**,C++ (`HPdProcessor.cpp`) 和 Python (`sim_foregroundPd.py`) 双端对齐:
**算法流程**:
1. **纹理门控前置**: Sobel 梯度 > 阈值的像素才参与后续计算
2. **Otsu 二值化**: 仅对有纹理的 valid 像素做 Otsu 分割
3. **双峰判定**: 若 min(高簇, 低簇) > 10%,取多数簇为前景
4. **单峰回退**: 全部纹理像素均值 ± 2σ 容差
5. **形态学清理**: close(2次) + open(1次),核 5×5
6. **覆盖率检查**: 前景 > 90% 或 < 50 像素则无效
**Block PD 提取** (`calcBlockMaskedPd`):
- 优先取 block 内前景像素均值
- 无前景回退到纹理像素的 top 20%
**直方图前景检测** (`calcBlockForegroundPd`):
- 64-bin 直方图 + 3点加权平滑
- 多峰取最右两峰谷底,单峰取最陡下降点,无峰回退 top 30%
### 开发计划
| 任务 | 时间 | 状态 |
|------|------|------|
| 全局前景掩码 (Otsu + 纹理门控) | 已完成 | **已完成** |
| Block 级前景 PD 提取 | 已完成 | **已完成** |
| 直方图峰检测前景方案 | 已完成 | **已完成** |
| Python 仿真可视化验证 | 已完成 | **已完成** |
| 前景检测评估(与 GT 对比)| 4.07 - 4.11 | 待实现 |
---
## 4. 性能优化加速
### 当前进展
已提交性能优化 commit (`454474df`),核心优化 3 项:
| 优化项 | 改动 | 效果 |
|--------|------|------|
| **NPU 输出缓存策略** | `svp_acl_rt_malloc``svp_acl_rt_malloc_cached` | 启用 CPU cache,减少 DDR 读取延迟 |
| **消除冗余拷贝** | postprocess 直接传入 `pdMap` 引用,移除中间 `vector` 拷贝 | 减少一次全图 float 数组拷贝 (384×160×4 = 245KB) |
| **缓冲区复用** | `GetOutputWithOutStride` 中 buffer.size() 匹配时跳过 resize | 避免每帧重新分配内存 |
同时增加 `svp_acl_rt_mem_invalidate` 保证 CPU cache 一致性(NPU 写入后 CPU 读取前刷新缓存)。
### 开发计划
| 任务 | 时间 | 状态 |
|------|------|------|
| NPU 输出缓存 + 消除冗余拷贝 + 缓冲区复用 | 已完成 | **已完成** |
| 端到端耗时 profiling(preprocess/infer/postprocess/block) | 3.20 - 3.22 | 待实现 |
| 预处理 NEON 加速(如有瓶颈)| 视 profiling 结果 | 待评估 |
---
## 5. ROI 可配置 / 分辨率可变
### 当前状态
当前 block 布局固定为 2×2 网格 + center block,由 `WindowManager::updateBlockList` 在尺寸变化时更新。输入分辨率固定 384×160(模型固定输入尺寸)。
### 开发计划
| 任务 | 时间 | 状态 |
|------|------|------|
| ROI block 数量/位置可配置(通过参数文件)| 4.14 - 4.18 | 待实现 |
| 动态分辨率适配(padding / 多分辨率模型)| 4.18 - 4.25 | 待实现 |
---
## 6. 滤波
### 当前状态
已有基础时域滤波框架 `PdTemporalFilter`(对 pd 和 confidence 做帧间平滑),以及 `CauchyFilter` 用于 PD/confidence 值滤波。
### 开发计划
| 任务 | 时间 | 状态 |
|------|------|------|
| 时域滤波参数调优(窗口大小/权重衰减)| 4.25 - 4.30 | 待实现 |
| 空域滤波(block 间一致性约束)| 4.30 - 5.07 | 待实现 |
| 滤波对收敛速度的影响评估 | 5.07 - 5.09 | 待实现 |
---
## 总体里程碑
| 阶段 | 时间范围 | 核心内容 |
|------|---------|---------|
| **Phase 1** | 3.20 - 4.01 | 数据整合 + 训练优化 + 端到端 profiling |
| **Phase 2** | 4.01 - 4.11 | 连续置信度 + 前景检测评估 |
| **Phase 3** | 4.14 - 4.25 | ROI 可配置 + 分辨率可变 |
| **Phase 4** | 4.25 - 5.09 | 滤波优化 + 系统集成验证 |
#!/usr/bin/env python3
"""PD dump 可视化工具"""
import numpy as np
import matplotlib.pyplot as plt
import os
import sys
import glob
def load_pd_frame(frame_dir):
"""加载一帧 PD dump 数据"""
meta = {}
with open(os.path.join(frame_dir, 'meta.txt')) as f:
for line in f:
k, v = line.strip().split('=')
meta[k] = int(v)
data = {}
for path in glob.glob(os.path.join(frame_dir, '*.raw')):
fname = os.path.basename(path)
size = os.path.getsize(path)
if size == 0:
continue
name = fname.replace('.raw', '')
parts = name.rsplit('_', 1)
if len(parts) == 2 and 'x' in parts[1]:
w, h = map(int, parts[1].split('x'))
key = parts[0]
pixels = w * h
if size == pixels:
data[key] = np.fromfile(path, dtype=np.uint8).reshape(h, w)
elif size == pixels * 2:
data[key] = np.fromfile(path, dtype=np.int16).reshape(h, w)
else:
print(f' Warning: {fname} size mismatch (expected {pixels} or {pixels*2}, got {size})')
return meta, data
def plot_frame(frame_dir, save=False):
"""可视化一帧的所有数据"""
meta, data = load_pd_frame(frame_dir)
frame_name = os.path.basename(frame_dir)
keys = sorted(data.keys())
if not keys:
print(f' No data in {frame_name}')
return
left_keys = sorted([k for k in keys if 'left' in k])
right_keys = sorted([k for k in keys if 'right' in k])
rows = max(len(left_keys), len(right_keys))
if rows == 0:
return
fig, axes = plt.subplots(rows, 2, figsize=(16, 3.5 * rows))
if rows == 1:
axes = [axes]
fig.suptitle(f'{frame_name}', fontsize=14)
for i in range(rows):
for j, key_list in enumerate([left_keys, right_keys]):
ax = axes[i][j]
if i < len(key_list):
key = key_list[i]
d = data[key]
if d.dtype == np.uint8:
ax.imshow(d, cmap='gray', vmin=0, vmax=255)
ax.set_title(f'{key} (uint8, {d.shape[1]}x{d.shape[0]})')
else:
vmax = max(np.abs(d).max(), 1)
ax.imshow(d, cmap='RdBu_r', vmin=-vmax, vmax=vmax)
ax.set_title(f'{key} (int16, range=[{d.min()},{d.max()}])')
ax.axis('off')
plt.tight_layout()
if save:
out = os.path.join(os.path.dirname(frame_dir), f'{frame_name}.png')
plt.savefig(out, dpi=150)
print(f' Saved: {out}')
plt.close()
else:
plt.show()
if __name__ == '__main__':
# 支持命令行传入目录: python3 pd_viewer.py [dump_dir]
if len(sys.argv) > 1:
pd_dir = os.path.abspath(sys.argv[1])
else:
pd_dir = os.path.expanduser('~/Desktop/pdaf_dump_latest/pdaf_dump')
if not os.path.isdir(pd_dir):
print(f'Directory not found: {pd_dir}')
sys.exit(1)
frames = sorted([f for f in glob.glob(os.path.join(pd_dir, 'pd_*')) if os.path.isdir(f)])
if not frames:
print(f'No pd_xxx directories found in {pd_dir}')
sys.exit(1)
print(f'Found {len(frames)} frames: {[os.path.basename(f) for f in frames]}')
# --save 参数:保存所有帧为 PNG 不弹窗
if '--save' in sys.argv:
for f in frames:
plot_frame(f, save=True)
else:
plot_frame(frames[0])
plt.show()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment