aysenur-mank commited on
Commit
99bf888
·
1 Parent(s): dbf0341

feat: done

Browse files
Files changed (6) hide show
  1. .gitignore +1 -0
  2. README.md +36 -6
  3. app.py +346 -0
  4. app_sl.py +272 -0
  5. hand_detector.py +262 -0
  6. requirements.txt +15 -0
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ /music
README.md CHANGED
@@ -1,12 +1,42 @@
1
  ---
2
- title: Visual Music App
3
- emoji: 📉
4
- colorFrom: gray
5
- colorTo: yellow
6
  sdk: gradio
7
- sdk_version: 6.5.1
8
  app_file: app.py
9
  pinned: false
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: El Hareketiyle Müzik Kontrol
3
+ emoji: 🎵
4
+ colorFrom: purple
5
+ colorTo: blue
6
  sdk: gradio
7
+ sdk_version: "4.0.0"
8
  app_file: app.py
9
  pinned: false
10
  ---
11
 
12
+ # 🎵 El Hareketiyle Müzik Kontrol
13
+
14
+ Kamera ile el hareketlerinizi algılayarak müzik kontrol edin!
15
+
16
+ ## 🎯 El Hareketleri
17
+
18
+ | Hareket | Eylem |
19
+ |---------|-------|
20
+ | ✋ Avuç aç (4-5 parmak) | **DURDUR** |
21
+ | ☝️ Sadece işaret parmağı | **OYNAT** |
22
+ | 👋 Eli hızla savur | **SONRAKİ** |
23
+
24
+ ## 🎶 Mevcut Şarkılar
25
+ - 🎵 GOT Main Theme
26
+ - 🎵 Hedwig's Theme
27
+ - 🎵 The Shire
28
+
29
+ ## 🚀 Kullanım
30
+ 1. "▶️ Müziği Başlat" butonuna tıklayın
31
+ 2. Kameranızı açın
32
+ 3. El hareketlerinizle müziği kontrol edin!
33
+
34
+ ## 💡 İpuçları
35
+ - Elinizi kameraya yakın tutun
36
+ - İyi aydınlatma sağlayın
37
+ - Parmakları net gösterin
38
+
39
+ ## 🛠️ Teknolojiler
40
+ - **Gradio** - Web arayüzü
41
+ - **MediaPipe** - El algılama
42
+ - **OpenCV** - Görüntü işleme
app.py ADDED
@@ -0,0 +1,346 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ El Hareketiyle Müzik Kontrol Uygulaması
3
+ Gradio + MediaPipe + Audio Player
4
+
5
+ Hugging Face Spaces için optimize edilmiş
6
+ """
7
+
8
+ import gradio as gr
9
+ import cv2
10
+ import numpy as np
11
+ from collections import deque
12
+ import time
13
+ import os
14
+ from pathlib import Path
15
+
16
+ # MediaPipe
17
+ import mediapipe as mp
18
+
19
+ mpHands = mp.solutions.hands
20
+ mpDraw = mp.solutions.drawing_utils
21
+
22
+ print("✓ MediaPipe yüklendi!")
23
+
24
+ # Müzik dosyalarını bul
25
+ MUSIC_DIR = Path(__file__).parent / "music"
26
+ MUSIC_FILES = []
27
+
28
+ if MUSIC_DIR.exists():
29
+ for ext in ['*.mp3', '*.wav', '*.ogg']:
30
+ MUSIC_FILES.extend(list(MUSIC_DIR.glob(ext)))
31
+ MUSIC_FILES = sorted(MUSIC_FILES)
32
+ print(f"✓ {len(MUSIC_FILES)} müzik dosyası bulundu!")
33
+ else:
34
+ print("⚠ music/ klasörü bulunamadı")
35
+
36
+
37
+ class MusicController:
38
+ """Müzik durumunu takip eden sınıf"""
39
+ def __init__(self):
40
+ self.current_index = 0
41
+ self.is_playing = False
42
+ self.music_files = MUSIC_FILES
43
+
44
+ def get_current_track(self):
45
+ if self.music_files:
46
+ return str(self.music_files[self.current_index])
47
+ return None
48
+
49
+ def get_current_name(self):
50
+ if self.music_files:
51
+ return self.music_files[self.current_index].stem
52
+ return "Müzik yok"
53
+
54
+ def next_track(self):
55
+ if self.music_files:
56
+ self.current_index = (self.current_index + 1) % len(self.music_files)
57
+ return self.get_current_track(), self.get_current_name()
58
+
59
+ def play(self):
60
+ self.is_playing = True
61
+
62
+ def pause(self):
63
+ self.is_playing = False
64
+
65
+
66
+ class HandGestureDetector:
67
+ """El hareketlerini algılayan sınıf"""
68
+
69
+ def __init__(self):
70
+ self.hands = mpHands.Hands(
71
+ static_image_mode=False,
72
+ max_num_hands=1,
73
+ min_detection_confidence=0.7,
74
+ min_tracking_confidence=0.7
75
+ )
76
+ self.tipIds = [4, 8, 12, 16, 20]
77
+ self.position_history = deque(maxlen=10)
78
+ self.last_swipe_time = 0
79
+ self.last_gesture_time = 0
80
+
81
+ def fingersUp(self, lmList):
82
+ """Hangi parmaklar yukarıda"""
83
+ fingers = []
84
+ if len(lmList) < 21:
85
+ return [0, 0, 0, 0, 0]
86
+
87
+ # Başparmak
88
+ if lmList[self.tipIds[0]][1] < lmList[self.tipIds[0] - 1][1]:
89
+ fingers.append(1)
90
+ else:
91
+ fingers.append(0)
92
+
93
+ # Diğer 4 parmak
94
+ for id in range(1, 5):
95
+ if lmList[self.tipIds[id]][2] < lmList[self.tipIds[id] - 2][2]:
96
+ fingers.append(1)
97
+ else:
98
+ fingers.append(0)
99
+
100
+ return fingers
101
+
102
+ def detect(self, frame):
103
+ """El algıla ve gesture döndür"""
104
+ if frame is None:
105
+ return None, None, "Kamera bekleniyor..."
106
+
107
+ # BGR'ye çevir (Gradio RGB verir)
108
+ frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
109
+ frame = cv2.flip(frame, 1) # Ayna
110
+
111
+ imgRGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
112
+ results = self.hands.process(imgRGB)
113
+
114
+ gesture = None
115
+ gesture_text = "👋 El gösterin"
116
+ current_time = time.time()
117
+ h, w = frame.shape[:2]
118
+
119
+ if results.multi_hand_landmarks:
120
+ for handLms in results.multi_hand_landmarks:
121
+ # El çiz
122
+ mpDraw.draw_landmarks(frame, handLms, mpHands.HAND_CONNECTIONS)
123
+
124
+ # Landmark listesi
125
+ lmList = []
126
+ for id, lm in enumerate(handLms.landmark):
127
+ cx, cy = int(lm.x * w), int(lm.y * h)
128
+ lmList.append([id, cx, cy])
129
+
130
+ if len(lmList) >= 21:
131
+ fingers = self.fingersUp(lmList)
132
+ totalFingers = sum(fingers)
133
+ wrist_x = lmList[0][1]
134
+
135
+ # Swipe algılama
136
+ self.position_history.append((wrist_x, current_time))
137
+
138
+ if len(self.position_history) >= 6:
139
+ positions = list(self.position_history)
140
+ x_diff = positions[-1][0] - positions[0][0]
141
+ time_diff = positions[-1][1] - positions[0][1]
142
+
143
+ if time_diff < 0.35 and abs(x_diff) > 120:
144
+ if current_time - self.last_swipe_time > 1.0:
145
+ gesture = "swipe"
146
+ self.last_swipe_time = current_time
147
+ self.position_history.clear()
148
+
149
+ # Gesture algılama
150
+ if gesture is None and current_time - self.last_gesture_time > 0.5:
151
+ if totalFingers >= 4:
152
+ gesture = "palm"
153
+ self.last_gesture_time = current_time
154
+ elif fingers[1] == 1 and sum(fingers[2:]) == 0:
155
+ gesture = "index"
156
+ self.last_gesture_time = current_time
157
+
158
+ # Görsel ve metin
159
+ if gesture == "palm":
160
+ cv2.putText(frame, "DURDUR", (50, 80),
161
+ cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 4)
162
+ gesture_text = "✋ DURDUR"
163
+ elif gesture == "index":
164
+ cv2.putText(frame, "OYNAT", (50, 80),
165
+ cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 255, 0), 4)
166
+ gesture_text = "☝️ OYNAT"
167
+ elif gesture == "swipe":
168
+ direction = ">>>" if x_diff > 0 else "<<<"
169
+ cv2.putText(frame, f"SONRAKI {direction}", (50, 80),
170
+ cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255, 165, 0), 3)
171
+ gesture_text = "👋 SONRAKİ"
172
+ else:
173
+ gesture_text = f"🖐️ {totalFingers} parmak"
174
+
175
+ # Debug
176
+ cv2.putText(frame, f"Parmak: {totalFingers}", (10, h - 20),
177
+ cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
178
+
179
+ # BGR -> RGB (Gradio için)
180
+ frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
181
+
182
+ return frame, gesture, gesture_text
183
+
184
+
185
+ # Global instances
186
+ detector = HandGestureDetector()
187
+ music_ctrl = MusicController()
188
+
189
+
190
+ def process_frame(frame, current_audio):
191
+ """Gradio için frame işleme"""
192
+ processed_frame, gesture, gesture_text = detector.detect(frame)
193
+
194
+ audio_file = current_audio
195
+ track_name = music_ctrl.get_current_name()
196
+ status = gesture_text
197
+
198
+ # Gesture'a göre aksiyon
199
+ if gesture == "swipe":
200
+ audio_file, track_name = music_ctrl.next_track()
201
+ status = f"👋 SONRAKİ: {track_name}"
202
+ elif gesture == "palm":
203
+ music_ctrl.pause()
204
+ status = f"✋ DURAKLATILDI: {track_name}"
205
+ elif gesture == "index":
206
+ music_ctrl.play()
207
+ status = f"☝️ ÇALIYOR: {track_name}"
208
+
209
+ return processed_frame, audio_file, f"🎵 {track_name}", status
210
+
211
+
212
+ def start_music():
213
+ """İlk müziği başlat"""
214
+ track = music_ctrl.get_current_track()
215
+ name = music_ctrl.get_current_name()
216
+ music_ctrl.play()
217
+ return track, f"🎵 {name}", f"☝️ ÇALIYOR: {name}"
218
+
219
+
220
+ def next_track():
221
+ """Sonraki şarkıya geç"""
222
+ track, name = music_ctrl.next_track()
223
+ return track, f"🎵 {name}"
224
+
225
+
226
+ # Müzik listesi HTML
227
+ def get_music_list_html():
228
+ if not MUSIC_FILES:
229
+ return "<p>Müzik dosyası bulunamadı</p>"
230
+
231
+ html = "<div style='background:#1a1a2e; padding:10px; border-radius:10px;'>"
232
+ for i, f in enumerate(MUSIC_FILES):
233
+ icon = "▶️" if i == music_ctrl.current_index else "🎵"
234
+ html += f"<p style='color:white; margin:5px 0;'>{icon} {i+1}. {f.stem}</p>"
235
+ html += "</div>"
236
+ return html
237
+
238
+
239
+ # Gradio arayüzü
240
+ with gr.Blocks(
241
+ title="🎵 El Hareketiyle Müzik Kontrol",
242
+ theme=gr.themes.Soft(),
243
+ css="""
244
+ .music-info {
245
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
246
+ padding: 15px;
247
+ border-radius: 10px;
248
+ color: white;
249
+ text-align: center;
250
+ font-size: 1.2em;
251
+ }
252
+ """
253
+ ) as demo:
254
+
255
+ gr.Markdown("""
256
+ # 🎵 El Hareketiyle Müzik Kontrol
257
+
258
+ Elinizi kameraya göstererek müzik kontrol edin!
259
+ """)
260
+
261
+ # Mevcut audio state
262
+ current_audio = gr.State(value=music_ctrl.get_current_track())
263
+
264
+ with gr.Row():
265
+ # Sol: Kamera
266
+ with gr.Column(scale=2):
267
+ gr.Markdown("### 📷 Kamera")
268
+
269
+ webcam = gr.Image(
270
+ sources=["webcam"],
271
+ streaming=True,
272
+ label="Kamera Girişi",
273
+ height=400
274
+ )
275
+
276
+ output_image = gr.Image(
277
+ label="🎯 El Algılama",
278
+ interactive=False,
279
+ height=400
280
+ )
281
+
282
+ # Sağ: Kontroller ve Müzik
283
+ with gr.Column(scale=1):
284
+ gr.Markdown("### 🎹 El Hareketleri")
285
+
286
+ gr.Markdown("""
287
+ | Hareket | Eylem |
288
+ |---------|-------|
289
+ | ✋ Avuç aç | **DURDUR** |
290
+ | ☝️ İşaret parmağı | **OYNAT** |
291
+ | 👋 El savur | **SONRAKİ** |
292
+ """)
293
+
294
+ gr.Markdown("---")
295
+ gr.Markdown("### 🎵 Müzik Çalar")
296
+
297
+ # Başlat butonu
298
+ start_btn = gr.Button("▶️ Müziği Başlat", variant="primary", size="lg")
299
+ next_btn = gr.Button("⏭️ Sonraki", size="lg")
300
+
301
+ # Şarkı adı
302
+ track_name = gr.Markdown(
303
+ value=f"🎵 {music_ctrl.get_current_name()}",
304
+ elem_classes=["music-info"]
305
+ )
306
+
307
+ # Audio player
308
+ audio_player = gr.Audio(
309
+ value=music_ctrl.get_current_track(),
310
+ label="🔊 Çalan Şarkı",
311
+ autoplay=False,
312
+ show_download_button=False
313
+ )
314
+
315
+ # Durum
316
+ status = gr.Textbox(
317
+ label="📊 Durum",
318
+ value="▶️ Müziği başlatmak için butona tıklayın",
319
+ interactive=False
320
+ )
321
+
322
+ gr.Markdown("---")
323
+ gr.Markdown("### 📋 Şarkı Listesi")
324
+ music_list = gr.HTML(value=get_music_list_html())
325
+
326
+ # Event handlers
327
+ start_btn.click(
328
+ fn=start_music,
329
+ outputs=[audio_player, track_name, status]
330
+ )
331
+
332
+ next_btn.click(
333
+ fn=next_track,
334
+ outputs=[audio_player, track_name]
335
+ )
336
+
337
+ # Webcam stream
338
+ webcam.stream(
339
+ fn=process_frame,
340
+ inputs=[webcam, current_audio],
341
+ outputs=[output_image, audio_player, track_name, status]
342
+ )
343
+
344
+
345
+ if __name__ == "__main__":
346
+ demo.launch()
app_sl.py ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ El Hareketiyle Müzik Kontrol Uygulaması
3
+ Streamlit + MediaPipe + Pygame
4
+ """
5
+
6
+ import streamlit as st
7
+ import cv2
8
+ import numpy as np
9
+ from pathlib import Path
10
+ import pygame
11
+ import time
12
+ from hand_detector import HandGestureDetector
13
+
14
+ # Sayfa ayarları
15
+ st.set_page_config(
16
+ page_title="🎵 El Hareketiyle Müzik Kontrol",
17
+ page_icon="🎵",
18
+ layout="wide"
19
+ )
20
+
21
+ # CSS stilleri
22
+ st.markdown("""
23
+ <style>
24
+ .main-title {
25
+ text-align: center;
26
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
27
+ -webkit-background-clip: text;
28
+ -webkit-text-fill-color: transparent;
29
+ font-size: 3rem;
30
+ font-weight: bold;
31
+ margin-bottom: 1rem;
32
+ }
33
+ .gesture-card {
34
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
35
+ border-radius: 15px;
36
+ padding: 20px;
37
+ margin: 10px 0;
38
+ text-align: center;
39
+ }
40
+ .status-playing {
41
+ background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
42
+ color: white;
43
+ padding: 10px 20px;
44
+ border-radius: 25px;
45
+ font-weight: bold;
46
+ }
47
+ .status-paused {
48
+ background: linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%);
49
+ color: white;
50
+ padding: 10px 20px;
51
+ border-radius: 25px;
52
+ font-weight: bold;
53
+ }
54
+ .music-list {
55
+ background: #1e1e2e;
56
+ border-radius: 10px;
57
+ padding: 15px;
58
+ color: white;
59
+ }
60
+ .current-song {
61
+ background: linear-gradient(90deg, #667eea, #764ba2);
62
+ padding: 10px;
63
+ border-radius: 8px;
64
+ margin: 5px 0;
65
+ }
66
+ </style>
67
+ """, unsafe_allow_html=True)
68
+
69
+
70
+ def init_pygame():
71
+ """Pygame mixer başlat"""
72
+ if not pygame.mixer.get_init():
73
+ pygame.mixer.init()
74
+
75
+
76
+ def get_music_files():
77
+ """Müzik dosyalarını listele"""
78
+ music_dir = Path(__file__).parent / "music"
79
+ music_dir.mkdir(exist_ok=True)
80
+
81
+ extensions = ['.mp3', '.wav', '.ogg']
82
+ music_files = []
83
+
84
+ for ext in extensions:
85
+ music_files.extend(music_dir.glob(f"*{ext}"))
86
+
87
+ return sorted(music_files)
88
+
89
+
90
+ def init_session_state():
91
+ """Session state başlat"""
92
+ if 'is_playing' not in st.session_state:
93
+ st.session_state.is_playing = False
94
+ if 'current_track' not in st.session_state:
95
+ st.session_state.current_track = 0
96
+ if 'music_started' not in st.session_state:
97
+ st.session_state.music_started = False
98
+ if 'camera_active' not in st.session_state:
99
+ st.session_state.camera_active = False
100
+
101
+
102
+ def play_music(filepath):
103
+ """Müzik çal"""
104
+ try:
105
+ pygame.mixer.music.load(str(filepath))
106
+ pygame.mixer.music.play()
107
+ return True
108
+ except Exception as e:
109
+ st.error(f"Müzik yüklenemedi: {e}")
110
+ return False
111
+
112
+
113
+ def main():
114
+ st.markdown('<h1 class="main-title">🎵 El Hareketiyle Müzik Kontrol</h1>', unsafe_allow_html=True)
115
+
116
+ init_pygame()
117
+ init_session_state()
118
+
119
+ # Müzik dosyalarını al
120
+ music_files = get_music_files()
121
+
122
+ # İki sütun: Sol taraf kamera, sağ taraf kontroller
123
+ col1, col2 = st.columns([2, 1])
124
+
125
+ with col2:
126
+ st.markdown("### 🎹 Kontroller")
127
+
128
+ # Hareket açıklamaları
129
+ st.markdown("""
130
+ <div class="gesture-card">
131
+ <h4>✋ Avuç Aç = DURDUR</h4>
132
+ <p>Elinizi açarak müziği durdurun</p>
133
+ </div>
134
+ """, unsafe_allow_html=True)
135
+
136
+ st.markdown("""
137
+ <div class="gesture-card">
138
+ <h4>☝️ İşaret Parmağı = OYNAT</h4>
139
+ <p>İşaret parmağınızı kaldırarak çalın</p>
140
+ </div>
141
+ """, unsafe_allow_html=True)
142
+
143
+ st.markdown("""
144
+ <div class="gesture-card">
145
+ <h4>👋 Savur = SONRAKİ</h4>
146
+ <p>Elinizi hızlıca sağa sola savurun</p>
147
+ </div>
148
+ """, unsafe_allow_html=True)
149
+
150
+ st.markdown("---")
151
+
152
+ # Müzik listesi
153
+ st.markdown("### 🎶 Müzik Listesi")
154
+
155
+ if not music_files:
156
+ st.warning("⚠️ 'music' klasörüne müzik dosyası ekleyin!")
157
+ st.info("Desteklenen formatlar: .mp3, .wav, .ogg")
158
+ else:
159
+ for i, music in enumerate(music_files):
160
+ if i == st.session_state.current_track:
161
+ st.markdown(f"""
162
+ <div class="current-song">
163
+ ▶️ {i+1}. {music.name}
164
+ </div>
165
+ """, unsafe_allow_html=True)
166
+ else:
167
+ st.text(f" {i+1}. {music.name}")
168
+
169
+ st.markdown("---")
170
+
171
+ # Durum göstergesi
172
+ if st.session_state.is_playing:
173
+ st.markdown('<p class="status-playing">🎵 Çalıyor...</p>', unsafe_allow_html=True)
174
+ else:
175
+ st.markdown('<p class="status-paused">⏸️ Duraklatıldı</p>', unsafe_allow_html=True)
176
+
177
+ with col1:
178
+ st.markdown("### 📷 Kamera Görüntüsü")
179
+
180
+ # Başlat/Durdur butonu
181
+ if not st.session_state.camera_active:
182
+ if st.button("🎬 Müzik Başlat & Kamera Aç", type="primary", use_container_width=True):
183
+ if music_files:
184
+ st.session_state.camera_active = True
185
+ st.session_state.music_started = True
186
+ st.rerun()
187
+ else:
188
+ st.error("Önce 'music' klasörüne müzik ekleyin!")
189
+ else:
190
+ if st.button("⏹️ Durdur & Kapat", type="secondary", use_container_width=True):
191
+ st.session_state.camera_active = False
192
+ st.session_state.is_playing = False
193
+ pygame.mixer.music.stop()
194
+ st.rerun()
195
+
196
+ # Kamera frame placeholder
197
+ frame_placeholder = st.empty()
198
+ status_placeholder = st.empty()
199
+
200
+ if st.session_state.camera_active and music_files:
201
+ # Kamerayı aç
202
+ cap = cv2.VideoCapture(0)
203
+ detector = HandGestureDetector()
204
+
205
+ # İlk müziği başlat
206
+ if st.session_state.music_started:
207
+ if play_music(music_files[st.session_state.current_track]):
208
+ st.session_state.is_playing = True
209
+ st.session_state.music_started = False
210
+
211
+ last_gesture = None
212
+ gesture_cooldown = 0.8
213
+ last_action_time = 0
214
+
215
+ try:
216
+ while st.session_state.camera_active:
217
+ ret, frame = cap.read()
218
+ if not ret:
219
+ st.error("Kamera okunamadı!")
220
+ break
221
+
222
+ frame = cv2.flip(frame, 1) # Ayna görünümü
223
+ gesture, annotated_frame = detector.detect_gesture(frame)
224
+
225
+ current_time = time.time()
226
+
227
+ # Hareket kontrolü (cooldown ile)
228
+ if gesture and (current_time - last_action_time) > gesture_cooldown:
229
+ if gesture == "palm" and st.session_state.is_playing:
230
+ # Durdur
231
+ pygame.mixer.music.pause()
232
+ st.session_state.is_playing = False
233
+ status_placeholder.info("⏸️ Müzik duraklatıldı")
234
+ last_action_time = current_time
235
+
236
+ elif gesture == "index" and not st.session_state.is_playing:
237
+ # Devam et
238
+ pygame.mixer.music.unpause()
239
+ st.session_state.is_playing = True
240
+ status_placeholder.success("▶️ Müzik devam ediyor")
241
+ last_action_time = current_time
242
+
243
+ elif gesture == "swipe":
244
+ # Sonraki şarkı
245
+ st.session_state.current_track = (st.session_state.current_track + 1) % len(music_files)
246
+ play_music(music_files[st.session_state.current_track])
247
+ st.session_state.is_playing = True
248
+ status_placeholder.warning(f"⏭️ Sonraki: {music_files[st.session_state.current_track].name}")
249
+ last_action_time = current_time
250
+
251
+ # Frame'i RGB'ye çevir ve göster
252
+ annotated_frame = cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
253
+ frame_placeholder.image(annotated_frame, channels="RGB", use_container_width=True)
254
+
255
+ # Müzik bitti mi kontrol et
256
+ if not pygame.mixer.music.get_busy() and st.session_state.is_playing:
257
+ # Otomatik sonraki şarkı
258
+ st.session_state.current_track = (st.session_state.current_track + 1) % len(music_files)
259
+ play_music(music_files[st.session_state.current_track])
260
+
261
+ time.sleep(0.03) # ~30 FPS
262
+
263
+ except Exception as e:
264
+ st.error(f"Hata: {e}")
265
+ finally:
266
+ cap.release()
267
+ detector.release()
268
+
269
+
270
+ if __name__ == "__main__":
271
+ main()
272
+
hand_detector.py ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ El Hareket Algılama Modülü
3
+ MediaPipe Hands kullanarak el hareketlerini algılar
4
+
5
+ Referans: https://medium.com/@odil.tokhirov/how-i-built-a-hand-gesture-recognition-model-in-python-part-1-db378cf196e6
6
+ """
7
+
8
+ import cv2
9
+ import numpy as np
10
+ from collections import deque
11
+ import time
12
+
13
+ # MediaPipe import
14
+ import mediapipe as mp
15
+
16
+ # MediaPipe modüllerini al
17
+ mpHands = mp.solutions.hands
18
+ mpDraw = mp.solutions.drawing_utils
19
+
20
+ print(f"✓ MediaPipe v{mp.__version__} yüklendi!")
21
+
22
+
23
+ class HandGestureDetector:
24
+ """
25
+ El hareketlerini algılayan sınıf
26
+
27
+ Kullanılan hareketler:
28
+ - palm: Avuç açık (4-5 parmak) -> Müzik durdur
29
+ - index: Sadece işaret parmağı -> Müzik başlat
30
+ - swipe: Hızlı yatay hareket -> Sonraki şarkı
31
+ """
32
+
33
+ def __init__(self):
34
+ print("Hand detector başlatılıyor...")
35
+
36
+ # MediaPipe Hands - basit konfigürasyon
37
+ self.hands = mpHands.Hands(
38
+ max_num_hands=1,
39
+ min_detection_confidence=0.7,
40
+ min_tracking_confidence=0.7
41
+ )
42
+
43
+ # Parmak uç noktaları (landmark indeksleri)
44
+ # Thumb=4, Index=8, Middle=12, Ring=16, Pinky=20
45
+ self.tipIds = [4, 8, 12, 16, 20]
46
+
47
+ # Swipe algılama
48
+ self.position_history = deque(maxlen=10)
49
+ self.last_swipe_time = 0
50
+ self.swipe_cooldown = 1.0
51
+
52
+ # Gesture cooldown
53
+ self.last_gesture_time = 0
54
+ self.gesture_cooldown = 0.5
55
+
56
+ print("✓ Hand detector hazır!")
57
+
58
+ def findHands(self, frame, draw=True):
59
+ """El bul ve landmark'ları döndür"""
60
+ imgRGB = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
61
+ self.results = self.hands.process(imgRGB)
62
+
63
+ if self.results.multi_hand_landmarks:
64
+ for handLms in self.results.multi_hand_landmarks:
65
+ if draw:
66
+ mpDraw.draw_landmarks(frame, handLms, mpHands.HAND_CONNECTIONS)
67
+
68
+ return frame
69
+
70
+ def findPosition(self, frame, handNo=0):
71
+ """El landmark pozisyonlarını liste olarak döndür"""
72
+ lmList = []
73
+
74
+ if self.results.multi_hand_landmarks:
75
+ if len(self.results.multi_hand_landmarks) > handNo:
76
+ myHand = self.results.multi_hand_landmarks[handNo]
77
+ h, w, c = frame.shape
78
+
79
+ for id, lm in enumerate(myHand.landmark):
80
+ cx, cy = int(lm.x * w), int(lm.y * h)
81
+ lmList.append([id, cx, cy])
82
+
83
+ return lmList
84
+
85
+ def fingersUp(self, lmList):
86
+ """
87
+ Hangi parmakların yukarıda olduğunu döndür
88
+ Returns: [thumb, index, middle, ring, pinky]
89
+ """
90
+ fingers = []
91
+
92
+ if len(lmList) < 21:
93
+ return [0, 0, 0, 0, 0]
94
+
95
+ # Başparmak - x ekseni kontrolü
96
+ # Sağ el için: parmak ucu (4) < IP eklemi (3) ise açık
97
+ if lmList[self.tipIds[0]][1] < lmList[self.tipIds[0] - 1][1]:
98
+ fingers.append(1)
99
+ else:
100
+ fingers.append(0)
101
+
102
+ # 4 parmak - y ekseni kontrolü
103
+ # Parmak ucu < PIP eklemi ise açık (y yukarı doğru küçülür)
104
+ for id in range(1, 5):
105
+ if lmList[self.tipIds[id]][2] < lmList[self.tipIds[id] - 2][2]:
106
+ fingers.append(1)
107
+ else:
108
+ fingers.append(0)
109
+
110
+ return fingers
111
+
112
+ def detect_gesture(self, frame):
113
+ """
114
+ Ana hareket algılama fonksiyonu
115
+
116
+ Returns:
117
+ gesture: "palm", "index", "swipe" veya None
118
+ annotated_frame: İşaretlenmiş frame
119
+ """
120
+ # El bul
121
+ annotated_frame = self.findHands(frame.copy(), draw=True)
122
+
123
+ # Pozisyonları al
124
+ lmList = self.findPosition(annotated_frame)
125
+
126
+ gesture = None
127
+ current_time = time.time()
128
+ h, w = frame.shape[:2]
129
+
130
+ if len(lmList) >= 21:
131
+ # Parmak durumları
132
+ fingers = self.fingersUp(lmList)
133
+ totalFingers = sum(fingers)
134
+
135
+ # El merkezi (bilek pozisyonu - landmark 0)
136
+ wrist_x = lmList[0][1]
137
+ wrist_y = lmList[0][2]
138
+
139
+ # ===== SWIPE ALGILAMA =====
140
+ self.position_history.append((wrist_x, current_time))
141
+
142
+ if len(self.position_history) >= 6:
143
+ positions = list(self.position_history)
144
+ x_diff = positions[-1][0] - positions[0][0]
145
+ time_diff = positions[-1][1] - positions[0][1]
146
+
147
+ # Hızlı yatay hareket = swipe
148
+ if time_diff < 0.35 and abs(x_diff) > 120:
149
+ if current_time - self.last_swipe_time > self.swipe_cooldown:
150
+ gesture = "swipe"
151
+ self.last_swipe_time = current_time
152
+ self.position_history.clear()
153
+
154
+ direction = ">>>" if x_diff > 0 else "<<<"
155
+ cv2.putText(annotated_frame, f"SONRAKI {direction}", (50, 80),
156
+ cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0, 165, 255), 3)
157
+ return gesture, annotated_frame
158
+
159
+ # ===== GESTURE ALGILAMA =====
160
+ if current_time - self.last_gesture_time > self.gesture_cooldown:
161
+
162
+ # AVUÇ AÇIK: 4 veya 5 parmak yukarıda
163
+ if totalFingers >= 4:
164
+ gesture = "palm"
165
+ self.last_gesture_time = current_time
166
+ cv2.putText(annotated_frame, "DURDUR", (50, 80),
167
+ cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 0, 255), 3)
168
+
169
+ # İŞARET PARMAĞI: Sadece işaret parmağı yukarıda
170
+ elif fingers == [0, 1, 0, 0, 0] or fingers == [1, 1, 0, 0, 0]:
171
+ gesture = "index"
172
+ self.last_gesture_time = current_time
173
+ cv2.putText(annotated_frame, "OYNAT", (50, 80),
174
+ cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 255, 0), 3)
175
+
176
+ # Debug bilgisi
177
+ cv2.putText(annotated_frame, f"Parmak: {totalFingers}", (10, h - 60),
178
+ cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
179
+
180
+ finger_str = f"B:{fingers[0]} I:{fingers[1]} O:{fingers[2]} Y:{fingers[3]} S:{fingers[4]}"
181
+ cv2.putText(annotated_frame, finger_str, (10, h - 30),
182
+ cv2.FONT_HERSHEY_SIMPLEX, 0.6, (200, 200, 200), 2)
183
+
184
+ # El merkezi göster
185
+ cv2.circle(annotated_frame, (wrist_x, wrist_y), 10, (255, 0, 255), -1)
186
+
187
+ else:
188
+ cv2.putText(annotated_frame, "El algilanmadi - Elinizi gosterin", (50, 50),
189
+ cv2.FONT_HERSHEY_SIMPLEX, 0.8, (100, 100, 255), 2)
190
+
191
+ return gesture, annotated_frame
192
+
193
+ def release(self):
194
+ """Kaynakları serbest bırak"""
195
+ self.hands.close()
196
+
197
+
198
+ def test_detector():
199
+ """Test fonksiyonu"""
200
+ print("\n" + "="*50)
201
+ print("KAMERA AÇILIYOR...")
202
+ print("="*50)
203
+
204
+ cap = cv2.VideoCapture(0)
205
+
206
+ if not cap.isOpened():
207
+ print("HATA: Kamera açılamadı!")
208
+ return
209
+
210
+ print("✓ Kamera açıldı!")
211
+
212
+ detector = HandGestureDetector()
213
+
214
+ print("\n" + "="*50)
215
+ print("EL HAREKETİ TEST MODU")
216
+ print("="*50)
217
+ print("Hareketler:")
218
+ print(" ✋ Avuç aç (4-5 parmak): DURDUR")
219
+ print(" ☝️ İşaret parmağı: OYNAT")
220
+ print(" 👋 Eli hızla savur: SONRAKİ")
221
+ print("\nÇıkmak için 'q' tuşuna basın.")
222
+ print("="*50 + "\n")
223
+
224
+ pTime = 0
225
+
226
+ while True:
227
+ ret, frame = cap.read()
228
+ if not ret:
229
+ print("Frame okunamadı!")
230
+ break
231
+
232
+ # Ayna görünümü
233
+ frame = cv2.flip(frame, 1)
234
+
235
+ # Hareket algıla
236
+ gesture, annotated = detector.detect_gesture(frame)
237
+
238
+ if gesture:
239
+ print(f">>> {gesture.upper()}")
240
+
241
+ # FPS hesapla
242
+ cTime = time.time()
243
+ fps = 1 / (cTime - pTime) if (cTime - pTime) > 0 else 0
244
+ pTime = cTime
245
+
246
+ cv2.putText(annotated, f"FPS: {int(fps)}", (10, 30),
247
+ cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
248
+
249
+ # Göster
250
+ cv2.imshow("El Hareketi Testi - 'q' ile cik", annotated)
251
+
252
+ if cv2.waitKey(1) & 0xFF == ord('q'):
253
+ break
254
+
255
+ cap.release()
256
+ detector.release()
257
+ cv2.destroyAllWindows()
258
+ print("\nTest sonlandırıldı.")
259
+
260
+
261
+ if __name__ == "__main__":
262
+ test_detector()
requirements.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Gradio ile çalışan uygulama için gereksinimler
2
+ gradio>=4.0.0
3
+ opencv-python-headless>=4.8.0
4
+ mediapipe>=0.10.0
5
+ numpy<2.0
6
+
7
+
8
+ # Streamlit ile çalışan uygulama için gereksinimler
9
+ # streamlit>=1.28.0
10
+ # opencv-python-headless>=4.8.0
11
+ # mediapipe>=0.10.0
12
+ # streamlit-webrtc>=0.45.0
13
+ # av>=10.0.0
14
+ # numpy<2.0
15
+