前几天看见一位博主用mediapipe写的拖动方块,于是我就有了写一个这个代码的想法,我原本要实现的功能是一只手给另一只手带上,但是随着我对里面函数的探索,我发现有点难实现,因为他results.multi_handedness里面可以知道左右手,但是点位在hand_landmarks.landmark这个里面,hand_landmarks.landmark不管你是左手还是右手,只要是手就往里面加点。于是戴戒指这个功能我就分成了两部分,右手拇指和食指达到一定距离后可以移动,左手的中指三个点位分别穿过戒指后,戒指就随左手中指的10号点位移动。
手的点位图:
这个程序目前只可以做到戒指的一维移动,也就是说戒指还只是图片,他只能保持原有的状态直线运动,当手竖起来的时候戒指的形状和手就不匹配了,这就需要通过其他算法完成了,我目前的水平还做不到。
这是戒指图片:
由于我还不会怎么弄动图,就只有放几张截图了
import cv2
import time
import math
import numpy as np
import mediapipe as mp
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(
static_image_mode=True,
max_num_hands=2,
min_detection_confidence=0.5)
cap = cv2.VideoCapture(0)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
img=cv2.imread("./ring.png")
ring_h,ring_w,ring_ch=img.shape
L1 = 0
L2 = 0
x=100
y=100
on_square = False
mid_12=False
mid_11=False
mid_10=False
while True:
rec,frame = cap.read()
frame = cv2.flip(frame,1)
frame.flags.writeable = False
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = hands.process(frame)
frame.flags.writeable = True
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
if results.multi_handedness:
for hand in results.multi_handedness: #如果是右手
if hand.classification[0].label=='Right':
# mp_drawing.draw_landmarks( # 显示手的点位
# frame,
# hand_landmarks,
# mp_hands.HAND_CONNECTIONS,
# mp_drawing_styles.get_default_hand_landmarks_style(),
# mp_drawing_styles.get_default_hand_connections_style())
x_list = []
y_list = []
for landmark in hand_landmarks.landmark:
x_list.append(landmark.x)
y_list.append(landmark.y)
index_finger_x, index_finger_y = int(x_list[8] * width),int(y_list[8] * height)
thumb_finger_x,thumb_finger_y = int(x_list[4] * width), int(y_list[4] * height)
finger_distance = math.hypot((thumb_finger_x - index_finger_x), (thumb_finger_y - index_finger_y))
if finger_distance < 100 :
if (index_finger_x > x-10 and index_finger_x < (x + ring_h+10)) and (
index_finger_y > y-10 and index_finger_y < (y + ring_w+10)):
if on_square == False:
L1 = index_finger_x - x
L2 = index_finger_y - y
on_square = True
else:
on_square = False
if on_square:
x = index_finger_x - L1
y = index_finger_y - L2
if hand.classification[0].label=='Left': #如果识别为左手,处理左手中指的行为
x_list = []
y_list = []
for landmark in hand_landmarks.landmark:
x_list.append(landmark.x)
y_list.append(landmark.y)
mid_finger_12_x,mid_finger_12_y=int(x_list[12]*width),int(y_list[12]*width)
mid_finger_11_x,mid_finger_11_y=int(x_list[11]*width),int(y_list[11]*width)
mid_finger_10_x,mid_finger_10_y=int(x_list[10]*width),int(y_list[10]*width)
# if(mid_finger_12_y<y+ring_w and mid_finger_12_y>y and not mid_10):
# mid_12=True
# if(mid_finger_11_y<y+ring_w and mid_finger_11_y>y and mid_12 and mid_finger_12_x>x):
# mid_11=True
# if(mid_finger_10_y<y+ring_w and mid_finger_10_y>y and mid_11):
# mid_10=True
# if mid_10: #跟随中指10点位移动
#这里可以先注释了省去戴的过程
x=mid_finger_10_x
y=mid_finger_10_y-130
overlay = frame.copy()
for i in range(ring_h):#这里是将原图片中接近白色的颜色筛除,只剩余戒指颜色
for j in range(ring_w):
px=img[i,j]
src2_beta=1
if(px[0],px[1],px[2])>=(245,245,245):
continue
color=(int(px[0]),int(px[1]),int(px[2]))
cv2.rectangle(frame, (x+i, y+j), (x+i,y+j),color,-1)
frame = cv2.addWeighted(overlay, 0.5, frame, src2_beta, 0)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()