OpenCV手势识别

作者: Lonelyroots | 来源:发表于2022-01-09 22:28 被阅读0次

    ...僵硬...

    太久没做Python识别类的项目了,所以今晚想放松放松,不过代码整的有点生疏,不仅写得慢,还不小心把我最爱的Ubuntu给整没了,只能明天重装!因为一些手部指令出来的效果不太好,本人上镜有点不舒服,所以就不上图啦!O(∩_∩)O!

    需安装模块:
    opencv-python==4.5.4.60
    opencv-contrib-python==4.5.5.62
    mediapipe==0.8.9.1
    opencv-python-headless==4.1.2.30
    通过这些模块,可以通过手势识别,做出一些与OpenCV有关的有趣指令,如图片加密解密,添加水印,将图片修改成为灰度图...

    # pip install opencv-python-headless==4.1.2.30 -i https://pypi.douban.com/simple
    
    import cv2
    import mediapipe as mp
    import math
    import time
    import numpy as np
    from PIL import Image, ImageTk
    import tkinter as tk
    
    cap = cv2.VideoCapture(0)
    mpHands = mp.solutions.hands
    hands = mpHands.Hands(
        static_image_mode=False,
        max_num_hands=2,
        model_complexity=1,
        min_detection_confidence=0.5,
        min_tracking_confidence=0.5
    )
    mpDraw = mp.solutions.drawing_utils
    handLmsStyle = mpDraw.DrawingSpec(color=(255,0,255),thickness=5)      # 点
    handConStyle = mpDraw.DrawingSpec(color=(0,255,0),thickness=10)     # 线
    pTime = 0
    cTime = 0
    
    def vector_2d_angle(v1,v2):
        ''' 求解二维向量的角度 '''
        v1_x=v1[0]
        v1_y=v1[1]
        v2_x=v2[0]
        v2_y=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_list
    
    def h_gesture(angle_list):
        '''
            # 二维约束的方法定义手势
            # fist five gun love one six three thumbup yeah
        '''
        thr_angle = 65.
        thr_angle_thumb = 53.
        thr_angle_s = 49.
        gesture_str = None
        if 65535. not in angle_list:
            if (angle_list[0]>5)  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 = "one"
            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 = "two"
            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 = "five"
            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 = "six"
            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 = "thumbUp"
        return gesture_str
    
    # 2.Canny边缘检测
    # 读入灰度图像
    pic1 = cv2.imread('pic1.png',0)
    # 高斯模糊图像降噪  (5,5)卷积核,卷积核越大,对图像越敏感
    pic2 = cv2.GaussianBlur(pic1, (5, 5), 0)
    # Canny边缘检测,左为低阈值,右为高阈值,阈值越小边缘越多也越杂
    pic2canny = cv2.Canny(pic2, 20, 70)
    # 闭运算连接断点
    kernel = np.ones((2, 2), np.uint8)
    jiance = cv2.morphologyEx(pic2canny, cv2.MORPH_CLOSE, kernel)
    
    # 3.旋转图片
    pic2 = cv2.imread('pic1.png')
    xy = cv2.flip(pic2,-1)
    
    # 4. 加密解密
    cst = cv2.cvtColor(pic1,cv2.COLOR_GRAY2RGB)
    retval4 = cv2.imwrite("cst.jpg",cst)      # 彩色图
    img1 = cv2.imread('cst.jpg')
    w,h,c = img1.shape
    key = np.random.randint(0,256,size=[w,h,c],dtype=np.uint8)      # 生成一个和图片一样大小的图片
    encryption = cv2.bitwise_xor(img1,key)      # 按位异或,相同为0,不同为1
    decryption = cv2.bitwise_xor(encryption,key)
    
    while (cap.isOpened()):
        ret,frame = cap.read()
        if ret:
            # 把BGR图像转换为RGB形式
            imgRGB = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
    
            frame = cv2.flip(imgRGB,1)
            result = hands.process(frame)
            print(result.multi_hand_landmarks)
            frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
            imgWidth = frame.shape[1]
            imgHeight = frame.shape[0]
    
            if result.multi_hand_landmarks:
                for handLms in result.multi_hand_landmarks:
                    mpDraw.draw_landmarks(frame, handLms, mpHands.HAND_CONNECTIONS, handLmsStyle, handConStyle)
                    hand_local = []
                    for i in range(21):
                        x = handLms.landmark[i].x*frame.shape[1]
                        y = handLms.landmark[i].y*frame.shape[0]
                        hand_local.append((x,y))
                    for j,lm in enumerate(handLms.landmark):
                        xPos = int(lm.x * imgWidth)
                        yPos = int(lm.y * imgHeight)
                        cv2.putText(frame,str(j),(xPos-25,yPos+5),cv2.FONT_HERSHEY_SIMPLEX,0.4,(0,0,255),2)
                        if j == 4:
                            cv2.circle(frame,(xPos,yPos),10,(0,0,255),cv2.FILLED)
                        print(i,xPos,yPos)
                    if hand_local:
                        angle_list = hand_angle(hand_local)
                        gesture_str = h_gesture(angle_list)
                        cv2.putText(frame,gesture_str,(0,100),0,1.3,(0,0,255),3)
                        if gesture_str == 'one':
                            cv2.imwrite('pic1.png',frame)
                        elif gesture_str == 'two':
                            cv2.imshow('jxw.png', jiance)
                        elif gesture_str == 'five':
                            cv2.imshow("result2", encryption)
                            cv2.imshow("result3", decryption)
                        elif gesture_str == 'six':
                            cv2.imshow("xy", xy)
                        elif gesture_str == 'thumbUp':
                            # break
                            cv2.destroyAllWindows()
    
            cTime = time.time()
            fps = 1/(cTime-pTime)
            pTime = cTime
            cv2.putText(frame,f"FPS:{int(fps)}",(30,50),cv2.FONT_HERSHEY_SIMPLEX,1,(0,60,30),3)
    
            cv2.imshow('img',frame)
        k = cv2.waitKey(1)
        if k == ord('q'):
            break
    cap.release()
    
    
    # 5.GUI编程
    """第一步,实例化object,建立窗口window、"""
    window = tk.Tk()
    """第二步,给窗口的可视化起名字"""
    window.title('My_Window')
    """第三步,给窗口制定大小,(长 乘(即x) 宽)"""
    window.geometry('1000x1000')
    """第四步,创建画布"""
    canvas = tk.Canvas(window, bg='white', height=500, width=1000)
    wifi_img = Image.open('pic1.png')
    wifi_img_up = Image.open('up.gif')
    wifi_img_r = Image.open('r.gif')
    wifi_img_d = Image.open('d.gif')
    wifi_img_l = Image.open('l.gif')
    image_file = ImageTk.PhotoImage(wifi_img)
    image_file_up = ImageTk.PhotoImage(wifi_img_up)
    image_file_r = ImageTk.PhotoImage(wifi_img_r)
    image_file_d = ImageTk.PhotoImage(wifi_img_d)
    image_file_l = ImageTk.PhotoImage(wifi_img_l)
    image = canvas.create_image(500, 0, anchor='n', image=image_file)
    
    """第五步,放置画布"""
    canvas.pack()
    
    """第六步,触发函数,用来一定指定图形"""
    def moveit_up():
        canvas.move(image, 0, -6)
    def moveit_r():
        canvas.move(image, 6, 0)
    def moveit_d():
        canvas.move(image, 0, 6)
    def moveit_l():
        canvas.move(image, -6, 0)
    
    """第七步,设置按钮"""
    b = tk.Button(window, image=image_file_up, text="move item", command=moveit_up).place(x=450, y=500)
    b = tk.Button(window, image=image_file_r, text="move item", command=moveit_r).place(x=550, y=600)
    b = tk.Button(window, image=image_file_d, text="move item", command=moveit_d).place(x=450, y=700)
    b = tk.Button(window, image=image_file_l, text="move item", command=moveit_l).place(x=350, y=600)
    
    """第八步,主窗口循环显示"""
    window.mainloop()
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    
    # 知识点:
    """
    高斯降噪、边缘检测
    打开摄像头
    手部识别
    旋转
    开运算闭运算
    GUI
    加密解密
    键盘控制
    """
    

    因为要用一只手截图,所以图片中只有一只手,哈哈!


    Hello
    Good job

    文章到这里就结束了!希望大家能多多支持Python(系列)!六个月带大家学会Python,私聊我,可以问关于本文章的问题!以后每天都会发布新的文章,喜欢的点点关注!一个陪伴你学习Python的新青年!不管多忙都会更新下去,一起加油!

    Editor:Lonelyroots

    相关文章

      网友评论

        本文标题:OpenCV手势识别

        本文链接:https://www.haomeiwen.com/subject/yaypcrtx.html