1. Présentation
Dans ce nouveau projet, après avoir vu des gens sur Instagram contrôler toutes sortes de choses, comme des photos et des vagues, avec leurs mains, j'ai fait quelques recherches sur le sujet et découvert MediaPip, une bibliothèque qui utilise l'apprentissage automatique pour suivre la position des mains, des visages et du corps humain avec un nuage de points plus ou moins précis. C’est à ce moment-là que j’ai eu l’idée de contrôler la musique avec mes mains, du volume au changement de chanson. Avec un peu d'aide, j'ai pu écrire un script Python qui me permet de faire cela. Appelé Suivi des mains Apple Music, dans mon cas, je l’ai fait avec Apple Music car c’est ma plateforme musicale. Cela aurait tout aussi bien fonctionné avec Spotify, à condition d'avoir Premium, car le contrôle de la musique à distance est payant. Pour le code, il suffit de créer un compte développeur. Je vous renvoie à mon premier projet, qui l'explique : Ici.
J'espère que ce projet vous plaira. Dans les prochains jours, je vais essayer de créer une interface épurée pour la rendre plus agréable que de compiler du code Python !
En plus, on peut s'amuser avec toutes sortes de choses, comme contrôler l'angle d'un servomoteur avec la main (mais je trouve ça plutôt basique). J’aimerais aller plus loin dans l’utilisation de MediaPipe, par exemple en associant un mot de passe à une expression faciale, comme les nouvelles clés d’authentification d’Apple pour les connaisseurs ^^…
1. Courte vidéo avec journaux

2. Coder
import cv2
import mediapipe as mp
import os
import time
import math
# Initialisation MediaPipe
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(
static_image_mode=False,
max_num_hands=2,
min_detection_confidence=0.75,
min_tracking_confidence=0.75
)
mp_draw = mp.solutions.drawing_utils
# FaceMesh
mp_face = mp.solutions.face_mesh
face_mesh = mp_face.FaceMesh(
static_image_mode=False,
max_num_faces=1,
refine_landmarks=True,
min_detection_confidence=0.7,
min_tracking_confidence=0.7
)
# Initialisation webcam
cap = cv2.VideoCapture(0)
# État du dernier geste
last_gesture = None
last_time = 0
gesture_delay = 2
# Volume initial
volume = 50 # Entre 0 et 100
previous_volume = volume # Pour éviter les appels trop fréquents
def count_fingers(hand_landmarks):
fingers = []
tips_ids = [8, 12, 16, 20]
# Pouce
if hand_landmarks.landmark[4].x < hand_landmarks.landmark[3].x:
fingers.append(1)
else:
fingers.append(0)
# Autres doigts
for tip_id in tips_ids:
if hand_landmarks.landmark[tip_id].y < hand_landmarks.landmark[tip_id - 2].y:
fingers.append(1)
else:
fingers.append(0)
return sum(fingers)
def send_command_to_apple_music(command):
if command == "playpause":
os.system("osascript -e 'tell application \"Music\" to playpause'")
elif command == "next":
os.system("osascript -e 'tell application \"Music\" to next track'")
elif command == "previous":
os.system("osascript -e 'tell application \"Music\" to previous track'")
def get_distance(lm1, lm2, frame_width, frame_height):
x1, y1 = int(lm1.x * frame_width), int(lm1.y * frame_height)
x2, y2 = int(lm2.x * frame_width), int(lm2.y * frame_height)
distance = math.hypot(x2 - x1, y2 - y1)
return distance, (x1, y1), (x2, y2)
while True:
success, frame = cap.read()
if not success:
break
frame = cv2.flip(frame, 1) # effet miroir
frame_height, frame_width = frame.shape[:2]
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
hand_results = hands.process(rgb)
face_results = face_mesh.process(rgb)
if hand_results.multi_hand_landmarks:
for hand_landmarks, hand_info in zip(hand_results.multi_hand_landmarks, hand_results.multi_handedness):
label = hand_info.classification[0].label # 'Left' ou 'Right'
mp_draw.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
# MAIN DROITE : contrôle de la musique
if label == 'Right':
finger_count = count_fingers(hand_landmarks)
cv2.putText(frame, f"Main droite: {finger_count} doigts", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
current_time = time.time()
if current_time - last_time > gesture_delay:
if finger_count == 5 and last_gesture != 5:
print("🖐 Lecture / Pause")
send_command_to_apple_music("playpause")
last_gesture = 5
last_time = current_time
elif finger_count == 2 and last_gesture != 2:
print("✌️ Suivant")
send_command_to_apple_music("next")
last_gesture = 2
last_time = current_time
elif finger_count == 3 and last_gesture != 3:
print("🤟 Précédent")
send_command_to_apple_music("previous")
last_gesture = 3
last_time = current_time
# MAIN GAUCHE : contrôle du volume (écartement pouce/index)
elif label == 'Left':
lm_list = hand_landmarks.landmark
dist, pt1, pt2 = get_distance(lm_list[4], lm_list[8], frame_width, frame_height)
# Mapping distance -> volume
min_dist, max_dist = 30, 200
dist_clamped = min(max(dist, min_dist), max_dist)
volume = int((dist_clamped - min_dist) / (max_dist - min_dist) * 100)
# Envoie volume système si changement
if abs(volume - previous_volume) > 2:
os.system(f"osascript -e 'set volume output volume {volume}'")
previous_volume = volume
# Affichage visuel entre pouce/index
cv2.line(frame, pt1, pt2, (0, 255, 0), 3)
cv2.circle(frame, pt1, 8, (255, 0, 0), -1)
cv2.circle(frame, pt2, 8, (255, 0, 0), -1)
else:
last_gesture = None
# Affichage FaceMesh
if face_results.multi_face_landmarks:
for face_landmarks in face_results.multi_face_landmarks:
mp_draw.draw_landmarks(
frame, face_landmarks, mp_face.FACEMESH_TESSELATION,
landmark_drawing_spec=None,
connection_drawing_spec=mp_draw.DrawingSpec(color=(0, 255, 255), thickness=1, circle_radius=1)
)
# Affichage volume
cv2.rectangle(frame, (50, 100), (80, 400), (200, 200, 200), 2)
volume_height = int(300 * (volume / 100))
cv2.rectangle(frame, (50, 400 - volume_height), (80, 400), (0, 255, 0), -1)
cv2.putText(frame, f"{volume}%", (45, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
cv2.imshow("Contrôle Apple Music + Volume + Face", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
J'espère que vous aimerez ^^. Je viendrai avec des nouveaux projets !!