欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

OpenCV實現(xiàn)手勢虛擬拖拽的使用示例(附demo)

 更新時間:2023年11月09日 16:37:43   作者:是Dream呀  
本文主要介紹了OpenCV實現(xiàn)手勢虛擬拖拽的使用示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、主要步驟及庫的功能介紹

1.主要步驟

要實現(xiàn)本次實驗,主要步驟如下:

  • 導(dǎo)入OpenCV庫。
  • 通過OpenCV讀取攝像頭的視頻流。
  • 使用膚色檢測算法(如色彩空間轉(zhuǎn)換和閾值分割)來識別手部區(qū)域。
  • 對手部區(qū)域進(jìn)行輪廓檢測,找到手的輪廓。
  • 根據(jù)手的輪廓,獲取手指關(guān)鍵點的像素坐標(biāo)。對于拖拽手勢,可以關(guān)注食指和中指的位置。
  • 計算食指和中指指尖之間的距離并判斷是否滿足條件觸發(fā)拖拽動作。
  • 如果滿足條件,可以使用勾股定理計算距離,并將矩形區(qū)域變色以示觸發(fā)拖拽。
  • 根據(jù)手指的位置更新矩形的坐標(biāo),使矩形跟隨手指運動。
  • 當(dāng)手指放開時停止矩形的移動。

2.需要的庫介紹

導(dǎo)入的庫在實現(xiàn)手勢虛擬拖拽的代碼中起著重要的作用,下面是對每個庫的簡要介紹:

  • OpenCV (cv2): OpenCV是一個開源的計算機(jī)視覺庫,提供了豐富的圖像和視頻處理功能,使用OpenCV來讀取攝像頭視頻流、進(jìn)行圖像處理和計算。

  • mediapipe (mp): mediapipe提供一系列預(yù)訓(xùn)練的機(jī)器學(xué)習(xí)模型和工具,用于實現(xiàn)計算機(jī)視覺和機(jī)器學(xué)習(xí)任務(wù)。我們使用mediapipe來進(jìn)行手部關(guān)鍵點檢測和姿勢估計

  • time: 我們使用time庫來計時和進(jìn)行時間相關(guān)的操作。

  • math: 在本次實驗我們使用math庫來計算距離和角度。

二、導(dǎo)入所需要的模塊

# 導(dǎo)入OpenCV
import cv2
# 導(dǎo)入mediapipe
import mediapipe as mp

# 導(dǎo)入其他依賴包
import time
import math

三、方塊管理類

(SquareManager)是一個方塊管理器,用于創(chuàng)建、顯示、更新和處理方塊的相關(guān)操作。

1.初始化方塊管理器

初始化方塊管理器,傳入方塊的長度(rect_width)作為參數(shù),并初始化方塊列表、距離、激活狀態(tài)和激活的方塊ID等屬性。

class SquareManager:
    def __init__(self, rect_width):
        # 方框長度
        self.rect_width = rect_width

        # 方塊列表
        self.square_count = 0
        self.rect_left_x_list = []
        self.rect_left_y_list = []
        self.alpha_list = []

        # 中指與矩形左上角點的距離
        self.L1 = 0
        self.L2 = 0

        # 激活移動模式
        self.drag_active = False

        # 激活的方塊ID
        self.active_index = -1

2.創(chuàng)建一個方塊

創(chuàng)建一個方塊,將方塊的左上角坐標(biāo)和透明度添加到相應(yīng)的列表中。

# 創(chuàng)建一個方塊,但是沒有顯示
    def create(self, rect_left_x, rect_left_y, alpha=0.4):
        # 將方塊的左上角坐標(biāo)和透明度添加到相應(yīng)的列表中
        self.rect_left_x_list.append(rect_left_x)
        self.rect_left_y_list.append(rect_left_y)
        self.alpha_list.append(alpha)
        self.square_count += 1

3.更新顯示方塊的位置

