python使用opencv实现手势识别并控制ppt

需要使用到的包

from collections import dequeimport cv2
import numpy as np
import math
import shutilimport sys
import os
import time#这个求出现频率最高的太慢了,所以把它放弃了
from collections import Counter

准备好安装包后需要获取图片

def star():while camera.isOpened():global frameret, frame = camera.read()frame = cv2.flip(frame, 1)cv2.imshow('ori', frame)## img=frame[0:int(0.8 * frame.shape[0]),#       int(0.5 * frame.shape[1]):frame.shape[1]][0:int(0.8 * frame.shape[0]),#       int(0.5 * frame.shape[1]):frame.shape[1]]frame,ndefects=grdetect(frame)# cv2.imshow('min', img)k = cv2.waitKey(1)if k == 27:camera.release()cv2.destroyAllWindows()break

写进方法start中
视频也是图片构成的,只是在不同帧展示不同的图片而已。这里根据自己电脑的性能选择取图片的频率。

然后一处图片的噪点

def _remove_background(frame):fgbg = cv2.createBackgroundSubtractorMOG2()  # 利用BackgroundSubtractorMOG2算法消除背景fgmask = fgbg.apply(frame)kernel = np.ones((3, 3), np.uint8)fgmask = cv2.erode(fgmask, kernel, iterations=1)res = cv2.bitwise_and(frame, frame, mask=fgmask)# cv2.imshow('res',fgmask)return res

最终是给机器看的,在让他处理之前尽量降低影响条件。

再根据皮肤识别获取手的大致形状

def _bodyskin_detetc(frame):# 肤色检测: YCrCb之Cr分量 + OTSU二值化ycrcb = cv2.cvtColor(frame, cv2.COLOR_BGR2YCrCb)  # 分解为YUV图像,得到CR分量(_, cr, _) = cv2.split(ycrcb)cr1 = cv2.GaussianBlur(cr, (5, 5), 0)  # 高斯滤波_, skin = cv2.threshold(cr1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)  # OTSU图像二值化# cv2.imshow('skin',skin)return skin

获取大致轮廓

def _get_contours(array):# 利用findContours检测图像中的轮廓, 其中返回值contours包含了图像中所有轮廓的坐标点contours, _ = cv2.findContours(array, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)return contours

接下来准对这个大致图形进行处理
这里利用到了 凹凸图处理(腐蚀,另外一个名词想不起来了!)


# 根据图像中凹凸点中的 (开始点, 结束点, 远点)的坐标, 利用余弦定理计算两根手指之间的夹角, 其必为锐角, 根据锐角的个数判别手势.
def _get_defects_count(array, contour,defects, verbose = False):ndefects = 0list=[]for i in range(defects.shape[0]):s,e,f,_ = defects[i,0]beg     = tuple(contour[s][0])end     = tuple(contour[e][0])far     = tuple(contour[f][0])a = math.sqrt((beg[0] - end[0]) ** 2 + (beg[1] - end[1]) ** 2)b = math.sqrt((beg[0] - far[0]) ** 2 + (beg[1] - far[1]) ** 2)c = math.sqrt((end[0] - far[0]) ** 2 + (end[1] - far[1]) ** 2)angle   = math.acos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c)) # * 57if angle <= math.pi/2 :#90:if far[1]>350:#有的不需要的杂点在这里给他筛出breakndefects = ndefects + 1if verbose:cv2.circle(array, far, 3, [255,0,0], -1)if verbose:cv2.line(array, beg, end, [0,255,0], 1)cv2.circle(array, beg, 3, [255, 255, 0], -1)list.append(beg)cv2.imshow('arry',array)return array,ndefects,list

根据处理咱们可以获取得到五个数据,咱们需要利用其中的三个数据 (开始点, 结束点, 远点)通过反余弦定理求出手指岔开角度,进而判断伸出手指的个数。
为了使系统稳定运行这里家里arry进行缓存50个前50帧图像处理结果然后综合判断此时此刻的识别结果。

然后就是利用手势操作ppt了


def grdetect(array):global num_pptstrDath=os.getcwd()+'/'+str(num_ppt)+'.JPG'print('strDath',strDath)#读取pptppt1 = cv2.imread(strDath)copy       = array.copy()array = _remove_background(array) # 移除背景, add by wnavythresh = _bodyskin_detetc(array)contours= _get_contours(thresh.copy()) # 计算图像的轮廓largecont  = max(contours, key = lambda contour: cv2.contourArea(contour))hull           = cv2.convexHull(largecont, returnPoints = False) # 计算轮廓的凸点try:defects        = cv2.convexityDefects(largecont, hull) # 计算轮廓的凹点except:print('凸点有问题')defects=Noneif defects is not None:# 利用凹陷点坐标, 根据余弦定理计算图像中锐角个数ndefects=''copy,ndefects,list = _get_defects_count(copy, largecont, defects, verbose = True)# 根据锐角个数判断手势, 会有一定的误差if ndefects == 0:num1.append(0)num2.append(0)min_lin=10000min_point=(0,0)if (sum(num1)<50 and sum(num2)<50):for i in range(len(list)):if min_lin>list[i][1]:min_lin=list[i][1]min_point=list[i]# print('min_point=',min_point)dx.append(min_point[0])dy.append(min_point[1])# print('ppt大小',ppt1.shape)#ppt大小 (720, 960, 3)cv2.rectangle(copy, (0, 0),(int(0.8 * frame.shape[1]), int(0.6 * frame.shape[0])), (255, 0, 0), 2)# print('宽:',0.8 * frame.shape[1],'高:',0.6 * frame.shape[0])#宽: 512.0 高: 288.0cv2.circle(copy, (sum(dx)//5,sum(dy)//5), 6, [255,0 , 255], -1)#宽512:960witch = int(np.interp(sum(dx)//5, [0, 512], [0, 960]))#高288:720height = int(np.interp(sum(dy)//5, [0, 288], [0, 720]))cv2.circle(ppt1, (witch, height), 6, [255, 0, 255], -1)cv2.imshow('copy',copy)try:cv2.imshow('ppt', ppt1)except:print('少一个手指一')print(0)elif ndefects == 1:num1.append(2)num2.append(0)if (sum(num1) > 50 and sum(num2) < 50):min_lin = 10000min_point = (0, 0)for i in range(len(list)):if min_lin > list[i][1]:min_lin = list[i][1]min_point = list[i]# print('min_point=', min_point)dx.append(min_point[0])dy.append(min_point[1])# 宽512:960witch = int(np.interp(sum(dx) // 5, [0, 512], [0, 960]))# 高288:720height = int(np.interp(sum(dy) // 5, [0, 288], [0, 720]))print('sum(num1)=',sum(num1))if sum(num1)>50 and sum(num2) <50:global imgCanvasglobal xp,ypif xp==0 and yp==0:xp,yp=witch,heightcv2.line(ppt1, (xp,yp),(witch, height),[0, 255, 0], 15)cv2.line(imgCanvas, (xp, yp), (witch, height), [155,155 , 0], 15)xp, yp = witch, heightcv2.imshow('ppt',ppt1)cv2.imshow('imgCanvas',imgCanvas)elif 20<sum(num1)<50 or sum(num2) != 0:img = cv2.putText(ppt1, "pencil loading....", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0, 255, 0), 2)try:cv2.imshow('ppt', img)except:print('少一个手指二')print(1+1)

代码真的太长了 这里沾不下!
其中有个难点就是 手写笔迹怎么檫除,为了解决这个问题引入了蒙版概念。
效果如下:
在这里插入图片描述
在这里插入图片描述
视屏地址:https://www.bilibili.com/video/BV1sf4y1u78g/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/328482.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DockerFile介绍与使用

一、DockerFile介绍 大家好&#xff0c;今天给大家分享一下关于 DockerFile 的介绍与使用&#xff0c;DockerFile 是一个用于定义如何构建 Docker 镜像的文本文件&#xff0c;具体来说&#xff0c;具有以下重要作用&#xff1a; 标准化构建&#xff1a;提供了一种统一、可重复…

