利用python+opencv实现手势识别(含源码,亲测)

先提前安装相应模块
如:

pip install pyserial    //python2
pip3 install pyserial   //python3
import cv2 as cv
import numpy as np
import math
import time
import serial

capture = cv.VideoCapture(0)

# video = "http://admin:admin@10.242.200.134:8081/"  # admin是账号:admin是密码 后面是局域网
# capture = cv.VideoCapture(video)


# 获得欧几里距离
def _get_eucledian_distance(vect1, vect2):
    distant = vect1[0] - vect2[0]
    dist = np.sqrt(np.sum(np.square(distant)))
    # 或者用numpy内建方法
    # vect1 = list(vect1)
    # vect2 = list(vect2)
    # dist = np.linalg.norm(vect1 - vect2)
    return dist


def gesture_recognition():

    while True:
        ret, frame = capture.read()  # 读取摄像头
        # frame = cv.flip(frame, 1)
        fgbg = cv.createBackgroundSubtractorMOG2()  # 利用BackgroundSubtractorMOG2算法消除背景
        # fgmask = bgModel.apply(frame)
        fgmask = fgbg.apply(frame)
        # kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
        # res = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
        kernel = np.ones((5, 5), np.uint8)
        fgmask = cv.erode(fgmask, kernel, iterations=1)  # 膨胀
        res = cv.bitwise_and(frame, frame, mask=fgmask)
        ycrcb = cv.cvtColor(res, cv.COLOR_BGR2YCrCb)  # 分解为YUV图像,得到CR分量
        (_, cr, _) = cv.split(ycrcb)
        cr1 = cv.GaussianBlur(cr, (5, 5), 0)  # 高斯滤波
        _, skin = cv.threshold(cr1, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)  # OTSU图像二值化
        # dst = cv.GaussianBlur(frame, (3, 3), 0)
        # gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
        # ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
        # cv.imshow("binary_image", binary)
        # hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)  # hsv 色彩空间 分割肤色
        # ycrcb = cv.cvtColor(frame, cv.COLOR_BGR2YCrCb)  # Ycrcb 色彩空间 分割肤色
        # # lower_hsv = np.array([0, 15, 0])
        # # upper_hsv = np.array([17, 170, 255])
        # lower_ycrcb = np.array([0, 135, 85])
        # upper_ycrcb = np.array([255, 180, 135])
        # # mask = cv.inRange(hsv, lowerb=lower_hsv, upperb=upper_hsv)  # hsv 掩码
        # mask = cv.inRange(ycrcb, lowerb=lower_ycrcb, upperb=upper_ycrcb)  # ycrcb 掩码
        # dst = cv.GaussianBlur(mask, (11, 11), 0)  # 高斯去噪
        # gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)

        # edge_output = cv.Canny(gray, 50, 150)  # 图像边缘提取
        # kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))  # 获取图像结构化元素
        # # dst = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel)  # 开操作
        # dst = cv.erode(skin, kernel)  # 膨胀操作
        gesture_roi = skin[0:350, 380:700]
        cv.imshow("dst_demo", skin)
        # cv.imshow("gesture_roi", gesture_roi)
        contours, heriachy = cv.findContours(gesture_roi, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)  # 获取轮廓点集(坐标)
        # if contours[0] < [30, 260]:
        #     cnt = contours[0]
        # elif 270 <= contours[0] < [60, 260]:
        #     cnt = contours[1]
        # else:
        #     cnt = contours[2]
        # cnt = contours[0]
        # print(cnt)
        # print(contours)
        # cnt = contours[0]
        for i, contour in enumerate(contours):  # 获取轮廓
            cv.drawContours(frame[0:350, 380:700], contours, i, (255, 0, 0), 1)  # 绘制轮廓
        #  得到面积
        # area = cv.contourArea(contour)
        # 得到外接矩形
        # x, y, w, h = cv.boundingRect(contour)
        # 得到的几何距是字典类型的
        # mm = cv.moments(contour)
        # cx = mm['m10']/mm['m00']
        # cy = mm['m01']/mm['m00']
        # center, radius = cv.minEnclosingCircle(contour)
        # center = (int(x), int(y))
        # radius = int(radius)
        # cv.circle(frame, center, radius, (0, 255, 255), 2)
        # cv.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2)
        # print(i)
        # cv.imshow("measure_contures", frame)
            x, y, w, h = cv.boundingRect(contour)
            # center = (int(x), int(y))
            cv.rectangle(frame[0:350, 380:700], (x, y), (x + w, y + h), (100, 100, 0), 1)
        # approxcurve = cv.approxPolyDP(contour, 4, False)
        # if approxcurve.shape[0] < 5:
        #     cv.drawContours(frame, contours, -1, (0, 255, 0), 3)

        hull = cv.convexHull(contour, True, returnPoints=False)  # 获得凸包点 x, y坐标
        defects = cv.convexityDefects(contour, hull)  # 计算轮廓的凹点
        # print(hull, defects)
        # cv.polylines(frame[0:350, 380:700], [hull], True, (0, 255, 0), 3)
        """
        defect反馈的是Nx4的数组,
        第一列表示的是起点(轮廓集合中点的编号)
        第二列表示的是终点(轮廓集合中点的编号)
        第三列表示的是最远点(轮廓集合中点的编号)
        第四列表示的是最远点到凸轮廓的最短距离
        """
        # cv.drawContours(frame[0:350, 380:700], hull, -1, (255, 0, 0), 5, 8)  # 绘制凸包

        # dist = np.sqrt(np.sum(np.square(vect1 - vect2)))
        ndefects = 0
        if defects is not None:  # 重要!

            for i in range(defects.shape[0]):
                s, e, f, d = defects[i, 0]
                # float(s)
                # float(e)
                # float(f)
                # float(d)
                start = tuple(contour[s][0])  # 起点
                end = tuple(contour[e][0])  # 终点
                far = tuple(contour[f][0])  # 最远点
                a = _get_eucledian_distance(start, end)
                b = _get_eucledian_distance(start, far)
                c = _get_eucledian_distance(end, far)
                angle = math.acos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c))
                cv.line(frame[0:350, 380:700], start, end, [255, 255, 0], 2)
                cv.circle(frame[0:350, 380:700], far, 5, [0, 0, 255], -1)
                if angle <= math.pi / 5:  # <30度:
                    ndefects = ndefects + 1
                print("数字 = %f" % ndefects)


        # cv.polylines(frame[50:350, 380:700], [hull], True, (0, 255, 0), 2)
        # retval = cv.pointPolygonTest(contour, center, True)
        # cv.drawContours(frame, defects, -1, (0, 255, 0), 3)
        # cv.imshow("defects", defects)
        cv.imshow("video", frame)
        c = cv.waitKey(50)
        if c == 27:

            break