根據(jù)方塊的狀態(tài),在圖像上繪制方塊,并使用透明度將疊加圖像疊加到原始圖像上。

 # 更新顯示方塊的位置
    def display(self, class_obj):
        # 遍歷方塊列表
        for i in range(0, self.square_count):
            x = self.rect_left_x_list[i]
            y = self.rect_left_y_list[i]
            alpha = self.alpha_list[i]

            overlay = class_obj.image.copy()
             # 如果方塊處于激活狀態(tài),繪制紫色方塊;否則繪制藍(lán)色方塊
            if (i == self.active_index):
                cv2.rectangle(overlay, (x, y), (x + self.rect_width, y + self.rect_width), (255, 0, 255), -1)
            else:
                cv2.rectangle(overlay, (x, y), (x + self.rect_width, y + self.rect_width), (255, 0, 0), -1)

            # 使用透明度將疊加圖像疊加到原始圖像上
            class_obj.image = cv2.addWeighted(overlay, alpha, class_obj.image, 1 - alpha, 0)

4.判斷落點方塊

判斷給定的坐標(biāo)是否在方塊內(nèi),并返回方塊的ID。

    # 判斷落在哪個方塊上,返回方塊的ID
    def checkOverlay(self, check_x, check_y):
        # 遍歷方塊列表
        for i in range(0, self.square_count):
            x = self.rect_left_x_list[i]
            y = self.rect_left_y_list[i]

            # 檢查指定點是否在方塊內(nèi)
            if (x < check_x < (x + self.rect_width)) and (y < check_y < (y + self.rect_width)):
                # 保存被激活的方塊ID
                self.active_index = i
                return i

        return -1

5.計算距離、更新位置

??setLen? 方法:計算激活方塊與指尖的距離。
??updateSquare? 方法:根據(jù)給定的新坐標(biāo)更新激活方塊的位置。

    # 計算與指尖的距離
    def setLen(self, check_x, check_y):
        # 計算距離
        self.L1 = check_x - self.rect_left_x_list[self.active_index]
        self.L2 = check_y - self.rect_left_y_list[self.active_index]

    # 更新方塊位置
    def updateSquare(self, new_x, new_y):
        self.rect_left_x_list[self.active_index] = new_x - self.L1
        self.rect_left_y_list[self.active_index] = new_y - self.L2

三、識別控制類

1.初始化識別控制類

class HandControlVolume:
    def __init__(self):
        # 初始化mediapipe
        self.mp_drawing = mp.solutions.drawing_utils
        self.mp_drawing_styles = mp.solutions.drawing_styles
        self.mp_hands = mp.solutions.hands

        # 中指與矩形左上角點的距離
        self.L1 = 0
        self.L2 = 0

        # image實例,以便另一個類調(diào)用
        self.image = None

HandControlVolume用于初始化mediapipe以及存儲中指與矩形左上角點的距離和image實例。

  • __init__ 方法:在初始化對象時,初始化mediapipe,包括drawing_utils、drawing_styles和hands。此外,還初始化了中指與矩形左上角點的距離和image實例。

通過mediapipe,可以進(jìn)行手部關(guān)鍵點檢測和姿勢估計,進(jìn)而進(jìn)行手勢識別和處理。為了使其他類能夠調(diào)用image實例,將其作為該類的屬性進(jìn)行存儲,方便地處理手勢識別和控制操作。

2.主函數(shù)

這部分代碼主要用于初始化和準(zhǔn)備處理視頻流以進(jìn)行手勢識別和交互。

    def recognize(self):
        # 計算刷新率
        fpsTime = time.time()

        # OpenCV讀取視頻流
        cap = cv2.VideoCapture(0)
        # 視頻分辨率
        resize_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        resize_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

        # 畫面顯示初始化參數(shù)
        rect_percent_text = 0

        # 初始化方塊管理器
        squareManager = SquareManager(150)

        # 創(chuàng)建多個方塊
        for i in range(0, 5):
            squareManager.create(200 * i + 20, 200, 0.6)

        with self.mp_hands.Hands(min_detection_confidence=0.7,
                                 min_tracking_confidence=0.5,
                                 max_num_hands=2) as hands:
            while cap.isOpened():

                # 初始化矩形
                success, self.image = cap.read()
                self.image = cv2.resize(self.image, (resize_w, resize_h))

                if not success:
                    print("空幀.")
                    continue
  • resize_w 和 resize_h:根據(jù)攝像頭分辨率獲取的視頻幀的寬度和高度,并作為后續(xù)處理的圖像尺寸進(jìn)行縮放。

  • rect_percent_text:畫面顯示初始化參數(shù),可能被用于屏幕上的文本顯示。

  • squareManager:初始化了方塊管理器類的實例,并設(shè)置方塊的長度為150。

