若该文为原创文章,转载请注明原文出处。
一、项目介绍
随着人工智能时代的到来,许多技术得到了空前的发展,让人们更加认识到了线上虚拟技术的强大。
通过mediapipe识别手的关键点,检测中指,实现隔空画画的操作。
通过两个手指的间距,实现点击选择颜色或橡皮檫。
二、运行
1、环境
环境搭建使用的是上一篇搭建的环境mediapipe_env
打开终端,输入下面命令,激活环境:
conda activate mediapipe
这次使用的是pycharm,软件自行安装,安装社区版本。
建立一个目录,把项目导入到pycharm里,然后设置环境
点击Add New Interpreter
选择环境的python.exe
终端选择,一定要powershell.exe
设置好可以在pycharm里的终端操作
2、运行
导入代码,右键运行
3 、结果
三、代码
这里不介绍原理及过程,想学习的人不会因为这些而去不学习,所以需要自行了解,项目难度不大,代码也相对的不复杂。直接上源码
一共两个文件,AiVirtualPainter.py和HandTrackingModule.py
AiVirtualPainter.py实现的是绘画功能,HandTrackingModule.py实现的是手关键点识别。
AiVirtualPainter.py
import cv2
import HandTrackingModule as htm
import os
import numpy as npfolderPath = "PainterImg/"
mylist = os.listdir(folderPath)
overlayList = []
for imPath in mylist:image = cv2.imread(f'{folderPath}/{imPath}')overlayList.append(image)
header = overlayList[0]
color = [255, 0, 0]
brushThickness = 15
eraserThickness = 40cap = cv2.VideoCapture(0) # 若使用笔记本自带摄像头则编号为0 若使用外接摄像头 则更改为1或其他编号
cap.set(3, 1280)
cap.set(4, 720)
# cap.set(3, 800)
# cap.set(4, 500)
detector = htm.handDetector()
xp, yp = 0, 0
imgCanvas = np.zeros((720, 1280, 3), np.uint8) # 新建一个画板
# imgCanvas = np.zeros((500, 800, 3), np.uint8) # 新建一个画板while True:# 1.import imagesuccess, img = cap.read()img = cv2.flip(img, 1) # 翻转# 2.find hand landmarksimg = detector.findHands(img)lmList = detector.findPosition(img, draw=True)if len(lmList) != 0:x1, y1 = lmList[8][1:]x2, y2 = lmList[12][1:]# 3. Check which fingers are upfingers = detector.fingersUp()# 4. If Selection Mode – Two finger are upif fingers[1] and fingers[2]:if y1 < 153:if 0 < x1 < 320:header = overlayList[0]color = [50, 128, 250]elif 320 < x1 < 640:header = overlayList[1]color = [0, 0, 255]elif 640 < x1 < 960:header = overlayList[2]color = [0, 255, 0]elif 960 < x1 < 1280:header = overlayList[3]color = [0, 0, 0]img[0:1280][0:153] = header# 5. If Drawing Mode – Index finger is upif fingers[1] and fingers[2] == False:cv2.circle(img, (x1, y1), 15, color, cv2.FILLED)print("Drawing Mode")if xp == 0 and yp == 0:xp, yp = x1, y1if color == [0, 0, 0]:cv2.line(img, (xp, yp), (x1, y1), color, eraserThickness) # ??cv2.line(imgCanvas, (xp, yp), (x1, y1), color, eraserThickness)else:cv2.line(img, (xp, yp), (x1, y1), color, brushThickness) # ??cv2.line(imgCanvas, (xp, yp), (x1, y1), color, brushThickness)xp, yp = x1, y1# Clear Canvas when all fingers are up# if all (x >= 1 for x in fingers):# imgCanvas = np.zeros((720, 1280, 3), np.uint8)# 实时显示画笔轨迹的实现imgGray = cv2.cvtColor(imgCanvas, cv2.COLOR_BGR2GRAY)_, imgInv = cv2.threshold(imgGray, 50, 255, cv2.THRESH_BINARY_INV)imgInv = cv2.cvtColor(imgInv, cv2.COLOR_GRAY2BGR)img = cv2.bitwise_and(img, imgInv)img = cv2.bitwise_or(img, imgCanvas)img[0:1280][0:153] = headercv2.imshow("Image", img)# cv2.imshow("Canvas", imgCanvas)# cv2.imshow("Inv", imgInv)cv2.waitKey(1)
HandTrackingModule.py
import cv2
import mediapipe as mp
import time
import mathclass handDetector():def __init__(self, mode=False, maxHands=2, detectionCon=0.8, trackCon=0.8):self.mode = modeself.maxHands = maxHandsself.detectionCon = detectionConself.trackCon = trackConself.mpHands = mp.solutions.handsself.hands = self.mpHands.Hands(self.mode, self.maxHands, self.detectionCon, self.trackCon)self.mpDraw = mp.solutions.drawing_utilsself.tipIds = [4, 8, 12, 16, 20]def findHands(self, img, draw=True):imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)self.results = self.hands.process(imgRGB)print(self.results.multi_handedness) # 获取检测结果中的左右手标签并打印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, draw=True):self.lmList = []if self.results.multi_hand_landmarks:for handLms in self.results.multi_hand_landmarks:for id, lm in enumerate(handLms.landmark):h, w, c = img.shapecx, cy = int(lm.x * w), int(lm.y * h)# print(id, cx, cy)self.lmList.append([id, cx, cy])if draw:cv2.circle(img, (cx, cy), 12, (255, 0, 255), cv2.FILLED)return self.lmListdef fingersUp(self):fingers = []# 大拇指if self.lmList[self.tipIds[0]][1] > self.lmList[self.tipIds[0] - 1][1]:fingers.append(1)else:fingers.append(0)# 其余手指for id in range(1, 5):if self.lmList[self.tipIds[id]][2] < self.lmList[self.tipIds[id] - 2][2]:fingers.append(1)else:fingers.append(0)# totalFingers = fingers.count(1)return fingersdef findDistance(self, p1, p2, img, draw=True, r=15, t=3):x1, y1 = self.lmList[p1][1:]x2, y2 = self.lmList[p2][1:]cx, cy = (x1 + x2) // 2, (y1 + y2) // 2if draw:cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), t)cv2.circle(img, (x1, y1), r, (255, 0, 255), cv2.FILLED)cv2.circle(img, (x2, y2), r, (255, 0, 255), cv2.FILLED)cv2.circle(img, (cx, cy), r, (0, 0, 255), cv2.FILLED)length = math.hypot(x2 - x1, y2 - y1)return length, img, [x1, y1, x2, y2, cx, cy]def main():pTime = 0cTime = 0cap = cv2.VideoCapture(0)detector = handDetector()while True:success, img = cap.read()img = detector.findHands(img) # 检测手势并画上骨架信息lmList = detector.findPosition(img) # 获取得到坐标点的列表if len(lmList) != 0:print(lmList[4])cTime = time.time()fps = 1 / (cTime - pTime)pTime = cTimecv2.putText(img, 'fps:' + str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3, (255, 0, 255), 3)cv2.imshow('Image', img)cv2.waitKey(1)if __name__ == "__main__":main()
源码网上有很多,有不懂可以联系博主,一起相互交流。
学习永无止境,AI是未来的发展方向,每天进步一点点,实现终身学习。
如有侵权,或需要完整代码,请及时联系博主。