Skip to content

Repository files navigation

Gaze Dataset Collector

视线追踪数据集采集程序 - Windows 桌面端

项目简介

本项目是一个用于采集视线追踪数据集的 Windows 桌面应用程序。程序通过笔记本摄像头采集用户注视屏幕红点时的数据,包括人脸关键点、头姿角度、ArUco 标记距离等信息,并生成隐私保护的剪切合成图。

主要特性

  • 5×5 网格红点采集:屏幕显示 25 个随机顺序的红点,每点显示 2.0 秒
  • 隐私保护:不保存完整人脸图像,仅保存眼部裁剪图、ArUco 标记区域和头姿轮廓
  • 自动打包:采集完成后自动生成 session.zip,方便发送
  • 跨设备支持:记录设备、摄像头、屏幕等信息,支持多设备采集
  • 鲁棒性:检测失败时标记为无效帧,但仍记录到 CSV 用于质量分析

技术栈

  • Python 3.10+
  • PyQt6:用户界面
  • OpenCV:摄像头读取、图像处理、ArUco 检测
  • MediaPipe Face Mesh:人脸关键点检测
  • pandas:CSV 数据写入
  • numpy:数值计算

环境要求

必需依赖

PyQt6>=6.4.0
PyQt6-Fluent-Widgets[full]>=1.3.0
pandas>=1.5.0
opencv-python>=4.12.0.88
opencv-contrib-python>=4.12.0.88  # 用于 ArUco 检测
mediapipe>=0.10.21
numpy>=1.26.4
pydantic
tqdm

安装依赖

不要使用 pip install -r app/requirements.txt
而是请手动按照 requirements 中的顺序手动运行 pip install xxx 来逐一单独安装每个依赖
因为上述 opencv 和 mediapipe 版本对 numpy 的版本要求不同,所以要最后安装numpy
此时会有警告便可忽略

注意opencv-python 某些版本可能不包含 ArUco 模块,此时需要额外安装 opencv-contrib-python

目录结构

gaze_dataset_collector/
├── app/                    # 主程序代码
│   ├── main.py            # 程序入口
│   ├── capture/           # 摄像头模块
│   │   └── camera.py
│   ├── data/              # 数据写入模块
│   │   └── writer.py
│   ├── privacy/           # 隐私处理模块
│   │   └── redact.py
│   ├── ui/                # UI 页面
│   │   ├── main_window.py
│   │   ├── page0_start.py
│   │   ├── page1_welcome.py
│   │   ├── page2_check.py
│   │   ├── page3_collect.py
│   │   └── page4_complete.py
│   ├── vision/            # 视觉算法模块
│   │   ├── facemesh.py
│   │   ├── headpose.py
│   │   └── aruco_distance.py
│   └── utils.py           # 工具函数
├── configs/               # 配置文件
│   └── config.json
├── outputs/               # 采集输出目录(自动创建)
├── tests/                 # 测试脚本
├── tools/                  # 工具脚本
│   └── generate_aruco_marker.py
├── README.md
└── 其他....

输出结构

每次采集会在 outputs/ 目录下生成如下结构:

outputs/
└── <user_id>/
    └── S<YYYYMMDD>_<HHMMSS>_DEV<device>_CAM<cam>_G<glass>/
        ├── labels.csv          # 数据标签文件
        ├── meta.json           # 元数据信息
        ├── frames_private/      # 隐私保护图片
        │   ├── 000000.jpg
        │   ├── 000001.jpg
        │   └── ...
        └── session.zip         # 自动打包文件

数据集字段字典

labels.csv 字段说明

labels.csv 是采集数据的核心文件,每行代表一帧数据。所有帧(无论 valid 与否)都会写入 CSV,但只有 valid=1 的帧会保存图片。