使用一個循環(huán),創(chuàng)建了五個方塊,并通過create方法將其添加到方塊管理器中。進(jìn)入循環(huán),從視頻流中讀取幀圖像,并將其調(diào)整為指定的尺寸。如果成功讀取幀圖像,則會進(jìn)一步處理,否則將輸出錯誤消息。

3.提高性能和處理圖像

                self.image.flags.writeable = False
                # 轉(zhuǎn)為RGB
                self.image = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)
                # 鏡像
                self.image = cv2.flip(self.image, 1)
                # mediapipe模型處理
                results = hands.process(self.image)

                self.image.flags.writeable = True
                self.image = cv2.cvtColor(self.image, cv2.COLOR_RGB2BGR)
  • self.image.flags.writeable = False:設(shè)置圖像為不可寫,以提高性能并避免數(shù)據(jù)拷貝。

  • self.image = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB):將BGR格式的圖像轉(zhuǎn)換為RGB格式,因為mediapipe模型處理的輸入圖像需要是RGB格式。

  • self.image = cv2.flip(self.image, 1):將圖像進(jìn)行鏡像翻轉(zhuǎn),以與mediapipe模型期望的手部位置對應(yīng)。

  • results = hands.process(self.image):將處理后的圖像傳遞給mediapipe的hands模型,進(jìn)行手勢識別和處理。

  • self.image = cv2.cvtColor(self.image, cv2.COLOR_RGB2BGR):將圖像從RGB格式轉(zhuǎn)換回BGR格式,以便后續(xù)的顯示和處理。

4.檢測手掌,標(biāo)記關(guān)鍵點和連接關(guān)系

                if results.multi_hand_landmarks:
                    # 遍歷每個手掌
                    for hand_landmarks in results.multi_hand_landmarks:
                        # 在畫面標(biāo)注手指
                        self.mp_drawing.draw_landmarks(
                            self.image,
                            hand_landmarks,
                            self.mp_hands.HAND_CONNECTIONS,
                            self.mp_drawing_styles.get_default_hand_landmarks_style(),
                            self.mp_drawing_styles.get_default_hand_connections_style())
  • if results.multi_hand_landmarks::檢查是否檢測到手掌。如果有檢測到手掌,則進(jìn)入下一步處理;否則跳過。

  • for hand_landmarks in results.multi_hand_landmarks::遍歷檢測到的每個手掌。

  • self.mp_drawing.draw_landmarks:使用mediapipe的draw_landmarks方法,在圖像上標(biāo)記手指的關(guān)鍵點和連接關(guān)系。

self.image:輸入的圖像。hand_landmarks:手掌的關(guān)鍵點。

self.mp_hands.HAND_CONNECTIONS:手指之間的連接關(guān)系。

5.解析檢測到的手掌并提取手指的關(guān)鍵點

檢測到的手掌并提取手指的關(guān)鍵點,然后將手指的坐標(biāo)存儲起來。

                        landmark_list = []

                        # 用來存儲手掌范圍的矩形坐標(biāo)
                        paw_x_list = []
                        paw_y_list = []
                        for landmark_id, finger_axis in enumerate(
                                hand_landmarks.landmark):
                            landmark_list.append([
                                landmark_id, finger_axis.x, finger_axis.y,
                                finger_axis.z
                            ])
                            paw_x_list.append(finger_axis.x)
                            paw_y_list.append(finger_axis.y)
                        if landmark_list:
                            # 比例縮放到像素
                            ratio_x_to_pixel = lambda x: math.ceil(x * resize_w)
                            ratio_y_to_pixel = lambda y: math.ceil(y * resize_h)

                            # 設(shè)計手掌左上角、右下角坐標(biāo)
                            paw_left_top_x, paw_right_bottom_x = map(ratio_x_to_pixel,
                                                                     [min(paw_x_list), max(paw_x_list)])
                            paw_left_top_y, paw_right_bottom_y = map(ratio_y_to_pixel,
                                                                     [min(paw_y_list), max(paw_y_list)])

                            # 給手掌畫框框
                            cv2.rectangle(self.image, (paw_left_top_x - 30, paw_left_top_y - 30),
                                          (paw_right_bottom_x + 30, paw_right_bottom_y + 30), (0, 255, 0), 2)

                            # 獲取中指指尖坐標(biāo)
                            middle_finger_tip = landmark_list[12]
                            middle_finger_tip_x = ratio_x_to_pixel(middle_finger_tip[1])
                            middle_finger_tip_y = ratio_y_to_pixel(middle_finger_tip[2])

                            # 獲取食指指尖坐標(biāo)
                            index_finger_tip = landmark_list[8]
                            index_finger_tip_x = ratio_x_to_pixel(index_finger_tip[1])
                            index_finger_tip_y = ratio_y_to_pixel(index_finger_tip[2])
                            # 中間點
                            between_finger_tip = (middle_finger_tip_x + index_finger_tip_x) // 2, (
                                        middle_finger_tip_y + index_finger_tip_y) // 2

                            thumb_finger_point = (middle_finger_tip_x, middle_finger_tip_y)
                            index_finger_point = (index_finger_tip_x, index_finger_tip_y)

  • landmark_list:一個列表,用于存儲手指的關(guān)鍵點信息。

  • paw_x_list 和 paw_y_list:用于存儲手掌范圍的矩形框的橫縱坐標(biāo)。

  • 在循環(huán)中,將每個手指的關(guān)鍵點的索引、x坐標(biāo)、y坐標(biāo)和z坐標(biāo)存儲在landmark_list中,同時將手掌范圍的橫縱坐標(biāo)存儲在paw_x_listpaw_y_list中。

如果landmark_list不為空,即有手指的關(guān)鍵點被檢測到ratio_x_to_pixel 和 ratio_y_to_pixel:兩個lambda函數(shù),用于將相對比例轉(zhuǎn)換為像素坐標(biāo)的函數(shù)。根據(jù)手掌范圍的矩形坐標(biāo),計算手掌區(qū)域的左上角和右下角坐標(biāo),并畫出方框。使用landmark_list中的信息獲取中指指尖坐標(biāo)和食指指尖坐標(biāo),并將它們轉(zhuǎn)換為像素坐標(biāo)。計算中指指尖坐標(biāo)和食指指尖坐標(biāo)的中間點。將中指指尖的坐標(biāo)和食指指尖的坐標(biāo)存儲在thumb_finger_pointindex_finger_point中。

解析檢測到的手掌信息,并提取手指的關(guān)鍵點坐標(biāo),將手指坐標(biāo)轉(zhuǎn)換為像素坐標(biāo),并將中指指尖和食指指尖的位置標(biāo)記在圖像上。

6.繪制指尖圓圈和連接線,計算距離

                            circle_func = lambda point: cv2.circle(self.image, point, 10, (255, 0, 255), -1)
                            self.image = circle_func(thumb_finger_point)
                            self.image = circle_func(index_finger_point)
                            self.image = circle_func(between_finger_tip)
                            # 畫2點連線
                            self.image = cv2.line(self.image, thumb_finger_point, index_finger_point, (255, 0, 255), 5)
                            # 勾股定理計算長度
                            line_len = math.hypot((index_finger_tip_x - middle_finger_tip_x),
                                                  (index_finger_tip_y - middle_finger_tip_y))
                            # 將指尖距離映射到文字
                            rect_percent_text = math.ceil(line_len)
  • cv2.line函數(shù),在圖像上繪制中指指尖和食指指尖之間的連接線。

  • math.hypot函數(shù)計算直角三角形斜邊的長度。

  • 將指尖之間的距離映射到rect_percent_text變量中,用作后續(xù)文本顯示的參數(shù)。

