Opencv小项目——手势数字刷TIKTOK
写在前面:
很久没更新了,之前的实习的记录也算是烂尾了,但是好在自己的实习记录还是有的,最近也忙碌了很多,终于放假了,今天下午正好没事,闲来无事就随便做个小玩意吧。
思来想去,就做个手势识别,再通过识别的数字来控制电脑端口的抖音,话不多说,让我们直接进入正题。
思路
-
导入库:
- 导入需要的库,包括
cv2
(OpenCV),math
,mediapipe
,pyautogui
,time
,webbrowser
。
- 导入需要的库,包括
-
打开抖音网站:
- 使用
webbrowser.open
打开抖音网站,即函数open_website()
。
- 使用
-
定义二维向量的角度计算函数:
vector_2d_angle
函数接收两个二维向量,计算它们之间的夹角。这个函数用于后续计算手指的角度。
-
获取手部关键点的角度列表:
hand_angle
函数接收手部关键点坐标,通过vector_2d_angle
计算大拇指、食指、中指、无名指和小拇指的角度,并返回一个角度列表。
-
根据角度确定手势:
h_gesture
函数接收角度列表,根据预定义的阈值判断手势类型,返回相应的手势字符串。
-
执行键盘动作:
perform_keyboard_action
函数接收手势字符串,根据手势执行相应的键盘动作。您可以根据需要添加更多手势和对应的键盘动作。
-
手势检测主循环:
detect_and_control_keyboard
函数使用mediapipe
检测手势。通过循环捕获摄像头图像,检测手部关键点,计算手势角度,执行相应的键盘动作,并在图像上显示手势。为了减缓循环速度,使用time.sleep(0.1)
增加每次循环的间隔时间。
-
主程序入口:
- 在
__main__
部分,首先打开抖音网站,然后等待一段时间(time.sleep(0.5)
),最后开始手势检测主循环。
- 在
if (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "0"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "1"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "2"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and (angle_list[3] < thr_angle_s) and (angle_list[4] > thr_angle):gesture_str = "3"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and (angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s):gesture_str = "4"elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and (angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s):gesture_str = "5"elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s):gesture_str = "6"elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "8"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s):gesture_str = "Pink Up"elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "Thumb Up"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] < thr_angle_s) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "Fuck"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] < thr_angle_s) and (angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s):gesture_str = "Princess"elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "Bye"elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s):gesture_str = "Spider-Man"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s):gesture_str = "Rock'n'Roll"
自己去探索吧! 各种手势哦
代码
代码如下:
import cv2
import math
import mediapipe as mp
import pyautogui
import time
import webbrowserdef open_website():url = "https://www.douyin.com/"webbrowser.open(url)def vector_2d_angle(v1, v2):# 求解二维向量的角度v1_x, v1_y = v1[0], v1[1]v2_x, v2_y = v2[0], v2[1]try:angle_ = math.degrees(math.acos((v1_x*v2_x + v1_y*v2_y) / (((v1_x**2 + v1_y**2)**0.5) * ((v2_x**2 + v2_y**2)**0.5))))except:angle_ = 65535.if angle_ > 180.:angle_ = 65535.return angle_def hand_angle(hand_):# 获取对应手相关向量的二维角度,根据角度确定手势angle_list = []# ---------------------------- thumb 大拇指角度angle_ = vector_2d_angle(((int(hand_[0][0]) - int(hand_[2][0])), (int(hand_[0][1]) - int(hand_[2][1]))),((int(hand_[3][0]) - int(hand_[4][0])), (int(hand_[3][1]) - int(hand_[4][1]))))angle_list.append(angle_)# ---------------------------- index 食指角度angle_ = vector_2d_angle(((int(hand_[0][0]) - int(hand_[6][0])), (int(hand_[0][1]) - int(hand_[6][1]))),((int(hand_[7][0]) - int(hand_[8][0])), (int(hand_[7][1]) - int(hand_[8][1]))))angle_list.append(angle_)# ---------------------------- middle 中指角度angle_ = vector_2d_angle(((int(hand_[0][0]) - int(hand_[10][0])), (int(hand_[0][1]) - int(hand_[10][1]))),((int(hand_[11][0]) - int(hand_[12][0])), (int(hand_[11][1]) - int(hand_[12][1]))))angle_list.append(angle_)# ---------------------------- ring 无名指角度angle_ = vector_2d_angle(((int(hand_[0][0]) - int(hand_[14][0])), (int(hand_[0][1]) - int(hand_[14][1]))),((int(hand_[15][0]) - int(hand_[16][0])), (int(hand_[15][1]) - int(hand_[16][1]))))angle_list.append(angle_)# ---------------------------- pink 小拇指角度angle_ = vector_2d_angle(((int(hand_[0][0]) - int(hand_[18][0])), (int(hand_[0][1]) - int(hand_[18][1]))),((int(hand_[19][0]) - int(hand_[20][0])), (int(hand_[19][1]) - int(hand_[20][1]))))angle_list.append(angle_)return angle_listdef h_gesture(angle_list):# 二维约束的方法定义手势thr_angle = 65. # 手指闭合则大于这个值(大拇指除外)thr_angle_thumb = 53. # 大拇指闭合则大于这个值thr_angle_s = 49. # 手指张开则小于这个值gesture_str = "Unknown"if 65535. not in angle_list:if (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "0"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "1"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "2"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and (angle_list[3] < thr_angle_s) and (angle_list[4] > thr_angle):gesture_str = "3"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and (angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s):gesture_str = "4"elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and (angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s):gesture_str = "5"elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s):gesture_str = "6"elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "8"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s):gesture_str = "Pink Up"elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "Thumb Up"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] < thr_angle_s) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "Fuck"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] < thr_angle_s) and (angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s):gesture_str = "Princess"elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):gesture_str = "Bye"elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s):gesture_str = "Spider-Man"elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and (angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s):gesture_str = "Rock'n'Roll"return gesture_strdef perform_keyboard_action(gesture_str):if gesture_str == "0":pyautogui.press('Space')if gesture_str == "1":pyautogui.press('Up')elif gesture_str == "2":pyautogui.press('down')elif gesture_str == "3":pyautogui.press("Z")elif gesture_str == "4":pyautogui.press("X")elif gesture_str == "5":pyautogui.hotkey('ctrl', 'w')elif gesture_str == "Fuck":pyautogui.keyDown('esc')# Add more gestures and corresponding keyboard actions if neededdef detect_and_control_keyboard():mp_drawing = mp.solutions.drawing_utilsmp_hands = mp.solutions.handshands = mp_hands.Hands(static_image_mode=False,max_num_hands=1,min_detection_confidence=0.75,min_tracking_confidence=0.75)cap = cv2.VideoCapture(0)while True:ret, frame = cap.read()frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)frame = cv2.flip(frame, 1)results = hands.process(frame)frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)if results.multi_hand_landmarks:for hand_landmarks in results.multi_hand_landmarks:mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)hand_local = []for i in range(21):x = hand_landmarks.landmark[i].x * frame.shape[1]y = hand_landmarks.landmark[i].y * frame.shape[0]hand_local.append((x, y))if hand_local:angle_list = hand_angle(hand_local)gesture_str = h_gesture(angle_list)print(gesture_str)cv2.putText(frame, gesture_str, (50, 100), 0, 1.3, (0, 0, 255), 2)# Perform keyboard action based on gestureperform_keyboard_action(gesture_str)cv2.imshow('MediaPipe Hands', frame)if cv2.waitKey(1) & 0xFF == 27:breaktime.sleep(0.1)cap.release()cv2.destroyAllWindows()if __name__ == '__main__':open_website() # Open Douyin in Microsoft Edgetime.sleep(0.5) # Give some time for the browser to open before starting hand gesture detectiondetect_and_control_keyboard()
运行结果:
相关文章:

Opencv小项目——手势数字刷TIKTOK
写在前面: 很久没更新了,之前的实习的记录也算是烂尾了,但是好在自己的实习记录还是有的,最近也忙碌了很多,终于放假了,今天下午正好没事,闲来无事就随便做个小玩意吧。 思来想去ÿ…...

【优化技术专题】「性能优化系列」针对Java对象压缩及序列化技术的探索之路
针对Java对象压缩及序列化技术的探索之路 序列化和反序列化为何需要有序列化呢?Java实现序列化的方式二进制格式 指定语言层级二进制格式 跨语言层级JSON 格式化类JSON格式化:XML文件格式化 序列化的分类在速度的对比上一般有如下规律:Java…...

Spring+SprinMVC+MyBatis配置方式简易模板
SpringSprinMVCMyBatis配置方式简易模板代码Demo GitHub访问 ssm-tpl-cfg 一、SQL数据准备 创建数据库test,执行下方SQL创建表ssm-tpl-cfg /*Navicat Premium Data TransferSource Server : 127.0.0.1Source Server Type : MySQLSource Server Versio…...

Windows ssh登录eNSP交换机
目录 1. Cloud IO配置1.1 创建UDP端口1.2 创建本地连接1.3 端口映射设置 2. 交换机配置2.1 配置vlanif2.2 配置vty2.3 配置ssh用户2.4 配置aaa2.5 使用Xshell工具登录2.6 用户和密码2.7 登录成功 3. 使用cmd 登录报错提示3.1 手动指定加密算法,提示密码长度无效3.2 …...

SwiftUI 纯手工打造 100% 可定制的导航栏
功能需求 何曾几时,我们是否也厌倦了 SwiftUI 界面中刻板守旧的导航栏外观,而想要自己动手充分展示灵动炸裂的创造力呢? 如上图所示:我们在 SwiftUI 中通过纯手工打造了一款 100 在本篇博文中,您将学到以下内容 功能需求1. 导航栏基本结构2. 如何感知当前发生用户拖拽行为…...

npm install 太慢?解决方法
在使用npm进行包管理时,有时会遇到安装速度缓慢的问题。这可能是由于网络原因或npm官方镜像服务器的繁忙导致的。下面介绍几种常见的解决方法: 使用淘宝镜像 淘宝镜像是一个提供npm包镜像的国内源,其速度较快且稳定。您可以通过以下命令将npm…...

DevOps系列文章之 GitLab CI/CD
CICD是什么? 由于目前公司使用的gitlab,大部分项目使用的CICD是gitlab的CICD,少部分用的是jenkins,使用了gitlab-ci一段时间后感觉还不错,因此总结一下 介绍gitlab的CICD之前,可以先了解CICD是什么 我们的开发模式…...

【CompletableFuture任务编排】游戏服务器线程模型及其线程之间的交互(以排行榜线程和玩家线程的交互为例子)
需求: 1.我们希望玩家的业务在玩家线程执行,无需回调,因此是多线程处理。 2.匹配线程负责匹配逻辑,是单独一个线程。 3.排行榜线程负责玩家的上榜等。 4.从排行榜线程获取到排行榜列表后,需要给玩家发奖修改玩家数…...

什么是浏览器指纹?详解浏览器指纹识别技术,教你防止浏览器指纹识别
在数字时代,我们的在线活动几乎总是留下痕迹。其中,浏览器指纹就像我们的数字身份证,让网站能够识别和追踪用户。对于跨境电商行业来说,了解这种追踪技术尤其重要,因为它可能影响账号的管理和安全。本文将详细介绍浏览…...

canvas绘制六芒星
查看专栏目录 canvas实例应用100专栏,提供canvas的基础知识,高级动画,相关应用扩展等信息。canvas作为html的一部分,是图像图标地图可视化的一个重要的基础,学好了canvas,在其他的一些应用上将会起到非常重…...

全网最详细!!Python 爬虫快速入门
1. 背景 最近在工作中有需要使用到爬虫的地方,需要根据 Gitlab Python 实现一套定时爬取数据的工具,所以借此机会,针对 Python 爬虫方面的知识进行了学习,也算 Python 爬虫入门了。 需要了解的知识点: Python 基础语…...

gitgud.io+Sapphire注册账号教程
gitgud.io是一个仓库,地址 https://gitgud.io/,点进去之后会看到注册页面。 意思是需要通过注册这个Sapphire账户来登录。点击右边的Sapphire,就跳转到Sapphire的登陆页面,点击创建新账号,就进入注册页面。࿰…...

【动态规划】【广度优先搜索】【状态压缩】847 访问所有节点的最短路径
作者推荐 视频算法专题 本文涉及知识点 动态规划汇总 广度优先搜索 状态压缩 LeetCode847 访问所有节点的最短路径 存在一个由 n 个节点组成的无向连通图,图中的节点按从 0 到 n - 1 编号。 给你一个数组 graph 表示这个图。其中,graph[i] 是一个列…...

python基础小知识:引用和赋值的区别
嗨喽~大家好呀,这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 1.引用 python中,赋值操作会产生相同对象的多个引用, 如果在原位置修改这个可变对象时,可能会影响程序其他位置对这个对象的…...

欧科云链与《警察技术》联合发布技术专题.pdf
欧科云链受《警察技术》邀请,于第201期期刊正式刊登“区块链生态安全与虚拟货币犯罪治理”技术专题。欧科云链作为该技术专题主要作者,直接参与本次期刊2篇文章撰写,同时为多篇文章提供欧科云链的最新数据和研究成果。 《警察技术》期刊创办于…...

【QT+QGIS跨平台编译】之一:【sqlite+Qt跨平台编译】(一套代码、一套框架,跨平台编译)
文章目录 一、sqlite3介绍二、文件下载三、文件分析四、pro文件五、编译实践 一、sqlite3介绍 SQLite是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的&…...

websocket实现聊天室(vue2 + node)
通过websocket实现简单的聊天室功能 需求分析如图: 搭建的项目结构如图: 前端步骤: vue create socket_demo (创建项目)views下面建立Home , Login组件路由里面配置路径Home组件内部开启websocket连接 前端相关组件代码: Login…...

RabbitMQ-消息延迟
一、死信交换机 1、描述 一个队列接收到的消息有过期时间,消息过期之后,如果配置有死信队列,消息就会进去死信队列。 2、图解 3、过程 当生产者将消息发送到exchange1,然后交换机将消息路由到队列queue1,但是队列que…...

【Oracle】如何给物化视图分区
文章目录 【Oracle】如何给物化视图分区给物化视图进行分区的例 【声明】文章仅供学习交流,观点代表个人,与任何公司无关。 编辑|SQL和数据库技术(ID:SQLplusDB) 收集Oracle数据库内存相关的信息 【Oracle】ORA-32017和ORA-00384错误处理 【Oracle】设置…...

10个常考的前端手写题,你全都会吗?
前言 📫 大家好,我是南木元元,热爱技术和分享,欢迎大家交流,一起学习进步! 🍅 个人主页:南木元元 今天来分享一下10个常见的JavaScript手写功能。 目录 1.实现new 2.call、apply、…...

vue组件间通信
Vue组件之间通信方式有哪些 一、父子组件通讯 1、props,emit 父组件可以通过props给子组件传递变量。子组件可以通过emit派发自定义事件,使父组件可以获得事件函数传递过来的形参。 2、$parent、$children、ref 父组件可以通过 c h i l d r e n 获取…...

编程框架概述:MVC, MVP, MVVM, Flux/Redux, 和 Clean Architecture
前言 在软件开发中,选择合适的编程框架和架构模式对于构建可维护和可扩展的应用程序至关重要。初学者在面对多种架构选项时可能会感到困惑。本文将详细介绍五种流行的编程框架:MVC、MVP、MVVM、Flux/Redux和Clean Architecture。 MVC(Model-V…...

多维时序 | Matlab实现CNN-BiLSTM-Mutilhead-Attention卷积双向长短期记忆神经网络融合多头注意力机制多变量时间序列预测
多维时序 | Matlab实现CNN-BiLSTM-Mutilhead-Attention卷积双向长短期记忆神经网络融合多头注意力机制多变量时间序列预测 目录 多维时序 | Matlab实现CNN-BiLSTM-Mutilhead-Attention卷积双向长短期记忆神经网络融合多头注意力机制多变量时间序列预测效果一览基本介绍程序设计…...

np.argsort排序问题(关于位次)-含GitHub上在numpy项目下提问的回复-总结可行方案
np.argsort 与获取位相关问题 位次: 数组中的数据在其排序之后的另一个数组中的位置 [1,0,2,3] 中 0的位次是1 1的位次是2 2的位次是3 3的位次是4 这里先直接给出结论,np.argsort()返回的索引排序与实际位次在确实在某些情况下会出现一致,但后来numpy的开…...

Element中的el-input-number+SpringBoot+mysql
1、编写模板 <el-form ref"form" label-width"100px"><el-form-item label"商品id:"><el-input v-model"id" disabled></el-input></el-form-item><el-form-item label"商品名称&a…...

Jupyter Notebook五分钟基础速通
1 作用 常用于数据分析 2 安装 2.1 Anaconda 通过直接安装Anaconda,会自动安装Jupyter Notebook 2.2 命令行安装 ① 3.x版本 pip3 install --upgrade pip pip3 install jupyter ② 2.x版本 pip install --upgrade pip pip install jupyter 3 启动 cmd窗口下…...

基于SpringBoot的SSM整合案例
项目目录: 数据库表以及表结构 user表结构 user_info表结构 引入依赖 父模块依赖: <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.12.RELEASE</version>…...
[SS]语义分割_转置卷积
转置卷积(Transposed Convolution) 抽丝剥茧,带你理解转置卷积(反卷积) 目录 一、概念 1、定义 2、运算步骤 二、常见参数 一、概念 1、定义 转置卷积(Transposed Convolution)…...

面板小程序命令行工具介绍
Ray 体系提供配套的工程化解决方案。 由于多端构建的一些客观原因,在构建流程的设计上,必须将工程套件安装在项目内。 项目内的依赖至少包含以下内容: {"dependencies": {"ray-js/ray": "latest"},"de…...

DBA技术栈MongoDB: 数据增改删除
该博文主要介绍mongoDB对文档数据的增加、更新、删除操作。 1.插入数据 以下案例演示了插入单个文档、多个文档、指定_id、指定多个索引以及插入大量文档的情况。在实际使用中,根据需求选择适合的插入方式。 案例1:插入单个文档 db.visitor.insert({…...