用python编写一个使用mediapipe、opencv的程序, 它可以通过打开摄像头识别人的手部,并只有食指伸直的时候,食指的指尖会进行持续线条的绘画, 绘画的内容会被保留在屏幕上,左侧有持续显示的三种颜色按钮和清除按钮, 当食指和中指同时伸直时,如果食指放在某一个按钮上,那么可以切换绘画线条的颜色或者是变为擦除绘画内容, 总共有4种颜色可以被选择:黑色、红色、蓝色和黄色
时间: 2023-06-18 17:02:24 浏览: 116
好的,这个功能可以使用OpenCV和MediaPipe库来实现。我们需要使用MediaPipe的Hand Tracking模块来检测手的位置,然后使用OpenCV来进行绘图操作。以下是一个基本的实现:
首先,我们需要安装必要的库:mediapipe和opencv-python。
```python
!pip install mediapipe opencv-python
```
然后,我们需要导入所需的库并初始化一些变量:
```python
import cv2
import mediapipe as mp
import numpy as np
# 初始化手部检测器
mp_drawing = mp.solutions.drawing_utils
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(max_num_hands=1, min_detection_confidence=0.5)
# 定义绘画变量
draw_color = (0, 0, 0)
draw_thickness = 5
drawing = False
last_point = None
# 创建一个空白画布
canvas = np.zeros((480, 640, 3), dtype=np.uint8)
```
然后,我们需要编写一个函数,该函数将手部检测结果作为输入,并返回一个布尔值,该值指示食指是否伸直:
```python
def is_index_finger_extended(hand_landmarks):
index_finger = hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP]
thumb = hand_landmarks.landmark[mp_hands.HandLandmark.THUMB_TIP]
return index_finger.y < thumb.y
```
接下来,我们需要编写一个函数,该函数将手部检测结果作为输入,并返回一个整数,该值表示食指在哪个按钮上:
```python
def get_button_index(hand_landmarks):
index_finger = hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP]
buttons = [
((20, 20), (100, 100), (0, 0, 0)), # 黑色
((20, 140), (100, 220), (0, 0, 255)), # 红色
((20, 260), (100, 340), (255, 0, 0)), # 蓝色
((20, 380), (100, 460), (0, 255, 255)), # 黄色
]
for i, (tl, br, _) in enumerate(buttons):
if tl[0] <= index_finger.x * 640 <= br[0] and tl[1] <= index_finger.y * 480 <= br[1]:
return i
return -1
```
这个函数将手指的位置与按钮位置进行比较,并返回相应的按钮索引。如果食指不在任何按钮上,则返回-1。
接下来,我们需要编写一个无限循环,该循环将读取摄像头帧,并进行手部检测和绘画操作:
```python
cap = cv2.VideoCapture(0)
while True:
# 读取帧
ret, frame = cap.read()
if not ret:
break
# 翻转帧并调整大小
frame = cv2.flip(frame, 1)
frame = cv2.resize(frame, (640, 480))
# 将帧转换为RGB格式并进行手部检测
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = hands.process(frame_rgb)
# 如果检测到手,则进行绘画操作
if results.multi_hand_landmarks:
# 获取手部关键点
hand_landmarks = results.multi_hand_landmarks[0]
# 检查食指是否伸直
index_finger_extended = is_index_finger_extended(hand_landmarks)
# 检查食指是否在按钮上
button_index = get_button_index(hand_landmarks)
# 如果食指伸直,则进行绘画
if index_finger_extended:
# 记录上一个点的位置
if last_point is None:
last_point = (int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].x * 640),
int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].y * 480))
else:
# 绘制线条
cv2.line(canvas, last_point, (int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].x * 640),
int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].y * 480)),
draw_color, draw_thickness)
last_point = (int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].x * 640),
int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].y * 480))
else:
# 重置上一个点的位置
last_point = None
# 如果食指和中指同时伸直并且在按钮上,则更改颜色或清空画布
if not index_finger_extended and \
hand_landmarks.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_TIP].y < hand_landmarks.landmark[
mp_hands.HandLandmark.INDEX_FINGER_TIP].y and \
button_index != -1:
if button_index == 0:
# 黑色
draw_color = (0, 0, 0)
elif button_index == 1:
# 红色
draw_color = (0, 0, 255)
elif button_index == 2:
# 蓝色
draw_color = (255, 0, 0)
elif button_index == 3:
# 黄色
draw_color = (0, 255, 255)
else:
# 清空画布
canvas = np.zeros((480, 640, 3), dtype=np.uint8)
else:
# 重置上一个点的位置
last_point = None
# 将画布和按钮绘制到帧上
frame = cv2.rectangle(frame, (20, 20), (100, 100), (0, 0, 0), -1)
frame = cv2.rectangle(frame, (20, 140), (100, 220), (0, 0, 255), -1)
frame = cv2.rectangle(frame, (20, 260), (100, 340), (255, 0, 0), -1)
frame = cv2.rectangle(frame, (20, 380), (100, 460), (0, 255, 255), -1)
frame = cv2.putText(frame, "Clear", (25, 430), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
frame = cv2.putText(frame, "Black", (25, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
frame = cv2.putText(frame, "Red", (25, 180), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
frame = cv2.putText(frame, "Blue", (25, 300), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
frame = cv2.putText(frame, "Yellow", (25, 420), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
frame = cv2.putText(frame, "Hand Drawing with Color Selection and Clearing", (10, 20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
frame = cv2.putText(frame, "By @YijunLiu", (10, 470), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
frame = cv2.putText(frame, "Press 'q' to Quit", (450, 470), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
frame = cv2.putText(frame, "Drawing with Color: " + str(draw_color), (150, 470), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
(255, 255, 255), 1)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = np.hstack((frame, canvas))
# 显示帧
cv2.imshow("Hand Tracking and Drawing", frame)
# 按下 'q' 键退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头和窗口
cap.release()
cv2.destroyAllWindows()
```
在这段代码中,我们首先读取摄像头帧,并将其调整大小和翻转。然后,我们将帧转换为RGB格式,并使用MediaPipe Hand Tracking模块进行手部检测。如果检测到手,则进行绘画操作。
在绘画操作中,我们首先检查食指是否伸直,如果是,则将当前位置连接到上一个位置,并更新上一个位置。如果食指不伸直,则重置上一个位置。
接下来,我们检查食指和中指是否同时伸直,并且是否在按钮上。如果是,则更改绘画颜色或清空画布。最后,我们将画布和按钮绘制到帧上,并将其显示在窗口中。
如果按下 'q' 键,则退出循环并释放摄像头和窗口。
完整代码如下:
阅读全文