GazeDiT:扩散模型生成注视精确的合成眼动训练数据——arXiv 2609.17814解读

论文:GazeDiT: Gaze-Accurate Diffusion Image Generation for Eye Tracking via Spatial Conditioning
作者:Dongze Wu 等
arXiv:2609.17814 (2026-09-15)
领域:Computer Vision (cs.CV)

核心创新

本文提出GazeDiT——首个能根据4D双眼注视标签生成注视精确合成人脸图像的扩散模型。通过SegFormer提取瞳孔/虹膜几何结构作为空间条件,物理眼渲染器生成注视一致的几何,解决合成数据注视标签不精确的核心痛点。

一句话总结: 想要1000张”驾驶员看向右后视镜”的图片?GazeDiT可以直接生成,且注视角度精确可控。

问题定义

合成眼动数据的痛点

方法 注视标签精确度 多样性 问题
文本条件扩散 低(文本→图像太粗) 高 “看右上方”具体几度?
3D渲染 高 低 过于完美,缺乏真实感
GAN 中 中 训练不稳定
GazeDiT 高 高 空间条件+物理渲染

核心挑战

注视标签是4D连续值(左右眼各2D),需要精确控制瞳孔/虹膜的微小几何变化——这是文本提示无法做到的。

方法详解

GazeDiT架构

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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import torch
import torch.nn as nn
import torch.nn.functional as F

class GazeDiT(nn.Module):
"""
GazeDiT: 注视精确扩散图像生成模型

论文: arXiv:2609.17814
核心创新:
1. 4D注视标签 → 物理眼渲染器 → 注视一致几何
2. 冻结SegFormer提取瞳孔/虹膜结构作为空间条件
3. 扩散模型在空间条件引导下生成图像

输入: 4D注视标签 + 随机噪声
输出: 注视精确的人脸/眼部图像
"""

def __init__(self, gaze_dim=4, feat_dim=256):
super().__init__()

# 1. 物理眼渲染器(不可学习,参数化)
self.eye_renderer = PhysicalEyeRenderer()

# 2. 冻结的SegFormer(提取瞳孔/虹膜几何)
self.segformer = self._load_frozen_segformer()

# 3. 空间条件编码
self.spatial_encoder = nn.Sequential(
nn.Linear(feat_dim * 2, feat_dim), # 左右眼特征
nn.GELU(),
nn.Linear(feat_dim, feat_dim)
)

# 4. 扩散模型UNet(简化版)
self.denoising_unet = GazeConditionedUNet(
condition_dim=feat_dim,
gaze_dim=gaze_dim
)

def _load_frozen_segformer(self):
"""加载冻结的SegFormer"""
# 简化:用小型分割网络模拟
seg = nn.Sequential(
nn.Conv2d(3, 64, 3, 1, 1), nn.ReLU(),
nn.Conv2d(64, 128, 3, 2, 1), nn.ReLU(),
nn.Conv2d(128, 256, 3, 2, 1), nn.ReLU(),
nn.AdaptiveAvgPool2d(1), nn.Flatten()
)
for p in seg.parameters():
p.requires_grad = False
return seg

def forward(self, noise, gaze_label, timesteps):
"""
Args:
noise: (B, 3, H, W) 噪声图像
gaze_label: (B, 4) 4D双眼注视 [left_x, left_y, right_x, right_y]
timesteps: (B,) 扩散时间步
Returns:
denoised: (B, 3, H, W) 去噪图像
"""
# 1. 物理渲染器生成注视一致的眼部几何
eye_geometry = self.eye_renderer(gaze_label) # (B, 3, H_eye, W_eye)

# 2. SegFormer提取空间条件
with torch.no_grad():
spatial_feat = self.segformer(eye_geometry) # (B, feat_dim)

# 3. 编码空间条件
# 模拟左右眼特征拼接
spatial_cond = self.spatial_encoder(
torch.cat([spatial_feat, spatial_feat], dim=-1)
) # (B, feat_dim)

# 4. 条件扩散去噪
denoised = self.denoising_unet(noise, spatial_cond, gaze_label, timesteps)

return denoised


class PhysicalEyeRenderer:
"""
物理眼渲染器

根据注视角度生成注视一致的眼部几何

参数化模型:
- 瞳孔位置随注视角度偏移
- 虹膜变形随角度变化
- 眼睑开度随角度调整
"""

def __call__(self, gaze_label):
"""
Args:
gaze_label: (B, 4) [left_yaw, left_pitch, right_yaw, right_pitch]
Returns:
eye_image: (B, 3, 64, 128) 双眼渲染图
"""
B = gaze_label.shape[0]
# 简化:生成参数化的眼部图像
eye_image = torch.zeros(B, 3, 64, 128)
# 左眼区域 [0:64, 0:64]
# 右眼区域 [0:64, 64:128]
for i in range(B):
# 瞳孔偏移 = 注视角度 × 缩放
left_x = 32 + gaze_label[i, 0] * 10
left_y = 32 + gaze_label[i, 1] * 8
right_x = 32 + gaze_label[i, 2] * 10 + 64
right_y = 32 + gaze_label[i, 3] * 8