SQL注入漏洞常用绕过方法

SQL注入漏洞 漏洞描述 Web 程序代码中对于用户提交的参数未做过滤就直接放到 SQL 语句中执行&#xff0c;导致参数中的特殊字符打破了原有的SQL 语句逻辑&#xff0c;黑客可以利用该漏洞执行任意 SQL 语句&#xff0c;如查询数据、下载数据、写入webshell 、执行系统命令以及…

企业OA办公系统开发笔记:1、搭建后端环境

文章目录 企业办公系统&#xff1a;搭建环境一、项目介绍1、介绍2、技术栈3、项目模块4、数据库 二、搭建环境1、搭建后端1.1、搭建父工程clfwzx-oa-parent1.2、搭建工具类父模块common1.3、搭建工具类common的子模块1.4、搭建实体类模块model和项目模块service-oa 2、配置依赖…

【前端】CSS基础(3)

文章目录 前言1. CSS常用元素属性1.1 字体属性1.1.1 字体1.1.2 字体大小1.1.3 字体颜色1.1.4 字体粗细1.1.5 文字样式 前言 这篇博客仅仅是对CSS的基本结构进行了一些说明&#xff0c;关于CSS的更多讲解以及HTML、Javascript部分的讲解可以关注一下下面的专栏&#xff0c;会持续…

做软件测试如何突破月薪20K?

IT行业从事技术岗位&#xff0c;尤其对于测试来说&#xff0c;月薪20K&#xff0c;即便在北上广深这类一线城市薪水也不算低了&#xff0c;可以说对于大部分测试岗位从业者来说&#xff0c;20K都是一个坎儿。 那么&#xff0c;问题来了&#xff0c;做软件测试如何可以达到月薪…

连锁收银系统如何助力实体门店私域运营

作为实体门店&#xff0c;私域运营是提升客户黏性和增加复购率的重要策略之一。而连锁收银系统在私域运营中扮演了关键的角色&#xff0c;它不仅可以帮助门店管理客户信息和消费记录&#xff0c;还能够通过数据分析和营销功能提供个性化的服务和推广活动。下面看看连锁收银系统…

Qt 6.7 正式发布!

本文翻译自&#xff1a;Qt 6.7 Released! 原文作者&#xff1a;Qt Group研发总监Volker Hilsheimer 在最新发布的Qt 6.7版本中&#xff0c;我们大大小小作出了许多改善&#xff0c;以便您在构建现代应用程序和用户体验时能够享受更多乐趣。 部分新增功能已推出了技术预览版&a…

证照之星是什么软件 证照之星哪个版本好用?证照之星支持哪些相机 证照之星XE免费版

许多人都需要使用证件照&#xff0c;为了满足这一需求&#xff0c;人们会使用照相机、手机、电脑等工具进行拍摄。除此之外&#xff0c;市面上还存在专门的证件照拍摄软件&#xff0c;比如证照之星。那么&#xff0c;各位小伙伴是否了解证照之星哪个版本好用&#xff0c;证照之…

什么?你设计接口什么都不考虑?

如果让你设计一个接口&#xff0c;你会考虑哪些问题&#xff1f; 1.接口参数校验 接口的入参和返回值都需要进行校验。 入参是否不能为空&#xff0c;入参的长度限制是多少&#xff0c;入参的格式限制&#xff0c;如邮箱格式限制 返回值是否为空&#xff0c;如果为空的时候是…

单位个人如何向期刊投稿发表文章?

在单位担任信息宣传员一职以来,我深感肩上的责任重大。每月的对外信息宣传投稿不仅是工作的核心,更是衡量我们部门成效的重要指标。起初,我满腔热血,以为只要勤勉努力,将精心撰写的稿件投至各大报社、报纸期刊的官方邮箱,就能顺利登上版面,赢得读者的青睐。然而,现实远比理想骨…

6、Qt—Log4Qt使用小记1

开发平台&#xff1a;Win10 64位 开发环境&#xff1a;Qt Creator 13.0.0 构建环境&#xff1a;Qt 5.15.2 MSVC2019 64位 一、Log4Qt简介 Log4Qt是使用Trolltech Qt Framework的Apache Software Foundation Log4j包的C 端口。它旨在供开源和商业Qt项目使用。所以 Log4Qt 是Apa…

OSPF实验

OSPF单区域实验案例 需求 实现全网互联互通 配置步骤 配置PC接口IP地址 配置路由器的接口IP地址 配置OSPF 创建ospf进程&#xff0c;定义router-id指定相应区域宣告网段进入ospf 验证结果 配置命令 第一步&#xff1a;配置PC接口IP地址 第二步&#xff1a;配置路由器接口…

Leaflet.canvaslabel在Ajax异步请求时bindPopup无效的解决办法

目录 前言 一、场景重现 1、遇到问题的代码 2、问题排查 二、通过实验验证猜想 1、排查LayerGroup和FeatureGroup 2、排查Leaflet.canvaslabel.js 三、柳暗花明又一村 1、点聚类的办法 2、歪打正着 总结 前言 在上一篇博客中介绍了基于SpringBoot的全国风景区WebGIS按…

【多模态】31、Qwen-VL | 一个开源的全能的视觉-语言多模态大模型

文章目录 一、背景二、方法2.1 模型架构2.2 输入和输出2.3 训练 三、效果3.1 Image Caption 和 General Visual Question Answering3.2 Text-oriented Visual Question Answering3.3 Refer Expression Comprehension3.4 视觉-语言任务的少样本学习3.5 真实世界用户行为中的指令…

BGP(border gateway protocol)边界网关协议初识篇

BGP它是一种路径矢量协议&#xff0c;用于决定数据包在互联网中的最佳路径。 1、工作原理&#xff1a; 自治系统&#xff08;AS&#xff09;间路由: BGP主要用于连接不同自治系统之间的路由器&#xff0c;其中每个自治系统&#xff08;AS&#xff09;代表一组具有共同路由的网…

Rust构造JSON和解析JSON

目录 一、Rust构造JSON和解析JSON 二、知识点 serde_json JSON 一、Rust构造JSON和解析JSON 添加依赖项 cargo add serde-json 代码&#xff1a; use serde_json::{Result, Value};fn main() -> Result<()>{//构造json结构 cpu_loadlet data r#"{"…

【C -> Cpp】由C迈向Cpp (6):静态、友元和内部类

标题&#xff1a;【C -&#xff1e; Cpp】由C迈向Cpp &#xff08;6&#xff09;&#xff1a;静态、友元和内部类 水墨不写bug &#xff08;图片来源于网络&#xff09; 目录 &#xff08;一&#xff09;静态成员 &#xff08;二&#xff09;友元 &#xff08;三&#xff09…

想让普通金额数字显示为逗号分隔的数字?

使用vueelement 后台传的数据 1.编写方法 放在method当中 /** 数字转换显示格式 */priceFormat (num, n) {n n || 2;let symbol ",";if (num null) return num;if (typeof num ! number) throw new TypeError(num参数应该是一个number类型);if (n < 0) thro…

eNSP中小型园区网络拓扑搭建(上)

→b站直通车&#xff0c;感谢大佬← →eNSP中小型园区网络拓扑搭建&#xff08;下&#xff09;← 不带配置命令的拓扑图已上传~ 项目背景&#xff1a; 某公司准备新建一张网络供企业办公使用。写字楼共3层&#xff0c;一层会客大厅、二层行政部及市场部、三层研发部。一层设…

基于java的超级玛丽游戏的设计与实现(论文 + 源码)

Java的超级玛丽游戏.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89313347 基于java的超级玛丽游戏的设计与实现 摘要 近年来&#xff0c;Java作为一种新的编程语言&#xff0c;以其简单性、可移植性和平台无关性等优点&#xff0c;得到了广泛地应用。J2SE称…