基于RK3576的AI视力检测系统
项目名称: 基于RK3576的AI视力检测系统
版本: v1.1
作者: lugl
日期: 2026年2月
Gitee: https://gitee.com/lugl/rk_3576
一、项目背景与目标
1.1 项目背景
随着人工智能技术的快速发展,视觉检测技术在医疗健康领域的应用越来越广泛。传统的视力检测需要专业医护人员操作,检测效率较低,且难以实现自动化。本项目基于米尔RK3576开发板,设计并实现了一套智能视力检测系统,旨在提供一种便捷、高效的视力检测方案。
RK3576是一款高性能ARM架构的开发板,搭载瑞芯微处理器,具备强大的AI推理能力,适合运行手势识别、图像处理等AI任务。
1.2 项目目标
- 实现自动视力检测:用户通过简单的手势即可完成左右眼的视力检测
- AI手势识别:利用MediaPipe实现精准的OK手势检测,作为启动测试的交互方式
- 智能化流程控制:自动识别E字方向、判断测试结果、自动切换测试眼别
- 语音交互:集成语音播报功能,提供清晰的测试指引和结果反馈
二、系统功能设计
2.1 功能架构
系统架构图说明:

架构说明:
- RK3576开发板: 核心控制器,运行所有业务逻辑
- 视频播放模块: 使用GStreamer进行硬件解码播放引导视频
- 手势识别模块: MediaPipe Hands检测OK手势作为启动信号
- 距离检测模块: 串口读取TOF传感器数据,检测用户距离
- 语音播报模块: ES8388音频编解码,播报欢迎词和检测结果
- UI显示模块: PySide6 Qt开发,HDMI输出到显示屏
数据流向:
- 摄像头采集图像 → MediaPipe手势识别 → 判断OK手势
- TOF传感器检测距离 → 串口通信 → 判断距离是否合适
- 随机生成E字方向 → 显示在屏幕上
- 用户手势 → 摄像头采集 → 手势识别 → 对比判断
- 测试结果 → 语音播报 + 屏幕显示
2.2 核心功能模块
| 模块 | 功能描述 |
| 视频播放模块 | 开机播放引导视频,支持GStreamer硬件解码 |
| 手势识别模块 | 使用MediaPipe检测OK手势,作为测试启动信号 |
| 距离检测模块 | 通过串口读取红外测距传感器数据,检测用户距离 |
| 视力测试模块 | 随机显示E字方向,根据用户手势判断是否正确 |
| 语音播报模块 | 播放欢迎语音、测试指引、视力结果等 |
| UI显示模块 | 使用PySide6显示视频、E字图片、状态信息 |
2.3 测试流程

