2024-12-22 20:19:12 [显示全部楼层]
15浏览
查看: 15|回复: 0

[M10项目] 行空板M10——隔空手势传屏

[复制链接]
本帖最后由 云天 于 2024-12-22 20:24 编辑

行空板M10——隔空手势传屏图3

【项目背景】

        随着智能手机和物联网技术的快速发展,手势控制作为一种新颖的交互方式,正在逐渐渗透到我们的日常生活中。华为手机的隔空手势截屏功能,就是一个很好的例子,它通过识别用户的手势来实现屏幕截图,不仅提高了用户体验,还展示了手势控制技术在移动设备上的应用潜力。

【项目设计】

        本项目旨在通过两个行空板实现类似的手势控制屏幕截图功能。我们将利用OpenCV库来采集手势图像,这是一个开源的计算机视觉和机器学习软件库,它提供了多种图像和视频处理功能,非常适合用于实时手势识别。同时,我们将使用Mediapipe库来识别手势,Mediapipe是一个由Google开发的跨平台框架,它集成了多种先进的机器学习模型,包括手势识别,能够实时准确地识别手部关键点和手势。

        项目的核心在于通过物联网技术,实现两个行空板之间的图像传输。当行空板1通过摄像头采集到的手势被识别为拳头时,它将触发屏幕截图功能,并将截图通过物联网发送给行空板2。而行空板2在识别到张开的手掌手势时,将接收并显示通过物联网传输过来的图片。

        这个项目不仅展示了手势识别技术在物联网领域的应用,还体现了如何通过智能硬件和软件的结合,实现更加直观和便捷的用户交互体验。通过这种方式,我们可以探索手势控制在智能家居、工业自动化、游戏娱乐等多个领域的应用潜力,推动智能交互技术的发展。

【硬件设计】

行空板M10——隔空手势传屏图1


摄像头通过USB接口连接行空板,供电使用充电宝。
【项目准备】
1.行空板安装 pyautogui,终端安装:sudo apt-get install scrot
2.行空板安装MediaPipe库,安装方法:https://www.unihiker.com.cn/wiki ... 3%E4%B8%8B%E8%BD%BD
【程序编写】
1.测试行空板画图,发送屏幕截图至siot物联网平台。
行空板M10——隔空手势传屏图2

2.增加手势(握拳)识别
  1. import cv2
  2. import mediapipe as mp
  3. import math
  4. import sys
  5. import siot
  6. import time
  7. import pyautogui
  8. import numpy as np
  9. from unihiker import GUI
  10. import base64
  11. from io import BytesIO
  12. from PIL import Image
  13. from unihiker import Audio
  14. sys.path.append("/root/mindplus/.lib/thirdExtension/nick-base64-thirdex")
  15. def frame2base64(frame):
  16.     frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
  17.     img = Image.fromarray(frame) #将每一帧转为Image
  18.     output_buffer = BytesIO() #创建一个BytesIO
  19.     img.save(output_buffer, format='JPEG') #写入output_buffer
  20.     byte_data = output_buffer.getvalue() #在内存中读取
  21.     base64_data = base64.b64encode(byte_data) #转为BASE64
  22.     return base64_data #转码成功 返回base64编码
  23. def base642base64(frame):
  24.     data=str('data:image/png;base64,')
  25.     base64data = str(frame2base64(frame))
  26.     framedata = base64data[2:(len(base64data)-1)]
  27.     base642base64_data = data + str(framedata)
  28.     return base642base64_data
  29. # 事件回调函数
  30. def mouse_move(x,y):
  31.     global HuaDongJianGe
  32.     global startX, startY,endX, endY,bs,img
  33.     global 画图
  34.     print((str(startX) + str((str(":") + str((str(startY) + str((str(" ") + str((str(endX) + str((str(":") + str(endY)))))))))))))
  35.     if ((time.time() - HuaDongJianGe) > 0.5):
  36.         bs = 0
  37.     HuaDongJianGe = time.time()
  38.     if (bs == 0):
  39.         startX = x
  40.         startY = y
  41.         endX = x
  42.         endY = y
  43.         bs = 1
  44.         画点=u_gui.fill_circle(x=x,y=y,r=2,color="#0000FF")
  45.         画图=u_gui.draw_line(x0=startX,y0=startY,x1=endX,y1=endY,width=5,color="#0000FF")
  46.     else:
  47.         startX = endX
  48.         startY = endY
  49.         endX = x
  50.         endY = y
  51.         画点=u_gui.fill_circle(x=x,y=y,r=2,color="#0000FF")
  52.         画图=u_gui.draw_line(x0=startX,y0=startY,x1=endX,y1=endY,width=5,color="#0000FF")
  53. def qingkong():
  54.     u_gui.clear()
  55. def jietu():
  56.     screenshot = pyautogui.screenshot()
  57.     screenshot.save('screenshot.png')
  58.     img = cv2.imread("screenshot.png", cv2.IMREAD_UNCHANGED)
  59.    
  60.     siot.publish(topic="df/pic", data=str(base642base64(img)))
  61. mp_hands = mp.solutions.hands
  62. hands = mp_hands.Hands(static_image_mode=False, max_num_hands=1, min_detection_confidence=0.5, min_tracking_confidence=0.5)
  63. mp_drawing = mp.solutions.drawing_utils
  64. u_audio = Audio()
  65. u_gui=GUI()
  66. u_gui.on_mouse_move(mouse_move)
  67. startX = 0
  68. startY = 0
  69. endX = 0
  70. endY = 0
  71. bs = 0
  72. bs2 = 0
  73. HuaDongJianGe = time.time()
  74. siot.init(client_id="7134840160197196",server="10.1.2.3",port=1883,user="siot",password="dfrobot")
  75. siot.connect()
  76. siot.loop()
  77. u_gui.on_mouse_move(mouse_move)
  78. def distance(point1, point2):
  79.     return math.sqrt((point2.x - point1.x)**2 + (point2.y - point1.y)**2)
  80. # 定义一个函数来判断手势
  81. def determine_gesture(landmark):
  82.     # 定义拳头和手掌张开的阈值
  83.     fist_threshold = 1  # 拳头的阈值,较小的距离表示拳头
  84.     open_hand_threshold = 1.5  # 手掌张开的阈值,较大的距离表示手掌张开
  85.     # 获取拇指尖和手腕之间的距离
  86.     middle_FINGER_TIP = landmark.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_TIP]
  87.     middle_FINGER_MCP = landmark.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_MCP]
  88.     wrist = landmark.landmark[mp_hands.HandLandmark.WRIST]
  89.     d1 = distance(middle_FINGER_TIP, wrist)
  90.     d2 = distance(middle_FINGER_MCP, wrist)
  91.     d=d1/d2
  92.     print(d1/d2)
  93.     # 根据距离判断手势
  94.    
  95.     if d < fist_threshold:
  96.         return "Fist"
  97.     elif d > open_hand_threshold:
  98.         return "Open Hand"
  99.     else:
  100.         return "Unknown"
  101.    
  102. # 打开摄像头
  103. cap = cv2.VideoCapture(0)
  104. while cap.isOpened():
  105.     success, image = cap.read()
  106.     if not success:
  107.         continue
  108.     image = cv2.resize(image,( 240, 320))
  109.    
  110.     # 将BGR图像转换为RGB
  111.     image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
  112.     image = cv2.flip(image, 1)
  113.     # 处理图像并获取手部关键点
  114.     results = hands.process(image)
  115.    
  116.     # 绘制手部关键点和连接线
  117.     image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
  118.     if results.multi_hand_landmarks:
  119.         for hand_landmarks in results.multi_hand_landmarks:
  120.             mp_drawing.draw_landmarks(image, hand_landmarks, mp_hands.HAND_CONNECTIONS)
  121.             # 判断手势
  122.             gesture = determine_gesture(hand_landmarks)
  123.             print(gesture)
  124.             if gesture=="Fist":
  125.               if bs2==0:
  126.                 bs2=1
  127.                 jietu()
  128.                 qingkong()
  129.                 u_audio.play("ding.mp3")
  130.             else:
  131.                 bs2=0
  132.             #cv2.putText(image, gesture, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
  133.     # 显示图像
  134.     #cv2.imshow("Image", image)
  135.     # 按'q'退出
  136.     #if cv2.waitKey(1) & 0xFF == ord('q'):
  137.         ##break
  138. # 释放资源
  139. cap.release()
  140. #cv2.destroyAllWindows()
复制代码

3.接收截图

行空板M10——隔空手势传屏图4

4.手势(手掌张开)接收程序
  1. import cv2
  2. import mediapipe as mp
  3. import math
  4. import sys
  5. import siot
  6. import time
  7. import pyautogui
  8. import numpy as np
  9. from unihiker import GUI
  10. import base64
  11. from io import BytesIO
  12. from PIL import Image
  13. from unihiker import Audio
  14. sys.path.append("/root/mindplus/.lib/thirdExtension/nick-base64-thirdex")
  15. def frame2base64(frame):
  16.     frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
  17.     img = Image.fromarray(frame) #将每一帧转为Image
  18.     output_buffer = BytesIO() #创建一个BytesIO
  19.     img.save(output_buffer, format='JPEG') #写入output_buffer
  20.     byte_data = output_buffer.getvalue() #在内存中读取
  21.     base64_data = base64.b64encode(byte_data) #转为BASE64
  22.     return base64_data #转码成功 返回base64编码
  23. def base642base64(frame):
  24.     data=str('data:image/png;base64,')
  25.     base64data = str(frame2base64(frame))
  26.     framedata = base64data[2:(len(base64data)-1)]
  27.     base642base64_data = data + str(framedata)
  28.     return base642base64_data
  29. # 事件回调函数
  30. def mouse_move(x,y):
  31.     global HuaDongJianGe
  32.     global startX, startY,endX, endY,bs,img
  33.     global 画图
  34.     print((str(startX) + str((str(":") + str((str(startY) + str((str(" ") + str((str(endX) + str((str(":") + str(endY)))))))))))))
  35.     if ((time.time() - HuaDongJianGe) > 0.5):
  36.         bs = 0
  37.     HuaDongJianGe = time.time()
  38.     if (bs == 0):
  39.         startX = x
  40.         startY = y
  41.         endX = x
  42.         endY = y
  43.         bs = 1
  44.         画点=u_gui.fill_circle(x=x,y=y,r=2,color="#0000FF")
  45.         画图=u_gui.draw_line(x0=startX,y0=startY,x1=endX,y1=endY,width=5,color="#0000FF")
  46.     else:
  47.         startX = endX
  48.         startY = endY
  49.         endX = x
  50.         endY = y
  51.         画点=u_gui.fill_circle(x=x,y=y,r=2,color="#0000FF")
  52.         画图=u_gui.draw_line(x0=startX,y0=startY,x1=endX,y1=endY,width=5,color="#0000FF")
  53. def qingkong():
  54.     u_gui.clear()
  55. def jietu():
  56.     screenshot = pyautogui.screenshot()
  57.     screenshot.save('screenshot.png')
  58.     img = cv2.imread("screenshot.png", cv2.IMREAD_UNCHANGED)
  59.    
  60.     siot.publish(topic="df/pic", data=str(base642base64(img)))
  61.   
  62. mp_hands = mp.solutions.hands
  63. hands = mp_hands.Hands(static_image_mode=False, max_num_hands=1, min_detection_confidence=0.5, min_tracking_confidence=0.5)
  64. mp_drawing = mp.solutions.drawing_utils
  65. u_audio = Audio()
  66. u_gui=GUI()
  67. u_gui.on_mouse_move(mouse_move)
  68. startX = 0
  69. startY = 0
  70. endX = 0
  71. endY = 0
  72. bs = 0
  73. bs2 = 0
  74. HuaDongJianGe = time.time()
  75. siot.init(client_id="7134840160197196",server="10.1.2.3",port=1883,user="siot",password="dfrobot")
  76. siot.connect()
  77. siot.loop()
  78. u_gui.on_mouse_move(mouse_move)
  79. def distance(point1, point2):
  80.     return math.sqrt((point2.x - point1.x)**2 + (point2.y - point1.y)**2)
  81. # 定义一个函数来判断手势
  82. def determine_gesture(landmark):
  83.     # 定义拳头和手掌张开的阈值
  84.     fist_threshold = 1  # 拳头的阈值,较小的距离表示拳头
  85.     open_hand_threshold = 1.5  # 手掌张开的阈值,较大的距离表示手掌张开
  86.     # 获取拇指尖和手腕之间的距离
  87.     middle_FINGER_TIP = landmark.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_TIP]
  88.     middle_FINGER_MCP = landmark.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_MCP]
  89.     wrist = landmark.landmark[mp_hands.HandLandmark.WRIST]
  90.     d1 = distance(middle_FINGER_TIP, wrist)
  91.     d2 = distance(middle_FINGER_MCP, wrist)
  92.     d=d1/d2
  93.     print(d1/d2)
  94.     # 根据距离判断手势
  95.    
  96.     if d < fist_threshold:
  97.         return "Fist"
  98.     elif d > open_hand_threshold:
  99.         return "Open Hand"
  100.     else:
  101.         return "Unknown"
  102.    
  103. # 打开摄像头
  104. cap = cv2.VideoCapture(0)
  105. while cap.isOpened():
  106.     success, image = cap.read()
  107.     if not success:
  108.         continue
  109.     image = cv2.resize(image,( 240, 320))
  110.    
  111.     # 将BGR图像转换为RGB
  112.     image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
  113.     image = cv2.flip(image, 1)
  114.     # 处理图像并获取手部关键点
  115.     results = hands.process(image)
  116.    
  117.     # 绘制手部关键点和连接线
  118.     image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
  119.     if results.multi_hand_landmarks:
  120.         for hand_landmarks in results.multi_hand_landmarks:
  121.             mp_drawing.draw_landmarks(image, hand_landmarks, mp_hands.HAND_CONNECTIONS)
  122.             # 判断手势
  123.             gesture = determine_gesture(hand_landmarks)
  124.             print(gesture)
  125.             if gesture=="Fist":
  126.               if bs2==0:
  127.                 bs2=1
  128.                 jietu()
  129.                 qingkong()
  130.                 u_audio.play("ding.mp3")
  131.             else:
  132.                 bs2=0
  133.             #cv2.putText(image, gesture, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
  134.     # 显示图像
  135.     #cv2.imshow("Image", image)
  136.     # 按'q'退出
  137.     #if cv2.waitKey(1) & 0xFF == ord('q'):
  138.         ##break
  139. # 释放资源
  140. cap.release()
  141. #cv2.destroyAllWindows()
复制代码
【演示视频】


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail