日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

圣诞纯情手势告白(Mediapipe基本使用手势识别详解)

發(fā)布時間:2024/3/24 编程问答 116 豆豆
生活随笔 收集整理的這篇文章主要介紹了 圣诞纯情手势告白(Mediapipe基本使用手势识别详解) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 環(huán)境安裝
  • 快速上手(手勢捕捉)
    • 獲取手的坐標(biāo)
    • 返回參數(shù)詳解
  • 不同算子
  • 手勢識別案例
    • 手指狀態(tài)判斷
    • 編碼
    • 升級版(圣誕表白器)
  • 總結(jié)

前言

本來不想寫這個的,但是轉(zhuǎn)了一圈國內(nèi)mediapipe 的比較少教程。沒有那么全面,所以這邊還是記錄一下吧。

環(huán)境安裝

如果你是 Anconada 那么你不需要安裝,但如果不是,你只需要輸入以下指令

pip install mediapipe

再次之前你必須掌握 python3
pyharm 使用
opencv 基本使用

快速上手(手勢捕捉)

這邊我們舉一個快爛大街的東西。

import mediapipe as mp import cv2cap = cv2.VideoCapture(0)mpHand = mp.solutions.hands #mp的手部捕捉 Hand = mpHand.Hands() #找到圖片當(dāng)中的手 mphanddraw = mp.solutions.drawing_utils #繪制工具while True:flag,img = cap.read()RGBImage = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #把圖片進(jìn)行轉(zhuǎn)換result = Hand.process(RGBImage)if(result.multi_hand_landmarks): #如果有手,那么就會得到手的列表記錄了手的坐標(biāo)for handlist in result.multi_hand_landmarks:mphanddraw.draw_landmarks(img,handlist,mpHand.HAND_CONNECTIONS)#繪制手的關(guān)節(jié) HAND_CONNECTIONS 把點(diǎn)連接起來cv2.imshow("Hands",img)if(cv2.waitKey(1)==ord("q")):breakcap.release() cv2.destroyAllWindows()


注釋應(yīng)該說得很清楚了,這里就還不闡述了。

獲取手的坐標(biāo)

從剛才的效果你可以發(fā)現(xiàn),handlist 包含了我們的一只手的完整坐標(biāo),并且可以繪制21個點(diǎn)
那么事實(shí)上 handlist 就是21個點(diǎn)的編號和坐標(biāo)(這個坐標(biāo)是按照百分比來算的),每個點(diǎn)對應(yīng)下面的圖

所以我們可以非常清楚的去捕捉到我們手的狀態(tài)。
接下來我們來對我們的手進(jìn)行重新繪制。

import mediapipe as mp import cv2cap = cv2.VideoCapture(0)mpHand = mp.solutions.hands #mp的手部捕捉 Hand = mpHand.Hands() #找到圖片當(dāng)中的手 mphanddraw = mp.solutions.drawing_utils #繪制工具while True:flag,img = cap.read()RGBImage = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #把圖片進(jìn)行轉(zhuǎn)換result = Hand.process(RGBImage)if(result.multi_hand_landmarks): #如果有手,那么就會得到手的列表記錄了手的坐標(biāo)for handlist in result.multi_hand_landmarks:for id,lm in enumerate(handlist.landmark):h,w,c = img.shapecx,cy = int(lm.x * w),int(lm.y * h)cv2.circle(img,(cx,cy),15,(255,0,255),cv2.FILLED)mphanddraw.draw_landmarks(img,handlist,mpHand.HAND_CONNECTIONS,)#繪制手的關(guān)節(jié) HAND_CONNECTIONS 把點(diǎn)連接起來cv2.imshow("Hands",img)if(cv2.waitKey(1)==ord("q")):breakcap.release() cv2.destroyAllWindows()

之后的話我們可以對代碼進(jìn)行優(yōu)化,我們知道我們可以直接獲取一個手掌的每一個關(guān)節(jié)的坐標(biāo),在我們的圖片上,這樣一來我們就可以對我們手的姿態(tài)進(jìn)行預(yù)測,判斷。這樣一來就好玩了。
例如這樣:

