bhacquin commited on
Commit
70351dc
·
verified ·
1 Parent(s): e28f651

Update demo.py

Browse files
Files changed (1) hide show
  1. demo.py +215 -109
demo.py CHANGED
@@ -8,31 +8,35 @@ import os
8
  import firebase_admin
9
  from firebase_admin import db, credentials
10
 
11
-
12
  ##################################################################
13
  # Constants
14
  ##################################################################
15
 
16
-
17
- NUMBER_OF_IMAGES_PER_ROW = 7
18
- NUMBER_OF_ROWS = 2
19
-
 
 
 
20
 
21
  #################################################################################################################################################
22
  # Authentication
23
  #################################################################################################################################################
24
 
25
-
26
- # read secret api key
27
  FIREBASE_API_KEY = os.environ['FirebaseSecret']
28
  FIREBASE_URL = os.environ['FirebaseURL']
29
  DATASET = os.environ['Dataset']
30
 
31
- # init firebase service
32
- firebase_creds = credentials.Certificate(json.loads(FIREBASE_API_KEY))
33
- firebase_app = firebase_admin.initialize_app(firebase_creds, {'databaseURL': FIREBASE_URL})
34
- firebase_data_ref = db.reference("data")
35
-
 
 
 
36
 
37
  ##################################################################
38
  # Data Layer
@@ -40,89 +44,114 @@ firebase_data_ref = db.reference("data")
40
 
41
 
42
  class Experiment(dict):
43
- def __init__(self, dataset, corruption, image_id, corrupted, options, selected_image=None):
 
 
 
44
  super().__init__(
45
  dataset=dataset,
46
- corruption=corruption,
47
- image_id=image_id,
48
- corrupted=corrupted,
49
- options=options,
50
- selected_image=selected_image,
51
  )
52
-
 
53
  def experiment_to_dict(experiment, skip=False):
 
 
 
 
54
  info = {
55
- # experiment info
56
  "dataset": experiment["dataset"],
57
- "corruption": experiment["corruption"],
58
- "image_number": experiment["image_id"],
59
-
60
- # chosen image set info
61
- "corrupted_filename": experiment["corrupted"]["name"],
62
- "options": [img["name"] for img in experiment["options"]],
63
  }
64
 
65
  if skip:
66
- info = {
67
- **info,
68
- # selected image info
69
- "selected_image": "None",
70
- "selected_algo": "None",
71
- }
72
  else:
73
- info = {
74
- **info,
75
- # selected image info
76
- "selected_image": experiment["options"][experiment["selected_image"]]["name"],
77
- "selected_algo": experiment["options"][experiment["selected_image"]]["algo"],
78
- }
79
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  return info
81
-
 
82
  def generate_new_experiment() -> Experiment:
83
- wanted_corruptions = ["spatter", "impulse_noise", "speckle_noise", "gaussian_noise", "pixelate", "jpeg_compression", "elastic_transform"]
84
- corruption = random.choice([f for f in list(Path(f"./images/{DATASET}").glob("*/*")) if f.is_dir() and f.name in wanted_corruptions])
85
- image_id = random.choice(list(corruption.glob("*")))
86
- imgs_to_sample = (NUMBER_OF_IMAGES_PER_ROW * NUMBER_OF_ROWS) // 2
87
-
88
- corrupted_image = {"name": str(random.choice(list(image_id.glob("*corrupted*"))))}
89
- sdedit_images = [
90
- {"name": str(img), "algo": "SDEdit"}
91
- for img in random.sample(list((image_id / "sde").glob(f"*")), imgs_to_sample)
92
- ]
93
- odedit_images = [
94
- {"name": str(img), "algo": "ODEdit"}
95
- for img in random.sample(list((image_id / "ode").glob(f"*")), imgs_to_sample)
96
- ]
97
- total_images = sdedit_images + odedit_images
98
- random.shuffle(total_images)
 
 
 
 
 
99
 
100
  return Experiment(
101
  DATASET,
102
- corruption.name,
103
- image_id.name,
104
- corrupted_image,
105
- total_images,
106
  )