流程说明:
- 系统初始化 - 启动摄像头、手势识别、距离传感器、音频系统
- 播放引导视频 - 开机自动播放intro_guide.mp4介绍使用方法
- 等待OK手势 - 视频结束后显示提示,用户做OK手势启动测试
- 右眼测试 - 随机显示E字方向,用户用手势回答,3次测试后判断结果
- 左眼测试 - 自动切换到左手,重复右眼测试流程
- 显示结果 - 播报双侧视力结果,显示在屏幕上
- 等待重新测试 - 用户可再次做OK手势重新开始测试
三、硬件与电路说明
3.1 硬件清单
| 设备 | 型号/规格 | 用途 |
| 开发板 | 米尔RK3576 | 核心控制器,运行AI推理和业务逻辑 |
| 摄像头 | Intel RealSense D435 | 采集RGB图像用于手势识别 |
| 距离传感器 | TOF激光测距模块 | 检测用户与设备的距离(2cm10m) |
| 音频编解码 | ES8388 | 音频输出(通过ALSA驱动) |
| 显示器 | HDMI显示屏 | 显示UI和视力表 |
Intel RealSense D435 深度摄像头特点
本项目选用Intel RealSense D435深度摄像头作为视觉采集设备,用于手势图像采集。相比普通USB摄像头具有以下优势:
双流输出
- 同时支持RGB彩色流和深度流
- 本项目使用RGB流(640x480)进行手势识别
- 深度流可用于未来扩展(如手势分割)
高质量图像
- RGB分辨率:1920x1080 @ 30fps
- 采集分辨率:640x480 @ 15fps(用于手势识别)
- 内置自动白平衡、自动曝光功能
- 适用于各种光照条件
即插即用
- 通过USB 3.0接口连接
- 提供跨平台的librealsense SDK (pyrealsense2)
- 支持Linux、Windows等操作系统
稳定性强
- 工业级品质,稳定性好
- 自动曝光和对焦,适应能力强
- 在复杂环境下仍能准确识别手势
易于集成
- Python绑定支持,易于开发
- 帧同步机制,确保数据一致性
- 实时性好,满足手势识别需求
TOF激光测距模块特点
本项目选用TOF(Time of Flight)激光测距模块作为距离检测设备,具有以下优势:
超宽测距范围
- 测距范围:2cm ~ 10m
- 覆盖从近到远的各种使用场景
高精度测量
快速响应
- 响应时间:<100ms
- 实时检测用户距离,适用于动态场景
抗干扰能力强
低功耗
3.2 硬件接线
RK3576开发板
│
├── USB3.0接口 ────> Intel RealSense D435 深度摄像头
│ │
├── 串口(UART) ─────> TOF激光测距模块
│ │
├── I2S/PCM ────────> 音频编解码 (ES8388) ──> 喇叭
│ │
└── HDMI ──────────> 显示器 (HDMI OUT)
3.3 系统环境
- 操作系统: Buildroot Linux (ARM64)
- Python版本: 3.10+
- AI框架: MediaPipe (Google)
- 视觉库: Intel RealSense SDK (librealsense)
- GUI框架: PySide6
- 多媒体: GStreamer + ALSA
- 音频格式: WAV (44.1kHz, 16bit, stereo)
四、关键技术说明
4.1 AI手势识别
使用Google的MediaPipe框架进行手势识别,主要特点:
- 模型: MediaPipe Hands (预训练模型)
- 输入: RGB图像 (640x480)
- 输出: 21个关键点坐标、手势分类
- 性能: 实时推理 (30fps)
4.1.1 MediaPipe Hands 21个关键点
MediaPipe Hands 模型输出21个手部关键点,编号从0到20:
8 12 16 20
│ │ │ │
▼ ▼ ▼ ▼
○───────────○───────────○───────────○ ← 食指、中指、无名指、小指
│ │ │ │
7 11 15 19
│ │ │ │
○───────────○───────────○───────────○
│ │ │ │
6 10 14 18
│ │ │ │
○───────────○───────────○───────────○
│ │ │ │
5 9 13 17
│ │
○───────────────────────○
│ │
4 13
│ │
○────┴───────────────────────┴────○
│ │
0 9
│ │
└────────────────────────────────┘
(手腕)
关键点索引说明:
- 0: 手腕
- 1-4: 拇指 (掌骨→近节指骨→远节指骨→指尖)
- 5-8: 食指
- 9-12: 中指
- 13-16: 无名指
- 17-20: 小指
4.1.2 手势识别核心代码
# 手势识别关键代码 (hand_gesture_task.py)
import mediapipe as mp
import numpy as np
import cv2
# 初始化MediaPipe Hands
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(
static_image_mode=False, # 视频流模式
max_num_hands=2, # 最多检测2只手
min_detection_confidence=0.7, # 检测置信度阈值
min_tracking_confidence=0.5 # 跟踪置信度阈值
)
def calculate_distance(p1, p2):
"""计算两个landmark之间的欧氏距离(归一化坐标)"""
return ((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2) ** 0.5
def recognize_gesture(landmarks):
"""
识别特殊手势:OK、NO(拳头)
返回: "OK", "NO", 或 None
"""
# 获取关键点
thumb_tip = landmarks[4] # 拇指尖
index_tip = landmarks[8] # 食指尖
middle_tip = landmarks[12] # 中指尖
ring_tip = landmarks[16] # 无名指尖
pinky_tip = landmarks[20] # 小指尖
wrist = landmarks[0] # 手腕
# === OK手势检测 ===
# 条件:拇指和食指接近,其他手指伸开
thumb_index_dist = calculate_distance(thumb_tip, index_tip)
if thumb_index_dist < 0.05:
# 检查中指是否伸开
if calculate_distance(middle_tip, wrist) > 0.3:
return "OK"
# === NO/拳头检测 ===
# 条件:所有指尖靠近手掌
tips = [index_tip, middle_tip, ring_tip, pinky_tip]
all_close = True
for tip in tips:
if calculate_distance(tip, wrist) > 0.15:
all_close = False
break
if all_close:
return "NO"
return None
def get_finger_direction(landmarks, h, w):
"""
获取食指指向的方向
返回: "上", "下", "左", "右", "静止"
"""
# 食指近端关节(5)和指尖(8)
x5, y5 = int(landmarks[5].x * w), int(landmarks[5].y * h)
x8, y8 = int(landmarks[8].x * w), int(landmarks[8].y * h)
dx = x8 - x5
dy = y8 - y5
threshold = 25 # 阈值,像素单位
# 判断是否静止
if abs(dx) < threshold and abs(dy) < threshold:
return "静止"
# 判断方向
if abs(dx) > abs(dy):
return "右" if dx > 0 else "左"
else:
return "下" if dy > 0 else "上"
def image_to_user_direction(img_dir):
"""
将图像坐标系转换为用户视角方向
图像左→用户右,图像右→用户左
"""
if img_dir == "左":
return "右"
elif img_dir == "右":
return "左"
else:
return img_dir
4.1.3 实时手势处理流程
def hand_gesture_worker():
"""手势识别工作线程"""
global current_hand_info, gesture_running
# 1. 初始化RealSense摄像头
pipeline = rs.pipeline()
config = rs.config()
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 15)
pipeline.start(config)
# 2. 主循环:持续处理每一帧
while gesture_running:
# 获取彩色帧
frames = pipeline.wait_for_frames(timeout_ms=1000)
color_frame = frames.get_color_frame()
if not color_frame:
continue
# 转换为numpy数组
color_image = np.asanyarray(color_frame.get_data())
h, w = color_image.shape[:2]
# BGR转RGB(MediaPipe需要RGB)
rgb = cv2.cvtColor(color_image, cv2.COLOR_BGR2RGB)
# 3. MediaPipe处理
results = hands.process(rgb)
# 4. 解析结果
lines = []
if results.multi_hand_landmarks and results.multi_handedness:
for hand_landmarks, handedness in zip(
results.multi_hand_landmarks,
results.multi_handedness
):
# 获取左右手判断
mp_label = handedness.classification[0].label
user_hand = "右手" if mp_label == "Left" else "左手"
# 尝试识别特殊手势
gesture = recognize_gesture(hand_landmarks.landmark)
if gesture:
lines.append(f"[{user_hand}] {gesture}")
else:
# 获取食指方向
direction = get_finger_direction(hand_landmarks.landmark, h, w)
# 转换视角
user_direction = image_to_user_direction(direction)
lines.append(f"[{user_hand}] {user_direction}")
# 更新全局状态
current_hand_info = "\n".join(lines) if lines else "未检测到手"
time.sleep(0.1) # 控制帧率
# 5. 清理资源
pipeline.stop()
hands.close()
4.1.4 手势在视力测试中的作用
本系统中,手势识别用于以下场景:
OK手势启动测试
- 用户做OK手势表示准备开始测试
- 系统检测到OK手势后自动启动
方向手势回答
- 测试过程中,用户通过伸手指方向来回答E字方向
- 系统检测食指方向,判断用户回答是否正确
左右手切换
- 右眼测试用右手,左眼测试用左手
- 通过
multi_handedness判断用户使用的是哪只手
4.2 视频播放技术
使用GStreamer实现视频播放,支持硬件解码:
# GStreamer视频解码管道 (intro_video_player.py)
pipeline_str = (
"filesrc location={video_path} ! "
"qtdemux ! "
"h264parse ! mppvideodec ! " # 瑞芯微硬件解码
"videoconvert ! video/x-raw,format=BGR ! "
"appsink name=sink emit-signals=true"
)
技术要点:
- 使用
mppvideodec 调用RK3576硬件解码器
- 通过AppSink将视频帧传递给Qt UI显示
- 音频使用独立管道通过ALSA播放
4.3 状态机设计
系统使用有限状态机管理测试流程:
class TestState:
# 系统状态
SYSTEM_STATE_IDLE = 0 # 系统空闲
SYSTEM_STATE_TESTING = 1 # 正在测试
# 应用状态
APP_STATE_WAITING_OK = 0 # 等待OK手势
APP_STATE_WAITING_HAND_OK = 1 # 等待举手
APP_STATE_TESTING = 2 # 正在测试
APP_STATE_SHOWING_RESULT = 3 # 显示结果
4.4 距离检测
通过串口读取红外测距传感器数据:
# 串口读取距离数据 (main.py)
def _read_distance(self):
try:
if self.serial_port and self.serial_port.in_waiting:
data = self.serial_port.readline()
if data.startswith(b'D:'):
distance = int(data[2:].strip())
return distance
except Exception as e:
print(f"读取距离失败: {e}")
return -1
五、调试过程与问题解决
5.1 主要问题与解决方案
| 问题 | 原因分析 | 解决方案 |
| 视频无法播放 | mp4v编码不支持 | 使用H.264编码重新转换视频 |
| 音频无声音 | 采样率不匹配(24kHz mono) | 转换为44.1kHz stereo |
| 手势识别不稳定 | 光照条件影响 | 调整检测阈值,增加置信度 |
| 距离传感器读数为0 | 串口波特率不匹配 | 改为115200波特率 |
| 测试结果不准确 | 左右手方向判断错误 | 修正手势方向与E字方向的映射关系 |
| 视频画面无法清除 | 停止时回调递归 | 添加stopping标志防止重复调用 |
| E字符不显示 | 停止视频后未显示char_label | 在_start_vision_test中添加显示逻辑 |
5.2 开发历程
2024-01 项目启动,搭建RK3576开发环境
2024-02 实现摄像头采集和显示
2024-02 集成MediaPipe手势识别
2024-02 实现OK手势检测触发测试
2024-02 添加距离传感器串口通信
2024-02 实现视力测试核心逻辑
2024-02 集成语音播报功能
2024-02 添加视频播放引导功能
2024-02 调试优化,修复各种bug
2024-02 最终测试,提交作品
六、项目亮点总结
6.1 技术创新
- 端侧AI推理: 利用RK3576的NPU实现实时手势识别,无需云端支持
- 多模态交互: 结合视频、语音、手势等多种交互方式
- 硬件加速: 使用GStreamer硬件解码播放视频,效率高
6.2 工程亮点
- 模块化设计: 清晰的分层架构,易于维护和扩展
- 状态机管理: 完善的测试流程状态控制
- 容错处理: 丰富的异常处理和恢复机制
- 用户友好: 语音引导+视频演示,操作简单
6.3 应用价值
- 可部署于社区健康站、学校、商场等场所
- 无需专业人员辅助,用户可自主完成检测
- 检测结果实时语音播报,方便快捷
- 成本可控,易于推广普及
七、技术参数
| 参数 | 数值 |
| 代码总量 | 3092行 |
| 视频解码分辨率 | 640x480 |
| 手势识别帧率 | 30fps |
| 距离检测精度 | ±10mm |
| 语音采样率 | 44.1kHz |
| 测试时间 | 约2-3分钟/次 |
八、文件结构
RK3576-Pro/
├── main.py # 主程序入口 (942行)
├── ui_vision_test.py # UI界面 (241行)
├── intro_video_player.py # 视频播放器 (618行)
├── hand_gesture_task.py # 手势识别 (187行)
├── generate_custom_audio.py # 音频生成脚本 (95行)
├── pic/ # E字视力表图片
│ ├── up.png
│ ├── down.png
│ ├── left.png
│ └── right.png
├── custom_audio/ # 语音文件
│ ├── welcome.wav
│ ├── switch_right_hand.wav
│ ├── result_*.wav
│ └── ...
└── videos/ # 视频文件
└── intro_guide.mp4
九、运行说明
9.1 依赖安装
# 安装Python依赖
pip install pyside6 mediapipe pygame numpy opencv-python
# 安装系统依赖
apt-get install gstreamer1.0-tools gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good alsa-utils
9.2 运行步骤
- 连接硬件设备(摄像头、传感器、音频设备)
- 启动开发板
- 运行主程序:
python3 main.py
- 按照屏幕提示和语音指引进行测试
十、总结与展望
本项目成功实现了一套基于RK3576的AI视力检测系统,通过MediaPipe实现精准的手势识别,结合PySide6实现友好的用户界面,利用GStreamer实现流畅的视频播放。系统运行稳定、操作简便,具有良好的用户体验。
未来可进一步优化:
- 增加更多视力测试模式
- 支持云端数据存储和分析
- 添加更多健康检测功能
- 优化AI模型提升识别准确率