opencv實戰項目 手勢識別-手勢控制鍵盤

手勢識別是一種人機交互技術,通過識別人的手勢動作,從而實現對計算機、智能手機、智能電視等設備的操作和控制。

1.? opencv實現手部追蹤(定位手部關鍵點)

2.opencv實戰項目 實現手勢跟蹤并返回位置信息(封裝調用)

3.opencv實戰項目 手勢識別-手勢控制鼠標

4.opencv實戰項目 手勢識別-手勢控制鍵盤

未完待續

本專欄記錄作者的學習之旅會一直更新下去,歡迎訂閱一起學習進步

本項目是使用了谷歌開源的框架mediapipe,里面有非常多的模型提供給我們使用,例如面部檢測,身體檢測,手部檢測等在這里插入圖片描述

?代碼需要用到opencv? ?HandTraqckModule模塊? ?mediapipe模塊和一個鍵盤控制模塊pynput,cvzone模塊

一、HandTraqckModule模塊?

前面的文章中有封裝手部檢測模塊的教程,這邊簡單的介紹一下,有新增加的模塊可以簡單學習一下

import cv2
import mediapipe as mp
import mathclass HandDetector:"""Finds Hands using the mediapipe library. Exports the landmarksin pixel format. Adds extra functionalities like finding howmany fingers are up or the distance between two fingers. Alsoprovides bounding box info of the hand found."""def __init__(self, mode=False, maxHands=2, detectionCon=0.5, minTrackCon=0.5):""":param mode: In static mode, detection is done on each image: slower:param maxHands: Maximum number of hands to detect:param detectionCon: Minimum Detection Confidence Threshold:param minTrackCon: Minimum Tracking Confidence Threshold"""self.mode = modeself.maxHands = maxHandsself.detectionCon = detectionConself.minTrackCon = minTrackConself.mpHands = mp.solutions.handsself.hands = self.mpHands.Hands(self.mode, self.maxHands,self.detectionCon, self.minTrackCon)self.mpDraw = mp.solutions.drawing_utilsself.tipIds = [4, 8, 12, 16, 20]self.fingers = []self.lmList = []def findHands(self, img, draw=True):"""Finds hands in a BGR image.:param img: Image to find the hands in.:param draw: Flag to draw the output on the image.:return: Image with or without drawings"""imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)self.results = self.hands.process(imgRGB)if self.results.multi_hand_landmarks:for handLms in self.results.multi_hand_landmarks:if draw:self.mpDraw.draw_landmarks(img, handLms,self.mpHands.HAND_CONNECTIONS)return imgdef findPosition(self, img, handNo=0, draw=True):"""Finds landmarks of a single hand and puts them in a listin pixel format. Also finds the bounding box around the hand.:param img: main image to find hand in:param handNo: hand id if more than one hand detected:param draw: Flag to draw the output on the image.:return: list of landmarks in pixel format; bounding box"""xList = []yList = []bbox = []bboxInfo = []self.lmList = []if self.results.multi_hand_landmarks:myHand = self.results.multi_hand_landmarks[handNo]for id, lm in enumerate(myHand.landmark):h, w, c = img.shapepx, py = int(lm.x * w), int(lm.y * h)xList.append(px)yList.append(py)self.lmList.append([px, py])if draw:cv2.circle(img, (px, py), 5, (255, 0, 255), cv2.FILLED)xmin, xmax = min(xList), max(xList)ymin, ymax = min(yList), max(yList)boxW, boxH = xmax - xmin, ymax - yminbbox = xmin, ymin, boxW, boxHcx, cy = bbox[0] + (bbox[2] // 2), \bbox[1] + (bbox[3] // 2)bboxInfo = {"id": id, "bbox": bbox, "center": (cx, cy)}if draw:cv2.rectangle(img, (bbox[0] - 20, bbox[1] - 20),(bbox[0] + bbox[2] + 20, bbox[1] + bbox[3] + 20),(0, 255, 0), 2)return self.lmList, bboxInfodef fingersUp(self):"""Finds how many fingers are open and returns in a list.Considers left and right hands separately:return: List of which fingers are up"""if self.results.multi_hand_landmarks:myHandType = self.handType()fingers = []# Thumbif myHandType == "Right":if self.lmList[self.tipIds[0]][0] > self.lmList[self.tipIds[0] - 1][0]:fingers.append(1)else:fingers.append(0)else:if self.lmList[self.tipIds[0]][0] < self.lmList[self.tipIds[0] - 1][0]:fingers.append(1)else:fingers.append(0)# 4 Fingersfor id in range(1, 5):if self.lmList[self.tipIds[id]][1] < self.lmList[self.tipIds[id] - 2][1]:fingers.append(1)else:fingers.append(0)return fingersdef findDistance(self, p1, p2, img, draw=True):"""Find the distance between two landmarks based on theirindex numbers.:param p1: Point1 - Index of Landmark 1.:param p2: Point2 - Index of Landmark 2.:param img: Image to draw on.:param draw: Flag to draw the output on the image.:return: Distance between the pointsImage with output drawnLine information"""if self.results.multi_hand_landmarks:x1, y1 = self.lmList[p1][0], self.lmList[p1][1]x2, y2 = self.lmList[p2][0], self.lmList[p2][1]cx, cy = (x1 + x2) // 2, (y1 + y2) // 2if draw:cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED)cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 3)cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)length = math.hypot(x2 - x1, y2 - y1)return length, img, [x1, y1, x2, y2, cx, cy]def handType(self):"""Checks if the hand is left or right:return: "Right" or "Left""""if self.results.multi_hand_landmarks:if self.lmList[17][0] < self.lmList[5][0]:return "Right"else:return "Left"def main():cap = cv2.VideoCapture(0)detector = HandDetector(detectionCon=0.8, maxHands=1)while True:# Get image framesuccess, img = cap.read()# Find the hand and its landmarksimg = detector.findHands(img)lmList, bboxInfo = detector.findPosition(img)print(detector.handType())# Displaycv2.imshow("Image", img)cv2.waitKey(1)if __name__ == "__main__":main()

  1. 導入庫:導入了必要的庫,包括 OpenCV (cv2) 用于圖像處理和顯示,Mediapipe (mediapipe) 用于手部檢測和跟蹤,以及數學庫 (math)。

  2. HandDetector 類:這是主要的手勢檢測器類,提供了多個方法來處理手部檢測和分析手勢。

    • __init__ 方法:初始化檢測器的參數,例如檢測模式、最大檢測手數、檢測和跟蹤的置信度閾值等。

    • findHands 方法:在給定的圖像中尋找手部,可以選擇是否繪制檢測結果。

    • findPosition 方法:找到單個手部的關鍵點位置(landmarks)并將它們存儲在像素格式的列表中,同時計算手部的邊界框信息。

    • fingersUp 方法:確定手勢中有多少個手指打開,將結果以列表形式返回。

    • findDistance 方法:計算兩個指定關鍵點之間的距離,并在圖像上繪制結果。

    • handType 方法:確定手的類型是左手還是右手。

具體就不展開講了

這個函數在有一個專門的包叫做cvzone里有,但是不知道是不是版本的問題,少了一些東西,運行不起來,只能自己手擼檢測模塊。

下面是主函數的代碼

import cv2
from cvzone.HandTrackingModule import HandDetector
from HandTrackingModule import *
from time import sleep
import numpy as np
import cvzone
from pynput.keyboard import Controllercap = cv2.VideoCapture(0)
cap.set(3, 1280)
cap.set(4, 720)detector =HandDetector(detectionCon=0.5)
keys = [["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"],["A", "S", "D", "F", "G", "H", "J", "K", "L", ";"],["Z", "X", "C", "V", "B", "N", "M", ",", ".", "/"]]
finalText = ""keyboard = Controller()def drawAll(img, buttonList):for button in buttonList:x, y = button.posw, h = button.sizecvzone.cornerRect(img, (button.pos[0], button.pos[1], button.size[0], button.size[1]),20, rt=0)cv2.rectangle(img, button.pos, (x + w, y + h), (255, 0, 255), cv2.FILLED)cv2.putText(img, button.text, (x + 20, y + 65),cv2.FONT_HERSHEY_PLAIN, 4, (255, 255, 255), 4)return img#
# def drawAll(img, buttonList):
#     imgNew = np.zeros_like(img, np.uint8)
#     for button in buttonList:
#         x, y = button.pos
#         cvzone.cornerRect(imgNew, (button.pos[0], button.pZXos[1], button.size[0], button.size[1]),
#                           20, rt=0)
#         cv2.rectangle(imgNew, button.pos, (x + button.size[0], y + button.size[1]),
#                       (255, 0, 255), cv2.FILLED)
#         cv2.putText(imgNew, button.text, (x + 40, y + 60),
#                     cv2.FONT_HERSHEY_PLAIN, 2, (255, 255, 255), 3)
#
#     out = img.copy()
#     alpha = 0.5
#     mask = imgNew.astype(bool)
#     print(mask.shape)
#     out[mask] = cv2.addWeighted(img, alpha, imgNew, 1 - alpha, 0)[mask]
#     return outclass Button():def __init__(self, pos, text, size=[85, 85]):self.pos = posself.size = sizeself.text = textbuttonList = []
for i in range(len(keys)):for j, key in enumerate(keys[i]):buttonList.append(Button([100 * j + 50, 100 * i + 50], key))while True:success, img = cap.read()img = detector.findHands(img)lmList, bboxInfo = detector.findPosition(img)img = drawAll(img, buttonList)if lmList:for button in buttonList:x, y = button.posw, h = button.sizeif x < lmList[8][0] < x + w and y < lmList[8][1] < y + h:cv2.rectangle(img, (x - 5, y - 5), (x + w + 5, y + h + 5), (175, 0, 175), cv2.FILLED)cv2.putText(img, button.text, (x + 20, y + 65),cv2.FONT_HERSHEY_PLAIN, 4, (255, 255, 255), 4)l, _, _ = detector.findDistance(8, 12, img, draw=False)print(l)## when clickedif l < 30:keyboard.press(button.text)cv2.rectangle(img, button.pos, (x + w, y + h), (0, 255, 0), cv2.FILLED)cv2.putText(img, button.text, (x + 20, y + 65),cv2.FONT_HERSHEY_PLAIN, 4, (255, 255, 255), 4)finalText += button.textsleep(0.15)cv2.rectangle(img, (50, 350), (700, 450), (175, 0, 175), cv2.FILLED)cv2.putText(img, finalText, (60, 430),cv2.FONT_HERSHEY_PLAIN, 5, (255, 255, 255), 5)cv2.imshow("Image", img)cv2.waitKey(1)
  1. 導入庫:導入了需要的庫,包括 OpenCV (cv2) 用于圖像處理和顯示,Mediapipe 中的 HandDetector 用于手部檢測,cvzone 用于繪制按鈕外觀,numpy 用于數組處理,pynput.keyboard 中的 Controller 用于模擬鍵盤輸入,time 用于延時。

  2. 設置攝像頭參數:通過 OpenCV 設置攝像頭的分辨率為 1280x720。

  3. 創建 HandDetector 實例:使用 HandDetector 類創建一個手勢檢測器實例,設置檢測的置信度閾值為 0.5。

  4. 創建按鈕列表:創建了一個包含虛擬鍵盤按鈕信息的列表,按鍵布局通過嵌套列表 keys 定義。

  5. 創建 Button 類:用于創建虛擬按鈕的類,每個按鈕包含位置、文本內容和大小。

  6. 主循環:進入一個無限循環,用于處理實時的攝像頭捕獲圖像幀。

    • 讀取圖像幀:從攝像頭捕獲圖像幀。

    • 手部檢測:使用手勢檢測器找出圖像中的手部和關鍵點。

    • 繪制按鈕:調用 drawAll 函數在圖像上繪制虛擬按鈕。

    • 遍歷按鈕列表:對每個按鈕進行檢查,看是否有手指觸摸到按鈕。

      • 如果手指在按鈕范圍內,繪制高亮效果。

      • 計算手指觸摸點與按鈕中心的距離,如果小于一定閾值,則模擬鍵盤按下并記錄輸入。

    • 繪制已輸入的文本:在圖像上繪制已輸入的文本。

    • 顯示圖像:通過 OpenCV 顯示處理后的圖像。

    • 等待鍵盤輸入:等待 1 毫秒,以便保持圖像窗口的響應性。

  7. 運行主程序:執行主循環,處理實時的攝像頭捕獲和手勢識別。

如果有遇到問題可以評論區留言,大家一起相互學習!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/35257.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/35257.shtml
英文地址,請注明出處:http://en.pswp.cn/news/35257.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

虛擬機安裝 Ubuntu桌面版,宿主機無法訪問虛擬機 ufw 防火墻簡單使用

虛擬機安裝 Ubuntu桌面版&#xff0c;宿主機無法訪問虛擬機 問題處理安裝ssh服務ufw防火墻 放行ssh服務ufw 常用命令 問題 本次安裝使用的 ubuntu-22.04.2-desktop-amd64 &#xff0c;網絡連接使用的是橋接&#xff0c;查看ubuntu的ip是正常的&#xff0c;與宿主機在同一個網段…

力扣的板子

板子 線性篩法求質因子的板子快速冪 線性篩法求質因子的板子 int limit 100000; //修改為題目中的數字的上限 bool isprime[100005] {0}; //保存所有1~limit中的數字是不是質數 int myprime[100005] {0}; //保存2~limit中所有數字的最小質因子 int primes[100000] {0}; …

airflow是什么

Airflow 簡介 Airflow是一個基于有向無環圖(DAG)的可編程、調度和監控的工作流平臺&#xff0c;它可以定義一組有依賴的任務&#xff0c;按照依賴依次執行。airflow提供了豐富的命令行工具用于系統管控&#xff0c;而其web管理界面同樣也可以方便的管控調度任務&#xff0c;并…

Lua 閉包

一、Lua 中的函數 Lua 中的函數是第一類值。意味著和其他的常見類型的值&#xff08;例如數值和字符串&#xff09;具有同等權限。 舉個例子&#xff0c;函數也可以像其他類型一樣存儲起來&#xff0c;然后調用 -- 將 a.p 指向 print 函數 a { p print } -- 使用 a.p 函數…

(原創)Flutter與Native頁面互相跳轉

前言 實際開發混合項目時&#xff0c;常常會有頁面跳轉的需求 如果是原生界面和flutter界面需要互相跳轉 這種情況應該怎么處理呢&#xff1f; 今天這篇博客主要就來介紹下這個情況 其實想一下&#xff0c;這個問題可以拆成四個小的問題來分析&#xff1a; 1&#xff1a;原生界…

什么是全局代理,手機怎么設置全局代理

目錄 什么是全局代理 全局代理的優缺點 優點 缺點 手機怎么設置全局代理 注意事項 總結 在計算機網絡和信息安全中&#xff0c;全局代理是一種常用的技術手段&#xff0c;用于將網絡流量通過代理服務器進行轉發和處理。本文將介紹什么是全局代理&#xff0c;探討全局代理…

pyspark筆記 pyspark.sql.functions

col qqpyspark 筆記 pyspark.sql.function col VS select_UQI-LIUWJ的博客-CSDN博客 取某一列 lit 創建一個包含指定值的列 date_trunc 將日期截取成由第一個參數指定的字符串值 year, yyyy, yy——截取到年month,mon,mm——截取到月day,dd ——截取到天microsecondmillis…

SpringBoot WebSocket配合react 使用消息通信

引入websocket依賴 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>配置websocket import org.springframework.context.annotation.Bean; import org.spr…

Highcharts引入

Highcharts是和jQuery一起使用的&#xff0c;所以需要下載好jQuery jQuery下載方式&#xff1a;訪問&#xff1a;http://cdn.staticfile.org/jquery/2.1.4/jquery.min.js&#xff0c;然后全選復制到自己新建的txt文檔中&#xff0c;最后把擴展名改為js。 Highcharts下載方式&…

pytest運行時參數說明,pytest詳解,pytest.ini詳解

一、Pytest簡介 1.pytest是一個非常成熟的全功能的Python測試框架&#xff0c;主要有一下幾個特點&#xff1a; 簡單靈活&#xff0c;容易上手&#xff0c;支持參數化 2.能夠支持簡單的單元測試和復雜的功能測試&#xff0c;還可以用來做selenium、appium等自動化測試&#xf…

使用sqlplus連接oracle,提示ORA-01034和ORA-27101

具體內容如下 PL/SQL Developer 處 登錄時 終端處 登錄時 ERROR: ORA-01034: ORACLE not available ORA-27101: shared memory realm does not exist Process ID: 0 Session ID: 0 Serial number: 0 解決方法是執行以下命令 sqlplus /nolog conn / as sysdba startup …

【Hilog】鴻蒙系統日志源碼分析

【Hilog】鴻蒙系統日志源碼分析 Hilog采用C/S結構&#xff0c;Hilogd作為服務端提供日志功能。Client端通過API調用&#xff08;最終通過socket通訊&#xff09;與HiLogd打交道。簡易Block圖如下。 這里主要分析一下。Hilog的讀、寫、壓縮落盤&#xff0c;以及higlog與android…

學術論文GPT源碼解讀:從chatpaper、chatwithpaper到gpt_academic

前言 之前7月中旬&#xff0c;我曾在微博上說準備做“20個LLM大型項目的源碼解讀” 針對這個事&#xff0c;目前的最新情況是 已經做了的&#xff1a;LLaMA、Alpaca、ChatGLM-6B、deepspeedchat、transformer、langchain、langchain-chatglm知識庫準備做的&#xff1a;chatpa…

GitHub上受歡迎的Android UI Library

內容 抽屜菜單ListViewWebViewSwitchButton按鈕點贊按鈕進度條TabLayout圖標下拉刷新ViewPager圖表(Chart)菜單(Menu)浮動菜單對話框空白頁滑動刪除手勢操作RecyclerViewCardColorDrawableSpinner布局模糊效果TabBarAppBar選擇器(Picker)跑馬燈日歷時間主題樣式ImageView通知聊…

chapter 1 formation of crystal, basic concepts

chapter 1 晶體的形成 1.1 Quantum Mechanics and atomic structure 1.1.1 Old Quantum Theory problems of planetary model: atom would be unstableradiate EM wave of continuous frequency to solve the prablom of planetary model: Bohr: Quantum atomic structureP…

React 實現文件分片上傳和下載

React 實現文件分片上傳和下載 在開發中&#xff0c;文件的上傳和下載是常見的需求。然而&#xff0c;當面對大型文件時&#xff0c;直接的上傳和下載方式可能會遇到一些問題&#xff0c;比如網絡傳輸不穩定、文件過大導致傳輸時間過長等等。為了解決這些問題&#xff0c;我們…

Vue中自定義.js變量

1、定義.js文件 order.js文件內容&#xff1a; // 訂單是否報賬 const EXPENESS_STATUS_NO0; const EXPENESS_STATUS_YES1; // 狀態 0-未發貨 1-發貨 2-確認收獲 const STATUS_NO0; const STATUS_SEND1; const STATUS_DELIVERY2; // 如何不加這個&#xff0c;vue中引…

yolov5、YOLOv7、YOLOv8改進:注意力機制CA

論文題目&#xff1a;《Coordinate Attention for Efficient Mobile NetWork Design》論文地址&#xff1a; https://arxiv.org/pdf/2103.02907.pdf 本文中&#xff0c;作者通過將位置信息嵌入到通道注意力中提出了一種新穎的移動網絡注意力機制&#xff0c;將其稱為“Coordin…

Nagle算法--網絡優化算法

Nagle Nagle算法是一種網絡優化算法&#xff0c;旨在減少小數據包的網絡傳輸次數&#xff0c;提高網絡傳輸效率。該算法由John Nagle在1984年提出&#xff0c;并被廣泛應用于TCP協議中。 Nagle算法的原理是將較小的數據包進行緩存&#xff0c;在緩存數據包的發送時機到來時&am…

拓撲布局和建立小型網絡

練習 2.6.1&#xff1a;拓撲布局和建立小型網絡 地址表 本實驗不包括地址表。 拓撲圖 學習目標 正確識別網絡中使用的電纜物理連接點對點交換網絡驗證每個網絡的基本連通性 簡介&#xff1a; 許多網絡問題都可以在網絡的物理層解決。因此&#xff0c;必須清楚了解網絡連接…