# 康达机器人人脸识别系统

## 项目简介

这是一个基于 CompreFace 的智能人脸识别系统，为康达新材的接待机器人提供实时人脸检测、识别和访客管理功能。系统通过 WebSocket 与机器人主控程序通信，支持视频展示、二维码引导和流媒体推送等多种功能。

## 核心功能

### 1. 人脸识别
- **实时检测**：基于 CompreFace API 进行高精度人脸检测
- **正脸检测**：使用姿态检测技术，获取人脸的yaw（偏航角）、pitch（俯仰角）、roll（翻滚角）数据，只识别正面人脸，有效过滤侧脸、抬头或低头
- **角度过滤**：通过REST API直接调用CompreFace的pose插件，设置±20°的角度阈值，确保只检测正脸
- **身份识别**：自动识别员工和访客，支持相似度阈值配置
- **防重复识别**：智能冷却机制，避免短时间内重复识别同一人
- **质量评估**：使用 Laplacian 方差评估图像清晰度

### 2. 访客引导
- **二维码展示**：陌生访客自动弹出访客预约流程二维码
- **SOTA 设计**：采用现代化 UI 设计，左侧二维码 + 右侧步骤说明
- **自动关闭**：可配置显示时长（默认 10 秒）

### 3. 展厅讲解
- **视频播放**：当机器人角色为"展厅讲解员"时自动播放展厅视频
- **状态叠加**：在视频上实时显示机器人状态（思考、倾听、讲话）
- **循环播放**：支持视频循环播放配置

### 4. WebSocket 通信
- **双向通信**：与机器人主控程序实时交互
- **状态同步**：获取机器人说话、思考、倾听状态
- **自动重连**：连接断开时自动重连，保证系统稳定性

### 5. 流媒体推送
- **RTMP/RTSP 推流**：支持将识别画面推送到流媒体服务器
- **异步推流**：独立线程处理推流，不影响主流程性能
- **自动重试**：推流失败自动重试，带冷却机制

### 6. 摄像头管理
- **自动重连**：摄像头断开时自动尝试重新连接
- **故障恢复**：连续失败达到阈值时触发完整重新初始化

## 技术架构

### 技术栈
- **Python 3.x**
- **OpenCV**：图像处理和摄像头控制
- **CompreFace**：人脸检测和识别服务
- **WebSocket**：实时通信
- **Pillow (PIL)**：中文字体渲染和图像合成
- **FFmpeg**：流媒体推送
- **asyncio**：异步事件循环

### 系统架构
```
┌─────────────────────────────────────────────────────────┐
│                    人脸识别系统主程序                      │
│                    (face_rec.py)                         │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │  摄像头模块   │  │  识别模块     │  │  显示模块     │  │
│  │              │  │              │  │              │  │
│  │ - 视频采集   │  │ - 人脸检测   │  │ - 信息叠加   │  │
│  │ - 自动重连   │  │ - 身份识别   │  │ - 二维码显示 │  │
│  │ - 质量评估   │  │ - 角色判定   │  │ - 视频播放   │  │
│  └──────────────┘  └──────────────┘  └──────────────┘  │
│                                                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │ WebSocket    │  │  推流模块     │  │  日志模块     │  │
│  │              │  │              │  │              │  │
│  │ - 状态同步   │  │ - FFmpeg推流 │  │ - 日志记录   │  │
│  │ - 消息通信   │  │ - 异步队列   │  │ - 日志轮转   │  │
│  │ - 自动重连   │  │ - 错误恢复   │  │              │  │
│  └──────────────┘  └──────────────┘  └──────────────┘  │
└─────────────────────────────────────────────────────────┘
           │                    │                    │
           ▼                    ▼                    ▼
    ┌─────────────┐      ┌──────────┐       ┌──────────┐
    │ CompreFace  │      │ 机器人主控│       │ 流媒体   │
    │   服务      │      │  程序     │       │  服务器  │
    └─────────────┘      └──────────┘       └──────────┘
```

## 安装部署

### 环境要求
- Python 3.7+
- Linux 系统（推荐 Ubuntu 20.04+）
- 摄像头设备
- X11 显示服务器

### 依赖安装
```bash
pip install opencv-python
pip install websockets
pip install pyyaml
pip install numpy
pip install Pillow
pip install compreface-sdk
pip install screeninfo
pip install psutil  # 可选，用于进程管理
```

### FFmpeg 安装（用于推流）
```bash
sudo apt-get update
sudo apt-get install ffmpeg
```

### 配置文件

编辑 `config.yaml` 配置系统参数：

```yaml
# CompreFace API 配置
compreface:
  host: "http://10.0.0.202"
  port: "8000"
  recognition_api_key: "your_recognition_key"
  detection_api_key: "your_detection_key"

# WebSocket 配置
websocket:
  url: "ws://127.0.0.1:3344"
  status_interval: 0.2

# 摄像头配置
camera:
  device_id: 0  # 或使用设备路径
  width: 1280
  height: 720
  fps: 30

# 人脸检测配置
face_detection:
  frame_interval: 10  # 检测帧间隔(每N帧检测一次)
  quality_threshold: 10  # 图像质量阈值(Laplacian方差)
  min_face_size: 80  # 最小人脸尺寸(像素)
  face_present_duration: 2.0  # 持续出现时长(秒)才触发识别
  max_yaw: 20.0  # 最大允许的偏航角(度)，超过此角度视为侧脸
  max_pitch: 20.0  # 最大允许的俯仰角(度)，超过此角度视为抬头或低头

# 人脸识别配置
face_recognition:
  recognition_cooldown: 20.0  # 识别冷却时间（秒）

role_mapping:
  stranger_threshold: 0.98  # 陌生人阈值

# 二维码配置
qrcode:
  image_path: "preview_qrcode_sota.jpg"
  display_duration: 30

# 视频配置
video:
  path: "exhibition.mp4"
  loop: true

# 推流配置（可选）
stream:
  enabled: false  # 是否启用推流
  rtmp_url: "rtsp://127.0.0.1/live/video"
```

### 运行方式

#### 方式一：直接运行
```bash
python face_rec.py
```

#### 方式二：使用启动脚本
```bash
chmod +x start.sh
./start.sh
```

#### 方式三：系统服务（推荐生产环境）
```bash
# 复制服务文件
sudo cp face_rec.service /etc/systemd/system/

# 重载服务
sudo systemctl daemon-reload

# 启动服务
sudo systemctl start face_rec

# 设置开机自启
sudo systemctl enable face_rec

# 查看服务状态
sudo systemctl status face_rec

# 查看日志
sudo journalctl -u face_rec -f
```

## 核心模块说明

### 1. FaceRecognitionSystem 类

系统主类，包含以下核心方法：

#### 初始化相关
- `__init__()`: 初始化系统，加载配置
- `_init_camera()`: 初始化摄像头
- `_init_compreface()`: 初始化 CompreFace 服务
- `_init_ffmpeg_stream()`: 初始化推流

#### 人脸识别
- `detect_faces()`: 检测人脸
- `recognize_face()`: 识别人脸
- `assess_frame_quality()`: 评估图像质量
- `determine_role()`: 判定人员角色
- `should_recognize()`: 判断是否需要识别

#### 显示相关
- `_show_qrcode()`: 显示二维码
- `_show_video()`: 显示展厅视频
- `draw_info_on_frame()`: 在画面上绘制信息
- `_draw_robot_status_on_video()`: 在视频上绘制机器人状态
- `_build_qrcode_instruction_canvas()`: 构建二维码指引画布

#### WebSocket 通信
- `connect_websocket()`: 连接 WebSocket
- `send_websocket_message()`: 发送消息
- `handle_websocket_messages()`: 处理接收消息
- `query_robot_status()`: 查询机器人状态

#### 推流相关
- `_start_stream_thread()`: 启动推流线程
- `_stream_worker()`: 推流工作线程
- `_push_frame_to_stream()`: 推送帧到流媒体
- `_force_cleanup_ffmpeg()`: 清理 FFmpeg 资源

#### 主流程
- `process_video_stream()`: 处理视频流主循环
- `run()`: 系统运行入口