import mediapipe as mp import cv2 import mathcap = cv2.VideoCapture(0) cap.set(3,1280) cap.set(4,720)mpHand = mp.solutions.hands #mp的手部捕捉 Hand = mpHand.Hands() #找到圖片當(dāng)中的手 mphanddraw = mp.solutions.drawing_utils #繪制工具while True:flag,img = cap.read()RGBImage = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #把圖片進(jìn)行轉(zhuǎn)換result = Hand.process(RGBImage)if(result.multi_hand_landmarks): #如果有手,那么就會得到手的列表記錄了手的坐標(biāo)hands_data = result.multi_hand_landmarksfor handlist in hands_data:h, w, c = img.shapeshizhi_postion = (int(handlist.landmark[8].x*w),int(handlist.landmark[8].y*h))muzhi_postion = (int(handlist.landmark[4].x * w), int(handlist.landmark[4].y * h))cv2.line(img, muzhi_postion, shizhi_postion, (255, 0, 0), 5)location = int(shizhi_postion[0]-muzhi_postion[0])**2\+ int(shizhi_postion[1]-muzhi_postion[1])**2location = int(math.sqrt(location))showpostion = (int(((muzhi_postion[0]+shizhi_postion[0])/2)) ,int(((muzhi_postion[1]+shizhi_postion[1])/2)))cv2.putText(img, str(location), showpostion, cv2.FONT_HERSHEY_PLAIN, 1, (255, 0, 255), 1)for id,lm in enumerate(handlist.landmark):cx,cy = int(lm.x * w),int(lm.y * h)# 我們標(biāo)注出大拇指和食指的距離cv2.circle(img,(cx,cy),15,(255,0,255),cv2.FILLED)cv2.putText(img,str(id),(cx,cy),cv2.FONT_HERSHEY_PLAIN,1,(0,255,255),1)mphanddraw.draw_landmarks(img,handlist,mpHand.HAND_CONNECTIONS,)#繪制手的關(guān)節(jié) HAND_CONNECTIONS 把點(diǎn)連接起來cv2.imshow("Hands",img)if(cv2.waitKey(1)==ord("q")):breakcap.release() cv2.destroyAllWindows()

所以就好玩了。

返回參數(shù)詳解

這個返回參數(shù)很重要,看前面的例子是吧。
首先 hands_data 是多只手的總體坐標(biāo),幾只手在屏幕上,那么 len()就是幾

handlist 是包含了一只手的21個點(diǎn)

handlist 包含了 [{點(diǎn)1},{點(diǎn)2}…]
所以么獲取 拇指頭就是 handlist.landmark[4].x * w
所以就ok了。

不同算子

這個其實(shí)我也不太好說那玩意叫啥,這里的話我先叫他算子。
那么這個有啥用呢,其實(shí)就是使用不同的算法模型,來幫助我們提取不同的特征,以便處理。

這里可以看到這里有很多不同的算子。
調(diào)用方式都是類似的,但是處理的方式可能有些許不同。
當(dāng)然我們這里還是先探討關(guān)于 hands這個東西改怎么玩。后面我們再來說說其他的玩意,到本系列最后說不定可以做一個手勢系統(tǒng),用我們身體的姿態(tài)來控制電腦,例如我們可以使用我們的手來充當(dāng)我們的鼠標(biāo)(右手)等等,那玩意應(yīng)該會比較酷!或者我們結(jié)合VR游戲驅(qū)動,我們將不需要游戲手柄,只需要一個像素良好的攝像頭,并且由于 mediapipe 是直接在CPU當(dāng)中運(yùn)行的,這就意味著我們可以在沒有顯卡 GPU 的設(shè)備運(yùn)行,Google官方也說過這玩意可以用到移動端,linux等。

ok 繼續(xù),關(guān)于前面的代碼,我們其實(shí)已經(jīng)可以來做一個簡單的音量控制器了,我們只需要對手指間距進(jìn)行換算即可。不夠這個任然不是我們的主題,我們今天的主題其實(shí)是如何識別出我們的手勢,例如識別
1 ~ 5。

手勢識別案例

OK ,那么接下來開始我們的案例,這個案例其實(shí)就是
Opencv 快速使用(基礎(chǔ)使用&手勢識別)


部分,當(dāng)時這個部分是直接copy的,結(jié)果發(fā)現(xiàn)這哥們的其實(shí)是抄我發(fā)的那個視頻的代碼(吐槽一波寫的真爛,有很嚴(yán)重的 OOM 問題。所以我打算自己寫一個算了,反正這個挺好玩的)

手指狀態(tài)判斷

首先我們不難發(fā)現(xiàn)其實(shí),其實(shí)對比官方給出的手指圖片以及我前面的那個手指的圖片。我們只需要對比關(guān)節(jié)的坐標(biāo)就可以判斷手有沒有立起來。


相當(dāng)直觀是吧。
但是這里其實(shí)還有個問題,那就是大拇指的問題。
由于大拇指太 短了 所以沒辦法這樣直接判斷,所以我們需要去使用x 的坐標(biāo)來判斷我們的手。但是這樣一來又出現(xiàn)問題了,那就是我們左右手的構(gòu)造有點(diǎn)不一樣。

所以我們有時候得去判斷一下我們那個手是左手還是右手

判斷左右手的方式相當(dāng)簡單,看 1 5 號 X 的相對位置就好了。但是還有個問題那就是手心手背的問題但是其實(shí)手心手背的投影和那個左右手的投影是一樣的。

編碼

