Spaces:
Runtime error
Runtime error
| """ | |
| El Hareketiyle Müzik Kontrol Uygulaması | |
| Gradio + MediaPipe + Audio Player | |
| Hugging Face Spaces için optimize edilmiş | |
| """ | |
| import gradio as gr | |
| import cv2 | |
| import numpy as np | |
| from collections import deque | |
| import time | |
| import os | |
| from pathlib import Path | |
| # MediaPipe | |
| import mediapipe as mp | |
| mpHands = mp.solutions.hands | |
| mpDraw = mp.solutions.drawing_utils | |
| print("✓ MediaPipe yüklendi!") | |
| # Müzik dosyalarını bul | |
| MUSIC_DIR = Path(__file__).parent / "music" | |
| MUSIC_FILES = [] | |
| if MUSIC_DIR.exists(): | |
| for ext in ['*.mp3', '*.wav', '*.ogg']: | |
| MUSIC_FILES.extend(list(MUSIC_DIR.glob(ext))) | |
| MUSIC_FILES = sorted(MUSIC_FILES) | |
| print(f"✓ {len(MUSIC_FILES)} müzik dosyası bulundu!") | |
| else: | |
| print("⚠ music/ klasörü bulunamadı") | |
| class MusicController: | |
| """Müzik durumunu takip eden sınıf""" | |
| def __init__(self): | |
| self.current_index = 0 | |
| self.is_playing = False | |
| self.music_files = MUSIC_FILES | |
| def get_current_track(self): | |
| if self.music_files: | |
| return str(self.music_files[self.current_index]) | |
| return None | |
| def get_current_name(self): | |
| if self.music_files: | |
| return self.music_files[self.current_index].stem | |
| return "Müzik yok" | |
| def next_track(self): | |
| if self.music_files: | |
| self.current_index = (self.current_index + 1) % len(self.music_files) | |
| return self.get_current_track(), self.get_current_name() | |
| def play(self): | |
| self.is_playing = True | |
| def pause(self): | |
| self.is_playing = False | |
| class HandGestureDetector: | |
| """El hareketlerini algılayan sınıf""" | |
| def __init__(self): | |
| self.hands = mpHands.Hands( | |
| static_image_mode=False, | |
| max_num_hands=1, | |
| min_detection_confidence=0.7, | |
| min_tracking_confidence=0.7 | |
| ) | |
| self.tipIds = [4, 8, 12, 16, 20] | |
| self.position_history = deque(maxlen=10) | |
| self.last_swipe_time = 0 | |
| self.last_gesture_time = 0 | |
| def fingersUp(self, lmList): | |
| """Hangi parmaklar yukarıda""" | |
| fingers = [] | |
| if len(lmList) < 21: | |
| return [0, 0, 0, 0, 0] | |
| # Başparmak | |
| if lmList[self.tipIds[0]][1] < lmList[self.tipIds[0] - 1][1]: | |
| fingers.append(1) | |
| else: | |
| fingers.append(0) | |
| # Diğer 4 parmak | |
| for id in range(1, 5): | |
| if lmList[self.tipIds[id]][2] < lmList[self.tipIds[id] - 2][2]: | |
| fingers.append(1) | |
| else: | |
| fingers.append(0) | |
| return fingers | |
| def detect(self, frame): | |
| """El algıla ve gesture döndür""" | |
| if frame is None: | |
| return None, None, "Kamera bekleniyor..." | |
| # BGR'ye çevir (Gradio RGB verir) | |
| frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) | |
| frame = cv2.flip(frame, 1) # Ayna | |
| imgRGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) | |
| results = self.hands.process(imgRGB) | |
| gesture = None | |
| gesture_text = "👋 El gösterin" | |
| current_time = time.time() | |
| h, w = frame.shape[:2] | |
| if results.multi_hand_landmarks: | |
| for handLms in results.multi_hand_landmarks: | |
| # El çiz | |
| mpDraw.draw_landmarks(frame, handLms, mpHands.HAND_CONNECTIONS) | |
| # Landmark listesi | |
| lmList = [] | |
| for id, lm in enumerate(handLms.landmark): | |
| cx, cy = int(lm.x * w), int(lm.y * h) | |
| lmList.append([id, cx, cy]) | |
| if len(lmList) >= 21: | |
| fingers = self.fingersUp(lmList) | |
| totalFingers = sum(fingers) | |
| wrist_x = lmList[0][1] | |
| # Swipe algılama | |
| self.position_history.append((wrist_x, current_time)) | |
| if len(self.position_history) >= 6: | |
| positions = list(self.position_history) | |
| x_diff = positions[-1][0] - positions[0][0] | |
| time_diff = positions[-1][1] - positions[0][1] | |
| if time_diff < 0.35 and abs(x_diff) > 120: | |
| if current_time - self.last_swipe_time > 1.0: | |
| gesture = "swipe" | |
| self.last_swipe_time = current_time | |
| self.position_history.clear() | |
| # Gesture algılama | |
| if gesture is None and current_time - self.last_gesture_time > 0.5: | |
| if totalFingers >= 4: | |
| gesture = "palm" | |
| self.last_gesture_time = current_time | |
| elif fingers[1] == 1 and sum(fingers[2:]) == 0: | |
| gesture = "index" | |
| self.last_gesture_time = current_time | |
| # Görsel ve metin | |
| if gesture == "palm": | |
| cv2.putText(frame, "DURDUR", (50, 80), | |
| cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 4) | |
| gesture_text = "✋ DURDUR" | |
| elif gesture == "index": | |
| cv2.putText(frame, "OYNAT", (50, 80), | |
| cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 0), 4) | |
| gesture_text = "☝️ OYNAT" | |
| elif gesture == "swipe": | |
| direction = ">>>" if x_diff > 0 else "<<<" | |
| cv2.putText(frame, f"SONRAKI {direction}", (50, 80), | |
| cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255, 165, 0), 3) | |
| gesture_text = "👋 SONRAKİ" | |
| else: | |
| gesture_text = f"🖐️ {totalFingers} parmak" | |
| # Debug | |
| cv2.putText(frame, f"Parmak: {totalFingers}", (10, h - 20), | |
| cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) | |
| # BGR -> RGB (Gradio için) | |
| frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) | |
| return frame, gesture, gesture_text | |
| # Global instances | |
| detector = HandGestureDetector() | |
| music_ctrl = MusicController() | |
| def process_frame(frame, current_audio): | |
| """Gradio için frame işleme""" | |
| processed_frame, gesture, gesture_text = detector.detect(frame) | |
| audio_file = current_audio | |
| track_name = music_ctrl.get_current_name() | |
| status = gesture_text | |
| # Gesture'a göre aksiyon | |
| if gesture == "swipe": | |
| audio_file, track_name = music_ctrl.next_track() | |
| status = f"👋 SONRAKİ: {track_name}" | |
| elif gesture == "palm": | |
| music_ctrl.pause() | |
| status = f"✋ DURAKLATILDI: {track_name}" | |
| elif gesture == "index": | |
| music_ctrl.play() | |
| status = f"☝️ ÇALIYOR: {track_name}" | |
| return processed_frame, audio_file, f"🎵 {track_name}", status | |
| def start_music(): | |
| """İlk müziği başlat""" | |
| track = music_ctrl.get_current_track() | |
| name = music_ctrl.get_current_name() | |
| music_ctrl.play() | |
| return track, f"🎵 {name}", f"☝️ ÇALIYOR: {name}" | |
| def next_track(): | |
| """Sonraki şarkıya geç""" | |
| track, name = music_ctrl.next_track() | |
| return track, f"🎵 {name}" | |
| # Müzik listesi HTML | |
| def get_music_list_html(): | |
| if not MUSIC_FILES: | |
| return "<p>Müzik dosyası bulunamadı</p>" | |
| html = "<div style='background:#1a1a2e; padding:10px; border-radius:10px;'>" | |
| for i, f in enumerate(MUSIC_FILES): | |
| icon = "▶️" if i == music_ctrl.current_index else "🎵" | |
| html += f"<p style='color:white; margin:5px 0;'>{icon} {i+1}. {f.stem}</p>" | |
| html += "</div>" | |
| return html | |
| # Gradio arayüzü | |
| with gr.Blocks( | |
| title="🎵 El Hareketiyle Müzik Kontrol", | |
| theme=gr.themes.Soft(), | |
| css=""" | |
| .music-info { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| padding: 15px; | |
| border-radius: 10px; | |
| color: white; | |
| text-align: center; | |
| font-size: 1.2em; | |
| } | |
| """ | |
| ) as demo: | |
| gr.Markdown(""" | |
| # 🎵 El Hareketiyle Müzik Kontrol | |
| Elinizi kameraya göstererek müzik kontrol edin! | |
| """) | |
| # Mevcut audio state | |
| current_audio = gr.State(value=music_ctrl.get_current_track()) | |
| with gr.Row(): | |
| # Sol: Kamera | |
| with gr.Column(scale=2): | |
| gr.Markdown("### 📷 Kamera") | |
| webcam = gr.Image( | |
| sources=["webcam"], | |
| streaming=True, | |
| label="Kamera Girişi", | |
| height=400 | |
| ) | |
| output_image = gr.Image( | |
| label="🎯 El Algılama", | |
| interactive=False, | |
| height=400 | |
| ) | |
| # Sağ: Kontroller ve Müzik | |
| with gr.Column(scale=1): | |
| gr.Markdown("### 🎹 El Hareketleri") | |
| gr.Markdown(""" | |
| | Hareket | Eylem | | |
| |---------|-------| | |
| | ✋ Avuç aç | **DURDUR** | | |
| | ☝️ İşaret parmağı | **OYNAT** | | |
| | 👋 El savur | **SONRAKİ** | | |
| """) | |
| gr.Markdown("---") | |
| gr.Markdown("### 🎵 Müzik Çalar") | |
| # Başlat butonu | |
| start_btn = gr.Button("▶️ Müziği Başlat", variant="primary", size="lg") | |
| next_btn = gr.Button("⏭️ Sonraki", size="lg") | |
| # Şarkı adı | |
| track_name = gr.Markdown( | |
| value=f"🎵 {music_ctrl.get_current_name()}", | |
| elem_classes=["music-info"] | |
| ) | |
| # Audio player | |
| audio_player = gr.Audio( | |
| value=music_ctrl.get_current_track(), | |
| label="🔊 Çalan Şarkı", | |
| autoplay=False, | |
| show_download_button=False | |
| ) | |
| # Durum | |
| status = gr.Textbox( | |
| label="📊 Durum", | |
| value="▶️ Müziği başlatmak için butona tıklayın", | |
| interactive=False | |
| ) | |
| gr.Markdown("---") | |
| gr.Markdown("### 📋 Şarkı Listesi") | |
| music_list = gr.HTML(value=get_music_list_html()) | |
| # Event handlers | |
| start_btn.click( | |
| fn=start_music, | |
| outputs=[audio_player, track_name, status] | |
| ) | |
| next_btn.click( | |
| fn=next_track, | |
| outputs=[audio_player, track_name] | |
| ) | |
| # Webcam stream | |
| webcam.stream( | |
| fn=process_frame, | |
| inputs=[webcam, current_audio], | |
| outputs=[output_image, audio_player, track_name, status] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |