汽车大赛+AI手识识别提交贴
本帖最后由 meiyao 于 2026-1-20 14:06 编辑一、功能使用摄像头实现AI手识检测识别,使用树莓派摄像头捕捉实时视频流。对视频流进行处理,然后再进行对比,是否是正确的手势,使用背景减除算法去除背景干扰,利用OpenCV的手势识别算法检测和跟踪手势,根据手势识别结果进行相应的操作控制灯光,或者对应的执行设备,舵机等装置。进行物体识别,或者是进行场景灯光调节,当正在看书时,出现阅读模式,点亮阅读灯,如果正在玩手机时,点切换为游戏模式,高亮白光灯。
二、模式介绍1、手识:1,2,32、模式:无人模式,阅读模式,手机模式3、灯光模式:白光,蓝光,**光
设置开机自动启动 上电后等几十秒就可以手势操作了对准摄像头 手正对摄像头30厘米左右就行 这个识别范围比较大手势1读书模式 暖色灯 舵机动手势2手机模式 冷色灯 舵机不动其他手势 保持灯的亮度和颜色无手势无人模式 灯光会暗
三、主要器件树莓派5-- PI5(4核2.4GHz Cortex-A76)-- 支持4K视频解码、硬件PWM、原生USB3.0(高速摄像头数据传输)舵机--SG90(9g微型舵机)-- 扭矩2.5kg·cm(5V供电)、响应速度0.12s/60°、控制信号周期20ms(50Hz)灯--WS2812(5050 RGB LED)--单线通信(NeoPixel协议)、24位真彩色(1677万色)、支持级联(最大100颗)串口屏--TJC804X550_011(4.3寸)--分辨率480×272、TJC自定义协议、支持触摸交互、预留UART接口(波特率115200)摄像头--九目4K USB免驱动--分辨率3840×2160@30FPS、自动对焦、UVC协议兼容(Linux原生支持)
舵机物理引脚:GPIO 12树莓派40针引脚:引脚32(GPIO 12)功能:PWM信号输出,控制舵机角度电压:3.3V PWM信号串口屏树莓派默认串口引脚:TXD (发送) GPIO14 引脚8RXD (接收) GPIO15 引脚10GND 引脚6(或任何GND)
四、连接原理图graph LR PI5[树莓派5] -->|GPIO18(PWM)| SG90[舵机] PI5-->|GPIO12(PWM)| WS2812[灯带] PI5-->|UART(TX/RX)| TJC[串口屏] PI5-->|USB3.0| Camera五、软件框架图框架图
软件工作流程图
六、代码
初始化串口通信
ser = serial.Serial(
port='/dev/serial0',# 树莓派默认串口设备
baudrate=9600, # 波特率
timeout=1 # 读取超时时间(秒)
)
串口通信数据定义
格式说明:每条指令以0xFF 0xFF 0xFF结尾
book_data = bytes([
0x70,0x61, 0x67, 0x65, 0x30, 0x2E, 0x70, 0x30, # "page0.p0"
0x2E,0x70, 0x69, 0x63, 0x3D, 0x30, # ".pic=0"
0xFF,0xFF, 0xFF # 结束标志
])# 对应"书本"命令,显示图片0
phone_data = bytes([
0x70,0x61, 0x67, 0x65, 0x30, 0x2E, 0x70, 0x30, # "page0.p0"
0x2E,0x70, 0x69, 0x63, 0x3D, 0x31, # ".pic=1"
0xFF,0xFF, 0xFF # 结束标志
])# 对应"手机"命令,显示图片1
nobody_data = bytes([
0x70,0x61, 0x67, 0x65, 0x30, 0x2E, 0x30, 0x30, # "page0.p0"
0x2E,0x70, 0x69, 0x63, 0x3D, 0x32, # ".pic=2"
0xFF,0xFF, 0xFF # 结束标志
])# 对应"无人"状态,显示图片2
DEBOUNCE_TIME = 1 # 防抖时间(秒),手势需稳定1秒才触发动作
#####################################
--- 舵机(Servo)控制模块 ---
#####################################
初始化舵机,连接到GPIO 12引脚
脉冲宽度范围:0.5ms-2.5ms,对应-90°到+90°
servo = Servo(12, min_pulse_width=0.5/1000,max_pulse_width=2.5/1000)
def servo_move():
"""
控制舵机旋转动作
舵机顺时针(CCW)旋转0.25秒后停止
"""
servo.value = 1 # 设置为最大值,舵机以最快速度逆时针旋转
print("CCW fast - 舵机逆时针旋转")
sleep(0.25) # 持续旋转0.25秒
servo.value = 0 # 设置为0,舵机停止
print("Stopped - 舵机停止")
sleep(0.2) # 短暂停顿
#####################################
--- LED控制模块(SPI版本)---
#####################################
LED配置参数
LED_COUNT = 4 # LED灯珠数量
LED_BRIGHTNESS = 0.7 # 正常亮度(范围0.0-1.0)
DIM_BRIGHTNESS = 0.05 # 休眠模式亮度
初始化SPI总线连接NeoPixel LED
spi_bus = board.SPI()
pixels = neopixel.NeoPixel_SPI(
spi_bus, # SPI总线
LED_COUNT, # LED数量
brightness=LED_BRIGHTNESS,# 初始亮度
pixel_order=neopixel.GRB, # LED颜色顺序(Green-Red-Blue)
auto_write=False # 手动控制刷新
)
def set_color(r, g, b):
"""
设置所有LED灯的颜色
参数:
r: 红色分量 (0-255)
g: 绿色分量 (0-255)
b: 蓝色分量 (0-255)
"""
for i inrange(LED_COUNT):
pixels = (r, g, b)
pixels.show()# 更新LED显示
def set_brightness(value):
"""
设置LED亮度
参数:
value: 亮度值(0.0-1.0)
"""
pixels.brightness = value
pixels.show()
#####################################
--- Mediapipe手势识别配置 ---
#####################################
初始化Mediapipe手部识别
mp_hands = mp.solutions.hands
手指关键点索引定义
FINGER_TIPS = # 大拇指、食指、中指、无名指、小指尖端
FINGER_DIPS = # 对应手指的中间关节
def is_finger_up(hand, tip, dip):
"""
判断手指是否伸直
原理: 指尖的y坐标小于中间关节的y坐标时,手指向上
注意: Mediapipe坐标系原点在左上角,y轴向下
"""
returnhand.landmark.y < hand.landmark.y
#####################################
--- 主程序循环 ---
#####################################
初始化摄像头
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) # 设置分辨率320x240
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)# 降低分辨率提高处理速度
手势状态变量
last_gesture = None # 最新检测到的手势
last_executed_gesture = None # 上一次执行过动作的手势
gesture_start_time = time.time()# 手势开始时间
current_color = (255, 255, 255)# 当前LED颜色,初始为白色
初始化Mediapipe手部识别模型
with mp_hands.Hands(
max_num_hands=1, # 最多识别1只手
min_detection_confidence=0.5,# 检测置信度阈值
min_tracking_confidence=0.5 # 跟踪置信度阈值
) as hands:
# 主循环
whileTrue:
# 读取摄像头帧
ok,frame = cap.read()
ifnot ok:
continue# 读取失败则跳过
# 将BGR转换为RGB(Mediapipe需要RGB格式)
rgb =cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# 手势识别处理
result = hands.process(rgb)
gesture = None # 当前检测到的手势
hand_present = False# 是否有手部被检测到
#-------------------------
# 1. 手势检测逻辑
#-------------------------
ifresult.multi_hand_landmarks:# 检测到手部
hand_present = True
hand = result.multi_hand_landmarks # 只处理第一只手
#计算除大拇指外的手指伸直数量
fingers_up = 0
for tip, dip in zip(FINGER_TIPS, FINGER_DIPS):
if is_finger_up(hand, tip, dip):
fingers_up += 1
#手势映射:
#1根手指伸直-> 手势1
#2根手指伸直-> 手势2
if fingers_up == 1:
gesture = 1
elif fingers_up == 2:
gesture = 2
#其他手指数量视为无效手势
#-------------------------
# 2. 无手状态处理(休眠模式)
#-------------------------
ifnot hand_present:
set_brightness(DIM_BRIGHTNESS)# 降低亮度进入休眠
last_gesture = None
last_executed_gesture = None
ser.write(nobody_data)# 发送无人状态到串口设备
continue# 跳过**处理
#-------------------------
# 3. 手部刚出现处理(唤醒模式)
#-------------------------
iflast_gesture is None:# 手部刚出现
set_brightness(LED_BRIGHTNESS)# 恢复亮度
#根据手势设置不同颜色
if gesture == 1:
current_color = (255, 150, 80)# 橙色
set_color(*current_color)
elif gesture == 2:
current_color = (100, 150, 255)#蓝色
set_color(*current_color)
else:
# 无效手势保持原颜色
set_color(*current_color)
#更新手势状态和时间
last_gesture = gesture
gesture_start_time = time.time()
continue
#-------------------------
# 4. 手势变化检测
#-------------------------
ifgesture != last_gesture:# 手势发生变化
last_gesture = gesture
gesture_start_time = time.time() # 重置计时器
print(f"检测到手势变化 →{gesture}")
continue
#-------------------------
# 5. 手势稳定触发(防抖处理)
#-------------------------
iftime.time() - gesture_start_time >= DEBOUNCE_TIME:
#如果与上次执行的手势相同,不重复执行
if gesture == last_executed_gesture:
continue
#记录本次执行的手势
last_executed_gesture = gesture
#根据手势执行对应动作
if gesture == 1:
print("执行:手势1动作(书本)")
ser.write(book_data)# 发送书本命令
current_color = (255, 150, 80)# 橙色
set_color(*current_color)
# 在新线程中控制舵机,避免阻塞主循环
t = threading.Thread(target=servo_move, daemon=True)
t.start()
elif gesture == 2:
print("执行:手势2动作(手机)")
ser.write(phone_data)# 发送手机命令
current_color = (100, 150, 255)#蓝色
set_color(*current_color)
else:
continue# 无效手势不执行
释放摄像头资源
cap.release()
释放舵机资源
servo.angle = None
七、实物连接图
八、视频PI5手识识别_哔哩哔哩_bilibili
牛呀,太强了!
页:
[1]