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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

【机器视觉案例】(10) AI视觉搭积木,手势移动虚拟物体,附python完整代码

發(fā)布時間:2023/11/27 生活经验 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【机器视觉案例】(10) AI视觉搭积木,手势移动虚拟物体,附python完整代码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

各位同學好,今天和大家分享一下如何使用 opencv+mediapipe 完成手勢移動虛擬物體,可自定義各種形狀的物體,通過手勢搭積木。先放張圖看效果。

規(guī)則:食指在某個物體內部,并且中指指尖和食指指尖的距離小于規(guī)定值指尖連線的中點變成綠色,認為是選中物體,物體變成紅色。可以移動物體物體中點隨著食指的位置移動,物體移動到指定位置后,指尖距離大于規(guī)定值,物體停下,變成淡藍色。


1. 安裝工具包

# 安裝工具包
pip install opencv-contrib-python  # 安裝opencv
pip install mediapipe  # 安裝mediapipe
# pip install mediapipe --user  #有user報錯的話試試這個
pip install cvzone  # 安裝cvzone# 導入工具包
import cv2
from cvzone.HandTrackingModule import HandDetector  # 手部追蹤方法
import time
import math
import random

21個手部關鍵點信息如下,本節(jié)我們主要研究食指根部"5"小指根部'17'的坐標信息。


2. 檢測手部關鍵點

(1) cvzone.HandTrackingModule.HandDetector() ?是手部關鍵點檢測方法

參數:

mode: 默認為 False,將輸入圖像視為視頻流。它將嘗試在第一個輸入圖像中檢測手,并在成功檢測后進一步定位手的坐標。在隨后的圖像中,一旦檢測到所有 maxHands 手并定位了相應的手的坐標,它就會跟蹤這些坐標,而不會調用另一個檢測,直到它失去對任何一只手的跟蹤。這減少了延遲,非常適合處理視頻幀。如果設置為 True,則在每個輸入圖像上運行手部檢測,用于處理一批靜態(tài)的、可能不相關的圖像。

maxHands: 最多檢測幾只手,默認為 2

detectionCon: 手部檢測模型的最小置信值(0-1之間),超過閾值則檢測成功。默認為 0.5

minTrackingCon: 坐標跟蹤模型的最小置信值 (0-1之間),用于將手部坐標視為成功跟蹤,不成功則在下一個輸入圖像上自動調用手部檢測。將其設置為更高的值可以提高解決方案的穩(wěn)健性,但代價是更高的延遲。如果 mode 為 True,則忽略這個參數,手部檢測將在每個圖像上運行。默認為 0.5

它的參數和返回值類似于官方函數 mediapipe.solutions.hands.Hands()

(2)cvzone.HandTrackingModule.HandDetector.findHands() ? ?找到手部關鍵點并繪圖

參數:

img: 需要檢測關鍵點的幀圖像,格式為BGR

draw: 是否需要在原圖像上繪制關鍵點及識別框

flipType: 圖像是否需要翻轉,當視頻圖像和我們自己不是鏡像關系時,設為True就可以了

返回值:

hands: 檢測到的手部信息,由0或1或2個字典組成的列表。如果檢測到兩只手就是由兩個字典組成的列表。字典中包含:21個關鍵點坐標,檢測框坐標及寬高,檢測框中心坐標,檢測出是哪一只手。

img: 返回繪制了關鍵點及連線后的圖像

代碼如下