字段名 类型 说明 缺省值/无效值
user_id str 用户 ID,例如 "U001" -
session_id str 会话 ID,格式 "SYYYYMMDD_HHMMSS_DEV_CAM_G" -
frame_idx int 帧序号,从 0 开始递增 -
timestamp_ms int 时间戳(毫秒),相对于会话开始时间 -
img_path str 图片相对路径,例如 "frames_private/000001.jpg" valid=0 时为空字符串
target_id int 当前目标点 ID,范围 [0, 24](5×5 网格共 25 个点) -
target_x float 目标点在屏幕上的 X 坐标(像素),原点在左上角 -
target_y float 目标点在屏幕上的 Y 坐标(像素),原点在左上角 -
target_elapsed_ms int 目标点已显示时间(毫秒),从该点开始显示时计时 -
valid int 帧有效性标志,1=有效,0=无效 -
face_score float 人脸检测分数,1.0=检测到,-1.0=未检测到 -1.0 表示未检测到
lm_score float 关键点质量分,范围 [0.0, 1.0] 0.0 表示未检测到或眼区不可用
head_yaw float 头部左右转头角度(度),范围通常 [-90, 90] -999.0 表示未检测到或计算失败
head_pitch float 头部抬头/低头角度(度),范围通常 [-90, 90] -999.0 表示未检测到或计算失败
head_roll float 头部歪头角度(度),范围通常 [-90, 90] -999.0 表示未检测到或计算失败
distance_proxy float 距离代理值,范围通常 [0, 1000] -1.0 表示未检测到 ArUco marker
illumination_mean float 图像平均亮度,范围 [0, 255] valid=0 时为 0.0
device_id str 设备 ID(Windows 上为计算机名) -
camera_name str 摄像头名称/型号 -
glass_id str 眼镜标识,"glass" 或 "no_glass" -
screen_w int 屏幕宽度(像素) -
screen_h int 屏幕高度(像素) -
frame_w int 摄像头帧宽度(像素) -
frame_h int 摄像头帧高度(像素) -

重要说明

  1. valid 判定逻辑valid=1 需要同时满足以下条件:

    • detected=True(FaceMesh 成功检测到人脸)
    • pose_valid=True(6 个关键点齐全且 PnP 求解成功)
    • 注意valid 判定不依赖 ArUco,即使 ArUco 未检测到也可以 valid=1
  2. lm_score 计算方式

    • 0.0:未检测到人脸
    • 0.2:检测到人脸但眼区不可用(尺寸异常/越界)
    • 0.0~1.0:基于眼区清晰度的评分(Laplacian 方差归一化),值越大质量越好
  3. distance_proxy 计算方式

    • 计算公式:distance_proxy = 1000.0 / marker_size_px
    • 值越大表示距离越近(marker 在图像中越大)
    • 例如:marker 在图像中为 50 像素时,distance_proxy ≈ 20.0

meta.json 字段说明

meta.json 包含整个采集会话的配置信息和环境参数,用于后续数据分析和复现。

字段名 类型 说明 缺省值/无效值
user_id str 用户 ID -
session_id str 会话 ID -
glass_id str 眼镜标识,"glass" 或 "no_glass" -
device_id str 设备 ID(Windows 上为计算机名) -
camera_name str 摄像头名称/型号 -
screen_w int 屏幕宽度(像素) -
screen_h int 屏幕高度(像素) -
frame_w int 摄像头帧宽度(像素) -
frame_h int 摄像头帧高度(像素) -
fps_target int 目标采集帧率(fps),通常为 15 -
grid dict 目标点网格配置,格式 {"rows": 5, "cols": 5} -
point_duration_ms int 每个目标点显示时长(毫秒),通常 2000ms -
stable_start_ms int 稳定期时长(毫秒),通常 500ms -
save_fps int 实际保存帧率(fps),通常为 15 -
tag_type str ArUco marker 类型标识(用于文档记录) -
tag_dict str ArUco 字典名称,例如 "DICT_4X4_50" -
tag_size_mm int ArUco marker 实际尺寸(毫米),用于距离计算参考 -
eye_crop_size int 眼区裁剪尺寸(像素),通常 128×128 -
distance_init_proxy float 会话级距离基准值 -1.0 表示未记录(Page2 中 ArUco 未稳定检测)
created_at str 会话创建时间(ISO 格式字符串),例如 "2024-01-01T12:00:00" -

重要说明

  1. distance_init_proxy:在 Page2 检查阶段,如果 ArUco 连续稳定检测到(默认连续 10 帧),会记录当前的 distance_proxy 值作为会话级距离基准。用于后续分析时作为距离参考基准。
  2. stable_start_ms:目标点显示后等待此时间才开始采集,确保用户已注视目标。
  3. save_fps:在稳定期后按此频率保存帧(例如 15fps = 每 66.67ms 一帧)。