def gesture_recognition_two():
    img = cv.imread("E:/pictureprocessing/practice/picture/practice_one.png")
    img = cv.flip(img, 1)
    # dst = cv.GaussianBlur(frame, (3, 3), 0)
    # gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
    # ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    # cv.imshow("binary_image", binary)
    # hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)  # 通过hsv将颜色过滤出来
    # lower_hsv = np.array([100, 43, 46])
    # upper_hsv = np.array([124, 255, 255])
    # mask = cv.inRange(hsv, lowerb=lower_hsv, upperb=upper_hsv)
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    dst = cv.GaussianBlur(binary, (1, 1), 0)  # 高斯去噪
    # cv.imshow("dst_demo", dst)
    contours, heriachy = cv.findContours(dst, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)  # 获取轮廓本身
    for i, contour in enumerate(contours):  # 获取轮廓
        cv.drawContours(img, contours, i, (0, 255, 0), 3)  # 绘制轮廓
        print(i)

    cv.imshow("img_demo", img)


cv.namedWindow("video")
gesture_recognition()
# gesture_recognition_two()

cv.waitKey(0)
capture.release()
cv.destroyAllWindows()

程序运行效果如下:
在这里插入图片描述
在这里插入图片描述

  • 18
    点赞
  • 196
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
### 回答1: PythonOpenCV库和MediaPipe工具包是可以一起使用的,以实现手势识别的功能。 首先,需要在Python安装OpenCV库和MediaPipe工具包。可以使用pip命令来安装它们: ``` pip install opencv-python pip install mediapipe ``` 安装完成后,就可以开始使用了。 首先,导入必要的库: ```python import cv2 import mediapipe as mp ``` 接下来,创建一个MediaPipe的Hand对象和一个OpenCV的VideoCapture对象,用于读取摄像头输入: ```python mp_hands = mp.solutions.hands hands = mp_hands.Hands() cap = cv2.VideoCapture(0) ``` 然后,使用一个循环来读取摄像头输入并进行手势识别: ```python while True: ret, frame = cap.read() if not ret: break frame_RGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results = hands.process(frame_RGB) if results.multi_handedness: for hand_landmarks in results.multi_hand_landmarks: # 在这里可以对hand_landmarks进行处理和识别手势的操作 cv2.imshow('Gesture Recognition', frame) if cv2.waitKey(1) == ord('q'): break ``` 在循环,首先将读取到的帧转换为RGB格式,然后使用Hands对象的process方法对该帧进行手势识别。得到的结果存储在results变量。 在对每个检测到的手部进行循环处理时,可以使用hand_landmarks来获取该手的关键点坐标。可以根据这些关键点的位置和运动轨迹来实现手势的识别和分析。 最后,通过cv2.imshow方法显示图像,并使用cv2.waitKey方法等待用户操作。当用户按下"q"键时,循环终止,程序退出。 通过以上步骤,就可以使用PythonOpenCV库和MediaPipe工具包实现手势识别的功能了。当然,实际的手势识别算法和操作需要根据具体需求进行进一步的开发和优化。 ### 回答2: Python OpenCV和MediaPipe结合使用可以实现手势识别。首先,我们需要安装必要的库和工具,包括Pythonopencv-python、mediapipe和其他依赖项。 然后,我们可以使用MediaPipe提供的HandTracking模块来检测手部的关键点。它使用机器学习模型来识别手势,并返回手部关键点的坐标。我们可以通过OpenCV的视频捕捉模块读取摄像头的实时图像。 接下来,我们通过应用MediaPipe的HandTracking模块获取手部关键点的坐标,并使用OpenCV将这些坐标绘制到图像上,以便我们可以实时看到手部的位置和动作。 完成这些基本的设置后,我们可以定义特定的手势,例如拇指和食指的指尖接触,作为一个简单的示例。我们可以通过检查特定的关键点之间的距离和角度来识别这种手势。如果关键点之间的距离较小并且角度较小,则我们可以确定手势是拇指和食指的指尖接触。 我们可以使用类似的方法来识别其他手势,比如手掌的张开和闭合,拳头的形成等等。我们可以定义一系列规则和阈值来确定特定手势的识别。 最后,我们可以根据检测到的手势执行特定的操作。例如,当识别到拇指和食指的指尖接触时,我们可以触发相机的快门,实现手势拍照。 总之,PythonOpenCV和MediaPipe结合使用可以实现手势识别。我们可以利用MediaPipe的HandTracking模块检测手部关键点,并使用OpenCV实时绘制手势位置。通过定义特定手势的规则,我们可以识别各种手势并执行相应操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值