文章目錄
- 前言
- 需求效果
- 專案結構
- 媒體資源
- HandDetecter 工具
- 手勢尋找
- 檢查手指起立
- 檢查某根手指起立
- Window
- 顯示視窗
- UI媒體資源
- Controller
- 手勢規則
- 繪圖
- 繪圖畫板
- 完整代碼
- ConterCenter.py
- HandDetecter.py
- SourseDetecter.py
- Window.py
- 總結
前言
在熬夜搞完計組實驗報告后,我Huterox又又回來了,那么今天其實是對上一篇博客
圣誕純情手勢告白(Mediapipe基本使用&手勢識別詳解)再次進階(不會真的有人以為這篇博客是寫來向妹紙表白的吧,開玩笑里面都是干貨呀!)那么同樣的里面有很多原理在今天的博文中都是在那篇博客有寫到的,怎么玩的都說的很清楚了,那么現在我要做的其實就只是對我上次寫的最原始的代碼進行封裝就好了,然后加一點功能,
需求效果
這個直接看下面的效果就知道了

專案結構

媒體資源
這里我要說一下的是那個媒體資源,由于這個Demo比較簡單我就沒上傳 github ,也不想上傳百度云盤了,那就這樣,就是這張圖片

你自己去截個圖,命名規則就是從上到下 依次為 0,1,2,3,4.jpg 注意這里的格式為jpg
然后 尺寸是 1280 x 720 這個自己注意轉換一下

HandDetecter 工具
手勢尋找
接下來我就慢慢來說說這個每一個工具干嘛的,有哪些玩意,
首先手勢尋找那就是 呼叫算子嘛

檢查手指起立
接下來由于我們需要跟蹤我們的食指,和中指,所以我們需要得到那些豎起來的 食指,那么這個檢查的話也很簡單,我們在開頭說的那篇博客里面已經說了原理,這里我就不復述了,這里說明一下的是,我們這個回傳的引數,

他的邏輯是,首先是檢查你有木有手掌出現在攝像頭上面(被檢測出來),如果有,那么就會依次從大拇指到小拇指去檢查手指有沒有立起來,然后直接把當前的手指頭的坐標寫進串列里面,
這里注意的就是我們只允許一只手在一個畫面畫圖,這里的話你可以看到直接 return 了,所以每次拿到的就是最新出現在畫面的手,
flag 是有木有立起來
x 是 x坐標
y 是 y坐標
檢查某根手指起立

這個就是拿到我們CheckHandUp() 回傳的串列,由于我們是按照順序來檢查手指的起立情況的,所以我們直接根據索引就可以知道每個拇指的起立情況,并且我們是的順序不管是左右手都是一樣的,
Window
顯示視窗
這個就是顯示我們整個的視窗,也就是這個界面:

這里就是幾個方法

下面是呼叫

UI媒體資源
這個就是先前那個說的UI資源嘛,

Windows PrintUI()這個方法呼叫了嘛,
Controller
手勢規則
這個就是規定我們的手勢怎么放嘛,首先
食指和中指一起是模式現在,不畫畫,只有一個食指伸出來那就去畫畫

核心邏輯就是判斷那個手指的位置嘛,看看有沒有伸出來,然后手指的位置大概在哪,
繪圖


兩個方法,一個是在畫板把圖片畫出來,一個是在我們的圖片中顯示,
繪圖畫板
這個是比較重要的邏輯部分,首先由于我們要記錄上一次的繪制圖形,所以我們不可能直接在我們攝像頭回傳的圖片上面去保存,因為那個背景是實時重繪的,保存不了,所以我們需要一個圖片是靜態的,

然后合并圖片
這個方法是在Window類里面的
合并的話也是為了做了一些特殊處理,保證合并后圖片不會太奇怪,

