Python使用Opencv图像处理方法完成手势识别(三)tkinter制作GUI界面

news2024/12/23 5:27:36

前面对手势识别已经差不多完成。
这一章来制作一个手势识别GUI界面和说一下精确度不够问题所在。
首先是精确度不够的问题:

  1. 让手势更规范,手掌张开点。
  2. 首先应该调节Hsv阈值,因为手掌和环境颜色与我的可能有差异。
  3. 调整面积,周长阈值,距离阈值,面积阈值和周长阈值越大,识别的物体更少(即近距离才能识别到),距离阈值就是用来过滤手掌最低点到两根手指最低点的阈值。
  4. 识别方法上更换,不使用我这种根据距离的方法。
  5. 使用机器学习的方法(比如mediapipe)

然后就是GUI的制作,使用的是python内置库tkinter。
界面如下:
在这里插入图片描述
完整代码如下:

import cv2
import numpy as np
import random
import tkinter
from image_handle import Img_handle
from PIL.ImageTk import PhotoImage
from PIL.Image import fromarray
from tkinter import filedialog
from tkinter.messagebox import showerror

class Img_handle:
    def __init__(self,area_min,lenth_min,distance,drawtype=0,area_max=100000,lenth_max=100000):
        #default area_min=20000 lenth_min=1000 distance=300
        self.area_min=area_min
        self.area_max=area_max
        self.lenth_min=lenth_min
        self.lenth_max=lenth_max
        self.distance=distance
        self.allpoint = []
        self.highHSV = np.array([15, 255, 255])
        self.lowHSV = np.array([0, 50, 50])
        self.drawtype=drawtype

    def change_distance(self,distance):
        self.distance=distance

    def change_Hsv(self,lowHSV,highHSV):
        self.highHSV=highHSV
        self.lowHSV=lowHSV

    def resize_img(self,size=list,img=None):
        if np.any(img):
            self.img=img
        size = [size[1], size[0], size[2]]
        mask = np.zeros(size, dtype=np.uint8)
        h, w = self.img.shape[0:2]
        dwh = min([size[0] / h, size[1] / w])
        self.img = cv2.resize(self.img, None, fx=dwh, fy=dwh)
        if h > w:
            dxy = int((size[1] - self.img.shape[1]) / 2)
            mask[:, dxy:self.img.shape[1] + dxy, :] = self.img
        else:
            dxy = int((size[0] - self.img.shape[0]) / 2)
            mask[dxy:self.img.shape[0] + dxy, :, :] = self.img
        return mask

    def img_handle(self,img=None):
        if np.any(img):
            self.img=img

        self.img = cv2.cvtColor(self.img, cv2.COLOR_BGR2HSV)

        cv2.GaussianBlur(self.img, [5, 5], 0)

        self.img = cv2.inRange(self.img, self.lowHSV, self.highHSV)

        kernel = np.ones([3, 3], dtype=np.uint8)
        self.img = cv2.morphologyEx(self.img, cv2.MORPH_CLOSE, kernel, iterations=1)
        kernel = np.ones([3, 3], dtype=np.uint8)
        self.img = cv2.morphologyEx(self.img, cv2.MORPH_DILATE, kernel, iterations=1)

        contours, num = cv2.findContours(self.img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        for contour in contours:
            area = cv2.contourArea(contour)
            lenth = cv2.arcLength(contour, True)
            if self.area_max >area > self.area_min and self.lenth_max >lenth > self.lenth_min:

                epsilon = 0.02 * cv2.arcLength(contour, True)
                self.allpoint = cv2.approxPolyDP(contour, epsilon, True)

                self.allpoint = self.allpoint.reshape(len(self.allpoint), 2)
                self.allpoint = np.array(self.allpoint, dtype=np.int32)
                if self.drawtype==0:

                    b = random.randint(0, 255)
                    g = random.randint(0, 255)
                    r = random.randint(0, 255)

                    cv2.polylines(self.output_img, [self.allpoint], True, [b, g, r], 4, 16)
        return self.img


    def get_distance(self, pt1, pt2):
        distance = ((pt2[0] - pt1[0]) ** 2 + (pt2[1] - pt1[1]) ** 2) ** (0.5)
        return distance

    def detect(self):
        num = 0
        if np.any(self.allpoint):
            maxindex  = np.argmax(self.allpoint, axis=0)
            for point in self.allpoint:
                distance = self.get_distance(self.allpoint[maxindex [1], :], point)
                if distance > self.distance:
                    if self.drawtype ==1:

                        b = random.randint(0, 255)
                        g = random.randint(0, 255)
                        r = random.randint(0, 255)

                        cv2.line(self.output_img,self.allpoint[maxindex [1],:],point,[b, g, r],4,16)
                    num += 1
            if num == 1:
                cv2.putText(self.output_img, 'one', [10, 50], cv2.FONT_HERSHEY_SIMPLEX, 2, [0, 0, 255], thickness=4)
                return '一'
            elif num == 2:
                cv2.putText(self.output_img, 'two', [10, 50], cv2.FONT_HERSHEY_SIMPLEX, 2, [0, 0, 255], thickness=4)
                return '二'
            elif num == 3:
                cv2.putText(self.output_img, 'three', [10, 50], cv2.FONT_HERSHEY_SIMPLEX, 2, [0, 0, 255], thickness=4)
                return '三'
            elif num == 4:
                cv2.putText(self.output_img, 'four', [10, 50], cv2.FONT_HERSHEY_SIMPLEX, 2, [0, 0, 255], thickness=4)
                return '四'
            elif num == 5:
                cv2.putText(self.output_img, 'five', [10, 50], cv2.FONT_HERSHEY_SIMPLEX, 2, [0, 0, 255], thickness=4)
                return '五'

    def get_hand(self,img):
        self.img = img
        if self.img.shape[0] != 480 and self.img.shape[1] != 640:
            self.img = self.resize_img([640,480,3])
        self.output_img=np.copy(self.img)
        last_img=self.img_handle()
        num=self.detect()
        return self.output_img,last_img,num

class GUI:
    def __init__(self):
        #
        self.hand=Img_handle(20000,1000,280)

        self.num=''
        self.video=''
        self.after=''
        self.file=['.mp4','.png','jpg']
        self.file_name=''

        self.root=tkinter.Tk()
        self.root.geometry('1000x700')
        self.root.title('手势识别')
        self.root.resizable(width=False,height=False)

        self.Img1label=tkinter.Label(self.root,text='',bg='white',bd=10)
        self.Img1label.place(x=200+40+100,y=20,width=640,height=480)

        self.Img2label=tkinter.Label(self.root,text='',bg='white',bd=10)
        self.Img2label.place(x=20,y=20+50+20+50+20+50+20,width=250,height=400)

        self.bt1=tkinter.Button(self.root,text='选择文件',command=self.path_get,font=('宋体',20),bg='green',bd=10)
        self.bt1.place(x=20,y=20,width=250,height=50)

        self.bt2=tkinter.Button(self.root,text='打开',command=self.img_open,font=('宋体',20),bg='blue',bd=10)
        self.bt2.place(x=20,y=20+50+20,width=250,height=50)

        self.bt3=tkinter.Button(self.root,text='打开摄像头',command=self.video_change,font=('宋体',20),bg='white',bd=10)
        self.bt3.place(x=20,y=20+50+20+50+20,width=250,height=50)

        self.string=tkinter.StringVar(self.root,value='')
        self.str_output=tkinter.Entry(self.root,textvariable=self.string,state='readonly',font=('宋体',38),bg='white',bd=10)
        self.str_output.place(x=200+40+100,y=20*3+480,width=640,height=140)

        #orient设置朝向
        #tickinterval设置刻度
        #resolution设置步长
        self.intvar = tkinter.IntVar(self.root)
        self.scale=tkinter.Scale(self.root,label='距离阈值',from_=0,to=800,\
        resolution=1,orient=tkinter.HORIZONTAL,tickinterval=200,variable=self.intvar,bg='white',bd=10)
        self.scale.place(x=20,y=700-80,width=250)
        self.get_scale()

    def video_change(self):
        if self.video:
            self.video.release()
        self.video = cv2.VideoCapture(0)
        if self.after:
            self.root.after_cancel(self.after)
        self.video_open()

    def video_open(self):
        res,img=self.video.read()
        if res == True and np.any(img):
            img1,img2,self.num=self.hand.get_hand(img)
            self.img1_show(img1)
            self.img2_show(img2)
        self.after=self.root.after(10,self.video_open)

    def img_open(self):
        if not self.file_name:
            showerror(title='警告', message='请选择视频或者图片')
        elif self.file[0] in self.file_name:
            if self.video:
                self.video.release()
            self.video = cv2.VideoCapture(self.file_name)
            if self.after:
                self.root.after_cancel(self.after)
            self.video_open()
        else:
            if self.video:
                self.video.release()
            img=cv2.imread(self.file_name)
            img1,img2,self.num=self.hand.get_hand(img)
            self.img1_show(img1)
            self.img2_show(img2)

    def path_get(self):
        self.file_name=filedialog.askopenfilename()
        num=0
        for path in self.file:
            if path not in self.file_name:
                    num+=1
        if num==3:
            showerror(title='警告',message='请选择视频或者图片')

    def get_scale(self):
        distance=self.intvar.get()
        self.hand.change_distance(distance)
        self.string.set('手势检测结果为%s'%(self.num))
        self.root.after(10, self.get_scale)

    def img1_show(self,img):
        img=cv2.cvtColor(img,cv2.COLOR_BGR2RGBA)
        img=fromarray(img)
        img=PhotoImage(img)
        self.Img1label.image=img
        self.Img1label['image']=img

    def img2_show(self,img):
        img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
        img = self.hand.resize_img([250, 400,3], img)
        img=cv2.cvtColor(img,cv2.COLOR_BGR2RGBA)
        img=fromarray(img)
        img=PhotoImage(img)
        self.Img2label.image=img
        self.Img2label['image']=img

    def open(self):
        showerror('注意',message='使用时先将距离阈值滑块调至273左右,再根据实际情况调节,最好带口罩识别防止误识别')
        self.root.mainloop()

    def close(self):
        if self.video:
            self.video.release()


GUI().open()
GUI().close()

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ADI Blackfin DSP处理器-BF533的开发详解7:SPI接口的驱动和应用(含源代码)

硬件准备 ADSP-EDU-BF533:BF533开发板 AD-HP530ICE:ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 接口功能介绍 SPI 接口是 4 线串口,可以连接 SPIFLASH,SPI 接口的 AD,DA 等等。ADSP-BF533 的 SPI 接口支持主…

【Python合集系列】爬虫有什么用,网友纷纷给出自己的答案,王老师,我..我想学那个..爬虫。可以嘛?“(代码免费分享)

导语 Hello,大家好呀!我是木木子吖~ 一个集美貌幽默风趣善良可爱并努力码代码的程序媛一枚。 听说关注我的人会一夜暴富发大财哦~ (哇哇哇 这真的爱😍😍) 生活中总有些东西值得爬一爬 爬虫…

Java 内存模型之 JMM

—— 计算机存储结构 计算机存储结构,从本地磁盘到主存到 CPU 缓存,也就是硬盘到内存,到CPU,一般对应的程序的操作就是从数据库到内存然后到CPU进行计算CPU拥有多级缓存,(CPU和物理主内存的速度不一致&…

群集搭建【LNMP+负载均衡+高可用+跳板机】

目录 项目需求 LNMP部署 web1部署 mysql部署 php部署 nfs部署 LNMP测试 负载均衡与高可用 web2部署 lb1部署 lb2部署 验证群集 跳板机功能 测试跳板机 项目需求 实验目标:根据拓扑图搭建环境,安装论坛,创建证书通过https访问,实现…

一文搞懂 Nginx

文章目录一、前言二、NGINX 指令与上下文2.1 指令2.2 上下文三、NGINX 静态文件处理3.1 静态文件配置3.2 静态文件类型处理四、NGINX 动态路由4.1 Location 匹配4.1.1 前缀匹配4.1.2 精准匹配4.1.3 正则匹配4.1.4 优先前缀匹配4.2 Location 匹配优先级4.2.1 匹配优先级对比4.2.…

学好selenium工具,能实现你想得到的所有事情

文章目录一、介绍背景二、开发与实现2.1、部署开发环境2.2、开始码代码<demo只为提供思路>2.3、思路分析2.4、难点解析三、总结一、介绍背景 情况是这样的&#xff1a;某段时间之前&#xff0c;开发想找我用ui自动化帮他们实现一个功能&#xff1a;在系统某些时候生成报告…

[附源码]计算机毕业设计大学生心理健康测评系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

零基础CSS入门教程(17)——内边距

本章目录1.任务目标2.默认情况3.有内边距4.小结1.任务目标 上一篇介绍了外边距&#xff0c;也就是元素跟相邻元素的距离。 本篇来介绍内边距&#xff0c;顾名思义&#xff0c;内边距是指的元素内部的内容&#xff0c;与元素的边的距离 2.默认情况 <!DOCTYPE html> <…

Velero 系列文章(一):基础

概述 Velero 是一个开源工具&#xff0c;可以安全地备份和还原&#xff0c;执行灾难恢复以及迁移 Kubernetes 集群资源和持久卷。 灾难恢复 Velero 可以在基础架构丢失&#xff0c;数据损坏和/或服务中断的情况下&#xff0c;减少恢复时间。 数据迁移 Velero 通过轻松地将 …

使用VictoriaMetrics 对Prometheus的数据进行分布式存储

前言 Prometheus 就是一个很好的时序数据库&#xff0c;对于监控数据量没有超过千万级的 情况下没必要进行分布式存储。一般的监控数据存3个月以内即可&#xff0c;所以数据量并不会很大。 并且生产环境可以搞多个Proms数据源在Grafana中做统一的告警。并且在时序数据库的排名…

windows安装minikube

由于学习的需要&#xff0c;需要在windows上搭建一套可以使用的k8s学习用&#xff0c;最后选择了minikube这个安装k8s&#xff0c;本博客介绍了minikube的安装步骤&#xff0c;详细命令以及截图 1、首先是本机windows安装docker&#xff0c;具体可以参考这个 win10安装docker…

奥曲肽-葡聚糖-亲和索的偶联物TOC-Dx40-Av)|紫杉醇-DHA-右旋糖酐偶联聚合物

中文名称&#xff1a;奥曲肽-葡聚糖-亲和索的偶联物 英文名称&#xff1a;TOC-Dx40-Av 纯度&#xff1a;95% 存储条件&#xff1a;-20C&#xff0c;避光&#xff0c;避湿 外观:固体或粘性液体 包装&#xff1a;瓶装/袋装 溶解性&#xff1a;溶于大部分有机溶剂&#xff0…

GC 算法总结_java培训

1.标记清除压缩(Mark-Sweep-Compact) 标记清除、标记压缩的结合使用 原理java培训GC 算法总结 2.算法总结 内存效率&#xff1a;复制算法>标记清除算法>标记整理算法&#xff08;此处的效率只是简单的对比时间复杂度&#xff0c;实际情况不一定如此&#xff09;。 内…

城市云灾备,为业务连续性保驾护航

摘要&#xff1a;华为云作为中国政务云基础设施领域领导者&#xff0c;基于华为公有云技术架构的政务云平台&#xff0c;具备领先的云灾备技术实力&#xff0c;支持IaaS、PaaS等云服务云原生灾备能力。本文分享自华为云社区《城市云灾备&#xff0c;为业务连续性保驾护航》&…

Delphi Base64 的“坑”

使用 Delphi 原生的Base64编码&#xff08;System.NetEncoding 单元&#xff09; &#xff0c;编码后的字符串每隔76个字符会增加一个回车换行&#xff08;#13#10&#xff09;&#xff0c;这样就导致和其他语言对接的时候出现问题&#xff0c;特别是Base64以后再进行签名&#…

元学习:IVIF:输入不同分辨率,输出任意分辨率

Different Input Resolutions and Arbitrary Output Resolution: A Meta Learning-Based Deep Framework for Infrared and Visible Image Fusion &#xff08;不同的输入分辨率和任意输出分辨率: 基于元学习的红外和可见光图像融合深度框架&#xff09; 在本文中&#xff0c…

Web大学生网页作业成品——城市环卫管理系统后台模板(HTML+CSS+JavaScript)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

浏览器中的音视频知识总结v1.0(工作中需要和视频打交道必看)

视频是什么 视频&#xff0c;其实就是一系列连续播放的图片&#xff0c;如果1s钟播放24张图片&#xff0c;那么人眼看到的就不再是一张张独立的图片&#xff0c;而是动起来的画面。其中一张图片称为一帧&#xff0c;1s播放的图片数称为帧率。常见的帧率有24帧/s&#xff0c;30帧…

[附源码]JAVA毕业设计西安市城市绿地管理系统(系统+LW)

[附源码]JAVA毕业设计西安市城市绿地管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项…

Linux网络原理及编程(3)——第十三节 HTTPS

我们本文主要来介绍https&#xff0c;主要来介绍https的加密原理。 大家应该都知道http和https的区别&#xff0c;区别很简单&#xff0c;主要就是在https是采用了加密协议的&#xff0c;而http完全是在网络上裸奔的。而我们现在几乎所有的连接都用的是https 我们首先需要明白…