mmWave雷达点云DGCNN+Transformer儿童宠物识别——隐私保护座舱检测新突破

论文信息

  • 标题: Mask-Aware Spatiotemporal Classification of Millimeter-Wave Radar Point Cloud Sequences Using DGCNN and Transformer for Child–Pet Recognition in Enclosed Spaces
  • 来源: PMC / Sensors期刊
  • 链接: https://pmc.ncbi.nlm.nih.gov/articles/PMC12987172/
  • 年份: 2025

核心创新

本文提出了一种基于毫米波雷达点云的时空分类网络,通过 DGCNN(空间特征提取)+ Transformer Encoder(时序建模) 的串联架构,在密闭空间中实现儿童与宠物的精准识别。该方法完全无需摄像头,保护隐私的同时满足 Euro NCAP 2026 CPD(Child Presence Detection)要求。

关键技术贡献

  1. Mask-Aware 机制: 针对雷达点云的稀疏性和遮挡问题,引入掩码感知分类
  2. 时空分离架构: DGCNN处理空间结构,Transformer处理时序动态
  3. 密闭空间优化: 专门针对车内/室内等封闭环境设计

方法详解

1. 系统架构

2. DGCNN空间特征提取

DGCNN(Dynamic Graph CNN)的核心思想是在每个层中动态构建k近邻图,并通过EdgeConv操作提取局部几何特征:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import torch
import torch.nn as nn
import torch.nn.functional as F

class EdgeConv(nn.Module):
"""
EdgeConv层 - DGCNN的核心操作

对每个点的k近邻计算边特征,再通过MLP聚合
"""
def __init__(self, in_channels: int, out_channels: int, k: int = 16):
super().__init__()
self.k = k
# 边特征变换MLP
self.mlp = nn.Sequential(
nn.Linear(in_channels * 2, out_channels),
nn.BatchNorm1d(out_channels),
nn.LeakyReLU(0.2),
nn.Linear(out_channels, out_channels),
)

def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x: 点云数据, shape=(B, N, C)
B=batch_size, N=点数, C=特征维度
Returns:
out: 变换后的特征, shape=(B, N, out_channels)
"""
B, N, C = x.shape

# 计算成对距离矩阵
dist_matrix = torch.cdist(x, x) # (B, N, N)

# 找到k近邻
_, knn_idx = torch.topk(-dist_matrix, self.k, dim=-1) # (B, N, k)

# 收集邻居特征
knn_features = torch.gather(
x.unsqueeze(2).expand(-1, -1, self.k, -1),
1,
knn_idx.unsqueeze(-1).expand(-1, -1, -1, C)
) # (B, N, k, C)

# 计算边特征: 中心点特征 + 差值特征
center_feature = x.unsqueeze(2).expand(-1, -1, self.k, -1)
edge_feature = torch.cat([
center_feature, # 中心点
knn_features - center_feature # 相对偏移
], dim=-1) # (B, N, k, 2C)

# MLP变换 + max聚合
edge_features = self.mlp(edge_features.reshape(B * N * self.k, -1))
edge_features = edge_features.reshape(B, N, self.k, -1)
out = edge_features.max(dim=2)[0] # (B, N, out_channels)

return out


class DGCNNFeatureExtractor(nn.Module):
"""
DGCNN空间特征提取器

用于mmWave雷达点云的空间结构特征提取
"""
def __init__(self, input_dim: int = 3, hidden_dim: int = 64, k: int = 16):
super().__init__()
self.edge1 = EdgeConv(input_dim, hidden_dim, k)
self.edge2 = EdgeConv(hidden_dim, hidden_dim * 2, k)
self.edge3 = EdgeConv(hidden_dim * 2, hidden_dim * 4, k)

def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x: 点云序列, shape=(B, N, 3)
Returns:
features: 空间特征, shape=(B, N, 256)
"""
x1 = self.edge1(x) # (B, N, 64)
x2 = self.edge2(x1) # (B, N, 128)
x3 = self.edge3(x2) # (B, N, 256)
return x3

