openfree commited on
Commit
9b7a196
·
verified ·
1 Parent(s): 9b3ad98

Delete index.html

Browse files
Files changed (1) hide show
  1. index.html +0 -273
index.html DELETED
@@ -1,273 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="ko">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <title>MediaPipe Holistic Demo + Recording</title>
6
- <!-- MediaPipe 필요한 라이브러리 CDN 불러오기 -->
7
- <script src="https://cdn.jsdelivr.net/npm/@mediapipe/[email protected]/camera_utils.js"></script>
8
- <script src="https://cdn.jsdelivr.net/npm/@mediapipe/[email protected]/control_utils.js"></script>
9
- <script src="https://cdn.jsdelivr.net/npm/@mediapipe/[email protected]/drawing_utils.js"></script>
10
- <script src="https://cdn.jsdelivr.net/npm/@mediapipe/[email protected]/holistic.js"></script>
11
- <style>
12
- body { margin: 0; padding: 0; }
13
- .container {
14
- display: flex;
15
- }
16
- .control-panel {
17
- margin: 10px;
18
- width: 300px;
19
- }
20
- .video-area {
21
- position: relative;
22
- }
23
- .output_canvas {
24
- display: block;
25
- }
26
- .video-controls {
27
- position: fixed;
28
- bottom: 20px;
29
- left: 50%;
30
- transform: translateX(-50%);
31
- z-index: 1000;
32
- display: flex;
33
- gap: 10px;
34
- }
35
- .control-button {
36
- padding: 10px 20px;
37
- background-color: rgba(0, 0, 0, 0.7);
38
- color: white;
39
- border: none;
40
- border-radius: 5px;
41
- cursor: pointer;
42
- font-size: 14px;
43
- }
44
- .control-button:hover {
45
- background-color: rgba(0, 0, 0, 0.9);
46
- }
47
- </style>
48
- </head>
49
- <body>
50
- <div class="container">
51
- <div class="control-panel"></div>
52
- <div class="video-area">
53
- <video class="input_video" style="display:none;"></video>
54
- <canvas class="output_canvas"></canvas>
55
- </div>
56
- </div>
57
-
58
- <div class="video-controls" id="video-controls">
59
- <!-- 녹화 버튼을 자바스크립트에서 동적으로 생성해 붙일 예정 -->
60
- </div>
61
-
62
- <script type="module">
63
- const controls = window;
64
- const mpHolistic = window;
65
- const drawingUtils = window;
66
-
67
- // HTML 엘리먼트 참조
68
- const videoElement = document.querySelector('.input_video');
69
- const canvasElement = document.querySelector('.output_canvas');
70
- const controlsElement = document.querySelector('.control-panel');
71
- const canvasCtx = canvasElement.getContext('2d');
72
- const controlsContainer = document.getElementById('video-controls');
73
-
74
- // MediaPipe의 FPS 유틸(선택적)
75
- const fpsControl = new controls.FPS();
76
-
77
- ///////////////////////////////////////////////////////
78
- // 1. MediaPipe Holistic 초기화
79
- ///////////////////////////////////////////////////////
80
- const holistic = new mpHolistic.Holistic({
81
- locateFile: (file) => {
82
- return `https://cdn.jsdelivr.net/npm/@mediapipe/holistic@${mpHolistic.VERSION}/${file}`;
83
- }
84
- });
85
-
86
- holistic.setOptions({
87
- modelComplexity: 1,
88
- smoothLandmarks: true,
89
- enableSegmentation: false,
90
- smoothSegmentation: true,
91
- refineFaceLandmarks: false,
92
- minDetectionConfidence: 0.5,
93
- minTrackingConfidence: 0.5,
94
- });
95
-
96
- // 결과 처리 콜백
97
- holistic.onResults((results) => {
98
- // FPS 업데이트
99
- fpsControl.tick();
100
-
101
- // 캔버스 초기화
102
- canvasCtx.save();
103
- canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
104
-
105
- // 원본 영상
106
- canvasCtx.drawImage(
107
- results.image,
108
- 0, 0,
109
- canvasElement.width,
110
- canvasElement.height
111
- );
112
-
113
- // Pose 랜드마크(연결선 + 점)
114
- if (results.poseLandmarks && mpHolistic.POSE_CONNECTIONS) {
115
- drawingUtils.drawConnectors(
116
- canvasCtx,
117
- results.poseLandmarks,
118
- mpHolistic.POSE_CONNECTIONS,
119
- { color: 'white', lineWidth: 2 }
120
- );
121
- drawingUtils.drawLandmarks(
122
- canvasCtx,
123
- results.poseLandmarks,
124
- { color: '#FF0000', lineWidth: 1 }
125
- );
126
- }
127
-
128
- // (필요하면) 손, 얼굴 랜드마크도 그리기 가능
129
-
130
- canvasCtx.restore();
131
- });
132
-
133
- ///////////////////////////////////////////////////////
134
- // 2. Control Panel(메뉴) 생성 (공식 예제 UI)
135
- ///////////////////////////////////////////////////////
136
- new controls
137
- .ControlPanel(controlsElement, {
138
- selfieMode: true,
139
- modelComplexity: 1,
140
- smoothLandmarks: true,
141
- enableSegmentation: false,
142
- smoothSegmentation: true,
143
- minDetectionConfidence: 0.5,
144
- minTrackingConfidence: 0.5,
145
- // 여기서 추가 옵션이나 UI 요소를 더 넣을 수 있음
146
- })
147
- .add([
148
- new controls.StaticText({ title: 'MediaPipe Holistic + Recording' }),
149
- fpsControl,
150
- new controls.Toggle({ title: '셀피 모드', field: 'selfieMode' }),
151
- new controls.Slider({
152
- title: '모델 복잡도',
153
- field: 'modelComplexity',
154
- discrete: ['경량', '일반', '고급'],
155
- }),
156
- new controls.Toggle({ title: '랜드마크 평활화', field: 'smoothLandmarks' }),
157
- new controls.Toggle({ title: '세그먼테이션', field: 'enableSegmentation' }),
158
- new controls.Toggle({ title: '세그먼테이션 평활화', field: 'smoothSegmentation' }),
159
- new controls.Slider({
160
- title: '최소 감지 신뢰도',
161
- field: 'minDetectionConfidence',
162
- range: [0, 1],
163
- step: 0.01
164
- }),
165
- new controls.Slider({
166
- title: '최소 추적 신뢰도',
167
- field: 'minTrackingConfidence',
168
- range: [0, 1],
169
- step: 0.01
170
- }),
171
- ])
172
- .on((options) => {
173
- // ControlPanel에서 변경된 옵션을 Holistic에 반영
174
- videoElement.classList.toggle('selfie', options.selfieMode);
175
- holistic.setOptions(options);
176
- });
177
-
178
- ///////////////////////////////////////////////////////
179
- // 3. 웹캠 열기 & 매 프레임 Holistic 처리
180
- ///////////////////////////////////////////////////////
181
- async function initCamera() {
182
- const stream = await navigator.mediaDevices.getUserMedia({
183
- video: true,
184
- audio: false
185
- });
186
- videoElement.srcObject = stream;
187
- await videoElement.play();
188
-
189
- // 비디오가 로드되면 캔버스 크기 설정 후, 프레임 반복
190
- videoElement.onloadedmetadata = () => {
191
- canvasElement.width = videoElement.videoWidth;
192
- canvasElement.height = videoElement.videoHeight;
193
- requestAnimationFrame(predictFrame);
194
- };
195
- }
196
-
197
- async function predictFrame() {
198
- await holistic.send({ image: videoElement });
199
- requestAnimationFrame(predictFrame);
200
- }
201
-
202
- // 페이지 로드시 카메라 초기화
203
- initCamera().catch((err) => {
204
- console.error('웹캠을 열 수 없습니다:', err);
205
- });
206
-
207
- ///////////////////////////////////////////////////////
208
- // 4. 녹화 시작/중지 버튼 & MediaRecorder
209
- ///////////////////////////////////////////////////////
210
- let mediaRecorder = null;
211
- let recordedChunks = [];
212
- let isRecording = false;
213
-
214
- function startRecording() {
215
- // 캔버스 스트림 추출 (FPS 30)
216
- const canvasStream = canvasElement.captureStream(30);
217
- mediaRecorder = new MediaRecorder(canvasStream, {
218
- mimeType: 'video/webm; codecs=vp9'
219
- });
220
-
221
- mediaRecorder.ondataavailable = (e) => {
222
- if (e.data && e.data.size > 0) {
223
- recordedChunks.push(e.data);
224
- }
225
- };
226
-
227
- mediaRecorder.onstop = () => {
228
- const blob = new Blob(recordedChunks, { type: 'video/webm' });
229
- const url = URL.createObjectURL(blob);
230
-
231
- const a = document.createElement('a');
232
- a.style.display = 'none';
233
- a.href = url;
234
- a.download = 'pose_recording.webm';
235
- document.body.appendChild(a);
236
- a.click();
237
-
238
- setTimeout(() => {
239
- document.body.removeChild(a);
240
- URL.revokeObjectURL(url);
241
- }, 100);
242
-
243
- recordedChunks = [];
244
- };
245
-
246
- mediaRecorder.start();
247
- console.log('녹화 시작!');
248
- }
249
-
250
- function stopRecording() {
251
- if (mediaRecorder) {
252
- mediaRecorder.stop();
253
- console.log('녹화 중지!');
254
- }
255
- }
256
-
257
- const recordBtn = document.createElement('button');
258
- recordBtn.textContent = '녹화 시작';
259
- recordBtn.className = 'control-button';
260
- recordBtn.onclick = () => {
261
- if (!isRecording) {
262
- startRecording();
263
- recordBtn.textContent = '녹화 중지';
264
- } else {
265
- stopRecording();
266
- recordBtn.textContent = '녹화 시작';
267
- }
268
- isRecording = !isRecording;
269
- };
270
- controlsContainer.appendChild(recordBtn);
271
- </script>
272
- </body>
273
- </html>