hyungonryu commited on
Commit
31bd05a
·
verified ·
1 Parent(s): 958cac2

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +266 -0
app.py ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ html_code = """
4
+ <!DOCTYPE html>
5
+ <html>
6
+ <head>
7
+ <meta charset="utf-8">
8
+ <title>Video Sync with Custom UI</title>
9
+ <style>
10
+ body { font-family: sans-serif; margin: 20px; }
11
+ table { margin: 0 auto; }
12
+ td { padding: 5px; vertical-align: middle; }
13
+ .slider, .timeline-slider { }
14
+ .video-container-wrapper { position: relative; display: inline-block; }
15
+ .video-container {
16
+ position: relative;
17
+ width: 640px;
18
+ height: 480px;
19
+ background: #000;
20
+ overflow: hidden;
21
+ }
22
+ .video {
23
+ position: absolute;
24
+ top: 0;
25
+ left: 0;
26
+ width: 640px;
27
+ height: 480px;
28
+ object-fit: cover;
29
+ }
30
+ .wipe-line {
31
+ position: absolute;
32
+ top: 0;
33
+ width: 2px;
34
+ height: 100%;
35
+ background: blue;
36
+ pointer-events: none;
37
+ }
38
+ </style>
39
+ </head>
40
+ <body>
41
+ <center>
42
+ <h1>Geostationary Satellite Time Interpolation</h1>
43
+ <h4>Hyun Gon Ryu | NVIDIA AI Technology Center Korea</h4>
44
+ </center>
45
+ <table>
46
+ <tr>
47
+ <td width="700">
48
+ <font size="1">
49
+ This demo video consists of images generated at one-minute intervals from the KMA GK2A satellite's full-disk images, originally captured at ten-minute intervals, using the VFI technique. By using the wipe scrollbar, you can compare the original video (delineated by a blue line) with the enhanced version. You can adjust the zoom and playback speed, and when played at 0.3x speed, the differences between the two videos become distinctly apparent.
50
+ </font>
51
+ </td>
52
+ </tr>
53
+ </table>
54
+
55
+ <!-- Video set selection -->
56
+ <table id="videoSetTable">
57
+ <tr>
58
+ <td>
59
+ Select Video Set:
60
+ <select id="videoSetSelect">
61
+ <option value="">No</option>
62
+ <option value="0">TongA Case | 20220116 | ir105</option>
63
+ <option value="1">SouthAsia | 20240820 | ir105</option>
64
+ <option value="2">EastAsia | 20240820 | ir105</option>
65
+ <option value="3">SouthWestAsia | 20240820 | ir105</option>
66
+ </select>
67
+ </td>
68
+ </tr>
69
+ </table>
70
+
71
+ <table id="controlTable">
72
+ <!-- 1st Row: Play button, Speed, Screen Size -->
73
+ <tr>
74
+ <td>
75
+ <button id="playPauseBtn">PLAY</button>
76
+ </td>
77
+ <td>
78
+ Screen Size:
79
+ <select id="scaleSelect">
80
+ <option value="0.5">0.5</option>
81
+ <option value="1" selected>1</option>
82
+ <option value="1.5">1.5</option>
83
+ <option value="2">2</option>
84
+ </select>
85
+ </td>
86
+ <td>
87
+ Speed:
88
+ <select id="speedSelect">
89
+ <option value="0.1">0.1</option>
90
+ <option value="0.2">0.2</option>
91
+ <option value="0.3">0.3</option>
92
+ <option value="0.4">0.4</option>
93
+ <option value="0.5">0.5</option>
94
+ <option value="0.6">0.6</option>
95
+ <option value="0.7">0.7</option>
96
+ <option value="0.8">0.8</option>
97
+ <option value="0.9">0.9</option>
98
+ <option value="1" selected>1</option>
99
+ <option value="2">2</option>
100
+ <option value="4">4</option>
101
+ </select>
102
+ </td>
103
+ </tr>
104
+
105
+ <!-- 2nd Row: Wipe Slider -->
106
+ <tr>
107
+ <td colspan="3">
108
+ <input type="range" id="wipeRange" class="slider" min="0" max="1" step="0.01" value="0.5">
109
+ </td>
110
+ </tr>
111
+
112
+ <!-- 3rd Row: Timeline Slider -->
113
+ <tr>
114
+ <td colspan="3">
115
+ <input type="range" id="timelineRange" class="timeline-slider" min="0" max="100" step="0.1" value="0">
116
+ </td>
117
+ </tr>
118
+
119
+ <!-- 4th Row: Video Area -->
120
+ <tr>
121
+ <td colspan="3">
122
+ <div class="video-container-wrapper">
123
+ <div class="video-container" id="videoContainer">
124
+ <video id="video1" class="video" src="video1.mp4" preload="auto" muted></video>
125
+ <video id="video2" class="video" src="video2.mp4" preload="auto" muted></video>
126
+ <div id="wipeLine" class="wipe-line"></div>
127
+ </div>
128
+ </div>
129
+ </td>
130
+ </tr>
131
+ </table>
132
+
133
+ <script>
134
+ // Base width remains constant.
135
+ const baseWidth = 640;
136
+
137
+ // Predefined video sets.
138
+ const videoSets = [
139
+ { label: "TongA Case", area: "TongaArea", date: "20220116", sensor: "ir105" },
140
+ { label: "SouthAsia", area: "SouthAsia", date: "20240820", sensor: "ir105" },
141
+ { label: "EastAsia", area: "EastAsia", date: "20240820", sensor: "ir105" },
142
+ { label: "SouthWestAsia", area: "WestAsia", date: "20240820", sensor: "ir105" },
143
+ ];
144
+
145
+ // Get DOM elements.
146
+ const video1 = document.getElementById("video1");
147
+ const video2 = document.getElementById("video2");
148
+ const playPauseBtn = document.getElementById("playPauseBtn");
149
+ const wipeRange = document.getElementById("wipeRange");
150
+ const timelineRange = document.getElementById("timelineRange");
151
+ const scaleSelect = document.getElementById("scaleSelect");
152
+ const speedSelect = document.getElementById("speedSelect");
153
+ const videoContainer = document.getElementById("videoContainer");
154
+ const wipeLine = document.getElementById("wipeLine");
155
+ const controlTable = document.getElementById("controlTable");
156
+ const videoSetSelect = document.getElementById("videoSetSelect");
157
+
158
+ let isPlaying = false;
159
+
160
+ // Update playback speed.
161
+ function updateSpeed() {
162
+ const speedValue = parseFloat(speedSelect.value);
163
+ video1.playbackRate = speedValue;
164
+ video2.playbackRate = speedValue;
165
+ }
166
+
167
+ // Update the wipe effect.
168
+ function updateWipe() {
169
+ const wipeValue = parseFloat(wipeRange.value);
170
+ const rightPercent = (1 - wipeValue) * 100;
171
+ video2.style.clipPath = `inset(0 ${rightPercent}% 0 0)`;
172
+ // Calculate position using the base width.
173
+ const lineX = baseWidth * wipeValue - (wipeLine.clientWidth / 2);
174
+ wipeLine.style.left = `${lineX}px`;
175
+ }
176
+
177
+ // Update timeline slider based on video progress.
178
+ function updateTimeline() {
179
+ if (video1.duration) {
180
+ const percent = (video1.currentTime / video1.duration) * 100;
181
+ timelineRange.value = percent;
182
+ }
183
+ }
184
+ video1.addEventListener("timeupdate", updateTimeline);
185
+
186
+ // Toggle play/pause.
187
+ function togglePlayPause() {
188
+ if (!isPlaying) {
189
+ video1.play();
190
+ video2.play();
191
+ playPauseBtn.textContent = "Pause";
192
+ isPlaying = true;
193
+ } else {
194
+ video1.pause();
195
+ video2.pause();
196
+ playPauseBtn.textContent = "Play";
197
+ isPlaying = false;
198
+ }
199
+ }
200
+
201
+ // Seek both videos.
202
+ function seekTimeline() {
203
+ if (video1.duration) {
204
+ const percent = timelineRange.value / 100;
205
+ const newTime = video1.duration * percent;
206
+ video1.currentTime = newTime;
207
+ video2.currentTime = newTime;
208
+ }
209
+ }
210
+
211
+ // Update scale and adjust related elements.
212
+ function updateScale() {
213
+ const scaleValue = parseFloat(scaleSelect.value);
214
+ videoContainer.style.transform = `scale(${scaleValue})`;
215
+ videoContainer.style.transformOrigin = "top left";
216
+ // Update slider and table widths to the visually scaled size.
217
+ const effectiveWidth = baseWidth * scaleValue;
218
+ wipeRange.style.width = effectiveWidth + "px";
219
+ timelineRange.style.width = effectiveWidth + "px";
220
+ controlTable.style.width = effectiveWidth + "px";
221
+ updateWipe();
222
+ }
223
+
224
+ // Update video sources based on selected video set.
225
+ function updateVideoSet() {
226
+ const selectedIndex = videoSetSelect.value;
227
+ if (selectedIndex === "") {
228
+ // "No" selected, you could reset the video sources if desired.
229
+ return;
230
+ }
231
+ const videoSet = videoSets[parseInt(selectedIndex)];
232
+ const area = videoSet.area;
233
+ const date = videoSet.date;
234
+ const sensor = videoSet.sensor;
235
+ // Construct filenames.
236
+ const originalFile = `${area}/video_${area}_${sensor}um_${date}_10min_010fps.mp4`;
237
+ const enhancedFile = `${area}/video_${area}_${sensor}um_${date}_01min_100fps.mp4`;
238
+ // Update video sources.
239
+ video1.setAttribute("src", originalFile);
240
+ video2.setAttribute("src", enhancedFile);
241
+ // Reload the videos.
242
+ video1.load();
243
+ video2.load();
244
+ }
245
+
246
+ // Event listeners.
247
+ playPauseBtn.addEventListener("click", togglePlayPause);
248
+ wipeRange.addEventListener("input", updateWipe);
249
+ timelineRange.addEventListener("input", seekTimeline);
250
+ scaleSelect.addEventListener("change", updateScale);
251
+ speedSelect.addEventListener("change", updateSpeed);
252
+ videoSetSelect.addEventListener("change", updateVideoSet);
253
+
254
+ // Initial setup.
255
+ updateWipe();
256
+ updateScale();
257
+ updateSpeed();
258
+ </script>
259
+ </body>
260
+ </html>
261
+ """
262
+
263
+ with gr.Blocks() as demo:
264
+ gr.HTML(html_code)
265
+
266
+ demo.launch()