107
 
108
- def save(experiment, corrupted_component, *img_components, mode):
109
- if mode == "save" and (experiment is None or experiment["selected_image"] is None):
110
- gr.Warning("You must select an image before submitting")
111
- return [experiment, corrupted_component, *img_components]
112
- if mode == "skip":
113
- experiment["selected_image"] = None
114
 
115
- dict_to_save = {
116
- **experiment_to_dict(experiment, skip=(mode=="skip")),
117
- "timestamp": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
118
- }
119
- firebase_data_ref.push(dict_to_save)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
- print("=====================")
122
- print(dict_to_save)
123
- print("=====================")
 
124
 
125
- gr.Info("Your choice has been saved to Firebase")
126
  return next()
127
 
128
 
@@ -132,61 +161,138 @@ def save(experiment, corrupted_component, *img_components, mode):
132
 
133
 
134
  def next():
 
 
 
135
  new_experiment = generate_new_experiment()
136
 
137
- new_img_components = [
138
- gr.Image(value=img["name"], label=f"{i}", elem_id="unsel", show_label=False, show_download_button=False, show_share_button=False, interactive=False)
139
- for i, img in enumerate(new_experiment["options"])
140
- ]
141
- new_corrupted_component = gr.Image(value=new_experiment["corrupted"]["name"], label="corr", elem_id="corrupted", show_label=False, show_download_button=False, show_share_button=False, interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
- return [new_experiment, new_corrupted_component, *new_img_components]
144
 
145
- def on_select(evt: gr.SelectData, experiment, *img_components): # SelectData is a subclass of EventData
146
- new_selected = int(evt.target.label)
147
 
148
- new_img_components = [
149
- gr.Image(value=img["name"], label=f"{i}", elem_id="unsel", show_label=False, show_download_button=False, show_share_button=False, interactive=False)
150
- for i, img in enumerate(experiment["options"])
151
- ]
152
- new_img_components[new_selected] = (
153
- gr.Image(value=experiment["options"][new_selected]["name"], label=f"{new_selected}", elem_id="sel", show_label=False, show_download_button=False, show_share_button=False, interactive=False)
154
- )
155
 
156
- experiment["selected_image"] = int(evt.target.label)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
- return [experiment, *new_img_components]
159
 
160
  css = """
161
  #unsel {border: solid 5px transparent !important; border-radius: 15px !important; draggable: false}
162
  #sel {border: solid 5px #00c0ff !important; border-radius: 15px !important; draggable: false}
163
- #corrupted {margin-left: 5%; margin-right: 5%; padding: 0 !important; draggable: false}
164
  #reducedHeight {height: 10px !important}
165
  #padded {padding-left: 2%; padding-right: 2%}
166
  """
167
 
168
- with gr.Blocks(title="Unsupervised Image Editing", css=css) as demo:
169
- experiment = gr.State(generate_new_experiment())
170
 
171
  with gr.Row(elem_id="padded"):
172
- corrupted_component = gr.Image(label="corr", elem_id="corrupted", show_label=False, show_download_button=False, show_share_button=False, interactive=False)
173
  with gr.Column(scale=3, elem_id="padded"):
174
- gr.Markdown("<div style='width: 100%'><h1 style='text-align: center; display: inline-block; width: 100%'>The sample on the left is a corrupted image</h1></div>")
175
- gr.Markdown("<div style='width: 100%'><h3 style='text-align: center; display: inline-block; width: 100%'>Below are decorrupted versions sampled from various models. Click on the picture you like best.<br/>⚠️Do not pay attention to the background. Consider first fidelity, then quality⚠️</h3></div>")
176
  btn_skip = gr.Button("I have no preference")
177
  btn_submit = gr.Button("Submit preference")
178
 
179
- img_components = []
180
- for row in range(NUMBER_OF_ROWS):
181
- with gr.Row():
182
- for col in range(NUMBER_OF_IMAGES_PER_ROW):
183
- img_components.append(gr.Image(label=f"{row * NUMBER_OF_IMAGES_PER_ROW + col}", elem_id="unsel", show_label=False, show_download_button=False, show_share_button=False, interactive=False))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
 
185
- btn_skip.click(partial(save, mode="skip"), [experiment, corrupted_component, *img_components], [experiment, corrupted_component, *img_components])
186
- btn_submit.click(partial(save, mode="save"), [experiment, corrupted_component, *img_components], [experiment, corrupted_component, *img_components])
187
- for img in img_components:
188
- img.select(on_select, [experiment, *img_components], [experiment, *img_components], show_progress="hidden")
 
 
 
 
 
 
 
 
 
189
 
190
- demo.load(next, None, [experiment, corrupted_component, *img_components])
 
 
 
 
 
191
 
192
- demo.launch()
 
8
  import firebase_admin
9
  from firebase_admin import db, credentials
10
 
 
11
  ##################################################################
12
  # Constants
13
  ##################################################################
14
 
15
+ # Constants for video display
16
+ NUMBER_OF_VIDEOS_PER_ROW = 2 # Displaying two videos per row
17
+ VIDEO_FOLDERS = {
18
+ "ours": "./videos/userstudy_200_ours/",
19
+ "omni": "./videos/userstudy_200_omni/"
20
+ }
21
+ NUMBER_OF_EXPERIMENTS = 200 # Assuming sample0.mp4 to sample199.mp4
22
 
23
  #################################################################################################################################################
24
  # Authentication
25
  #################################################################################################################################################
26
 
27
+ # Read secret API key and other configurations from environment variables
 
28
  FIREBASE_API_KEY = os.environ['FirebaseSecret']
29
  FIREBASE_URL = os.environ['FirebaseURL']
30
  DATASET = os.environ['Dataset']
31
 
32
+ # Initialize Firebase service
33
+ try:
34
+ firebase_creds = credentials.Certificate(json.loads(FIREBASE_API_KEY))
35
+ firebase_app = firebase_admin.initialize_app(firebase_creds, {'databaseURL': FIREBASE_URL})
36
+ firebase_data_ref = db.reference("data")
37
+ except Exception as e:
38
+ print(f"Failed to initialize Firebase: {e}")
39
+ raise e
40
 
41
  ##################################################################
42
  # Data Layer
 
44
 
45
 
46
  class Experiment(dict):
47
+ """
48
+ Represents an experiment consisting of two videos and the user's selection.
49
+ """
50
+ def __init__(self, dataset, video_left, video_right, selected_video=None):
51
  super().__init__(
52
  dataset=dataset,
53
+ video_left=video_left,
54
+ video_right=video_right,
55
+ selected_video=selected_video,
 
 
56
  )
57
+
58
+
59
  def experiment_to_dict(experiment, skip=False):
60
+ """
61
+ Converts the Experiment object to a dictionary for Firebase storage.
62
+ Includes whether the selected video is from 'omni' or 'ours' folder.
63
+ """
64
  info = {
 
65
  "dataset": experiment["dataset"],
66
+ "video_left": experiment["video_left"],
67
+ "video_right": experiment["video_right"],
 
 
 
 
68
  }
69
 
70
  if skip:
71
+ info["selected_video"] = "None"
72
+ info["Control"] = "None"
 
 
 
 
73
  else:
74
+ info["selected_video"] = experiment["selected_video"]
75
+
76
+ # Determine "Control" based on which video was selected
77
+ if experiment["selected_video"] == "left":
78
+ selected_video_path = Path(experiment["video_left"])
79
+ elif experiment["selected_video"] == "right":
80
+ selected_video_path = Path(experiment["video_right"])
81
+ else:
82
+ selected_video_path = None
83
+
84
+ if selected_video_path:
85
+ # Check the parent folder name to determine the source
86
+ if "userstudy_200_omni" in selected_video_path.parts:
87
+ info["Control"] = "OmniControl"
88
+ elif "userstudy_200_ours" in selected_video_path.parts:
89
+ info["Control"] = "Ours"
90
+ else:
91
+ info["Control"] = "Unknown"
92
+ else:
93
+ info["Control"] = "Unknown"
94
+
95
+ info["timestamp"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
96
+
97
  return info
98
+
99
+
100
  def generate_new_experiment() -> Experiment:
101
+ """
102
+ Generates a new experiment by randomly selecting a sample number and fetching corresponding videos from both folders.
103
+ The positions of the videos (left/right) are randomized.
104
+ """
105
+ # Randomly select an integer between 0 and 199 inclusive
106
+ random_int = random.randint(0, NUMBER_OF_EXPERIMENTS - 1)
107
+ video_name = f"sample{random_int}.mp4"
108
+
109
+ # Paths to the two videos
110
+ video_ours_path = Path(VIDEO_FOLDERS["ours"]) / video_name
111
+ video_omni_path = Path(VIDEO_FOLDERS["omni"]) / video_name
112
+
113
+ # Ensure that both videos exist
114
+ if not video_ours_path.exists() or not video_omni_path.exists():
115
+ raise FileNotFoundError(f"One or both video files not found: {video_ours_path}, {video_omni_path}")
116
+
117
+ # Randomly decide the order (left/right)
118
+ if random.choice([True, False]):
119
+ video_left, video_right = video_ours_path, video_omni_path
120
+ else:
121
+ video_left, video_right = video_omni_path, video_ours_path
122
 
123
  return Experiment(
124
  DATASET,
125
+ str(video_left),
126
+ str(video_right),
 
 
127
  )
128
 
 
 
 
 
 
 
129
 
130
+ def save(mode, experiment, video_left_component, video_right_component):
131
+ """
132
+ Saves the user's selection to Firebase.
133
+ - mode: "save" or "skip"
134
+ """
135
+ if mode == "save":
136
+ if experiment is None or experiment["selected_video"] is None:
137
+ gr.Warning("You must select a video before submitting")
138
+ return [experiment, video_left_component, video_right_component]
139
+ elif mode == "skip":
140
+ experiment["selected_video"] = "None"
141
+
142
+ try:
143
+ dict_to_save = experiment_to_dict(experiment, skip=(mode == "skip"))
144
+ firebase_data_ref.push(dict_to_save)
145
+
146
+ print("=====================")
147
+ print(dict_to_save)
148
+ print("=====================")
149
 
150
+ gr.Info("Your choice has been saved to Firebase")
151
+ except Exception as e:
152
+ gr.Warning(f"Failed to save your choice: {e}")
153
+ print(f"Error saving to Firebase: {e}")
154
 
 
155
  return next()
156
 
157
 
 
161
 
162
 
163
  def next():
164
+ """
165
+ Prepares the next set of videos for the user to evaluate.
166
+ """
167
  new_experiment = generate_new_experiment()
168
 
169
+ # Create video components with initial state as unselected
170
+ video_left_component = gr.Video(
171
+ value=new_experiment["video_left"],
172
+ label="left",
173
+ elem_id="unsel",
174
+ show_label=False,
175
+ show_download_button=False,
176
+ show_share_button=False,
177
+ interactive=True
178
+ )
179
+ video_right_component = gr.Video(
180
+ value=new_experiment["video_right"],
181
+ label="right",
182
+ elem_id="unsel",
183
+ show_label=False,
184
+ show_download_button=False,
185
+ show_share_button=False,
186
+ interactive=True
187
+ )
188
 
189
+ return [new_experiment, video_left_component, video_right_component]
190
 
 
 
191
 
192
+ def on_select(evt: gr.SelectData, experiment, video_left_component, video_right_component):
193
+ """
194
+ Handles the selection of a video by the user.
195
+ """
196
+ selected_label = evt.value # Assuming evt.value contains the label ("left" or "right")
 
 
197
 
198
+ if selected_label.lower() == "left":
199
+ experiment["selected_video"] = "left"
200
+ elif selected_label.lower() == "right":
201
+ experiment["selected_video"] = "right"
202
+ else:
203
+ experiment["selected_video"] = None # For safety
204
+
205
+ # Update the video components to reflect selection
206
+ if experiment["selected_video"] == "left":
207
+ video_left_component.update(elem_id="sel")
208
+ video_right_component.update(elem_id="unsel")
209
+ elif experiment["selected_video"] == "right":
210
+ video_left_component.update(elem_id="unsel")
211
+ video_right_component.update(elem_id="sel")
212
+ else:
213
+ video_left_component.update(elem_id="unsel")
214
+ video_right_component.update(elem_id="unsel")
215
+
216
+ return [experiment, video_left_component, video_right_component]
217
 
 
218
 
219
  css = """
220
  #unsel {border: solid 5px transparent !important; border-radius: 15px !important; draggable: false}
221
  #sel {border: solid 5px #00c0ff !important; border-radius: 15px !important; draggable: false}
 
222
  #reducedHeight {height: 10px !important}
223
  #padded {padding-left: 2%; padding-right: 2%}
224
  """
225
 
226
+ with gr.Blocks(title="Unsupervised Video Editing", css=css) as demo:
227
+ experiment = gr.State()
228
 
229
  with gr.Row(elem_id="padded"):
 
230
  with gr.Column(scale=3, elem_id="padded"):
231
+ gr.Markdown("<div style='width: 100%'><h1 style='text-align: center; display: inline-block; width: 100%'>Choose Your Preferred Video</h1></div>")
232
+ gr.Markdown("<div style='width: 100%'><h3 style='text-align: center; display: inline-block; width: 100%'>Select the video you prefer.<br/>⚠️Consider fidelity and quality⚠️</h3></div>")
233
  btn_skip = gr.Button("I have no preference")
234
  btn_submit = gr.Button("Submit preference")
235
 
236
+ with gr.Row():
237
+ # Initialize video components; values will be set on load
238
+ video_left_component = gr.Video(
239
+ label="left",
240
+ elem_id="unsel",
241
+ show_label=False,
242
+ show_download_button=False,
243
+ show_share_button=False,
244
+ interactive=True
245
+ )
246
+ video_right_component = gr.Video(
247
+ label="right",
248
+ elem_id="unsel",
249
+ show_label=False,
250
+ show_download_button=False,
251
+ show_share_button=False,
252
+ interactive=True
253
+ )
254
+
255
+ # Configure the skip and submit buttons
256
+ btn_skip.click(
257
+ fn=save,
258
+ inputs=[gr.State(), video_left_component, video_right_component],
259
+ outputs=[gr.State(), video_left_component, video_right_component],
260
+ _js=None,
261
+ queue=False,
262
+ show_progress=False,
263
+ api_name=None,
264
+ mode="skip" # Pass mode as "skip"
265
+ )
266
+ btn_submit.click(
267
+ fn=save,
268
+ inputs=[gr.State(), video_left_component, video_right_component],
269
+ outputs=[gr.State(), video_left_component, video_right_component],
270
+ _js=None,
271
+ queue=False,
272
+ show_progress=False,
273
+ api_name=None,
274
+ mode="save" # Pass mode as "save"
275
+ )
276
 
277
+ # Attach select events to video components
278
+ video_left_component.select(
279
+ fn=on_select,
280
+ inputs=[gr.SelectData(), experiment, video_left_component, video_right_component],
281
+ outputs=[experiment, video_left_component, video_right_component],
282
+ show_progress="hidden"
283
+ )
284
+ video_right_component.select(
285
+ fn=on_select,
286
+ inputs=[gr.SelectData(), experiment, video_left_component, video_right_component],
287
+ outputs=[experiment, video_left_component, video_right_component],
288
+ show_progress="hidden"
289
+ )
290
 
291
+ # Load the first experiment on app startup
292
+ demo.load(
293
+ fn=next,
294
+ inputs=None,
295
+ outputs=[experiment, video_left_component, video_right_component]
296
+ )
297
 
298
+ demo.launch()