7.跟蹤手指之間的距離

                            if squareManager.drag_active:
                                # 更新方塊
                                squareManager.updateSquare(between_finger_tip[0], between_finger_tip[1])
                                if (line_len > 100):
                                    # 取消激活
                                    squareManager.drag_active = False
                                    squareManager.active_index = -1

                            elif (line_len < 100) and (squareManager.checkOverlay(between_finger_tip[0],
                                                                                  between_finger_tip[1]) != -1) and (
                                    squareManager.drag_active == False):
                                # 激活
                                squareManager.drag_active = True
                                # 計算距離
                                squareManager.setLen(between_finger_tip[0], between_finger_tip[1])

如果squareManagerdrag_active屬性為True,即矩形的移動模式已經(jīng)激活,使用squareManager.updateSquare方法更新矩形的位置。如果兩個手指之間的距離大于100,即手指之間的距離超過了閾值,取消矩形的激活模式,將drag_active設(shè)置為False,將active_index設(shè)置為-1。

否則,如果兩個手指之間的距離小于100,且手指之間存在重疊的矩形,并且矩形的移動模式未激活。激活矩形的移動模式,將drag_active設(shè)置為True。根據(jù)手指之間的距離,計算并設(shè)置矩形的長度,使用squareManager.setLen方法。

8.顯示圖像

                squareManager.display(self)

                # 顯示距離
                cv2.putText(self.image, "Distance:" + str(rect_percent_text), (10, 120), cv2.FONT_HERSHEY_PLAIN, 3,
                            (255, 0, 0), 3)

                # 顯示當(dāng)前激活
                cv2.putText(self.image, "Active:" + (
                    "None" if squareManager.active_index == -1 else str(squareManager.active_index)), (10, 170),
                            cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3)

                # 顯示刷新率FPS
                cTime = time.time()
                fps_text = 1 / (cTime - fpsTime)
                fpsTime = cTime
                cv2.putText(self.image, "FPS: " + str(int(fps_text)), (10, 70),
                            cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3)
                # 顯示畫面
                cv2.imshow('virtual drag and drop', self.image)

                if cv2.waitKey(5) & 0xFF == 27:
                    break
            cap.release()

control = HandControlVolume()
control.recognize()

主函數(shù)(recognize)的結(jié)尾部分,用于顯示圖像、矩形的狀態(tài)和刷新率,并等待按鍵響應(yīng)。使用squareManager.display方法顯示矩形。cv2.waitKey函數(shù)等待按鍵輸入,如果按下的鍵是ESC鍵(對應(yīng)的ASCII碼為27),則退出循環(huán)。

在屏幕上顯示處理后的圖像、矩形的狀態(tài)和刷新率,并等待按鍵響應(yīng)。這樣可以實現(xiàn)交互式的虛擬拖放功能。接下來我們看一下實際的操作效果。

四、實戰(zhàn)演示

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

通過演示我們可以實現(xiàn)通過手部對方塊進(jìn)行拖拽,效果可以達(dá)到良好的狀態(tài)。

五、源碼分享

import cv2
import mediapipe as mp
import time
import math
class SquareManager:
    def __init__(self, rect_width):

        # 方框長度
        self.rect_width = rect_width

        # 方塊list
        self.square_count = 0
        self.rect_left_x_list = []
        self.rect_left_y_list = []
        self.alpha_list = []

        # 中指與矩形左上角點的距離
        self.L1 = 0
        self.L2 = 0

        # 激活移動模式
        self.drag_active = False

        # 激活的方塊ID
        self.active_index = -1

    # 創(chuàng)建一個方塊,但是沒有顯示
    def create(self, rect_left_x, rect_left_y, alpha=0.4):
        self.rect_left_x_list.append(rect_left_x)
        self.rect_left_y_list.append(rect_left_y)
        self.alpha_list.append(alpha)
        self.square_count += 1

    # 更新位置
    def display(self, class_obj):
        for i in range(0, self.square_count):
            x = self.rect_left_x_list[i]
            y = self.rect_left_y_list[i]
            alpha = self.alpha_list[i]

            overlay = class_obj.image.copy()

            if (i == self.active_index):
                cv2.rectangle(overlay, (x, y), (x + self.rect_width, y + self.rect_width), (255, 0, 255), -1)
            else:
                cv2.rectangle(overlay, (x, y), (x + self.rect_width, y + self.rect_width), (255, 0, 0), -1)

            # Following line overlays transparent rectangle over the self.image
            class_obj.image = cv2.addWeighted(overlay, alpha, class_obj.image, 1 - alpha, 0)

    # 判斷落在哪個方塊上,返回方塊的ID
    def checkOverlay(self, check_x, check_y):
        for i in range(0, self.square_count):
            x = self.rect_left_x_list[i]
            y = self.rect_left_y_list[i]

            if (x < check_x < (x + self.rect_width)) and (y < check_y < (y + self.rect_width)):
                # 保存被激活的方塊ID
                self.active_index = i

                return i

        return -1

    # 計算與指尖的距離
    def setLen(self, check_x, check_y):
        # 計算距離
        self.L1 = check_x - self.rect_left_x_list[self.active_index]
        self.L2 = check_y - self.rect_left_y_list[self.active_index]

    # 更新方塊    
    def updateSquare(self, new_x, new_y):
        # print(self.rect_left_x_list[self.active_index])
        self.rect_left_x_list[self.active_index] = new_x - self.L1
        self.rect_left_y_list[self.active_index] = new_y - self.L2


# 識別控制類
class HandControlVolume:
    def __init__(self):
        # 初始化medialpipe
        self.mp_drawing = mp.solutions.drawing_utils
        self.mp_drawing_styles = mp.solutions.drawing_styles
        self.mp_hands = mp.solutions.hands

        # 中指與矩形左上角點的距離
        self.L1 = 0
        self.L2 = 0

        # image實例,以便另一個類調(diào)用
        self.image = None

    # 主函數(shù)
    def recognize(self):
        # 計算刷新率
        fpsTime = time.time()

        # OpenCV讀取視頻流
        cap = cv2.VideoCapture(0)
        # 視頻分辨率
        resize_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        resize_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

        # 畫面顯示初始化參數(shù)
        rect_percent_text = 0

        # 初始化方塊管理器
        squareManager = SquareManager(150)

        # 創(chuàng)建多個方塊
        for i in range(0, 5):
            squareManager.create(200 * i + 20, 200, 0.6)

        with self.mp_hands.Hands(min_detection_confidence=0.7,
                                 min_tracking_confidence=0.5,
                                 max_num_hands=2) as hands:
            while cap.isOpened():

                # 初始化矩形
                success, self.image = cap.read()
                self.image = cv2.resize(self.image, (resize_w, resize_h))

                if not success:
                    print("空幀.")
                    continue

                # 提高性能
                self.image.flags.writeable = False
                # 轉(zhuǎn)為RGB
                self.image = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)
                # 鏡像
                self.image = cv2.flip(self.image, 1)
                # mediapipe模型處理
                results = hands.process(self.image)

                self.image.flags.writeable = True
                self.image = cv2.cvtColor(self.image, cv2.COLOR_RGB2BGR)
                # 判斷是否有手掌
                if results.multi_hand_landmarks:
                    # 遍歷每個手掌
                    for hand_landmarks in results.multi_hand_landmarks:
                        # 在畫面標(biāo)注手指
                        self.mp_drawing.draw_landmarks(
                            self.image,
                            hand_landmarks,
                            self.mp_hands.HAND_CONNECTIONS,
                            self.mp_drawing_styles.get_default_hand_landmarks_style(),
                            self.mp_drawing_styles.get_default_hand_connections_style())

                        # 解析手指,存入各個手指坐標(biāo)
                        landmark_list = []

                        # 用來存儲手掌范圍的矩形坐標(biāo)
                        paw_x_list = []
                        paw_y_list = []
                        for landmark_id, finger_axis in enumerate(
                                hand_landmarks.landmark):
                            landmark_list.append([
                                landmark_id, finger_axis.x, finger_axis.y,
                                finger_axis.z
                            ])
                            paw_x_list.append(finger_axis.x)
                            paw_y_list.append(finger_axis.y)
                        if landmark_list:
                            # 比例縮放到像素
                            ratio_x_to_pixel = lambda x: math.ceil(x * resize_w)
                            ratio_y_to_pixel = lambda y: math.ceil(y * resize_h)

                            # 設(shè)計手掌左上角、右下角坐標(biāo)
                            paw_left_top_x, paw_right_bottom_x = map(ratio_x_to_pixel,
                                                                     [min(paw_x_list), max(paw_x_list)])
                            paw_left_top_y, paw_right_bottom_y = map(ratio_y_to_pixel,
                                                                     [min(paw_y_list), max(paw_y_list)])

                            # 給手掌畫框框
                            cv2.rectangle(self.image, (paw_left_top_x - 30, paw_left_top_y - 30),
                                          (paw_right_bottom_x + 30, paw_right_bottom_y + 30), (0, 255, 0), 2)

                            # 獲取中指指尖坐標(biāo)
                            middle_finger_tip = landmark_list[12]
                            middle_finger_tip_x = ratio_x_to_pixel(middle_finger_tip[1])
                            middle_finger_tip_y = ratio_y_to_pixel(middle_finger_tip[2])

                            # 獲取食指指尖坐標(biāo)
                            index_finger_tip = landmark_list[8]
                            index_finger_tip_x = ratio_x_to_pixel(index_finger_tip[1])
                            index_finger_tip_y = ratio_y_to_pixel(index_finger_tip[2])
                            # 中間點
                            between_finger_tip = (middle_finger_tip_x + index_finger_tip_x) // 2, (
                                        middle_finger_tip_y + index_finger_tip_y) // 2
                            # print(middle_finger_tip_x)
                            thumb_finger_point = (middle_finger_tip_x, middle_finger_tip_y)
                            index_finger_point = (index_finger_tip_x, index_finger_tip_y)
                            # 畫指尖2點
                            circle_func = lambda point: cv2.circle(self.image, point, 10, (255, 0, 255), -1)
                            self.image = circle_func(thumb_finger_point)
                            self.image = circle_func(index_finger_point)
                            self.image = circle_func(between_finger_tip)
                            # 畫2點連線
                            self.image = cv2.line(self.image, thumb_finger_point, index_finger_point, (255, 0, 255), 5)
                            # 勾股定理計算長度
                            line_len = math.hypot((index_finger_tip_x - middle_finger_tip_x),
                                                  (index_finger_tip_y - middle_finger_tip_y))
                            # 將指尖距離映射到文字
                            rect_percent_text = math.ceil(line_len)

                            # 激活模式,需要讓矩形跟隨移動
                            if squareManager.drag_active:
                                # 更新方塊
                                squareManager.updateSquare(between_finger_tip[0], between_finger_tip[1])
                                if (line_len > 100):
                                    # 取消激活
                                    squareManager.drag_active = False
                                    squareManager.active_index = -1

                            elif (line_len < 100) and (squareManager.checkOverlay(between_finger_tip[0],
                                                                                  between_finger_tip[1]) != -1) and (
                                    squareManager.drag_active == False):
                                # 激活
                                squareManager.drag_active = True
                                # 計算距離
                                squareManager.setLen(between_finger_tip[0], between_finger_tip[1])

                # 顯示方塊,傳入本實例,主要為了半透明的處理
                squareManager.display(self)

                # 顯示距離
                cv2.putText(self.image, "Distance:" + str(rect_percent_text), (10, 120), cv2.FONT_HERSHEY_PLAIN, 3,
                            (255, 0, 0), 3)

                # 顯示當(dāng)前激活
                cv2.putText(self.image, "Active:" + (
                    "None" if squareManager.active_index == -1 else str(squareManager.active_index)), (10, 170),
                            cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3)

                # 顯示刷新率FPS
                cTime = time.time()
                fps_text = 1 / (cTime - fpsTime)
                fpsTime = cTime
                cv2.putText(self.image, "FPS: " + str(int(fps_text)), (10, 70),
                            cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 0), 3)
                # 顯示畫面
                cv2.imshow('virtual drag and drop', self.image)

                if cv2.waitKey(5) & 0xFF == 27:
                    break
            cap.release()