import mediapipe as mp import cv2 import mathcap = cv2.VideoCapture(0)mpHand = mp.solutions.hands #mp的手部捕捉 Hand = mpHand.Hands() #找到圖片當(dāng)中的手 mphanddraw = mp.solutions.drawing_utils #繪制工具TipsId = [4,8,12,16,20] #定點(diǎn)的坐標(biāo) while True:flag,img = cap.read()RGBImage = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #把圖片進(jìn)行轉(zhuǎn)換result = Hand.process(RGBImage)if(result.multi_hand_landmarks): #如果有手,那么就會得到手的列表記錄了手的坐標(biāo)hands_data = result.multi_hand_landmarksfor handlist in hands_data:h, w, c = img.shapefingers = []#判斷大拇指的開關(guān)if(handlist.landmark[TipsId[0]-3].x < handlist.landmark[TipsId[0]+1].x):if handlist.landmark[TipsId[0]].x > handlist.landmark[TipsId[0]-1].x:fingers.append(0)else:fingers.append(1)else:if handlist.landmark[TipsId[0]].x < handlist.landmark[TipsId[0] - 1].x:fingers.append(0)else:fingers.append(1)# 判斷其他手指for id in range(1,5):if(handlist.landmark[TipsId[id]].y > handlist.landmark[TipsId[id]-2].y):fingers.append(0)else:fingers.append(1)# 獲得手指個數(shù)totoalfingle = fingers.count(1)cv2.putText(img,str(totoalfingle),(50,50),cv2.FONT_HERSHEY_PLAIN,5,(255,255,255),5)# 這個只是繪制手指關(guān)節(jié)的,可以忽略這段代碼for id,lm in enumerate(handlist.landmark):cx,cy = int(lm.x * w),int(lm.y * h)cv2.circle(img,(cx,cy),15,(255,0,255),cv2.FILLED)cv2.putText(img,str(id),(cx,cy),cv2.FONT_HERSHEY_PLAIN,1,(0,255,255),1)mphanddraw.draw_landmarks(img,handlist,mpHand.HAND_CONNECTIONS,)cv2.imshow("Hands",img)if(cv2.waitKey(1)==ord("q")):breakcap.release() cv2.destroyAllWindows()

效果

升級版(圣誕表白器)

接下來到此我們應(yīng)該就已經(jīng)結(jié)束了,但是突然想起來那啥,我們其實(shí)不僅可以顯示文字在我們的文字,還可以疊加圖片,
SO MAYBE IT CAN WORK SOME INTERESTING THINGS SUCH AS
CONFESS TO SOMEBODY WHICH I CAN NOT USE IT RIGHT NOW!

FUCK,叫我狗糧制造機(jī),謝謝!
效果

代碼

import mediapipe as mp import cv2 import oscap = cv2.VideoCapture(0) cap.set(3,1280) cap.set(4,720) mpHand = mp.solutions.hands #mp的手部捕捉 Hand = mpHand.Hands() #找到圖片當(dāng)中的手 mphanddraw = mp.solutions.drawing_utils #繪制工具MediaPath = "Media" picsdir = os.listdir(MediaPath) pics = [] for pic in picsdir:img = cv2.imread(f"{MediaPath}/{pic}")pics.append(img)TipsId = [4,8,12,16,20] #定點(diǎn)的坐標(biāo) while True:flag,img = cap.read()RGBImage = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #把圖片進(jìn)行轉(zhuǎn)換result = Hand.process(RGBImage)if(result.multi_hand_landmarks): #如果有手,那么就會得到手的列表記錄了手的坐標(biāo)hands_data = result.multi_hand_landmarksfor handlist in hands_data:h, w, c = img.shapefingers = []#判斷大拇指的開關(guān)if(handlist.landmark[TipsId[0]-2].x < handlist.landmark[TipsId[0]+1].x):if handlist.landmark[TipsId[0]].x > handlist.landmark[TipsId[0]-1].x:fingers.append(0)else:fingers.append(1)else:if handlist.landmark[TipsId[0]].x < handlist.landmark[TipsId[0] - 1].x:fingers.append(0)else:fingers.append(1)# 判斷其他手指for id in range(1,5):if(handlist.landmark[TipsId[id]].y > handlist.landmark[TipsId[id]-2].y):fingers.append(0)else:fingers.append(1)# 獲得手指個數(shù),繪制圖片totoalfingle = fingers.count(1)coverpic = pics[totoalfingle-1]hc, wc, cc = coverpic.shapeimg[0:wc,0:hc] = coverpic# 這個只是繪制手指關(guān)節(jié)的,可以忽略這段代碼for id,lm in enumerate(handlist.landmark):cx,cy = int(lm.x * w),int(lm.y * h)cv2.circle(img,(cx,cy),15,(255,0,255),cv2.FILLED)mphanddraw.draw_landmarks(img,handlist,mpHand.HAND_CONNECTIONS,)cv2.imshow("Hands",img)if(cv2.waitKey(1)==ord("q")):breakcap.release() cv2.destroyAllWindows()

圖片自己準(zhǔn)備去(如果有人表白成功了記得踹我)

總結(jié)

最基本的使用其實(shí)就是這樣的,后面你想怎么架構(gòu),就怎么架構(gòu),這個無所謂,按照這個模板來套就可以了。

總結(jié)

以上是生活随笔為你收集整理的圣诞纯情手势告白(Mediapipe基本使用手势识别详解)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。