### 2. 工作流程

```
启动系统
    ↓
初始化配置、日志、CompreFace、摄像头
    ↓
连接 WebSocket（后台任务）
    ↓
启动推流（如果启用）
    ↓
┌─────────────────────────────────────┐
│         主循环（异步）                │
│                                     │
│  1. 读取摄像头帧                     │
│  2. 检查机器人角色，控制视频播放      │
│  3. 更新视频帧（如果正在播放）        │
│  4. 检查二维码超时                   │
│  5. 每 N 帧进行人脸检测              │
│  6. 检测到人脸 → 持续出现 2 秒       │
│  7. 触发人脸识别                     │
│  8. 判定角色（员工/访客/陌生人）      │
│  9. 发送识别结果到机器人             │
│ 10. 陌生人 → 显示二维码              │
│ 11. 绘制识别信息到画面               │
│ 12. 推送画面到流媒体（如果启用）      │
│ 13. 显示画面                         │
│                                     │
│  按 'q' 退出                         │
└─────────────────────────────────────┘
    ↓
清理资源（摄像头、推流、窗口）
    ↓
退出系统
```

## 文件说明

```
kanda-robot-facial-recognition/
├── face_rec.py                    # 主程序
├── config.yaml                    # 配置文件
├── start.sh                       # 启动脚本
├── face_rec.service               # systemd 服务文件
├── preview_qrcode_sota.png        # 二维码引导图片（新版）
├── qrcode.jpg                     # 二维码图片（旧版）
├── exhibition.mp4                 # 展厅讲解视频
├── preview_qrcode.py              # 二维码预览生成工具
├── face_recognition.log           # 运行日志
├── 001保存摄像头流.py              # 工具：保存摄像头视频流
├── 002查看摄像头id.py              # 工具：查看摄像头设备 ID
├── 003查看GUI后端.py               # 工具：查看 GUI 后端
└── README.md                      # 本文档
```

## 配置说明

### 人脸识别参数

- `frame_interval`: 检测帧间隔，建议 5-15
- `quality_threshold`: 图像质量阈值，建议 10-50
- `min_face_size`: 最小人脸尺寸（像素），建议 60-100
- `face_present_duration`: 持续出现时长（秒），建议 1.5-3.0
- `max_yaw`: 最大允许的偏航角（度），超过此角度视为侧脸，推荐 20°
- `max_pitch`: 最大允许的俯仰角（度），超过此角度视为抬头或低头，推荐 20°
- `stranger_threshold`: 陌生人阈值，建议 0.95-0.99
- `recognition_cooldown`: 识别冷却时间（秒），建议 15-30

### 摄像头设备 ID

**方式一：使用数字 ID**
```yaml
camera:
  device_id: 0  # 通常是第一个摄像头
```

**方式二：使用设备路径（推荐，更稳定）**
```bash
# 查看可用摄像头
ls /dev/v4l/by-id/

# 使用设备路径
camera:
  device_id: "/dev/v4l/by-id/usb-xxx-video-index0"
```

### WebSocket 消息格式

**发送识别结果**
```json
{
  "type": "face_recognition",
  "message": {
    "person_name": "张三",
    "person_role": "员工",
    "similarity": 0.99,
    "timestamp": "2025-12-18 10:30:00"
  }
}
```

**接收机器人状态**
```json
{
  "type": "status",
  "message": {
    "is_speaking": false,
    "is_thinking": true,
    "listening": false,
    "role_name": "展厅讲解员"
  }
}
```

## 常见问题

### Q1: 摄像头无法打开
**A:** 
1. 检查摄像头是否被其他程序占用
2. 确认设备 ID 是否正确：`ls /dev/video*`
3. 检查用户权限：`sudo usermod -a -G video $USER`
4. 重启系统

### Q2: 无法显示中文
**A:**
1. 确认系统已安装中文字体
2. 修改 `config.yaml` 中的 `font_path` 配置
3. 常见字体路径：
   - Ubuntu: `/usr/share/fonts/truetype/wqy/wqy-microhei.ttc`
   - CentOS: `/usr/share/fonts/wqy-microhei/wqy-microhei.ttc`