使用方法

运行程序

python app/main.py

使用流程

  1. Page 0 - 启动页:点击"开始配置"进入配置页面

  2. Page 1 - 配置页面

    • 输入 用户 ID(必须手动输入,不能为空)
    • 选择是否戴眼镜(glass / no_glass
    • 选择摄像头(自动检测可用摄像头)
    • 选择采集分辨率(1920×1080 / 1280×720 / 640×480)
    • 点击"进入检查页面"
  3. Page 2 - 检查页面

    • 实时显示检测状态:
      • face detected:是否检测到人脸
      • lm_score:关键点质量分(0.0~1.0,值越大质量越好)
      • head pose yaw/pitch/roll:头姿角度(度)
      • aruco detected:是否检测到 ArUco 标记
      • distance_proxy:距离代理值(值越大表示距离越近)
      • valid:帧有效性(1=有效,0=无效)
    • 显示隐私剪切预览图(左眼/右眼/ArUco/骨架图)
    • 提示用户前后移动,观察 distance_proxy 变化
    • valid 连续稳定 N 帧后(默认 10 帧,可配置),"开始采集"按钮可用
    • 如果 ArUco 稳定检测,会记录 distance_init_proxy 作为会话级距离基准
  4. Page 3 - 采集页面

    • 全屏显示 25 个随机顺序的红点
    • 每个红点显示 2.0 秒
    • 前 500ms 为稳定期(不保存数据)
    • 之后以 15fps 保存数据
    • 采集完成后自动进入 Page 4
  5. Page 4 - 完成页面

    • 显示采集统计:总帧数、有效帧数、无效帧数、有效率
    • 显示样例图预览(最多 3 张)
    • 显示 session.zip 文件路径
    • 提供"打开输出文件夹"按钮
    • 点击"退出"结束程序

采集规则

  • 网格布局:5×5 = 25 个点,均匀分布在屏幕上(边距 10%)
  • 点显示时间:每个点显示 2000ms
  • 稳定期:每个点出现后的前 500ms 不保存数据(等待用户注视目标)
  • 保存频率:稳定期后以 15fps 保存(约每 66.67ms 一帧)
  • 有效性判断:需要同时满足以下条件才保存图片
    • 检测到人脸(detected=True
    • 头姿估计有效(6 个关键点齐全且 PnP 求解成功,pose_valid=True
    • 注意valid 判定不依赖 ArUco,即使 ArUco 未检测到也可以 valid=1
  • 无效帧处理valid=0 时仍写入 CSV(用于质量分析),但 img_path 为空,不保存图片

配置说明

配置文件位于 configs/config.json

{
  "grid": { "rows": 5, "cols": 5 },
  "point_duration_ms": 2000,
  "stable_start_ms": 500,
  "save_fps": 15,
  "capture_resolution": { "w": 1280, "h": 720 },
  "eye_crop_size": 128,
  "tag_type": "aruco",
  "tag_dict": "DICT_4X4_50",
  "tag_size_mm": 30,
  "page2_valid_stable_n": 10
}

配置参数说明

  • grid:网格行列数(默认 5×5)
  • point_duration_ms:每个点显示时长(毫秒)
  • stable_start_ms:稳定期时长(毫秒)
  • save_fps:保存帧率
  • capture_resolution:摄像头采集分辨率(可在 UI 中选择)
  • eye_crop_size:眼部裁剪尺寸(64 或 128)
  • tag_type:标记类型(目前仅支持 aruco)
  • tag_dict:ArUco 字典类型
  • tag_size_mm:ArUco 标记物理尺寸(毫米)
  • page2_valid_stable_n:Page2 中 valid 连续稳定帧数要求

工具脚本

生成 ArUco Marker

用于打印 ArUco 标记的工具脚本:

python tools/generate_aruco_marker.py

输出

  • tools/aruco_DICT_4X4_50_id0.png:PNG 图片
  • tools/aruco_DICT_4X4_50_id0_A4.pdf:A4 PDF(含 40mm 校验线)

打印要求

  • A4 纸张 100% 原始比例打印
  • 打印后用 PDF 中的 40mm 校验线确认缩放无误
  • 标记应清晰可见,建议使用较厚的纸张

开发者说明

项目架构

本项目采用模块化设计,主要模块如下:

核心模块

  • app/vision/facemesh.py:人脸关键点检测模块

    • 使用 MediaPipe FaceMesh 检测人脸并提取 468 个关键点
    • 计算眼区清晰度评分(lm_score),用于质量筛选
    • 提取 6 个固定关键点用于头姿估计(PnP)
    • 提供眼区裁剪框用于隐私拼图生成
  • app/vision/headpose.py:头姿估计模块

    • 使用 OpenCV 的 solvePnP 算法,通过 6 个 2D 关键点与 3D 人脸模型匹配求解旋转角度
    • 输出 yaw/pitch/roll 三个角度(度)
  • app/vision/aruco_distance.py:ArUco 标记检测与距离代理值计算

    • 检测图像中的 ArUco 标记
    • 计算 distance_proxy(距离代理值),用于估计用户与屏幕的相对距离
  • app/privacy/redact.py:隐私保护图像生成模块

    • 生成隐私保护的剪切合成图,不保存完整人脸
    • 合成图包含:左眼裁剪、右眼裁剪、ArUco marker 裁剪、黑底骨架图
  • app/data/writer.py:数据写入模块

    • 负责将采集的数据写入 labels.csvmeta.json
    • 保存有效帧的隐私拼图到 frames_private/
    • 自动打包为 session.zip
  • app/capture/camera.py:摄像头读取模块

    • 使用 OpenCV VideoCapture 后台线程持续读取帧
    • 通过 Qt 信号机制将帧传递给 UI(线程安全)

UI 模块

  • app/ui/main_window.py:主窗口,管理页面导航
  • app/ui/page0_start.py:启动页面
  • app/ui/page1_welcome.py:配置页面(用户 ID、眼镜、摄像头、分辨率)
  • app/ui/page2_check.py:检查页面(实时显示检测状态,预览采集质量)
  • app/ui/page3_collect.py:采集页面(25 点采集流程)
  • app/ui/page4_complete.py:完成页面(统计信息、样例图、ZIP 路径)

数据流设计

  1. 图像采集CameraStream 在后台线程持续读取摄像头帧,通过 Qt 信号发送到主线程
  2. 人脸检测FaceMesh 处理每帧图像,输出检测结果和关键点坐标
  3. 头姿估计headpose.py 使用 FaceMesh 的 6 个关键点计算 yaw/pitch/roll
  4. 距离估计aruco_distance.py 检测 ArUco marker 并计算 distance_proxy
  5. 隐私处理redact.py 生成隐私保护的剪切合成图
  6. 数据写入SessionWriter 将所有帧写入 CSV,仅保存有效帧的图片

隐私保护

程序采用隐私保护设计:

  1. 不保存完整人脸图像:仅保存眼部裁剪图(64×64 或 128×128)
  2. 合成图格式:将左眼、右眼、ArUco 标记区域和头姿轮廓合成到一张 640×240 的图片中
  3. 轮廓绘制:使用黑底 + 线框/关键点,不包含完整脸部纹理
  4. 无效帧处理:检测失败时不保存图片,但仍记录到 CSV 用于质量分析

常见问题

Q: 程序无法检测到摄像头?

A:

  1. 检查 Windows 摄像头权限是否开启
  2. 确认摄像头未被其他程序占用(微信/QQ/浏览器/其他视频软件)
  3. 尝试重启程序或重启电脑

Q: ArUco 标记检测不到?

A:

  1. 确保已安装 opencv-contrib-python(不是 opencv-python
  2. 检查 ArUco 标记是否清晰可见
  3. 调整光照条件,避免过亮或过暗
  4. 确保标记在摄像头视野内

Q: 采集的有效率很低?

A:

  1. 确保人脸正对摄像头,光照充足
  2. 保持头部稳定,避免快速移动
  3. 检查摄像头分辨率设置,过低可能影响检测
  4. 注意:valid 判定不依赖 ArUco,即使 ArUco 未检测到也可以 valid=1

Q: 打包后的 exe 无法运行?

A:

  1. 确保 configs/config.json 与 exe 在同一目录
  2. 检查是否有必要的 DLL 文件
  3. 查看错误日志,确认缺少的依赖

许可证

本项目仅供学术研究使用。

联系方式

如有问题或建议,请联系项目维护者。

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages