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、…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
Python训练营-Day26-函数专题1:函数定义与参数
题目1:计算圆的面积 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求:函数接收一个位置参数 radi…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...
raid存储技术
1. 存储技术概念 数据存储架构是对数据存储方式、存储设备及相关组件的组织和规划,涵盖存储系统的布局、数据存储策略等,它明确数据如何存储、管理与访问,为数据的安全、高效使用提供支撑。 由计算机中一组存储设备、控制部件和管理信息调度的…...