### Q3: WebSocket 连接失败
**A:**
1. 确认机器人主控程序已启动
2. 检查 WebSocket URL 配置
3. 查看防火墙设置
4. 系统会自动重连，检查日志确认状态

### Q4: 推流失败
**A:**
1. 确认 FFmpeg 已安装：`ffmpeg -version`
2. 检查流媒体服务器是否运行
3. 验证 RTMP/RTSP URL 格式
4. 查看日志中的 FFmpeg 错误信息

### Q5: 识别准确率低
**A:**
1. 提高 `quality_threshold` 确保图像清晰
2. 调整 `stranger_threshold` 阈值
3. 确保光线充足
4. 在 CompreFace 中添加更多训练照片

### Q6: 侧脸也被识别了
**A:**
1. 调整 `max_yaw` 和 `max_pitch` 参数，降低角度阈值
2. 默认设置为 ±30 度，可改为 ±20 度提高严格程度
3. 检查 CompreFace 服务是否支持 pose 插件
4. 查看日志中的角度检查信息进行调试

### Q7: 系统服务无法启动
**A:**
1. 检查服务文件路径配置
2. 确认 Python 环境和依赖
3. 查看日志：`sudo journalctl -u face_rec -n 50`
4. 检查 DISPLAY 和 XAUTHORITY 环境变量

## 性能优化建议

1. **降低检测频率**：增大 `frame_interval` 值
2. **降低分辨率**：适当降低摄像头分辨率
3. **关闭推流**：生产环境不需要时关闭推流功能
4. **调整日志级别**：生产环境使用 INFO 或 WARNING
5. **使用 GPU**：如有 GPU，配置 OpenCV 使用 CUDA 加速

## 维护和监控

### 日志查看
```bash
# 查看应用日志
tail -f face_recognition.log

# 查看系统服务日志
sudo journalctl -u face_rec -f

# 查看启动脚本日志
tail -f /home/unitree/robot_face_rec/logs/face_rec/*.log
```

### 性能监控
```bash
# 查看 CPU 和内存占用
top -p $(pgrep -f face_rec.py)

# 查看 GPU 使用（如果使用 NVIDIA GPU）
nvidia-smi

# 查看进程状态
ps aux | grep face_rec
```

### 重启服务
```bash
# 重启服务
sudo systemctl restart face_rec

# 强制停止
sudo systemctl kill face_rec

# 完全重启（包括清理资源）
sudo systemctl stop face_rec
sleep 2
sudo systemctl start face_rec
```

## 开发和调试

### 调试模式
修改 `config.yaml`：
```yaml
logging:
  level: "DEBUG"
```

### 测试工具
```bash
# 测试摄像头
python 001保存摄像头流.py

# 查看摄像头 ID
python 002查看摄像头id.py

# 预览二维码设计
python preview_qrcode.py
```

## 更新日志

### v1.1.0 (2025-12-18)
- ✅ 新增正脸检测功能，基于CompreFace姿态检测技术过滤侧脸
- ✅ 添加人脸角度阈值配置（max_yaw: 20°, max_pitch: 20°）
- ✅ 使用REST API直接调用CompreFace，绕过SDK限制获取pose数据
- ✅ 优化人脸识别准确性，适用于门禁场景，只识别正面人脸
- ✅ 二维码显示时间延长至30秒，方便访客操作
- ✅ 二维码指引界面改为全屏显示，提升用户体验
- ✅ 修复PIL兼容性问题，解决圆角矩形渲染错误

### v1.0.0 (2025-12-03)
- ✅ 完整的人脸检测和识别功能
- ✅ WebSocket 双向通信
- ✅ 二维码 SOTA 设计展示
- ✅ 展厅讲解视频播放
- ✅ 机器人状态叠加显示
- ✅ FFmpeg 流媒体推送
- ✅ 异步推流队列优化
- ✅ 摄像头自动重连机制
- ✅ 完善的日志系统

## 技术支持

如有问题，请联系开发团队或查看项目文档。

---

**泰奥理 © 2025**
