Files changed (3) hide show
  1. .github/workflows/jekyll-docker.yml +0 -20
  2. README.md +4 -2
  3. index.html +201 -430
.github/workflows/jekyll-docker.yml DELETED
@@ -1,20 +0,0 @@
1
- name: Jekyll site CI
2
-
3
- on:
4
- push:
5
- branches: [ "main" ]
6
- pull_request:
7
- branches: [ "main" ]
8
-
9
- jobs:
10
- build:
11
-
12
- runs-on: ubuntu-latest
13
-
14
- steps:
15
- - uses: actions/checkout@v4
16
- - name: Build the site in the jekyll/builder container
17
- run: |
18
- docker run \
19
- -v ${{ github.workspace }}:/srv/jekyll -v ${{ github.workspace }}/_site:/srv/jekyll/_site \
20
- jekyll/builder:latest /bin/bash -c "chmod -R 777 /srv/jekyll && jekyll build --future"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -1,9 +1,11 @@
1
  ---
2
- title: Episode Visualizer
3
  emoji: 📉
4
  colorFrom: blue
5
  colorTo: pink
6
  sdk: static
7
  app_file: index.html
8
  pinned: false
9
- ---
 
 
 
1
  ---
2
+ title: Test
3
  emoji: 📉
4
  colorFrom: blue
5
  colorTo: pink
6
  sdk: static
7
  app_file: index.html
8
  pinned: false
9
+ ---
10
+
11
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,430 +1,201 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Motion Capture Visualization</title>
8
- <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>
10
- <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap" rel="stylesheet">
11
- <!--'Orbitron', sans-serif;Arial, Helvetica, sans-serif-->
12
- <style>
13
- body {
14
- margin: 0;
15
- padding: 20px;
16
- font-family: 'Orbitron', 'Arial', sans-serif;
17
- background-color: #1a1a1a;
18
- color: #ffffff;
19
- min-height: 90vh;
20
- }
21
-
22
- h1 {
23
- width: 1280px;
24
- color: #ffffff;
25
- margin: 0 auto 30px;
26
- font-size: 30px;
27
- text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.5)
28
- }
29
-
30
- .main-container {
31
- display: grid;
32
- grid-template-columns: 250px 1fr;
33
- gap: 20px;
34
- max-width: 1280px;
35
- margin: 0 auto;
36
- height: calc(100vh - 80px);
37
- }
38
-
39
- /* Panel A: Episodes List */
40
- #episodes-container {
41
- background-color: #2a2a2a;
42
- border-radius: 10px;
43
- padding: 15px;
44
- height: 90%;
45
- overflow-y: auto;
46
- }
47
-
48
- #episodes-title {
49
- color: #ffffff;
50
- margin-top: 0;
51
- padding-bottom: 10px;
52
- border-bottom: 1px solid #3a3a3a;
53
- }
54
-
55
- #episodes-grid {
56
- display: flex;
57
- flex-direction: column;
58
- gap: 4px;
59
- margin-top: 15px;
60
- }
61
-
62
- .episode-radio {
63
- padding: 8px;
64
- border-radius: 6px;
65
- transition: background-color 0.2s;
66
- }
67
-
68
- .episode-radio:hover {
69
- background-color: #3a3a3a;
70
- }
71
-
72
- .episode-radio input[type="radio"] {
73
- margin-right: 10px;
74
- }
75
-
76
- .episode-radio label {
77
- cursor: pointer;
78
- }
79
-
80
- /* Right Content Container */
81
- .content-container {
82
- display: grid;
83
- grid-template-columns: 1fr;
84
- grid-template-rows: auto 1fr;
85
- gap: 20px;
86
- height: 100%;
87
- }
88
-
89
- /* Video Container */
90
- .video-container {
91
- display: flex;
92
- flex-direction: column;
93
- align-items: center;
94
- background-color: #2a2a2a;
95
- border-radius: 10px;
96
- padding: 22px;
97
- height: fit-content;
98
- }
99
-
100
- video {
101
- width: 720px;
102
- border-radius: 6px;
103
- margin-bottom: 15px;
104
- background-color: #000;
105
- }
106
-
107
- .controls {
108
- display: flex;
109
- gap: 10px;
110
- justify-content: center;
111
- padding: 10px 0;
112
- }
113
-
114
- .controls button {
115
- background-color: #3a3a3a;
116
- border: none;
117
- border-radius: 6px;
118
- padding: 4px 8px;
119
- cursor: pointer;
120
- transition: background-color 0.2s;
121
- font-size: 18px;
122
- }
123
-
124
- .controls button:hover {
125
- background-color: #4a4a4a;
126
- }
127
-
128
- /* Plot Container */
129
- #plotDiv {
130
- background-color: #2a2a2a;
131
- border-radius: 10px;
132
- padding: 15px;
133
- width: 720px;
134
- height: 550px;
135
- }
136
-
137
- #loadingIndicator {
138
- position: fixed;
139
- top: 50%;
140
- left: 50%;
141
- transform: translate(-50%, -50%);
142
- background-color: rgba(0, 0, 0, 0.8);
143
- padding: 20px 40px;
144
- border-radius: 10px;
145
- display: none;
146
- }
147
-
148
- /* Scrollbar Styling */
149
- ::-webkit-scrollbar {
150
- width: 8px;
151
- }
152
-
153
- ::-webkit-scrollbar-track {
154
- background: #2a2a2a;
155
- }
156
-
157
- ::-webkit-scrollbar-thumb {
158
- background: #4a4a4a;
159
- border-radius: 4px;
160
- }
161
-
162
- ::-webkit-scrollbar-thumb:hover {
163
- background: #5a5a5a;
164
- }
165
-
166
- </style>
167
- </head>
168
-
169
- <body>
170
- <h1>Motion Capture Visualization</h1>
171
-
172
- <div class="main-container">
173
- <!-- Panel A: Episodes List -->
174
- <div id="episodes-container">
175
- <h3 id="episodes-title">Episodes</h3>
176
- <div id="episodes-grid"></div>
177
- </div>
178
-
179
- <div class="content-container">
180
- <!-- Panel B: Video Player -->
181
- <div class="video-container">
182
- <video id="laptopVideo">
183
- <source src="https://huggingface.co/datasets/cyberorigin/fold_towels/resolve/main/Video/video.mp4"
184
- type="video/mp4">
185
- Your browser does not support the video tag.
186
- </video>
187
- <div class="controls">
188
- <button id="playPauseBtn">▶️</button>
189
- <button id="rewindBtn">⏪</button>
190
- <button id="forwardBtn">⏩</button>
191
- <button id="restartBtn">↩️</button>
192
- </div>
193
- <!-- Panel C: Plot Visualization -->
194
- <div id="plotDiv"></div>
195
- </div>
196
- </div>
197
- </div>
198
-
199
- <div id="loadingIndicator">Loading...</div>
200
-
201
- <script>
202
- let csvFilePath = 'https://huggingface.co/datasets/cyberorigin/fold_towels/resolve/main/MoCap/mocap.csv';
203
- const body_part_names = [
204
- 'Left Shoulder', 'Right Upper Arm', 'Left Lower Leg', 'Spine1', 'Right Upper Leg',
205
- 'Spine3', 'Right Lower Arm', 'Left Foot', 'Right Lower Leg', 'Right Shoulder',
206
- 'Left Hand', 'Left Upper Leg', 'Right Foot', 'Spine', 'Spine2', 'Left Lower Arm',
207
- 'Left Toe', 'Neck', 'Right Hand', 'Right Toe', 'Head', 'Left Upper Arm', 'Hips'
208
- ];
209
- const laptopVideo = document.getElementById('laptopVideo');
210
- const playPauseBtn = document.getElementById('playPauseBtn');
211
- const rewindBtn = document.getElementById('rewindBtn');
212
- const forwardBtn = document.getElementById('forwardBtn');
213
- const restartBtn = document.getElementById('restartBtn');
214
- const radioButtons = document.querySelectorAll('input[name="videoOption"]');
215
- const episodeContainer = document.getElementById('episodes-container');
216
- const episodesGrid = document.getElementById('episodes-grid');
217
- document.addEventListener('DOMContentLoaded', loadEpisodesCsv);
218
- function loadEpisodesCsv() {
219
- fetch("https://huggingface.co/datasets/cyberorigin/test/resolve/main/episodes.csv")
220
- .then(response => response.text())
221
- .then(data => {
222
- const lines = data.split('\n');
223
- processEpisodes(lines);
224
- })
225
- .catch(error => console.error('Error loading CSV file:', error));
226
- }
227
- function processEpisodes(lines) {
228
- episodesGrid.innerHTML = '';
229
- lines.forEach((line, index) => {
230
- if (line.trim() !== '' && index != 0) {
231
- const id = line.split(',')[0];
232
- const episodeNumber = index;
233
-
234
- const radioDiv = document.createElement('div');
235
- radioDiv.className = 'episode-radio';
236
-
237
- const radio = document.createElement('input');
238
- radio.type = 'radio';
239
- radio.id = `episode${episodeNumber}`;
240
- radio.name = 'episodeGroup';
241
- radio.addEventListener('change', () => updateVideoAndCSVSource(id));
242
-
243
- const label = document.createElement('label');
244
- label.htmlFor = `episode${episodeNumber}`;
245
- label.textContent = `Episode ${episodeNumber}`;
246
-
247
- radioDiv.appendChild(radio);
248
- radioDiv.appendChild(label);
249
- episodesGrid.appendChild(radioDiv);
250
- }
251
- });
252
- }
253
-
254
-
255
- let totalEpisodes = 100;
256
- // const container = document.getElementById('episodes-container')
257
-
258
- let animationFrameId;
259
- let isPlaying = false;
260
- function togglePlayPause() {
261
- if (!isPlaying) {
262
- laptopVideo.play();
263
- playPauseBtn.textContent = '⏸️';
264
- isPlaying = true;
265
- animate3DVisualization();
266
- } else {
267
- laptopVideo.pause();
268
- playPauseBtn.textContent = '▶️';
269
- isPlaying = false;
270
- cancelAnimationFrame(animationFrameId);
271
- }
272
- }
273
-
274
- function rewind() {
275
- laptopVideo.currentTime -= 5;
276
- update3DVisualization();
277
- }
278
-
279
- function forward() {
280
- laptopVideo.currentTime += 5;
281
- update3DVisualization();
282
- }
283
-
284
- function restart() {
285
- laptopVideo.currentTime = 0;
286
- update3DVisualization();
287
- }
288
- playPauseBtn.addEventListener('click', togglePlayPause);
289
- rewindBtn.addEventListener('click', rewind);
290
- forwardBtn.addEventListener('click', forward);
291
- restartBtn.addEventListener('click', restart);
292
- function getCoordinates(data, coordinate) {
293
- return body_part_names.map(part => parseFloat(data[`${part}_${coordinate}`]));
294
- }
295
- let frames;
296
- function processData(results) {
297
- console.log("Processing data:", results);
298
- const motion_capture_data = results.data.filter((_, index) => index % 3 === 0);
299
- frames = motion_capture_data.map((row, index) => ({
300
- name: index.toString(),
301
- data: [{
302
- x: getCoordinates(row, 'x'),
303
- y: getCoordinates(row, 'y'),
304
- z: getCoordinates(row, 'z'),
305
- mode: 'markers',
306
- type: 'scatter3d',
307
- marker: { size: 4.8, color: "blue" }
308
- }]
309
- }));
310
- if (frames.length === 0) {
311
- console.error("No frames were created from the data");
312
- return;
313
- }
314
- const initialFrame = frames[0].data[0]
315
- // Config canvas layout styles
316
- const layout = {
317
- title: {
318
- text: '3D Motion Capture',
319
- font: {
320
- color: 'white',
321
- size: 20
322
- },
323
- x: 0.5,
324
- y: 1.2
325
- },
326
- paper_bgcolor: 'black',
327
- plot_bgcolor: 'black',
328
- scene: {
329
- xaxis: {
330
- title: 'X',
331
- color: 'white',
332
- gridcolor: 'gray'
333
- },
334
- yaxis: {
335
- title: 'Y',
336
- color: 'white',
337
- gridcolor: 'gray'
338
- },
339
- zaxis: {
340
- title: 'Z',
341
- color: 'white',
342
- gridcolor: 'gray'
343
- },
344
- bgcolor: 'black'
345
- },
346
- font: {color: 'white'},
347
- margin: {
348
- l: 2,
349
- r: 2,
350
- b: 2,
351
- t: 50,
352
- pad: 4,
353
- },
354
- }
355
- Plotly.newPlot('plotDiv', [initialFrame], layout)
356
- }
357
-
358
- function update3DVisualization() {
359
- if (!frames) return
360
- const currentTime = laptopVideo.currentTime
361
- const totalDuration = laptopVideo.duration
362
- const frameIndex = Math.floor((currentTime / totalDuration) * frames.length)
363
- const frame = frames[Math.min(frameIndex, frames.length - 1)]
364
- Plotly.animate('plotDiv', frame, {
365
- transition: {duration: 0},
366
- frame: {duration: 0, redraw: true},
367
- })
368
- }
369
-
370
- function animate3DVisualization() {
371
- update3DVisualization()
372
- if (isPlaying) {
373
- animationFrameId = requestAnimationFrame(animate3DVisualization)
374
- }
375
- }
376
-
377
- //function updateVideoAndCSVSource() {
378
- //const selectedOption = document.querySelector('input[name="videoOption"]:checked').value;
379
- //const videoUrl = `https://huggingface.co/datasets/cyberorigin/${selectedOption}/resolve/main/Video/video.mp4`;
380
- //if (selectedOption != "twist_the_tube") {
381
- // csvFilePath = `https://huggingface.co/datasets/cyberorigin/${selectedOption}/resolve/main/MoCap/mocap.csv`;
382
- //}
383
- //else {
384
- // csvFilePath = `https://huggingface.co/datasets/cyberorigin/${selectedOption}/resolve/main/MoCap/MoCap.csv`;
385
- //}
386
- function updateVideoAndCSVSource(id) {
387
- const selectedOption = document.querySelector('input[name="episodeGroup"]:checked').value;
388
- const videoUrl = `https://huggingface.co/datasets/cyberorigin/pick_and_place/resolve/main/color/${id}.mp4`;
389
- csvFilePath = `https://huggingface.co/datasets/cyberorigin/pick_and_place/resolve/main/motion_capture/${id}.csv`;
390
-
391
- laptopVideo.pause();
392
-
393
- laptopVideo.querySelector('source').src = videoUrl;
394
-
395
- laptopVideo.load();
396
-
397
- isPlaying = false;
398
- playPauseBtn.textContent = '▶️';
399
- // Fetch and process the new CSV data
400
- fetchAndProcessActionCSV();
401
- }
402
-
403
- function fetchAndProcessActionCSV() {
404
- fetch(csvFilePath)
405
- .then(response => {
406
- if (!response.ok) {
407
- throw new Error(`HTTP error! status: ${response.status}`);
408
- }
409
- return response.text();
410
- })
411
- .then(csvString => {
412
- console.log("CSV data loaded successfully");
413
- Papa.parse(csvString, {
414
- header: true,
415
- dynamicTyping: true,
416
- complete: processData
417
- });
418
- })
419
- .catch(error => console.error('Error loading the CSV file:', error));
420
- }
421
-
422
- //radioButtons.forEach(radio => {
423
- // radio.addEventListener('change', updateVideoAndCSVSource);
424
- //});
425
- // Initial CSV fetch and processing
426
- fetchAndProcessActionCSV();
427
- </script>
428
- </body>
429
-
430
- </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Synchronized 3D Motion Capture Visualization with Video</title>
8
+ <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>
10
+ <style>
11
+ body {
12
+ font-family: Arial, sans-serif;
13
+ margin: 0;
14
+ padding: 20px;
15
+ display: flex;
16
+ flex-direction: column;
17
+ align-items: center;
18
+ }
19
+
20
+ #plotDiv {
21
+ width: 100%;
22
+ height: 600px;
23
+ }
24
+
25
+ .video-container {
26
+ display: flex;
27
+ justify-content: space-around;
28
+ width: 100%;
29
+ margin-bottom: 20px;
30
+ }
31
+
32
+ .video-wrapper {
33
+ width: 45%;
34
+ }
35
+
36
+ video {
37
+ width: 100%;
38
+ height: auto;
39
+ }
40
+
41
+ .controls {
42
+ display: flex;
43
+ justify-content: center;
44
+ margin-top: 10px;
45
+ }
46
+
47
+ button {
48
+ margin: 0 5px;
49
+ font-size: 20px;
50
+ }
51
+ </style>
52
+ </head>
53
+
54
+ <body>
55
+ <h1>Synchronized 3D Motion Capture Visualization with Video</h1>
56
+
57
+ <div class="video-container">
58
+ <div class="video-wrapper">
59
+ <video id="laptopVideo">
60
+ <source src="https://huggingface.co/datasets/cyberorigin/fold_towels/resolve/main/Video/video.mp4" type="video/mp4">
61
+ Your browser does not support the video tag.
62
+ </video>
63
+ </div>
64
+ </div>
65
+
66
+ <div class="controls">
67
+ <button id="playPauseBtn">▶️</button>
68
+ <button id="rewindBtn">⏪</button>
69
+ <button id="forwardBtn">⏩</button>
70
+ <button id="restartBtn">↩️</button>
71
+ </div>
72
+
73
+ <div id="plotDiv"></div>
74
+
75
+ <script>
76
+ const body_part_names = [
77
+ 'Left Shoulder', 'Right Upper Arm', 'Left Lower Leg', 'Spine1', 'Right Upper Leg',
78
+ 'Spine3', 'Right Lower Arm', 'Left Foot', 'Right Lower Leg', 'Right Shoulder',
79
+ 'Left Hand', 'Left Upper Leg', 'Right Foot', 'Spine', 'Spine2', 'Left Lower Arm',
80
+ 'Left Toe', 'Neck', 'Right Hand', 'Right Toe', 'Head', 'Left Upper Arm', 'Hips'
81
+ ];
82
+
83
+ const laptopVideo = document.getElementById('laptopVideo');
84
+ const playPauseBtn = document.getElementById('playPauseBtn');
85
+ const rewindBtn = document.getElementById('rewindBtn');
86
+ const forwardBtn = document.getElementById('forwardBtn');
87
+ const restartBtn = document.getElementById('restartBtn');
88
+
89
+ let animationFrameId;
90
+ let isPlaying = false;
91
+ let frames;
92
+
93
+ function togglePlayPause() {
94
+ if (!isPlaying) {
95
+ laptopVideo.play();
96
+ playPauseBtn.textContent = '⏸️';
97
+ isPlaying = true;
98
+ animate3DVisualization();
99
+ } else {
100
+ laptopVideo.pause();
101
+ playPauseBtn.textContent = '▶️';
102
+ isPlaying = false;
103
+ cancelAnimationFrame(animationFrameId);
104
+ }
105
+ }
106
+
107
+ function rewind() {
108
+ laptopVideo.currentTime -= 5;
109
+ update3DVisualization();
110
+ }
111
+
112
+ function forward() {
113
+ laptopVideo.currentTime += 5;
114
+ update3DVisualization();
115
+ }
116
+
117
+ function restart() {
118
+ laptopVideo.currentTime = 0;
119
+ update3DVisualization();
120
+ }
121
+
122
+ playPauseBtn.addEventListener('click', togglePlayPause);
123
+ rewindBtn.addEventListener('click', rewind);
124
+ forwardBtn.addEventListener('click', forward);
125
+ restartBtn.addEventListener('click', restart);
126
+
127
+ function getCoordinates(data, coordinate) {
128
+ return body_part_names.map(part => parseFloat(data[`${part}_${coordinate}`]));
129
+ }
130
+
131
+ function processData(results) {
132
+ console.log("Processing data:", results);
133
+
134
+ const motion_capture_data = results.data.filter((_, index) => index % 3 === 0);
135
+ frames = motion_capture_data.map((row, index) => ({
136
+ name: index.toString(),
137
+ data: [{
138
+ x: getCoordinates(row, 'x'),
139
+ y: getCoordinates(row, 'y'),
140
+ z: getCoordinates(row, 'z'),
141
+ mode: 'markers',
142
+ type: 'scatter3d',
143
+ marker: { size: 5, color: 'blue' }
144
+ }]
145
+ }));
146
+ if (frames.length === 0) {
147
+ console.error("No frames were created from the data");
148
+ return;
149
+ }
150
+ const initialFrame = frames[0].data[0];
151
+
152
+ const layout = {
153
+ title: '3D Motion Capture',
154
+ scene: {
155
+ xaxis: { title: 'X' },
156
+ yaxis: { title: 'Y' },
157
+ zaxis: { title: 'Z' }
158
+ }
159
+ };
160
+
161
+ Plotly.newPlot('plotDiv', [initialFrame], layout);
162
+ }
163
+
164
+ function update3DVisualization() {
165
+ if (!frames) return;
166
+ const currentTime = laptopVideo.currentTime;
167
+ const totalDuration = laptopVideo.duration;
168
+ const frameIndex = Math.floor((currentTime / totalDuration) * frames.length);
169
+ const frame = frames[Math.min(frameIndex, frames.length - 1)];
170
+ Plotly.animate('plotDiv', frame, {
171
+ transition: { duration: 0 },
172
+ frame: { duration: 0, redraw: true }
173
+ });
174
+ }
175
+
176
+ function animate3DVisualization() {
177
+ update3DVisualization();
178
+ if (isPlaying) {
179
+ animationFrameId = requestAnimationFrame(animate3DVisualization);
180
+ }
181
+ }
182
+
183
+ async function loadDataset() {
184
+ const response = await fetch('https://huggingface.co/api/datasets/cyberorigin/fold_towels/resolve/main/MoCap/mocap.csv');
185
+ if (!response.ok) {
186
+ throw new Error(`HTTP error! status: ${response.status}`);
187
+ }
188
+ const csvString = await response.text();
189
+ console.log("CSV data loaded successfully");
190
+ Papa.parse(csvString, {
191
+ header: true,
192
+ dynamicTyping: true,
193
+ complete: processData
194
+ });
195
+ }
196
+
197
+ loadDataset().catch(error => console.error('Error loading the CSV file:', error));
198
+ </script>
199
+ </body>
200
+
201
+ </html>