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、…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