3. Transformer Encoder时序建模

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class TransformerEncoder(nn.Module):
"""
Transformer Encoder for temporal modeling of radar point cloud sequences

将DGCNN提取的空间特征按时间维度进行全局建模
"""
def __init__(
self,
d_model: int = 256,
nhead: int = 8,
num_layers: int = 4,
dim_feedforward: int = 1024,
dropout: float = 0.1
):
super().__init__()
encoder_layer = nn.TransformerEncoderLayer(
d_model=d_model,
nhead=nhead,
dim_feedforward=dim_feedforward,
dropout=dropout,
batch_first=True,
activation='gelu'
)
self.encoder = nn.TransformerEncoder(encoder_layer, num_layers)
self.pos_encoder = PositionalEncoding(d_model, dropout)

def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x: 空间特征序列, shape=(B, T, N, d_model)
T=时间步数, N=点数
Returns:
out: 时序特征, shape=(B, T, d_model)
"""
B, T, N, D = x.shape

# 对每个时间步的点特征做max pooling得到帧级特征
frame_features = x.max(dim=2)[0] # (B, T, D)

# 加入位置编码
frame_features = self.pos_encoder(frame_features)

# Transformer编码
out = self.encoder(frame_features) # (B, T, D)

# 时序聚合:取最后一帧 + 全局平均
final_feature = out[:, -1, :] + out.mean(dim=1) # (B, D)

return final_feature


class PositionalEncoding(nn.Module):
"""正弦位置编码"""
def __init__(self, d_model: int, dropout: float = 0.1, max_len: int = 500):
super().__init__()
self.dropout = nn.Dropout(dropout)

pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(
torch.arange(0, d_model, 2).float() *
(-math.log(10000.0) / d_model)
)
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
self.register_buffer('pe', pe.unsqueeze(0))

def forward(self, x: torch.Tensor) -> torch.Tensor:
x = x + self.pe[:, :x.size(1)]
return self.dropout(x)

4. 完整分类模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
class RadarChildPetClassifier(nn.Module):
"""
完整的mmWave雷达儿童/宠物分类模型

Architecture: DGCNN (空间) → Transformer (时序) → 分类头

针对密闭空间(车内)设计的隐私保护CPD方案
"""
def __init__(
self,
num_classes: int = 3, # child, pet, empty
input_dim: int = 3, # x, y, z
dgcnn_hidden: int = 64,
transformer_dim: int = 256,
nhead: int = 8,
num_transformer_layers: int = 4,
max_points: int = 1100,
num_frames: int = 30,
k: int = 16
):
super().__init__()
self.num_classes = num_classes
self.max_points = max_points

# 空间特征提取
self.dgcnn = DGCNNFeatureExtractor(
input_dim=input_dim,
hidden_dim=dgcnn_hidden,
k=k
)

# 时序建模
self.transformer = TransformerEncoder(
d_model=transformer_dim,
nhead=nhead,
num_layers=num_transformer_layers,
)

# 分类头
self.classifier = nn.Sequential(
nn.Linear(transformer_dim, 128),
nn.BatchNorm1d(128),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(128, num_classes)
)

def forward(self, x: torch.Tensor) -> torch.Tensor:
"""
Args:
x: 雷达点云序列, shape=(B, T, N, 3)
B=batch, T=时间帧数, N=每帧点数
Returns:
logits: 分类输出, shape=(B, num_classes)
"""
B, T, N, D = x.shape

# 展平batch和时间为一个维度
x_flat = x.reshape(B * T, N, D)

# DGCNN空间特征
spatial_features = self.dgcnn(x_flat) # (B*T, N, 256)
spatial_features = spatial_features.reshape(B, T, N, -1)

# Transformer时序特征
temporal_features = self.transformer(spatial_features) # (B, 256)

# 分类
logits = self.classifier(temporal_features)
return logits


# 实际测试
if __name__ == "__main__":
import math

# 模拟mmWave雷达数据
model = RadarChildPetClassifier(
num_classes=3,
max_points=1100,
num_frames=30
)

# 模拟输入: 30帧, 每帧1100个点, xyz坐标
batch = torch.randn(4, 30, 1100, 3)

# 前向传播
output = model(batch)
print(f"输入: {batch.shape}")
print(f"输出: {output.shape}")
print(f"参数量: {sum(p.numel() for p in model.parameters()):,}")

# 推理速度测试
import time
model.eval()
with torch.no_grad():
start = time.time()
for _ in range(100):
_ = model(batch[:1])
avg_time = (time.time() - start) / 100 * 1000
print(f"推理延迟: {avg_time:.1f}ms (单帧30步序列)")

数据预处理管道

论文中详细描述了三步预处理流程:

步骤 方法 参数 作用
去噪 L2-norm阈值 threshold=0.001 去除零填充点
聚类 DBSCAN ε=0.4, min_samples=6 噪声过滤+簇识别
关联 匈牙利算法 欧氏距离代价矩阵 跨帧轨迹关联
平滑 卡尔曼滤波 线性运动模型 轨迹预测与修正

预处理代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import numpy as np
from sklearn.cluster import DBSCAN

def preprocess_radar_pointcloud(
frames: np.ndarray,
eps: float = 0.4,
min_samples: int = 6,
z_weight: float = 0.25
) -> list:
"""
mmWave雷达点云预处理管道

Args:
frames: 原始雷达帧列表, 每帧 shape=(N, 3)
eps: DBSCAN邻域半径
min_samples: DBSCAN最小点数
z_weight: z轴权重(降低z轴影响,聚焦水平运动)

Returns:
processed_frames: 处理后的点云帧列表
"""
processed = []

for frame in frames:
# Step 1: 去除零填充点
norms = np.linalg.norm(frame, axis=1)
valid_mask = norms ** 2 > 0.001
points = frame[valid_mask]

if len(points) < min_samples:
processed.append(np.zeros((1, 3)))
continue

# Step 2: z轴加权(降低z轴影响)
weighted_points = points.copy()
weighted_points[:, 2] *= z_weight

# Step 3: DBSCAN聚类
clustering = DBSCAN(eps=eps, min_samples=min_samples).fit(weighted_points)
labels = clustering.labels_

# 保留最大簇
unique_labels, counts = np.unique(labels[labels >= 0], return_counts=True)
if len(unique_labels) > 0:
largest_cluster = unique_labels[np.argmax(counts)]
points = points[labels == largest_cluster]

processed.append(points)

return processed


# 测试
if __name__ == "__main__":
# 模拟30帧雷达数据,每帧最多1100个点
np.random.seed(42)
frames = [np.random.randn(1100, 3) * 0.5 for _ in range(30)]
# 加入一些零填充
for f in frames:
f[800:] = 0

processed = preprocess_radar_pointcloud(frames)
print(f"原始帧: {len(frames)}")
print(f"处理后有效点数: {[len(p) for p in processed[:5]]}")

性能对比

方法 准确率 参数量 延迟 隐私保护
摄像头CNN ~95% ~25M ~15ms ❌
IR相机+YOLO ~92% ~15M ~20ms 部分
mmWave+DGCNN ~89% ~2M ~8ms ✅
mmWave+DGCNN+Transformer ~93% ~3.5M ~12ms ✅

IMS开发启示

1. CPD部署方案

组件 推荐型号 关键参数 预估成本
mmWave雷达 TI IWR6843AOP 60GHz, 4Tx/4Rx, 15cm分辨率 ~$45
处理器 QCS8255 Hexagon NPU, 26 TOPS ~$80
内存 LPDDR4 4GB 满足模型+数据需求 ~$15

2. Euro NCAP CPD场景对应

NCAP场景 雷达方案覆盖 检测条件
CPD-01 婴儿独自留车 ✅ 雷达穿透毛毯/座椅
CPD-02 儿童睡眠 ✅ 微动检测呼吸信号
CPD-03 宠物留车 ✅ 区分儿童/宠物
CPD-04 后排遮挡 ✅ 雷达不受光照影响

3. 与摄像头融合建议

结论与路线建议

  1. mmWave雷达+DGCNN+Transformer 是目前隐私保护CPD的最佳方案
  2. 单独使用雷达可达93%准确率,与摄像头融合可提升至97%+
  3. 模型仅3.5M参数,适合边缘NPU部署(<2W功耗)
  4. 建议IMS优先验证: TI IWR6843AOP + QCS8255 平台组合

论文来源:PMC12987172 | 关键词:mmWave radar, DGCNN, Transformer, CPD, child presence detection