control = HandControlVolume()
control.recognize()

到此這篇關(guān)于OpenCV實現(xiàn)手勢虛擬拖拽的使用示例的文章就介紹到這了,更多相關(guān)OpenCV 手勢虛擬拖拽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python腳本破解壓縮文件口令實例教程(zipfile)

    Python腳本破解壓縮文件口令實例教程(zipfile)

    這篇文章主要給大家介紹了關(guān)于Python腳本破解壓縮文件口令(zipfile)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Python具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • 在Python 字典中一鍵對應(yīng)多個值的實例

    在Python 字典中一鍵對應(yīng)多個值的實例

    今天小編就為大家分享一篇在Python 字典中一鍵對應(yīng)多個值的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-02-02
  • python+opencv實現(xiàn)堆疊圖片

    python+opencv實現(xiàn)堆疊圖片

    這篇文章主要為大家詳細(xì)介紹了python+opencv實現(xiàn)堆疊圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Python爬取12306車次信息代碼詳解

    Python爬取12306車次信息代碼詳解

    這篇文章主要介紹了Python爬取12306車次信息代碼詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • Python使用sort和class實現(xiàn)的多級排序功能示例

    Python使用sort和class實現(xiàn)的多級排序功能示例

    這篇文章主要介紹了Python使用sort和class實現(xiàn)的多級排序功能,涉及Python基于面向?qū)ο蟮脑乇闅v、列表排序、添加等相關(guān)操作技巧,需要的朋友可以參考下
    2018-08-08
  • Python?numpy之線性代數(shù)與隨機(jī)漫步

    Python?numpy之線性代數(shù)與隨機(jī)漫步

    這篇文章主要介紹了Python?numpy之線性代數(shù)與隨機(jī)漫步,線性代數(shù),矩陣計算,優(yōu)化與內(nèi)存;比如矩陣乘法,分解,行列式等數(shù)學(xué)知識,是所有數(shù)組類庫的重要組成部分
    2022-07-07
  • Python將視頻轉(zhuǎn)換為圖片介紹

    Python將視頻轉(zhuǎn)換為圖片介紹

    大家好,本篇文章主要講的是Python將視頻轉(zhuǎn)換為圖片介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • 如何運行.ipynb文件的圖文講解

    如何運行.ipynb文件的圖文講解

    今天小編大家分享一篇如何運行.ipynb文件的圖文講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • 利用django如何解析用戶上傳的excel文件

    利用django如何解析用戶上傳的excel文件

    這篇文章主要給大家介紹了關(guān)于利用django如何解析用戶上傳的excel文件的相關(guān)資料,這是最近在工作中遇到的一個問題,覺著有必要分享出給大家,需要的朋友可以參考借鑒,下面來一起看看詳細(xì)的介紹吧。
    2017-07-07
  • Python隊列的定義與使用方法示例

    Python隊列的定義與使用方法示例

    這篇文章主要介紹了Python隊列的定義與使用方法,結(jié)合具體實例形式分析了Python定義及使用隊列的具體操作技巧與注意事項,需要的朋友可以參考下
    2017-06-06

最新評論