import cv2
from cvzone.HandTrackingModule import HandDetector
import time
import math#(1)捕獲攝像頭
cap = cv2.VideoCapture(0) # 捕獲電腦攝像頭
cap.set(3, 1280)  # 設置顯示窗口寬度1280
cap.set(4, 720)   # 顯示窗口高度720pTime = 0  # 處理第一幀圖像的起始時間#(2)接收手部檢測方法
detector = HandDetector(mode=False, # 靜態(tài)圖模式,若為True,每一幀都會調用檢測方法,導致檢測很慢maxHands=1, # 最多檢測幾只手detectionCon=0.8, # 最小檢測置信度minTrackCon=0.5)  # 最小跟蹤置信度#(3)處理每一幀圖像
while True:# 返回圖像是否讀取成功,以及讀取的幀圖像imgsuccess, img = cap.read()#(4)獲取手部關鍵點信息# 檢測手部信息,返回手部關鍵點信息hands字典,繪制關鍵點和連線后的圖像imghands, img = detector.findHands(img)print(hands)#(5)圖像顯示# 計算FPS值cTime = time.time()  # 處理一幀圖像所需的時間fps = 1/(cTime-pTime) pTime = cTime  # 更新處理下一幀的起始時間# 把fps值顯示在圖像上,img畫板,顯示字符串,顯示的坐標位置,字體,字體大小,顏色,線條粗細cv2.putText(img, str(int(fps)), (50,70), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,0), 3)# 顯示圖像,輸入窗口名及圖像數據# cv2.namedWindow("img", 0)  # 窗口大小可手動調整cv2.imshow('img', img)    if cv2.waitKey(1) & 0xFF==27:  #每幀滯留1毫秒后消失,ESC鍵退出break# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()

打印檢測到的手部關鍵點信息hands列表lmList中存放21個手部關鍵點的像素坐標,bbox中存放檢測框的左上角坐標和框的寬高center存放檢測框的中心坐標type檢測的是左手還是右手

-----------------------------------------------------------------
[{'lmList': [[227, 607], [335, 585], [439, 515], [508, 440], [563, 384], [434, 384], [491, 292], [520, 231], [543, 176], [380, 349], [423, 241], [445, 169], [459, 106], [320, 336], [347, 228], [368, 156], [387, 94], [250, 339], [255, 245], [264, 183], [279, 126]],'bbox': (227, 94, 336, 513), 
'center': (395, 350), 
'type': 'Right'}]
[{'lmList': [[219, 628], [324, 605], [427, 532], [489, 451], [540, 390], [424, 401], [483, 310], [511, 250], [532, 195], [369, 366], [415, 263], [436, 192], [449, 129], [308, 353], [340, 250], [362, 181], [382, 120], [238, 358], [248, 268], [261, 209], [278, 154]], 
'bbox': (219, 120, 321, 508), 
'center': (379, 374), 
'type': 'Right'}]
-----------------------------------------------------------------

圖像顯示結果如下:


3. 繪制虛擬物體

首先,在提取視頻幀圖像之前先設置好虛擬物體的初始位置,將每個矩形的左上坐標點[ptx, pty]保存在一個列表中?ptList.append([ptx, pty]),因為后續(xù)移動物體時,每次移動需要改變單個物體的位置,而其他物體的位置不變,保存在列表中易于后需更改坐標位置。

在讀取視頻幀圖像之后通過for循環(huán)遍歷每個矩形的左上坐標 pt,在圖像上繪制出來。為了顯示的清晰一些,采用半透明矩形透明度 alphaReserve 等于0時全顏色填充,等于1時無填充。

import cv2
import time
from cvzone.HandTrackingModule import HandDetector  # 導入手部檢測模塊#(1)視頻捕獲
cap = cv2.VideoCapture(0)  # 0代表電腦自帶的攝像頭
cap.set(3, 1280)  # 設置圖像顯示窗口的寬
cap.set(4, 720)   # 設置圖像顯示窗口的高pTime = 0  # 處理一幀圖像的初始時間color = (255,255,0)  # 可移動物體的默認顏色w, h = 150, 150   # 矩形寬和高#(2)在頻幕上構造物體的函數
def creObj(img, color, ptx, pty, w, h):# 透明矩形參數設置alphaReserve = 0.6  # 透明度BChannel, GChannel, RChannel = color  # 設置矩形顏色 yMin, yMax = pty, pty+h  # 矩形框的y坐標范圍xMin, xMax = ptx, ptx+w  # 矩形框的y坐標范圍# 繪制透明矩形img[yMin:yMax, xMin:xMax, 0] = img[yMin:yMax, xMin:xMax, 0] * alphaReserve + BChannel * (1 - alphaReserve)img[yMin:yMax, xMin:xMax, 1] = img[yMin:yMax, xMin:xMax, 1] * alphaReserve + GChannel * (1 - alphaReserve)img[yMin:yMax, xMin:xMax, 2] = img[yMin:yMax, xMin:xMax, 2] * alphaReserve + RChannel * (1 - alphaReserve)# 美化邊界框line = 35 # 邊緣線段長度cv2.rectangle(img, (ptx,pty), (ptx+w,pty+h), (255,0,255), 2) # 邊框cv2.line(img, (ptx,pty), (ptx,pty+line), (0,255,255), 5)  # 左上角cv2.line(img, (ptx,pty), (ptx+line,pty), (0,255,255), 5) cv2.line(img, (ptx+w,pty), (ptx+w-line,pty), (0,255,255), 5)  # 右上角cv2.line(img, (ptx+w,pty), (ptx+w,pty+line), (0,255,255), 5)   cv2.line(img, (ptx,pty+h), (ptx+line,pty+h), (0,255,255), 5)  # 左下角cv2.line(img, (ptx,pty+h), (ptx,pty+h-line), (0,255,255), 5) cv2.line(img, (ptx+w,pty+h), (ptx+w-line,pty+h), (0,255,255), 5)  # 右下角cv2.line(img, (ptx+w,pty+h), (ptx+w,pty+h-line), (0,255,255), 5) # 返回繪制后的圖像return img#(3)接收手部檢測方法
detector = HandDetector(mode=False,  # 視頻流maxHands=1,  # 最多檢測一只手detectionCon=0.8,  # 手部檢測的最小置信度minTrackCon=0.5)   # 手部跟蹤的最小置信度#(4)在屏幕上創(chuàng)建初始矩形
ptList = []  # 存放每個矩形的左上角坐標# 通過循環(huán)創(chuàng)建9個矩形,初始排列方式為3行3列
for i in range(3):  # 3行for j in range(3):  # 3列# 指定每個矩形的左上角坐標ptx = 200 * j + 100  # x坐標,起始位置為x=100,水平方向兩個矩形間隔200個像素pty = 200 * i + 100  # y坐標,起始位置為y=100,每次換行下移200個像素# 將每個矩形的左上角坐標保存起來ptList.append([ptx, pty])#(5)處理每一幀視頻圖像
while True:# 返回是否讀取成功和讀取的圖像success, img = cap.read()# 圖像翻轉,呈鏡像關系img = cv2.flip(img, flipCode=1)  # 1代表水平翻轉,0代表豎直翻轉#(6)手部關鍵點檢測# 返回檢測到的手部關鍵點信息,以及繪制關鍵點后的圖像hands, img = detector.findHands(img, flipType=False)  # 由于上面翻轉過圖像了,這里就設置flipType不翻轉   #(7)繪制可移動物體for pt in ptList:  # 遍歷所有矩形的左上角        img = creObj(img, color, pt[0], pt[1], w, h)#(8)顯示圖像# 記錄執(zhí)行時間      cTime = time.time()      # 計算fpsfps = 1/(cTime-pTime)# 重置起始時間pTime = cTime# 把fps顯示在窗口上;img畫板;取整的fps值;顯示位置的坐標;設置字體;字體比例;顏色;厚度cv2.putText(img, str(int(fps)), (10,70), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,0), 3)# 顯示圖像cv2.imshow('image', img)  #窗口名,圖像變量if cv2.waitKey(1) & 0xFF==27:  #每幀滯留1毫秒后消失break# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()

圖像顯示結果如下:


4. 移動物體

從下面代碼的第(7)步開始,計算食指指尖 lmList[8] 中指指尖?lmList[12] 之間的距離,并繪制指尖連線cv2.line。使用計算平方和再開根的方法math.sqrt(),計算指尖距離。如果像素距離小于80就認為是選擇該物體,指尖連線中點變成綠色

第(8)步確定食指在哪個矩形的內部。遍歷所有的矩形的左上角坐標ptList,如果食指關鍵點坐標在某個矩形框內部,就記錄下該矩形所在列表中的索引changed = index,接下來改變這個矩形的坐標位置。

找到了食指在哪個矩形內之后,如果指尖距離小于規(guī)定值,代表移動該物體,讓該矩形的中點落在食指關鍵點的位置?cx, cy = finTip,那么矩形就可以跟著食指一起移動了,并且,更改每一幀的矩形的左上坐標 ptList[index] = pt,時刻改變矩形在屏幕上的位置。

有時食指關鍵點會在幾個矩形的內部,這樣的話,這幾個矩形的中點都變成了食指指尖關鍵點,使這幾個矩形都重合在一起,為了避免這種情況,當我們選擇了一個矩形時,就?break?斷開當前循壞,不再判斷食指在哪個物體內部,這樣就可以每次只移動一個物體。

import cv2
import time
import math
from cvzone.HandTrackingModule import HandDetector  # 導入手部檢測模塊#(1)視頻捕獲
cap = cv2.VideoCapture(0)  # 0代表電腦自帶的攝像頭
cap.set(3, 1280)  # 設置圖像顯示窗口的寬
cap.set(4, 720)   # 設置圖像顯示窗口的高pTime = 0  # 處理一幀圖像的初始時間changed = None # 初始狀態(tài)不需要改變矩形顏色color = (255,255,0)  # 可移動物體的默認顏色medColor = (255,0,0)  # 中指和食指指尖中點的初始顏色w, h = 150, 150   # 矩形寬和高#(2)在頻幕上構造物體的函數
def creObj(img, color, ptx, pty, w, h):# 透明矩形參數設置alphaReserve = 0.6  # 透明度BChannel, GChannel, RChannel = color  # 設置矩形顏色 yMin, yMax = pty, pty+h  # 矩形框的y坐標范圍xMin, xMax = ptx, ptx+w  # 矩形框的y坐標范圍# 繪制透明矩形img[yMin:yMax, xMin:xMax, 0] = img[yMin:yMax, xMin:xMax, 0] * alphaReserve + BChannel * (1 - alphaReserve)img[yMin:yMax, xMin:xMax, 1] = img[yMin:yMax, xMin:xMax, 1] * alphaReserve + GChannel * (1 - alphaReserve)img[yMin:yMax, xMin:xMax, 2] = img[yMin:yMax, xMin:xMax, 2] * alphaReserve + RChannel * (1 - alphaReserve)# 美化邊界框line = 35 # 邊緣線段長度cv2.rectangle(img, (ptx,pty), (ptx+w,pty+h), (255,0,255), 2) # 邊框cv2.line(img, (ptx,pty), (ptx,pty+line), (0,255,255), 5)  # 左上角cv2.line(img, (ptx,pty), (ptx+line,pty), (0,255,255), 5) cv2.line(img, (ptx+w,pty), (ptx+w-line,pty), (0,255,255), 5)  # 右上角cv2.line(img, (ptx+w,pty), (ptx+w,pty+line), (0,255,255), 5)   cv2.line(img, (ptx,pty+h), (ptx+line,pty+h), (0,255,255), 5)  # 左下角cv2.line(img, (ptx,pty+h), (ptx,pty+h-line), (0,255,255), 5) cv2.line(img, (ptx+w,pty+h), (ptx+w-line,pty+h), (0,255,255), 5)  # 右下角cv2.line(img, (ptx+w,pty+h), (ptx+w,pty+h-line), (0,255,255), 5) # 返回繪制后的圖像return img#(3)接收手部檢測方法
detector = HandDetector(mode=False,  # 視頻流maxHands=1,  # 最多檢測一只手detectionCon=0.8,  # 手部檢測的最小置信度minTrackCon=0.5)   # 手部跟蹤的最小置信度#(4)在屏幕上創(chuàng)建初始矩形
ptList = []  # 存放每個矩形的左上角坐標# 通過循環(huán)創(chuàng)建9個矩形,初始排列方式為3行3列
for i in range(3):  # 3行for j in range(3):  # 3列# 指定每個矩形的左上角坐標ptx = 200 * j + 100  # x坐標,起始位置為x=100,水平方向兩個矩形間隔200個像素pty = 200 * i + 100  # y坐標,起始位置為y=100,每次換行下移200個像素# 將每個矩形的左上角坐標保存起來ptList.append([ptx, pty])#(4)處理每一幀視頻圖像
while True:# 返回是否讀取成功和讀取的圖像success, img = cap.read()# 圖像翻轉,呈鏡像關系img = cv2.flip(img, flipCode=1)  # 1代表水平翻轉,0代表豎直翻轉#(5)手部關鍵點檢測# 返回檢測到的手部關鍵點信息,以及繪制關鍵點后的圖像hands, img = detector.findHands(img, flipType=False)  # 由于上面翻轉過圖像了,這里就設置flipType不翻轉   #(6)繪制可移動物體for index, pt in enumerate(ptList):  # 遍歷所有矩形的左上角# 如果索引等于需要改變的矩形索引,就改變該矩形的顏色,否則就不變if index == changed:color = (0,0,255)else:color = (255,255,0)img = creObj(img, color, pt[0], pt[1], w, h)#(7)計算食指和中指間的距離    if hands:  # 如果檢測到手部信息才接下去執(zhí)行# 將該只手的21個關鍵點坐標提取出來,hands是字典存放手信息lmList = hands[0]['lmList']# 獲取食指指尖的坐標(像素坐標)finTip = lmList[8]  # 存放x和y坐標# 獲取中指指尖坐標checkTip = lmList[12]# 繪制食指和中指指尖的連線cv2.line(img, finTip, checkTip, (255,0,0), 9)cv2.circle(img, finTip, 15, (255,0,0), cv2.FILLED) # 以食指尖為圓心畫圓cv2.circle(img, checkTip, 15, (255,0,0), cv2.FILLED) # 以中指尖為圓心畫圓# 以兩指尖的中點為圓心畫圓,如果距離小于規(guī)定值,顏色改變cv2.circle(img, ((finTip[0]+checkTip[0])//2, (finTip[1]+checkTip[1])//2), 15, medColor, cv2.FILLED) # 計算食指和中指間的距離distance = math.sqrt((finTip[0]-checkTip[0])**2 + (finTip[1]-checkTip[1])**2)# 如果距離小于80認為是選擇物體,指尖指尖中點的顏色改變if distance < 80:medColor = (0,255,0)else:  # 如果大于80,就重置指尖中點顏色medColor = (255,0,0)#(8)判斷食指指尖在哪個矩形的內部for index, pt in enumerate(ptList):  # 遍歷所有矩形的左上角坐標ptx, pty = pt  # 提取每個矩形左上角的x和y坐標     # finTip保存食指指尖的x和y坐標if ptx<=finTip[0]<=ptx+w and pty<=finTip[1]<=pty+h:  # 如果食指指尖在某個矩形框內部# 記錄下該矩形的索引changed = index# 如果食指和中指間的距離小于80,那就認為是移動物體if distance < 80:# 讓物體中心點位于指尖位置cx, cy = finTip# 改變左上角坐標pt = [cx-w//2, cy-h//2]# 改變列表中的該索引對應的左上角坐標ptList[index] = pt# 找到了就退出循環(huán),代表一次只移動一個矩形break# 如果物體移動到了指定位置,那就松手else:  # 重置矩形的顏色color = (255,255,0)  changed = None  #(7)顯示圖像# 記錄執(zhí)行時間      cTime = time.time()      # 計算fpsfps = 1/(cTime-pTime)# 重置起始時間pTime = cTime# 把fps顯示在窗口上;img畫板;取整的fps值;顯示位置的坐標;設置字體;字體比例;顏色;厚度cv2.putText(img, str(int(fps)), (10,70), cv2.FONT_HERSHEY_PLAIN, 3, (255,0,0), 3)# 顯示圖像cv2.imshow('image', img)  #窗口名,圖像變量if cv2.waitKey(1) & 0xFF==27:  #每幀滯留1毫秒后消失break# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()

沒選擇物體時:

移動物體時:

總結

以上是生活随笔為你收集整理的【机器视觉案例】(10) AI视觉搭积木,手势移动虚拟物体,附python完整代码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。