1.安装mediapipe库和cv2库
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install Mediapipe==0.8.9.1 -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
这里我主要还是弄明白了这个pycharm编辑器和项目之间的关系,我在这里浪费了一下午的时间去配置环境
1.pycharm里面的环境存在于anaconda里面,你的每个项目都可以创建对应的解释器,但是其实这个解释器就是你安装的python的版本
所以每次使用的解释器都来自这里【anaconda环境下】
2.当出现无法安装一些库的时候,可以选择去windows终端去建立,当然以及在pycharm里面不可以创建的python版本也可以在终端创建。
3.当一些库无法找到的时候,可以去对应的官网下载对应python版本的库,然后在windows终端pip直接安装,但是前提记得把whl文件放入到对应的解释器的Scripts里面再去安装。当无法找到你的whl文件的时候,可以尝试把文件的完整地址带上。
代码如下及理解:
while True:
count = 0
success, img = cap.read()#BGR存储格式
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)#转为RGB存储
results = hands.process(imgRGB)#处理返回的手的标志点以及处理
if results.multi_hand_landmarks:#返回none或手的标志点坐标
for handLms in results.multi_hand_landmarks:
for id, lm in enumerate(handLms.landmark):
#id是索引,总共21个,lm指的是每个点对应的x,y的坐标,在0-1之间,因为是相对于窗口来计算的
h, w, c = img.shape
#h 表示图像的高度(height),即图像在垂直方向上的像素数;
#w 表示图像的宽度(width),即图像在水平方向上的像素数;
#c 表示图像的通道数(channels),即图像的颜色通道数量,
#如灰度图像的通道数为1,彩色图像的通道数为3。
cx, cy = int(lm.x*w), int(lm.y*h)
#转换为实际的像素坐标
xs[id] = cx
ys[id] = cy
#写入到每个id的数组里面
cv2.circle(img, (cx, cy), 5, (0, 255, 105), cv2.FILLED)
#将每个点以坐标为圆心,放大,以及更改颜色
cv2.putText(img, str(int(id)), (cx, cy), cv2.FONT_HERSHEY_PLAIN, 2,
(200, 20, 50), 3)
#周围显示的数字的颜色,以及大小
K_count()
mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS)
#计算当前图像的帧率
cTime = time.time()
fps = 1 / (cTime - pTime)
pTime = cTime
cv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3,
(255, 0, 255), 1)
cv2.imshow("Image", img)
k = cv2.waitKey(1)
if k == 27:
cap.release()
cv2.destroyAllWindows()
exit()
核心代码分析:
def K_count():
k=5 #因为0-4s是大拇指的id
i=0
while(k<20):
#计算其他四个手指每个的中心坐标
aveX1 = (xs[k] + xs[k+1] + xs[k+2] + xs[k+3]) / 4
aveY1 = (ys[k] + ys[k+1] + ys[k+2] + ys[k+3]) / 4
#使用最小二乘法求得每个手指的斜率,判断了坟墓为0的情况
t = (xs[k] * xs[k] + xs[k+1] * xs[k+1] + xs[k+2] * xs[k+2] + xs[k+3] * xs[k+3] - 4 * aveX1 * aveX1)
if(abs (t - 0) < 0.000001):
t += 0.000001
if aveX1 != 0 and aveY1 != 0:
k1 = (xs[k] * ys[k] + xs[k+1] * ys[k+1] + xs[k+2] * ys[k+2] + xs[k+3] * ys[k+3] - 4 * aveX1 * aveY1) /t
else:
k1 = 0
ks[i] = k1
i += 1
k += 4
#计算每个手指相对于中心平均值的偏离程度
avek = sum(ks)/4
ks0 = abs(ks[0] - avek)
ks1 = abs(ks[1] - avek)
ks2 = abs(ks[2] - avek)
ks3 = abs(ks[3] - avek)
print(ks[1])
#根据id4和id8的距离来决定要不要停止
dis = point_distance(xs[4], ys[4], xs[8], ys[8])
if (ks0+ks1+ks2+ks3) < 3.5 and dis > 100 and abs(ks[1]) > 3:
print("前进")
elif (ks0+ks1+ks2+ks3) < 3.5 and dis > 100 and -1 < ks[1] < 0:
print("左转")
elif (ks0 + ks1 + ks2 + ks3) < 3.5 and dis > 100 and 0 < ks[1] < 1:
print("右转")
elif dis < 100:
print("停止")
对于接下来该怎么的判断,可以根据自己的要求进行改变。根据斜率,每个点的距离,以及到摄像头的距离,都可以灵活判断。核心还是在于mediapipe库的调用。
整体代码:
# -*-coding:utf-8-*-
import cv2
import mediapipe as mp
import time
import math
cap = cv2.VideoCapture(0)
#该函数的参数
#static_image_mode,max_num_hands,min_detection_confidence,min_tracking_confidence
mpHands = mp.solutions.hands
hands = mpHands.Hands()
mpDraw = mp.solutions.drawing_utils
pTime = 0#开始时间初始化
cTime = 0#目前时间初始化
xs = []
ys = []
ks = []
#大小为21的数组初始化
for i in range(0,21):
xs.append(0)
ys.append(0)
for i in range(0,4):
ks.append(0)
#计算两点间的距离
def point_distance(x1, y1, x2, y2 ):
dis = abs(math.sqrt((x2 - x1)*(x2 - x1)+(y2 - y1)*(y2 - y1)))
return dis
def K_count():
k=5
i=0
while(k<20):
aveX1 = (xs[k] + xs[k+1] + xs[k+2] + xs[k+3]) / 4
aveY1 = (ys[k] + ys[k+1] + ys[k+2] + ys[k+3]) / 4
t = (xs[k] * xs[k] + xs[k+1] * xs[k+1] + xs[k+2] * xs[k+2] + xs[k+3] * xs[k+3] - 4 * aveX1 * aveX1)
if(abs (t - 0) < 0.000001):
t += 0.000001
if aveX1 != 0 and aveY1 != 0:
k1 = (xs[k] * ys[k] + xs[k+1] * ys[k+1] + xs[k+2] * ys[k+2] + xs[k+3] * ys[k+3] - 4 * aveX1 * aveY1) /t
else:
k1 = 0
ks[i] = k1
i += 1
k += 4
avek = sum(ks)/4
#print(avek)
ks0 = abs(ks[0] - avek)
ks1 = abs(ks[1] - avek)
ks2 = abs(ks[2] - avek)
ks3 = abs(ks[3] - avek)
#ks0 = (ks[0] - avek)
#ks1 = (ks[1] - avek)
#ks2 = (ks[2] - avek)
#ks3 = (ks[3] - avek)
print(ks[1])
dis = point_distance(xs[4], ys[4], xs[8], ys[8])
if (ks0+ks1+ks2+ks3) < 3.5 and dis > 100 and abs(ks[1]) > 3:
print("前进")
elif (ks0+ks1+ks2+ks3) < 3.5 and dis > 100 and -1 < ks[1] < 0:
print("左转")
elif (ks0 + ks1 + ks2 + ks3) < 3.5 and dis > 100 and 0 < ks[1] < 1:
print("右转")
elif dis < 100:
print("停止")
while True:
count = 0
success, img = cap.read()#BGR存储格式
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)#转为RGB存储
#处理返回的手的标志点以及处理
results = hands.process(imgRGB)
if results.multi_hand_landmarks:#返回none或手的标志点坐标
for handLms in results.multi_hand_landmarks:
#id是索引,lm是x,y坐标
for id, lm in enumerate(handLms.landmark):
h, w, c = img.shape
cx, cy = int(lm.x*w), int(lm.y*h)
# print(id, cx, cy)
xs[id] = cx
ys[id] = cy
cv2.circle(img, (cx, cy), 5, (0, 255, 105), cv2.FILLED)
cv2.putText(img, str(int(id)), (cx, cy), cv2.FONT_HERSHEY_PLAIN, 2,
(200, 20, 50), 3)
K_count()
mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS)
cTime = time.time()
fps = 1 / (cTime - pTime)
pTime = cTime
cv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3,
(255, 0, 255), 1)
cv2.imshow("Image", img)
k = cv2.waitKey(1)
if k == 27:
cap.release()
cv2.destroyAllWindows()
exit()