Files changed (3) hide show
  1. .github/workflows/jekyll-docker.yml +0 -20
  2. README.md +4 -2
  3. index.html +61 -310
.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
@@ -4,93 +4,33 @@
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
- font-family: 'Orbitron', sans-serif;
15
  margin: 0;
16
  padding: 20px;
17
  display: flex;
18
  flex-direction: column;
19
  align-items: center;
20
- background-color: #000;
21
- color: #fff;
22
  }
23
 
24
- h1 {
25
- color: gold;
26
- text-shadow: 2px 2px 4px rgba(255, 215, 0, 0.5);
27
- }
28
-
29
- .main-container {
30
- display: flex;
31
  width: 100%;
32
- max-width: 1500px;
33
- margin-top: 100px;
34
- }
35
-
36
- .episode-list {
37
- width: 150px;
38
- margin-right: 0px;
39
- }
40
-
41
- .episode-list label {
42
- display: block;
43
- margin-bottom: 10px;
44
- color: #ddd;
45
- }
46
-
47
- .content-container {
48
- display: flex;
49
- justify-content: space-between;
50
- flex-grow: 1;
51
- margin-left: 120px;
52
  }
53
 
54
  .video-container {
55
- width: 58%;
56
- }
57
-
58
- #plotDiv {
59
- width: 460px;
60
- height: 485px;
61
- }
62
-
63
- #episodes-container {
64
- max-height: 500px;
65
- width: 210px;
66
- overflow-y: auto;
67
- overflow-x: hidden;
68
- border: 1px solid #ccc;
69
- border-radius: 5px;
70
- background-color: #222;
71
- margin-left: 10px;
72
- }
73
-
74
- #episodes-title {
75
- background-color: #222;
76
- color: #fff;
77
- padding: 10px;
78
- margin: 0;
79
- position: sticky;
80
- top: 0;
81
- z-index: 1;
82
- }
83
-
84
- #episodes-grid {
85
- display: grid;
86
- grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
87
- gap: 2px;
88
- padding: 10px;
89
  }
90
 
91
- .episode-radio {
92
- display: flex;
93
- align-items: center;
94
  }
95
 
96
  video {
@@ -101,191 +41,55 @@
101
  .controls {
102
  display: flex;
103
  justify-content: center;
104
- margin-top: 2px;
105
  }
106
 
107
- · button {
108
  margin: 0 5px;
109
  font-size: 20px;
110
- background-color: #333;
111
- color: #fff;
112
- border: none;
113
- padding: 5px 10px;
114
- cursor: pointer;
115
- }
116
-
117
- .checkbox-container label {
118
- display: block;
119
- margin-bottom: 20px;
120
- }
121
-
122
- #loadingIndicator {
123
- display: none;
124
- position: fixed;
125
- top: 50%;
126
- left: 50%;
127
- transform: translate(-50%, -50%);
128
- background-color: rgba(0, 0, 0, 0.7);
129
- color: rgb(255, 255, 255);
130
- padding: 20px;
131
- border-radius: 5px;
132
- z-index: 1000;
133
- }
134
-
135
- .checkbox-list {
136
- max-height: 400px;
137
- /* 设置最大高度,超过此高度会出现滚动条 */
138
- overflow-y: auto;
139
- /* 添加垂直滚动条 */
140
- padding-right: 10px;
141
- /* 为滚动条留出空间 */
142
- }
143
-
144
- .checkbox-list label {
145
- display: block;
146
- margin-bottom: 0px;
147
- color: #ddd;
148
- }
149
-
150
- .checkbox-list input[type="checkbox"] {
151
- margin-right: 10px;
152
- }
153
-
154
- /* 自定义滚动条样式(针对WebKit浏览器) */
155
- .checkbox-list::-webkit-scrollbar {
156
- width: 0px;
157
- }
158
-
159
- .checkbox-list::-webkit-scrollbar-track {
160
- background: #333;
161
- border-radius: 4px;
162
- }
163
-
164
- .checkbox-list::-webkit-scrollbar-thumb {
165
- background: #666;
166
- border-radius: 4px;
167
- }
168
-
169
- .checkbox-list::-webkit-scrollbar-thumb:hover {
170
- background: #888;
171
  }
172
  </style>
173
  </head>
174
 
175
  <body>
176
- <h1>Motion Capture Visualization</h1>
177
-
178
- <div class="main-container">
179
- <!--
180
- <div class="episode-list">
181
- <h3>Episodes</h3>
182
- <label><input type="checkbox"> Episode 1</label>
183
- <label><input type="checkbox"> Episode 2</label>
184
- <label><input type="checkbox"> Episode 29</label>
185
- <label><input type="checkbox"> Episode 30</label>
186
  </div>
187
- -->
188
- <div id="episodes-container">
189
- <h3 id="episodes-title">Episodes</h3>
190
- <div id="episodes-grid"></div>
191
- </div>
192
- <div class="content-container">
193
- <!--
194
- <div class="checkbox-container">
195
- <h3>Tasks</h3>
196
- <label>
197
- <input type="radio" name="videoOption" value="fold_towels" checked> Fold towels
198
- </label>
199
- <label>
200
- <input type="radio" name="videoOption" value="pipette"> Pipette
201
- </label>
202
- <label>
203
- <input type="radio" name="videoOption" value="take_the_item"> Take the item
204
- </label>
205
- <label>
206
- <input type="radio" name="videoOption" value="twist_the_tube"> Twist the tube
207
- </label>
208
- </div>-->
209
 
210
- <div class="video-container">
211
- <video id="laptopVideo">
212
- <source src="https://huggingface.co/datasets/cyberorigin/fold_towels/resolve/main/Video/video.mp4"
213
- type="video/mp4">
214
- Your browser does not support the video tag.
215
- </video>
216
- <div class="controls">
217
- <button id="playPauseBtn">▶️</button>
218
- <button id="rewindBtn">⏪</button>
219
- <button id="forwardBtn">⏩</button>
220
- <button id="restartBtn">↩️</button>
221
- </div>
222
- </div>
223
- <div id="plotDiv"></div>
224
- </div>
225
  </div>
226
 
227
- <div id="loadingIndicator">Loading...</div>
228
 
229
  <script>
230
- let csvFilePath = 'https://huggingface.co/datasets/cyberorigin/fold_towels/resolve/main/MoCap/mocap.csv';
231
  const body_part_names = [
232
  'Left Shoulder', 'Right Upper Arm', 'Left Lower Leg', 'Spine1', 'Right Upper Leg',
233
  'Spine3', 'Right Lower Arm', 'Left Foot', 'Right Lower Leg', 'Right Shoulder',
234
  'Left Hand', 'Left Upper Leg', 'Right Foot', 'Spine', 'Spine2', 'Left Lower Arm',
235
  'Left Toe', 'Neck', 'Right Hand', 'Right Toe', 'Head', 'Left Upper Arm', 'Hips'
236
  ];
 
237
  const laptopVideo = document.getElementById('laptopVideo');
238
  const playPauseBtn = document.getElementById('playPauseBtn');
239
  const rewindBtn = document.getElementById('rewindBtn');
240
  const forwardBtn = document.getElementById('forwardBtn');
241
  const restartBtn = document.getElementById('restartBtn');
242
- const radioButtons = document.querySelectorAll('input[name="videoOption"]');
243
- const episodeContainer = document.getElementById('episodes-container');
244
- const episodesGrid = document.getElementById('episodes-grid');
245
- document.addEventListener('DOMContentLoaded', loadEpisodesCsv);
246
- function loadEpisodesCsv() {
247
- fetch("https://huggingface.co/datasets/cyberorigin/test/resolve/main/episodes.csv")
248
- .then(response => response.text())
249
- .then(data => {
250
- const lines = data.split('\n');
251
- processEpisodes(lines);
252
- })
253
- .catch(error => console.error('Error loading CSV file:', error));
254
- }
255
- function processEpisodes(lines) {
256
- episodesGrid.innerHTML = '';
257
- lines.forEach((line, index) => {
258
- if (line.trim() !== '' && index != 0) {
259
- const id = line.split(',')[0];
260
- const episodeNumber = index;
261
-
262
- const radioDiv = document.createElement('div');
263
- radioDiv.className = 'episode-radio';
264
-
265
- const radio = document.createElement('input');
266
- radio.type = 'radio';
267
- radio.id = `episode${episodeNumber}`;
268
- radio.name = 'episodeGroup';
269
- radio.addEventListener('change', () => updateVideoAndCSVSource(id));
270
-
271
- const label = document.createElement('label');
272
- label.htmlFor = `episode${episodeNumber}`;
273
- label.textContent = `Episode ${episodeNumber}`;
274
-
275
- radioDiv.appendChild(radio);
276
- radioDiv.appendChild(label);
277
- episodesGrid.appendChild(radioDiv);
278
- }
279
- });
280
- }
281
-
282
-
283
- let totalEpisodes = 100; //获取episode的数量
284
- // const container = document.getElementById('episodes-container')
285
- // 循环创建复选框
286
 
287
  let animationFrameId;
288
  let isPlaying = false;
 
 
289
  function togglePlayPause() {
290
  if (!isPlaying) {
291
  laptopVideo.play();
@@ -299,28 +103,34 @@
299
  cancelAnimationFrame(animationFrameId);
300
  }
301
  }
 
302
  function rewind() {
303
  laptopVideo.currentTime -= 5;
304
  update3DVisualization();
305
  }
 
306
  function forward() {
307
  laptopVideo.currentTime += 5;
308
  update3DVisualization();
309
  }
 
310
  function restart() {
311
  laptopVideo.currentTime = 0;
312
  update3DVisualization();
313
  }
 
314
  playPauseBtn.addEventListener('click', togglePlayPause);
315
  rewindBtn.addEventListener('click', rewind);
316
  forwardBtn.addEventListener('click', forward);
317
  restartBtn.addEventListener('click', restart);
 
318
  function getCoordinates(data, coordinate) {
319
  return body_part_names.map(part => parseFloat(data[`${part}_${coordinate}`]));
320
  }
321
- let frames;
322
  function processData(results) {
323
  console.log("Processing data:", results);
 
324
  const motion_capture_data = results.data.filter((_, index) => index % 3 === 0);
325
  frames = motion_capture_data.map((row, index) => ({
326
  name: index.toString(),
@@ -330,7 +140,7 @@
330
  z: getCoordinates(row, 'z'),
331
  mode: 'markers',
332
  type: 'scatter3d',
333
- marker: { size: 4.8, color: "blue" }
334
  }]
335
  }));
336
  if (frames.length === 0) {
@@ -338,47 +148,19 @@
338
  return;
339
  }
340
  const initialFrame = frames[0].data[0];
 
341
  const layout = {
342
- title: {
343
- text: '3D Motion Capture',
344
- font: {
345
- color: 'white',
346
- size: 20 // 设置字体大小
347
- },
348
- x: 0.5, // 设置标题在x轴的位置(0.5表示居中)
349
- y: 1.2
350
- },
351
- paper_bgcolor: 'black',
352
- plot_bgcolor: 'black',
353
  scene: {
354
- xaxis: {
355
- title: 'X',
356
- color: 'white',
357
- gridcolor: 'gray'
358
- },
359
- yaxis: {
360
- title: 'Y',
361
- color: 'white',
362
- gridcolor: 'gray'
363
- },
364
- zaxis: {
365
- title: 'Z',
366
- color: 'white',
367
- gridcolor: 'gray'
368
- },
369
- bgcolor: 'black'
370
- },
371
- font: { color: 'white' },
372
- margin: {
373
- l: 2, // 左边距
374
- r: 2, // 右边距
375
- b: 2, // 底部边距
376
- t: 50, // 顶部边距
377
- pad: 4 // 图表内边距
378
  }
379
  };
 
380
  Plotly.newPlot('plotDiv', [initialFrame], layout);
381
  }
 
382
  function update3DVisualization() {
383
  if (!frames) return;
384
  const currentTime = laptopVideo.currentTime;
@@ -390,61 +172,30 @@
390
  frame: { duration: 0, redraw: true }
391
  });
392
  }
 
393
  function animate3DVisualization() {
394
  update3DVisualization();
395
  if (isPlaying) {
396
  animationFrameId = requestAnimationFrame(animate3DVisualization);
397
  }
398
  }
399
- //function updateVideoAndCSVSource() {
400
- //const selectedOption = document.querySelector('input[name="videoOption"]:checked').value;
401
- //const videoUrl = `https://huggingface.co/datasets/cyberorigin/${selectedOption}/resolve/main/Video/video.mp4`;
402
- //if (selectedOption != "twist_the_tube") {
403
- // csvFilePath = `https://huggingface.co/datasets/cyberorigin/${selectedOption}/resolve/main/MoCap/mocap.csv`;
404
- //}
405
- //else {
406
- // csvFilePath = `https://huggingface.co/datasets/cyberorigin/${selectedOption}/resolve/main/MoCap/MoCap.csv`;
407
- //}
408
- function updateVideoAndCSVSource(id) {
409
- const selectedOption = document.querySelector('input[name="episodeGroup"]:checked').value;
410
- const videoUrl = `https://huggingface.co/datasets/cyberorigin/pick_and_place/resolve/main/color/${id}.mp4`;
411
- csvFilePath = `https://huggingface.co/datasets/cyberorigin/pick_and_place/resolve/main/motion_capture/${id}.csv`;
412
-
413
- laptopVideo.pause();
414
-
415
- laptopVideo.querySelector('source').src = videoUrl;
416
 
417
- laptopVideo.load();
418
-
419
- isPlaying = false;
420
- playPauseBtn.textContent = '▶️';
421
- // Fetch and process the new CSV data
422
- fetchAndProcessActionCSV();
423
- }
424
- function fetchAndProcessActionCSV() {
425
- fetch(csvFilePath)
426
- .then(response => {
427
- if (!response.ok) {
428
- throw new Error(`HTTP error! status: ${response.status}`);
429
- }
430
- return response.text();
431
- })
432
- .then(csvString => {
433
- console.log("CSV data loaded successfully");
434
- Papa.parse(csvString, {
435
- header: true,
436
- dynamicTyping: true,
437
- complete: processData
438
- });
439
- })
440
- .catch(error => console.error('Error loading the CSV file:', error));
441
  }
442
- //radioButtons.forEach(radio => {
443
- // radio.addEventListener('change', updateVideoAndCSVSource);
444
- //});
445
- // Initial CSV fetch and processing
446
- fetchAndProcessActionCSV();
447
  </script>
448
  </body>
449
 
450
- </html>
 
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 {
 
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();
 
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(),
 
140
  z: getCoordinates(row, 'z'),
141
  mode: 'markers',
142
  type: 'scatter3d',
143
+ marker: { size: 5, color: 'blue' }
144
  }]
145
  }));
146
  if (frames.length === 0) {
 
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;
 
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>