# 绘制瞳孔(简化)
eye_image[i, :, int(left_y), int(left_x)] = 0 # 黑色瞳孔
eye_image[i, :, int(right_y), int(right_x)] = 0

return eye_image


class GazeConditionedUNet(nn.Module):
"""注视条件UNet扩散模型(简化版)"""

def __init__(self, condition_dim=256, gaze_dim=4):
super().__init__()

# 时间嵌入
self.time_embed = nn.Sequential(
nn.Linear(1, 64), nn.GELU(),
nn.Linear(64, condition_dim)
)

# 注视嵌入
self.gaze_embed = nn.Sequential(
nn.Linear(gaze_dim, 64), nn.GELU(),
nn.Linear(64, condition_dim)
)

# 条件融合
self.cond_fuse = nn.Linear(condition_dim * 3, condition_dim)

# UNet编码器
self.encoder = nn.Sequential(
nn.Conv2d(3, 64, 3, 1, 1), nn.GroupNorm(8, 64), nn.SiLU(),
nn.Conv2d(64, 128, 3, 2, 1), nn.GroupNorm(8, 128), nn.SiLU(),
nn.Conv2d(128, 256, 3, 2, 1), nn.GroupNorm(8, 256), nn.SiLU(),
)

# 条件注入(FiLM)
self.film = nn.Linear(condition_dim, 256 * 2)

# UNet解码器
self.decoder = nn.Sequential(
nn.ConvTranspose2d(256, 128, 4, 2, 1), nn.GroupNorm(8, 128), nn.SiLU(),
nn.ConvTranspose2d(128, 64, 4, 2, 1), nn.GroupNorm(8, 64), nn.SiLU(),
nn.Conv2d(64, 3, 3, 1, 1)
)

def forward(self, x, cond, gaze, t):
# 编码
feat = self.encoder(x) # (B, 256, H/4, W/4)

# 条件注入
t_emb = self.time_embed(t.unsqueeze(-1).float())
g_emb = self.gaze_embed(gaze)
combined = self.cond_fuse(torch.cat([cond, t_emb, g_emb], dim=-1))

# FiLM调制
film_params = self.film(combined) # (B, 512)
scale, shift = film_params.chunk(2, dim=-1)
feat = feat * (1 + scale.unsqueeze(-1).unsqueeze(-1)) + shift.unsqueeze(-1).unsqueeze(-1)

# 解码
out = self.decoder(feat)
return out


# 测试
if __name__ == "__main__":
model = GazeDiT(gaze_dim=4, feat_dim=256)

noise = torch.randn(4, 3, 64, 128)
gaze = torch.randn(4, 4) * 0.5 # 4D注视
t = torch.randint(0, 1000, (4,))

out = model(noise, gaze, t)
print(f"Noise input: {noise.shape}")
print(f"Gaze label: {gaze.shape}")
print(f"Generated image: {out.shape}")
print(f"Parameters: {sum(p.numel() for p in model.parameters() if p.requires_grad):,}")

实验结果

注视标签精度

方法 尾部注视误差(°) 对比
文本条件扩散 >5.0 标签不精确
GazeDiT ~2.8 接近真实图像
同一估计器在真实图像 ~2.5 上界

下游眼动追踪改善

数据配置 困难样本注视误差(°) 改善
仅真实数据 3.05 基线
真实+GazeDiT合成 2.80 8.2%↓

IMS 应用启示

1. DMS训练数据合成的关键工具

场景 GazeDiT价值 说明
罕见注视角度 🔴 高 极端左右/上下看
眼镜遮挡 🔴 高 生成各种眼镜+注视组合
不同光照 🟡 中 需扩展条件
不同人种/年龄 🟡 中 需扩展身份条件
太阳镜 🔴 高 解决太阳镜数据不足

2. 座舱数据合成管道集成

1
2
3
4
5
6
7
GazeDiT → 生成注视精确的人脸图像
↓
NVIDIA Cosmos → 生成座舱场景变异
↓
合成数据集 → 训练DMS注视估计器
↓
QCS8255部署

3. 解决太阳镜问题

GazeDiT可生成大量”佩戴太阳镜+特定注视角度”的合成数据,直接缓解GazeDPTR论文中太阳镜导致16°+误差的问题。

4. 开发建议

优先级 行动
🔴 高 评估GazeDiT在车内DMS场景的可用性
🟡 中 扩展到红外图像生成(DMS用IR)
🟡 中 生成太阳镜+注视数据集
🟢 低 与NVIDIA Cosmos集成

论文下载


本文为论文解读类博客,包含方法详解、代码复现、性能对比、IMS落地指导。