完整代碼
基本的專案解釋部分就OK了,那么接下來依次上代碼
ConterCenter.py
from Utils.HandDetecter import HandDetected
from Utils.SourseDetecter import SourseDetecter
from Utils.Window import Window
import numpy
class Controller(object):
def __init__(self):
self.HandDetected = HandDetected()
self.window_w = 1300
self.window_h = 720
self.Window = Window(width=self.window_w,height=self.window_h)
self.SourseDetecter = SourseDetecter()
self.ID = 0
self.PenColor = (0, 0, 255) #默認顏色
self.PenPostion = (0,0)
self.Canvas = numpy.zeros((self.window_h,self.window_w,3),numpy.uint8)
self.PenSize = 15
def ControllerFingerTrack(self,result,img):
# 我們負責跟蹤食指和中指
postions = self.HandDetected.CheckHandUp(result)
if(postions):
indexFinger = postions[self.HandDetected.INDEXFINGER]
middleFinger = postions[self.HandDetected.MIDDLEFINGER]
if(indexFinger.get('flag') and middleFinger.get('flag') ):
#食指,中指立起來了開始檢測是否選擇功能
indexFinger_x ,indexFinger_y =int( indexFinger.get("x")*self.window_w),int (indexFinger.get("y")*self.window_h )
middleFinger_x,middleFinger_y = int( middleFinger.get("x")*self.window_w),int(middleFinger.get("y")*self.window_h )
center_x = int((indexFinger_x+middleFinger_x)/2)
center_y = int((indexFinger_y+middleFinger_y)/2)
self.Window.cv.circle(img, (center_x,center_y), 35, self.PenColor, self.Window.cv.FILLED)
#開始具體的功能模塊
if(0<=center_y and center_y<=125):
if(center_x>=125 and center_x<=260):
self.ID = 1
self.PenSize = 15
self.PenColor=(0,0,255)
if(center_x>=365 and center_x<=505):
self.ID = 2
self.PenSize = 15
self.PenColor = (255,0,0)
if(center_x>=615 and center_x<=755):
self.ID = 3
self.PenSize=15
self.PenColor=(0,255,0)
if(center_x>=1065 and center_x<=1205):
self.ID = 4
self.PenSize= 30
self.PenColor=(0,0,0)
return img
def DrawPenController(self,result,img):
# 開始繪制圖形
postions = self.HandDetected.CheckHandUp(result)
h, w, c = img.shape
if (postions):
indexFinger = postions[self.HandDetected.INDEXFINGER]
middleFinger = postions[self.HandDetected.MIDDLEFINGER]
if (indexFinger.get('flag') and not middleFinger.get('flag')):
indexFinger_x, indexFinger_y = int(indexFinger.get("x") * self.window_w), int(
indexFinger.get("y") * self.window_h)
self.Window.cv.circle(img, (indexFinger_x, indexFinger_y), self.PenSize, self.PenColor, self.Window.cv.FILLED)
if (self.PenPostion == (0,0)):
self.PenPostion = (indexFinger_x,indexFinger_y)
self.Window.cv.line(self.Canvas,self.PenPostion,(indexFinger_x,indexFinger_y),self.PenColor,self.PenSize)
self.PenPostion = (indexFinger_x,indexFinger_y)
else:
self.PenPostion = (0, 0)
return img
def ShowDrawWay(self,img):
h, w, c = img.shape
self.Canvas = self.Window.cv.resize(self.Canvas, (w, h))
img = self.Window.addImg(img, self.Canvas)
# img = self.Window.cv.addWeighted(img,0.5,self.Canvas,0.5,0)
return img
def Main(self):
while True:
flag,img = self.Window.cap.read()
img = self.Window.cv.flip(img, 1)
result,img = self.HandDetected.findHands(img,True)
img = self.ControllerFingerTrack(result,img)
img = self.DrawPenController(result,img)
img = self.ShowDrawWay(img)
img = self.Window.PrintUi(img, self.ID)
self.Window.show("Canvas",img)
if(self.Window.cv.waitKey(1)==ord("q")):
return
if __name__=="__main__":
Controller = Controller()
Controller.Main()
HandDetecter.py
import mediapipe as mp
import cv2
import os
from Utils.SourseDetecter import SourseDetecter
class HandDetected(object):
def __init__(self):
self.mpHand = mp.solutions.hands
self.Hand = self.mpHand.Hands()
self.mphanddraw = mp.solutions.drawing_utils
self.THUMB = 0
self.INDEXFINGER=1
self.MIDDLEFINGER=2
self.RIGHTFINGER=3
self.PINKY=4
def findHands(self,img,flag=False,name="Hands"):
#你只需要將從攝像頭獲取的圖片傳入這個函式即可
rgbimg = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
result = self.Hand.process(rgbimg)
if(flag):
self.MarkHands(result,img,name)
return result,img
def GetHandPoints(self,result):
pass
def FindUPFings(self,result,ID):
#改方法適合一次性查看一個手指的狀況,不適合同時跟蹤多個手指
if(result.multi_hand_landmarks):
fingers = self.CheckHandUp(result)
if(fingers[ID].get('flag')):
return fingers[ID]
def CheckHandUp(self,result):
TipsId = [4, 8, 12, 16, 20] # 定點的坐標
hands_data = result.multi_hand_landmarks
if (hands_data):
for handlist in hands_data:
fingers = []
#判斷大拇指的開關
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:
data = {"flag":0,"x":int(handlist.landmark[TipsId[0]].x),"y":handlist.landmark[TipsId[0]].y}
fingers.append(data)
else:
data = {"flag": 1, "x": int(handlist.landmark[TipsId[0]].x), "y": handlist.landmark[TipsId[0]].y}
fingers.append(data)
else:
if handlist.landmark[TipsId[0]].x < handlist.landmark[TipsId[0] - 1].x:
data = {"flag": 0, "x": handlist.landmark[TipsId[0]].x, "y": handlist.landmark[TipsId[0]].y}
fingers.append(data)
else:
data = {"flag": 1, "x": handlist.landmark[TipsId[0]].x, "y": handlist.landmark[TipsId[0]].y}
fingers.append(data)
# 判斷其他手指
for id in range(1,5):
if(handlist.landmark[TipsId[id]].y > handlist.landmark[TipsId[id]-2].y):
data = {"flag": 0, "x": handlist.landmark[TipsId[id]].x, "y": handlist.landmark[TipsId[id]].y}
fingers.append(data)
else:
data = {"flag": 1, "x": handlist.landmark[TipsId[id]].x,
"y": handlist.landmark[TipsId[id]].y}
fingers.append(data)
return fingers
else:
return None
def MarkHands(self,result,img,name):
#是否對檢測到的手部進行標注,之后回傳標注好的圖片
hands_data = result.multi_hand_landmarks
if (hands_data):
for handlm in hands_data:
h, w, c = img.shape
self.mphanddraw.draw_landmarks(img, handlm, self.mpHand.HAND_CONNECTIONS, )
def __str__(self):
print("HandDetected for Identify Hands")
if __name__=="__main__":
pass
SourseDetecter.py
import os
import cv2
import time
class SourseDetecter(object):
def __init__(self):
pass
@staticmethod
def GetUiImgs(path):
if(os.path.exists(path)):
imgs = os.listdir(path)
imgFiles = []
for img in imgs:
imgFile = cv2.imread(f"{path}/{img}")
imgFiles.append(imgFile)
return imgFiles
else:
raise FileNotFoundError("Not is File")
if __name__=="__main__":
root_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))+"\\"
img2 = SourseDetecter.GetUiImgs(root_path+"Media")[0]
Window.py
import cv2
import os
from Utils.SourseDetecter import SourseDetecter
class Window(object):
def __init__(self,sourse=0,width = 640,height = 480):
self.cv = cv2
self.cap = self.cv.VideoCapture(sourse)
self.cap.set(3,width)
self.cap.set(4,height)
self.SourseUi=[]
root_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) + "\\"
try:
self.SourseUi = SourseDetecter.GetUiImgs(root_path+"Media")
except Exception as e:
self.SourseUi = []
print(e)
def PrintUi(self,img,ID):
if (self.SourseUi):
hui, wui, cui = self.SourseUi[ID].shape
img[0:hui,0:wui] = self.SourseUi[ID]
return img
else:
return None
def show(self,name,img):
self.cv.imshow(name,img)
def addImg(self,img1,img2):
#合并兩個圖片,img2為需要被合并的圖片
imgGray = self.cv.cvtColor(img2,self.cv.COLOR_BGR2GRAY) #對畫布圖片進行灰度處理,降低合并后的差異
_,imgInv = self.cv.threshold(imgGray,50,255,self.cv.THRESH_BINARY_INV)
imgInv = self.cv.cvtColor(imgInv,self.cv.COLOR_GRAY2BGR) # 處理后重新轉換會彩色圖片
img1 = self.cv.bitwise_and(img1,imgInv)
img1 = self.cv.bitwise_or(img1,img2)
return img1
def release(self):
self.cap.release()
self.cv.destroyAllWindows()
def __str__(self):
print("For Show img")
總結
提前祝大家新年快樂~
此外:
收藏>點贊 ?收費 :免費
這是我最后的倔強!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/397510.html
標籤:其他
上一篇:JavaCV音視頻開發寶典:JavaCV混合螢屏錄屏和系統聲音錄制mp4視頻檔案(windows桌面螢屏和系統聲音混合錄制)
下一篇:集成學習讓你的模型更快更準
