demo interface changes

#1
by niulx - opened
Files changed (10) hide show
  1. .gitattributes +0 -1
  2. README.md +0 -19
  3. app.py +270 -273
  4. img2.png +0 -3
  5. img3.png +0 -0
  6. img4.png +0 -0
  7. main.py +6 -13
  8. requirements.txt +8 -12
  9. segment.py +14 -32
  10. utils.py +1 -0
.gitattributes DELETED
@@ -1 +0,0 @@
1
- img2.png filter=lfs diff=lfs merge=lfs -text
 
 
README.md CHANGED
@@ -3,25 +3,6 @@ title: "D-Edit"
3
  colorFrom: "red"
4
  colorTo: "blue"
5
  sdk: "gradio"
6
- sdk_version: 5.0.2
7
- python_version: "3.10"
8
  app_file: app.py
9
  pinned: false
10
- models:
11
- - CompVis/stable-diffusion-v1-4
12
- tags:
13
- - image-editing
14
- - diffusion
15
- - research
16
  ---
17
-
18
- # D-Edit
19
-
20
- Public research demo for **D-Edit: A Generic Framework for Image Editing**.
21
-
22
- - [Paper on arXiv](https://arxiv.org/abs/2403.04880)
23
- - [Hugging Face paper page](https://huggingface.co/papers/2403.04880)
24
-
25
- The demo first segments an input image and then optimizes object embeddings and the diffusion model for text-guided editing. Segmentation runs on CPU; the optimization and editing stage requires CUDA.
26
-
27
- The public configuration defaults to a training batch size of 1, limits queue concurrency to one request, and clears cached GPU memory between optimization and editing. These safeguards are intended to fit the workflow on a 16 GB GPU such as an Nvidia T4.
 
3
  colorFrom: "red"
4
  colorTo: "blue"
5
  sdk: "gradio"
 
 
6
  app_file: app.py
7
  pinned: false
 
 
 
 
 
 
8
  ---
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -1,9 +1,6 @@
 
1
  import os
2
  import copy
3
- import gc
4
- import spaces
5
- import torch
6
- from main import run_main
7
  from PIL import Image
8
  import matplotlib
9
  import numpy as np
@@ -13,19 +10,9 @@ from utils_mask import process_mask_to_follow_priority, mask_union, visualize_ma
13
  from pathlib import Path
14
  from PIL import Image
15
  from functools import partial
16
- import time
17
-
18
  LENGTH=512 #length of the square area displaying/editing images
19
  TRANSPARENCY = 150 # transparency of the mask in display
20
- DEFAULT_TRAIN_BATCH_SIZE = 1
21
- MAX_TRAIN_BATCH_SIZE = 4
22
-
23
-
24
- def clear_cuda_cache():
25
- gc.collect()
26
- if torch.cuda.is_available():
27
- torch.cuda.empty_cache()
28
-
29
 
30
  def add_mask(mask_np_list_updated, mask_label_list):
31
  mask_new = np.zeros_like(mask_np_list_updated[0])
@@ -45,24 +32,89 @@ def create_segmentation(mask_np_list):
45
  segmentation = Image.fromarray(np.uint8(segmentation*255))
46
  return segmentation
47
 
 
 
 
 
 
 
 
 
 
48
 
49
- def run_segmentation_wrapper(image):
 
 
50
  try:
51
- print(image.shape)
52
- image, mask_np_list,mask_label_list = run_segmentation(image)
53
- #image = image.convert('RGB')
 
 
54
  segmentation = create_segmentation(mask_np_list)
55
  print("!!", len(mask_np_list))
56
- max_val = len(mask_np_list)-1
57
- sliderup = gr.Slider(value = 0, minimum=0, maximum=max_val, step=1, visible=True)
58
- gr.Info('Segmentation finish. Select mask id and move to the next step.')
59
- return image, segmentation, mask_np_list, mask_label_list, image, sliderup, sliderup , 'Segmentation finish. Select mask id and move to the next step.'
60
- except Exception as e:
61
- print(e)
62
- sliderup = gr.Slider(value = 0, minimum=0, maximum=1, step=1, visible=False)
63
- gr.Warning('Please upload an image before proceeding.')
64
- return None,None,None,None,None, sliderup, sliderup , 'Please upload an image before proceeding.'
65
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
  def transparent_paste_with_mask(backimg, foreimg, mask_np,transparency = 128):
68
  backimg_solid_np = np.array(backimg)
@@ -74,8 +126,11 @@ def transparent_paste_with_mask(backimg, foreimg, mask_np,transparency = 128):
74
  bimg_np = np.array(bimg)
75
  mask_np = mask_np[:,:,np.newaxis]
76
 
77
- new_img_np = bimg_np*mask_np + (1-mask_np)* backimg_solid_np
78
- return Image.fromarray(np.uint8(new_img_np))
 
 
 
79
 
80
  def show_segmentation(image, segmentation, flag):
81
  if flag is False:
@@ -106,32 +161,17 @@ def edit_mask_add(canvas, image, idx, mask_np_list):
106
  return mask_np_list_updated, image_edit
107
 
108
  def slider_release(index, image, mask_np_list_updated, mask_label_list):
109
- if index > len(mask_np_list_updated)-1:
110
- return image, "out of range", ""
 
111
  else:
112
  mask_np = mask_np_list_updated[index]
113
  mask_label = mask_label_list[index]
114
- index = mask_label.rfind('-')
115
- mask_label = mask_label[:index]
116
- if mask_label == 'handbag':
117
- mask_prompt = "white handbag"
118
- elif mask_label == 'person':
119
- mask_prompt = "little boy"
120
- elif mask_label == 'wall-other-merged':
121
- mask_prompt = "white wall"
122
- elif mask_label == 'table-merged':
123
- mask_prompt = "table"
124
- else:
125
- mask_prompt = mask_label
126
  segmentation = create_segmentation(mask_np_list_updated)
127
  new_image = transparent_paste_with_mask(image, segmentation, mask_np, transparency = TRANSPARENCY)
128
- gr.Info('Edit '+ mask_label)
129
- return new_image, mask_label, mask_prompt
130
- def image_change():
131
- return gr.Slider(value = 0, minimum=0, maximum=1, step=1, visible=False)
132
 
133
  def save_as_orig_mask(mask_np_list_updated, mask_label_list, input_folder="example_tmp"):
134
- print(mask_np_list_updated)
135
  try:
136
  assert np.all(sum(mask_np_list_updated)==1)
137
  except:
@@ -146,7 +186,6 @@ def save_as_orig_mask(mask_np_list_updated, mask_label_list, input_folder="examp
146
  visualize_mask_list_clean(mask_np_list_updated, savepath)
147
 
148
  def save_as_edit_mask(mask_np_list_updated, mask_label_list, input_folder="example_tmp"):
149
- print(mask_np_list_updated)
150
  try:
151
  assert np.all(sum(mask_np_list_updated)==1)
152
  except:
@@ -158,30 +197,12 @@ def save_as_edit_mask(mask_np_list_updated, mask_label_list, input_folder="examp
158
  savepath = os.path.join(input_folder, "seg_edited.png")
159
  visualize_mask_list_clean(mask_np_list_updated, savepath)
160
 
161
-
162
-
163
- def button_clickable(is_clickable):
164
- return gr.Button(interactive=is_clickable)
165
-
166
-
167
-
168
- def load_pil_img():
169
- from PIL import Image
170
- return Image.open("example_tmp/text/out_text_0.png")
171
-
172
- def change_image(img):
173
- return None
174
-
175
-
176
  import shutil
177
  if os.path.isdir("./example_tmp"):
178
  shutil.rmtree("./example_tmp")
179
 
180
-
181
-
182
-
183
  from segment import run_segmentation
184
-
185
  with gr.Blocks() as demo:
186
  image = gr.State() # store mask
187
  image_loaded = gr.State()
@@ -197,227 +218,203 @@ with gr.Blocks() as demo:
197
  with gr.Row():
198
  gr.Markdown("""# D-Edit""")
199
 
200
-
201
- with gr.Row():
202
- with gr.Column():
203
- canvas = gr.Image(value = None, type="numpy", label="Show Mask", show_label=True, height=LENGTH, width=LENGTH, interactive=True)
204
- example_inps = [['./img.png'],['./img2.png'],['./img3.png'],['./img4.png']]
205
- gr.Examples(examples=example_inps, inputs=[canvas],
206
- label='examples', cache_examples='lazy', outputs=[],
207
- fn=change_image)
208
- gr.Markdown(f"Each image must first undergo segmentation. Afterwards, you can modify the \n mask ID and the prompt for image editing, then proceed with the editing process. \n The link of D-edit paper: [https://arxiv.org/abs/2403.04880v2](https://arxiv.org/abs/2403.04880v2), [https://huggingface.co/papers/2403.04880](https://huggingface.co/papers/2403.04880)")
209
-
210
- with gr.Column():
211
- result_info0 = gr.Text(label="Response")
212
- segment_button = gr.Button("Step 1. Run segmentation")
213
- flag = gr.State(False)
214
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  # mask_np_list_updated.value = copy.deepcopy(mask_np_list.value) #!!
216
  mask_np_list_updated = mask_np_list
217
- gr.Markdown("""<p style="text-align: center; font-size: 20px">Edit Mask (Do not change it during the editing process)</p>""")
218
- slider = gr.Slider(0, 20, step=1, label = 'mask id', visible=False)
219
- label = gr.Text(label='label')
220
-
221
-
222
-
 
 
 
 
 
 
 
223
 
224
- result_info = gr.Text(label="Response")
225
-
226
- opt_flag = gr.State(0)
227
- gr.Markdown("""<p style="text-align: center; font-size: 20px">Optimization settings</p>""")
228
- with gr.Accordion(label="Advanced settings", open=False):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  num_tokens = gr.Number(value="5", label="num tokens to represent each object", interactive= True)
230
  num_tokens_global = num_tokens
231
- embedding_learning_rate = gr.Textbox(value="0.00025", label="Embedding optimization: Learning rate", interactive= True )
232
- max_emb_train_steps = gr.Number(value="6", label="embedding optimization: Training steps", interactive= True )
233
 
234
- diffusion_model_learning_rate = gr.Textbox(value="0.0002", label="UNet Optimization: Learning rate", interactive= True )
235
- max_diffusion_train_steps = gr.Number(value="28", label="UNet Optimization: Learning rate: Training steps", interactive= True )
236
 
237
- train_batch_size = gr.Number(
238
- value=DEFAULT_TRAIN_BATCH_SIZE,
239
- minimum=1,
240
- maximum=MAX_TRAIN_BATCH_SIZE,
241
- precision=0,
242
- label="Batch size",
243
- info="Keep this at 1 for T4 and other 16 GB GPUs.",
244
- interactive=True,
245
- )
246
- gradient_accumulation_steps=gr.Number(value=2, minimum=1, precision=0, label="Gradient accumulation", interactive= True )
247
-
248
- def run_optimization_wrapper (
249
- mask_np_list,
250
- mask_label_list,
251
- image,
252
- opt_flag,
253
- num_tokens,
254
- embedding_learning_rate ,
255
- max_emb_train_steps ,
256
- diffusion_model_learning_rate ,
257
- max_diffusion_train_steps,
258
- train_batch_size,
259
- gradient_accumulation_steps,
260
- ):
261
- try:
262
  run_optimization = partial(
263
- run_main,
264
- mask_np_list=mask_np_list,
265
- mask_label_list=mask_label_list,
266
- image_gt=np.array(image),
267
  num_tokens=int(num_tokens),
268
  embedding_learning_rate = float(embedding_learning_rate),
269
- max_emb_train_steps = min(int(max_emb_train_steps),50),
270
  diffusion_model_learning_rate= float(diffusion_model_learning_rate),
271
- max_diffusion_train_steps = min(int(max_diffusion_train_steps),100),
272
- train_batch_size=max(1, min(int(train_batch_size), MAX_TRAIN_BATCH_SIZE)),
273
- gradient_accumulation_steps=max(1, int(gradient_accumulation_steps))
274
  )
275
  run_optimization()
276
- gr.Info("Optimization Finished! Move to the next step.")
277
- return "Optimization finished! Move to the next step."#,gr.Button("Step 3. Run Editing",interactive = True)
278
- except torch.cuda.OutOfMemoryError as exc:
279
- print(f"CUDA out of memory during optimization: {exc}")
280
- clear_cuda_cache()
281
- message = "GPU memory is full. Keep Batch size at 1 and try again."
282
- gr.Error(message)
283
- return f"Error: {message}"
284
- except Exception as exc:
285
- print(f"Optimization failed: {exc}")
286
- message = "Optimization failed. Check the image and mask, then try again."
287
- gr.Error(message)
288
- return f"Error: {message}"
289
-
290
-
291
-
292
- if 1:
293
- with gr.Row():
294
- with gr.Column():
295
- canvas_text_edit = gr.Image(value = None, type = "pil", label="Editing results", show_label=True,visible = True)
296
- # canvas_text_edit = gr.Gallery(label = "Edited results")
297
-
298
- with gr.Column():
299
- gr.Markdown("""<p style="text-align: center; font-size: 20px">Editing setting</p>""")
300
- tgt_prompt = gr.Textbox(value="text prompt", label="Editing: Text prompt", interactive= True )
301
- with gr.Accordion(label="Advanced settings", open=False):
302
- slider2 = gr.Slider(0, 20, step=1, label = 'mask id', visible=False)
303
- guidance_scale = gr.Textbox(value="5", label="Editing: CFG guidance scale", interactive= True )
304
- num_sampling_steps = gr.Number(value="20", label="Editing: Sampling steps", interactive= True )
 
 
 
 
 
 
 
 
 
305
  edge_thickness = gr.Number(value="10", label="Editing: Edge thickness", interactive= True )
306
  strength = gr.Textbox(value="0.5", label="Editing: Mask strength", interactive= True )
307
-
308
- add_button = gr.Button("Step 2. Run Editing",interactive = True)
309
- def run_edit_text_wrapper(
310
- mask_np_list,
311
- mask_label_list,
312
- image,
313
- num_tokens,
314
- guidance_scale,
315
- num_sampling_steps ,
316
- strength ,
317
- edge_thickness,
318
- tgt_prompt ,
319
- tgt_index
320
- ):
 
 
 
 
 
 
 
 
 
 
 
 
321
 
322
- run_edit_text = partial(
323
- run_main,
324
- mask_np_list=mask_np_list,
325
- mask_label_list=mask_label_list,
326
- image_gt=np.array(image),
327
- load_trained=True,
328
- text=True,
329
- num_tokens = int(num_tokens),
330
- guidance_scale = float(guidance_scale),
331
- num_sampling_steps = int(num_sampling_steps),
332
- strength = float(strength),
333
- edge_thickness = int(edge_thickness),
334
- num_imgs = 1,
335
- tgt_prompt = tgt_prompt,
336
- tgt_index = int(tgt_index)
 
 
 
 
 
337
  )
338
- run_edit_text()
339
- gr.Info('Image editing completed.')
340
- return load_pil_img()
341
-
342
-
343
-
344
- @spaces.GPU(duration=120)
345
- def run_total_wrapper(mask_np_list, mask_label_list, image_loaded, opt_flag, num_tokens, embedding_learning_rate, max_emb_train_steps, diffusion_model_learning_rate, max_diffusion_train_steps, train_batch_size, gradient_accumulation_steps, num_tokens_global, guidance_scale, num_sampling_steps, strength, edge_thickness, tgt_prompt, slider2):
346
- if not torch.cuda.is_available():
347
- message = "GPU hardware is required for Step 2. Please try again after the Space receives a GPU."
348
- gr.Error(message)
349
- return f"Error: {message}", None
350
- if image_loaded is None or not mask_np_list:
351
- message = "Run Step 1 segmentation before starting the edit."
352
- gr.Error(message)
353
- return f"Error: {message}", None
354
-
355
- try:
356
- result_info = run_optimization_wrapper(mask_np_list, mask_label_list, image_loaded, opt_flag, num_tokens, embedding_learning_rate, max_emb_train_steps, diffusion_model_learning_rate, max_diffusion_train_steps, train_batch_size, gradient_accumulation_steps)
357
- if not result_info.startswith("Optimization finished"):
358
- return result_info, None
359
- clear_cuda_cache()
360
- canvas_text_edit = run_edit_text_wrapper(mask_np_list, mask_label_list, image_loaded, num_tokens_global, guidance_scale, num_sampling_steps, strength, edge_thickness, tgt_prompt, slider2)
361
- return result_info, canvas_text_edit
362
- except torch.cuda.OutOfMemoryError as exc:
363
- print(f"CUDA out of memory during editing: {exc}")
364
- message = "GPU memory is full. Keep Batch size at 1 and reduce the training steps."
365
- gr.Error(message)
366
- return f"Error: {message}", None
367
- except Exception as exc:
368
- print(f"Editing failed: {exc}")
369
- message = "Editing failed. Please retry with the default settings."
370
- gr.Error(message)
371
- return f"Error: {message}", None
372
- finally:
373
- clear_cuda_cache()
374
-
375
-
376
- add_button.click(
377
- run_total_wrapper,
378
- inputs=[
379
- mask_np_list,
380
- mask_label_list,
381
- image_loaded,
382
- opt_flag,
383
- num_tokens,
384
- embedding_learning_rate,
385
- max_emb_train_steps,
386
- diffusion_model_learning_rate,
387
- max_diffusion_train_steps,
388
- train_batch_size,
389
- gradient_accumulation_steps,
390
- num_tokens_global,
391
- guidance_scale,
392
- num_sampling_steps,
393
- strength,
394
- edge_thickness,
395
- tgt_prompt,
396
- slider2
397
- ],
398
- outputs=[result_info, canvas_text_edit],
399
- )
400
-
401
-
402
-
403
-
404
- canvas.upload(image_change, inputs=[], outputs=[slider])
405
-
406
- slider.release(slider_release,
407
- inputs = [slider, image_loaded, mask_np_list_updated, mask_label_list],
408
- outputs= [canvas, label,tgt_prompt])
409
-
410
- slider.change(
411
- lambda x: x,
412
- inputs=[slider],
413
- outputs=[slider2]
414
- )
415
-
416
 
417
- segment_button.click(run_segmentation_wrapper,
418
- [canvas] ,
419
- [image_loaded, segmentation, mask_np_list, mask_label_list, canvas, slider, slider2, result_info0] )
420
 
421
 
422
 
423
- demo.queue(max_size=4, default_concurrency_limit=1).launch()
 
1
+
2
  import os
3
  import copy
 
 
 
 
4
  from PIL import Image
5
  import matplotlib
6
  import numpy as np
 
10
  from pathlib import Path
11
  from PIL import Image
12
  from functools import partial
13
+ from main import run_main
 
14
  LENGTH=512 #length of the square area displaying/editing images
15
  TRANSPARENCY = 150 # transparency of the mask in display
 
 
 
 
 
 
 
 
 
16
 
17
  def add_mask(mask_np_list_updated, mask_label_list):
18
  mask_new = np.zeros_like(mask_np_list_updated[0])
 
32
  segmentation = Image.fromarray(np.uint8(segmentation*255))
33
  return segmentation
34
 
35
+ def load_mask_ui(input_folder="example_tmp",load_edit = False):
36
+ if not load_edit:
37
+ mask_list, mask_label_list = load_mask(input_folder)
38
+ else:
39
+ mask_list, mask_label_list = load_mask_edit(input_folder)
40
+
41
+ mask_np_list = []
42
+ for m in mask_list:
43
+ mask_np_list. append( m.cpu().numpy())
44
 
45
+ return mask_np_list, mask_label_list
46
+
47
+ def load_image_ui(load_edit, input_folder="example_tmp"):
48
  try:
49
+ for img_path in Path(input_folder).iterdir():
50
+ if img_path.name in ["img_512.png"]:
51
+ image = Image.open(img_path)
52
+ mask_np_list, mask_label_list = load_mask_ui(input_folder, load_edit = load_edit)
53
+ image = image.convert('RGB')
54
  segmentation = create_segmentation(mask_np_list)
55
  print("!!", len(mask_np_list))
56
+ return image, segmentation, mask_np_list, mask_label_list, image
57
+ except:
58
+ print("Image folder invalid: The folder should contain image.png")
59
+ return None, None, None, None, None
60
+
61
+ # def run_edit_text(
62
+ # num_tokens,
63
+ # num_sampling_steps,
64
+ # strength,
65
+ # edge_thickness,
66
+ # tgt_prompt,
67
+ # tgt_idx,
68
+ # guidance_scale,
69
+ # input_folder="example_tmp"
70
+ # ):
71
+ # subprocess.run(["python",
72
+ # "main.py" ,
73
+ # "--text=True",
74
+ # "--name={}".format(input_folder),
75
+ # "--dpm={}".format("sd"),
76
+ # "--resolution={}".format(512),
77
+ # "--load_trained",
78
+ # "--num_tokens={}".format(num_tokens),
79
+ # "--seed={}".format(2024),
80
+ # "--guidance_scale={}".format(guidance_scale),
81
+ # "--num_sampling_step={}".format(num_sampling_steps),
82
+ # "--strength={}".format(strength),
83
+ # "--edge_thickness={}".format(edge_thickness),
84
+ # "--num_imgs={}".format(2),
85
+ # "--tgt_prompt={}".format(tgt_prompt) ,
86
+ # "--tgt_index={}".format(tgt_idx)
87
+ # ])
88
+
89
+ # return Image.open(os.path.join(input_folder, "text", "out_text_0.png"))
90
+
91
+
92
+ # def run_optimization(
93
+ # num_tokens,
94
+ # embedding_learning_rate,
95
+ # max_emb_train_steps,
96
+ # diffusion_model_learning_rate,
97
+ # max_diffusion_train_steps,
98
+ # train_batch_size,
99
+ # gradient_accumulation_steps,
100
+ # input_folder = "example_tmp"
101
+ # ):
102
+ # subprocess.run(["python",
103
+ # "main.py" ,
104
+ # "--name={}".format(input_folder),
105
+ # "--dpm={}".format("sd"),
106
+ # "--resolution={}".format(512),
107
+ # "--num_tokens={}".format(num_tokens),
108
+ # "--embedding_learning_rate={}".format(embedding_learning_rate),
109
+ # "--diffusion_model_learning_rate={}".format(diffusion_model_learning_rate),
110
+ # "--max_emb_train_steps={}".format(max_emb_train_steps),
111
+ # "--max_diffusion_train_steps={}".format(max_diffusion_train_steps),
112
+ # "--train_batch_size={}".format(train_batch_size),
113
+ # "--gradient_accumulation_steps={}".format(gradient_accumulation_steps)
114
+
115
+ # ])
116
+ # return
117
+
118
 
119
  def transparent_paste_with_mask(backimg, foreimg, mask_np,transparency = 128):
120
  backimg_solid_np = np.array(backimg)
 
126
  bimg_np = np.array(bimg)
127
  mask_np = mask_np[:,:,np.newaxis]
128
 
129
+ try:
130
+ new_img_np = bimg_np*mask_np + (1-mask_np)* backimg_solid_np
131
+ return Image.fromarray(new_img_np)
132
+ except:
133
+ import pdb; pdb.set_trace()
134
 
135
  def show_segmentation(image, segmentation, flag):
136
  if flag is False:
 
161
  return mask_np_list_updated, image_edit
162
 
163
  def slider_release(index, image, mask_np_list_updated, mask_label_list):
164
+
165
+ if index > len(mask_np_list_updated):
166
+ return image, "out of range"
167
  else:
168
  mask_np = mask_np_list_updated[index]
169
  mask_label = mask_label_list[index]
 
 
 
 
 
 
 
 
 
 
 
 
170
  segmentation = create_segmentation(mask_np_list_updated)
171
  new_image = transparent_paste_with_mask(image, segmentation, mask_np, transparency = TRANSPARENCY)
172
+ return new_image, mask_label
 
 
 
173
 
174
  def save_as_orig_mask(mask_np_list_updated, mask_label_list, input_folder="example_tmp"):
 
175
  try:
176
  assert np.all(sum(mask_np_list_updated)==1)
177
  except:
 
186
  visualize_mask_list_clean(mask_np_list_updated, savepath)
187
 
188
  def save_as_edit_mask(mask_np_list_updated, mask_label_list, input_folder="example_tmp"):
 
189
  try:
190
  assert np.all(sum(mask_np_list_updated)==1)
191
  except:
 
197
  savepath = os.path.join(input_folder, "seg_edited.png")
198
  visualize_mask_list_clean(mask_np_list_updated, savepath)
199
 
200
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  import shutil
202
  if os.path.isdir("./example_tmp"):
203
  shutil.rmtree("./example_tmp")
204
 
 
 
 
205
  from segment import run_segmentation
 
206
  with gr.Blocks() as demo:
207
  image = gr.State() # store mask
208
  image_loaded = gr.State()
 
218
  with gr.Row():
219
  gr.Markdown("""# D-Edit""")
220
 
221
+ with gr.Tab(label="1 Edit mask"):
222
+ with gr.Row():
223
+ with gr.Column():
224
+ canvas = gr.Image(value = "./img.png", type="numpy", label="Draw Mask", show_label=True, height=LENGTH, width=LENGTH, interactive=True)
225
+
226
+ segment_button = gr.Button("1.1 Run segmentation")
227
+ segment_button.click(run_segmentation,
228
+ [canvas, block_flag] ,
229
+ [block_flag] )
230
+
231
+ text_button = gr.Button("Waiting 1.1 to complete")
232
+ text_button.click(load_image_ui,
233
+ [ false] ,
234
+ [image_loaded, segmentation, mask_np_list, mask_label_list, canvas] )
235
+
236
+ load_edit_button = gr.Button("Waiting 1.1 to complete")
237
+ load_edit_button.click(load_image_ui,
238
+ [ true] ,
239
+ [image_loaded, segmentation, mask_np_list, mask_label_list, canvas] )
240
+
241
+ show_segment = gr.Checkbox(label = "Waiting 1.1 to complete")
242
+ flag = gr.State(False)
243
+ show_segment.select(show_segmentation,
244
+ [image_loaded, segmentation, flag],
245
+ [canvas, flag])
246
+ def show_more_buttons():
247
+ return gr.Button("1.2 Load original masks"), gr.Button("1.2 Load edited masks") , gr.Checkbox(label = "Show Segmentation")
248
+ block_flag.change(show_more_buttons, [], [text_button,load_edit_button,show_segment ])
249
+
250
+
251
  # mask_np_list_updated.value = copy.deepcopy(mask_np_list.value) #!!
252
  mask_np_list_updated = mask_np_list
253
+ with gr.Column():
254
+ gr.Markdown("""<p style="text-align: center; font-size: 20px">Edit Mask (Optional)</p>""")
255
+ slider = gr.Slider(0, 20, step=1, interactive=True)
256
+ label = gr.Textbox()
257
+ slider.release(slider_release,
258
+ inputs = [slider, image_loaded, mask_np_list_updated, mask_label_list],
259
+ outputs= [canvas, label]
260
+ )
261
+ add_button = gr.Button("Add")
262
+ add_button.click( edit_mask_add,
263
+ [canvas, image_loaded, slider, mask_np_list_updated] ,
264
+ [mask_np_list_updated, canvas]
265
+ )
266
 
267
+ save_button2 = gr.Button("Set and Save as edited masks")
268
+ save_button2.click( save_as_edit_mask,
269
+ [mask_np_list_updated, mask_label_list] ,
270
+ [] )
271
+
272
+ save_button = gr.Button("Set and Save as original masks")
273
+ save_button.click( save_as_orig_mask,
274
+ [mask_np_list_updated, mask_label_list] ,
275
+ [] )
276
+
277
+ back_button = gr.Button("Back to current seg")
278
+ back_button.click( load_mask_ui,
279
+ [] ,
280
+ [ mask_np_list_updated,mask_label_list] )
281
+
282
+ add_mask_button = gr.Button("Add new empty mask")
283
+ add_mask_button.click(add_mask,
284
+ [mask_np_list_updated, mask_label_list] ,
285
+ [mask_np_list_updated, mask_label_list] )
286
+
287
+ with gr.Tab(label="2 Optimization"):
288
+ with gr.Row():
289
+ with gr.Column():
290
+
291
+ txt_box = gr.Textbox("Click to start optimization...", interactive = False)
292
+
293
+ opt_flag = gr.State(0)
294
+ gr.Markdown("""<p style="text-align: center; font-size: 20px">Optimization settings (SD)</p>""")
295
  num_tokens = gr.Number(value="5", label="num tokens to represent each object", interactive= True)
296
  num_tokens_global = num_tokens
297
+ embedding_learning_rate = gr.Textbox(value="0.0001", label="Embedding optimization: Learning rate", interactive= True )
298
+ max_emb_train_steps = gr.Number(value="200", label="embedding optimization: Training steps", interactive= True )
299
 
300
+ diffusion_model_learning_rate = gr.Textbox(value="0.00005", label="UNet Optimization: Learning rate", interactive= True )
301
+ max_diffusion_train_steps = gr.Number(value="200", label="UNet Optimization: Learning rate: Training steps", interactive= True )
302
 
303
+ train_batch_size = gr.Number(value="5", label="Batch size", interactive= True )
304
+ gradient_accumulation_steps=gr.Number(value="5", label="Gradient accumulation", interactive= True )
305
+
306
+ add_button = gr.Button("Run optimization")
307
+ def run_optimization_wrapper (
308
+ opt_flag,
309
+ num_tokens,
310
+ embedding_learning_rate ,
311
+ max_emb_train_steps ,
312
+ diffusion_model_learning_rate ,
313
+ max_diffusion_train_steps,
314
+ train_batch_size,
315
+ gradient_accumulation_steps
316
+ ):
 
 
 
 
 
 
 
 
 
 
 
317
  run_optimization = partial(
318
+ run_main,
 
 
 
319
  num_tokens=int(num_tokens),
320
  embedding_learning_rate = float(embedding_learning_rate),
321
+ max_emb_train_steps = int(max_emb_train_steps),
322
  diffusion_model_learning_rate= float(diffusion_model_learning_rate),
323
+ max_diffusion_train_steps = int(max_diffusion_train_steps),
324
+ train_batch_size=int(train_batch_size),
325
+ gradient_accumulation_steps=int(gradient_accumulation_steps)
326
  )
327
  run_optimization()
328
+ return opt_flag+1
329
+
330
+ add_button.click(run_optimization_wrapper,
331
+ inputs = [
332
+ opt_flag,
333
+ num_tokens,
334
+ embedding_learning_rate ,
335
+ max_emb_train_steps ,
336
+ diffusion_model_learning_rate ,
337
+ max_diffusion_train_steps,
338
+ train_batch_size,
339
+ gradient_accumulation_steps
340
+ ],
341
+ outputs = [opt_flag]
342
+ )
343
+
344
+ def change_text(txt_box):
345
+ return gr.Textbox("Optimization Finished!", interactive = False)
346
+ def change_text2(txt_box):
347
+ return gr.Textbox("Start optimization, check logs for progress...", interactive = False)
348
+ add_button.click(change_text2, txt_box, txt_box)
349
+ opt_flag.change(change_text, txt_box, txt_box)
350
+
351
+ with gr.Tab(label="3 Editing"):
352
+ with gr.Tab(label="3.1 Text-based editing"):
353
+
354
+ with gr.Row():
355
+ with gr.Column():
356
+ canvas_text_edit = gr.Image(value = None, type = "pil", label="Editing results", show_label=True)
357
+ # canvas_text_edit = gr.Gallery(label = "Edited results")
358
+
359
+ with gr.Column():
360
+ gr.Markdown("""<p style="text-align: center; font-size: 20px">Editing setting (SD)</p>""")
361
+
362
+ tgt_prompt = gr.Textbox(value="White bag", label="Editing: Text prompt", interactive= True )
363
+ tgt_index = gr.Number(value="0", label="Editing: Object index", interactive= True )
364
+ guidance_scale = gr.Textbox(value="6", label="Editing: CFG guidance scale", interactive= True )
365
+ num_sampling_steps = gr.Number(value="50", label="Editing: Sampling steps", interactive= True )
366
  edge_thickness = gr.Number(value="10", label="Editing: Edge thickness", interactive= True )
367
  strength = gr.Textbox(value="0.5", label="Editing: Mask strength", interactive= True )
368
+
369
+ add_button = gr.Button("Run Editing")
370
+ def run_edit_text_wrapper(
371
+ num_tokens,
372
+ guidance_scale,
373
+ num_sampling_steps ,
374
+ strength ,
375
+ edge_thickness,
376
+ tgt_prompt ,
377
+ tgt_index
378
+ ):
379
+
380
+ run_edit_text = partial(
381
+ run_main,
382
+ load_trained=True,
383
+ text=True,
384
+ num_tokens = int(num_tokens_global.value),
385
+ guidance_scale = float(guidance_scale),
386
+ num_sampling_steps = int(num_sampling_steps),
387
+ strength = float(strength),
388
+ edge_thickness = int(edge_thickness),
389
+ num_imgs = 1,
390
+ tgt_prompt = tgt_prompt,
391
+ tgt_index = int(tgt_index)
392
+ )
393
+ return run_edit_text()
394
 
395
+ add_button.click(run_edit_text_wrapper,
396
+ inputs = [num_tokens_global,
397
+ guidance_scale,
398
+ num_sampling_steps,
399
+ strength ,
400
+ edge_thickness,
401
+ tgt_prompt ,
402
+ tgt_index
403
+ ],
404
+ outputs = [canvas_text_edit]
405
+ )
406
+
407
+ def load_pil_img():
408
+ from PIL import Image
409
+ return Image.open("example_tmp/text/out_text_0.png")
410
+
411
+ load_button = gr.Button("Load results")
412
+ load_button.click(load_pil_img,
413
+ inputs = [],
414
+ outputs = [canvas_text_edit]
415
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
 
 
 
 
417
 
418
 
419
 
420
+ demo.queue().launch(share=True, debug=True)
img2.png DELETED

Git LFS Details

  • SHA256: f0d93d36051ad4f4ce9b371d4122830bdbbda01c2a27e23a538b13e5cb3715f6
  • Pointer size: 132 Bytes
  • Size of remote file: 1.4 MB
img3.png DELETED
Binary file (259 kB)
 
img4.png DELETED
Binary file (45.9 kB)
 
main.py CHANGED
@@ -12,9 +12,6 @@ from utils_mask import check_mask_overlap_torch, check_cover_all_torch, visualiz
12
  def run_main(
13
  name="example_tmp",
14
  name_2=None,
15
- mask_np_list=None,
16
- mask_label_list=None,
17
- image_gt=None,
18
  dpm="sd",
19
  resolution=512,
20
  seed=42,
@@ -74,17 +71,13 @@ def run_main(
74
  base_output_folder = "."
75
 
76
  input_folder = os.path.join(base_input_folder, name)
77
- mask_list = []
78
- for mask_np in mask_np_list:
79
- mask = torch.from_numpy(mask_np.astype(np.uint8))
80
- mask_list.append(mask)
81
-
82
- #mask_list, mask_label_list = load_mask(input_folder)
83
  assert mask_list[0].shape[0] == resolution, "Segmentation should be done on size {}".format(resolution)
84
- #try:
85
- # image_gt = load_image(os.path.join(input_folder, "img_{}.png".format(resolution) ), size = resolution)
86
- #except:
87
- # image_gt = load_image(os.path.join(input_folder, "img_{}.jpg".format(resolution) ), size = resolution)
88
 
89
  if image:
90
  input_folder_2 = os.path.join(base_input_folder, name_2)
 
12
  def run_main(
13
  name="example_tmp",
14
  name_2=None,
 
 
 
15
  dpm="sd",
16
  resolution=512,
17
  seed=42,
 
71
  base_output_folder = "."
72
 
73
  input_folder = os.path.join(base_input_folder, name)
74
+
75
+ mask_list, mask_label_list = load_mask(input_folder)
 
 
 
 
76
  assert mask_list[0].shape[0] == resolution, "Segmentation should be done on size {}".format(resolution)
77
+ try:
78
+ image_gt = load_image(os.path.join(input_folder, "img_{}.png".format(resolution) ), size = resolution)
79
+ except:
80
+ image_gt = load_image(os.path.join(input_folder, "img_{}.jpg".format(resolution) ), size = resolution)
81
 
82
  if image:
83
  input_folder_2 = os.path.join(base_input_folder, name_2)
requirements.txt CHANGED
@@ -1,16 +1,12 @@
1
- huggingface_hub
2
- matplotlib==3.9.4
3
-
4
- accelerate==0.34.2
5
- diffusers==0.30.2
6
- numpy==1.26.4
7
- torch==2.8.0
8
- torchvision==0.23.0
9
  transformers==4.37.2
10
- xformers==0.0.32.post2
 
 
 
11
  scipy
12
- setuptools
13
  tqdm
 
14
  safetensors
15
- peft==0.13.2
16
- pydantic==2.10.6
 
1
+ torch==2.2.0
2
+ torchvision==0.17.0
 
 
 
 
 
 
3
  transformers==4.37.2
4
+ accelerate==0.23.0
5
+ gradio==3.41.1
6
+ xformers==0.0.24
7
+ diffusers==0.26.3
8
  scipy
 
9
  tqdm
10
+ numpy
11
  safetensors
12
+ peft
 
segment.py CHANGED
@@ -3,7 +3,6 @@ from transformers import AutoImageProcessor, Mask2FormerForUniversalSegmentation
3
  from PIL import Image
4
  import torch
5
  from collections import defaultdict
6
- from functools import lru_cache
7
  import matplotlib.pyplot as plt
8
  from matplotlib import cm
9
  import matplotlib.patches as mpatches
@@ -11,17 +10,6 @@ import os
11
  import numpy as np
12
  import argparse
13
  import matplotlib
14
- import gradio as gr
15
-
16
-
17
- @lru_cache(maxsize=1)
18
- def get_segmentation_model():
19
- model_id = "facebook/mask2former-swin-base-coco-panoptic"
20
- processor = AutoImageProcessor.from_pretrained(model_id)
21
- model = Mask2FormerForUniversalSegmentation.from_pretrained(model_id)
22
- model.eval()
23
- return processor, model
24
-
25
 
26
  def load_image(image_path, left=0, right=0, top=0, bottom=0, size = 512):
27
  if type(image_path) is str:
@@ -56,18 +44,14 @@ def draw_panoptic_segmentation(segmentation, segments_info,save_folder=None, nos
56
  instances_counter = defaultdict(int)
57
  handles = []
58
  label_list = []
59
-
60
- mask_np_list = []
61
-
62
  if not noseg:
63
  if torch.min(segmentation) == 0:
64
  mask = segmentation==0
65
  mask = mask.cpu().detach().numpy() # [512,512] bool
66
- print(mask.shape)
67
  segment_label = "rest"
 
68
  color = viridis(0)
69
  label = f"{segment_label}-{0}"
70
- mask_np_list.append(mask)
71
  handles.append(mpatches.Patch(color=color, label=label))
72
  label_list.append(label)
73
 
@@ -77,11 +61,10 @@ def draw_panoptic_segmentation(segmentation, segments_info,save_folder=None, nos
77
  if torch.min(segmentation) != 0:
78
  segment_id -= 1
79
  mask = mask.cpu().detach().numpy() # [512,512] bool
80
- print(mask.shape)
81
- mask_np_list.append(mask)
82
  segment_label = model.config.id2label[segment['label_id']]
83
  instances_counter[segment['label_id']] += 1
84
-
85
  color = viridis(segment_id)
86
 
87
  label = f"{segment_label}-{segment_id}"
@@ -89,10 +72,8 @@ def draw_panoptic_segmentation(segmentation, segments_info,save_folder=None, nos
89
  label_list.append(label)
90
  else:
91
  mask = np.full(segmentation.shape, True)
92
- print(mask.shape)
93
-
94
  segment_label = "all"
95
- mask_np_list.append(mask)
96
  color = viridis(0)
97
  label = f"{segment_label}-{0}"
98
  handles.append(mpatches.Patch(color=color, label=label))
@@ -103,16 +84,17 @@ def draw_panoptic_segmentation(segmentation, segments_info,save_folder=None, nos
103
  # plt.savefig(os.path.join(save_folder, 'mask_clear.png'), dpi=500)
104
  ax.legend(handles=handles)
105
  plt.savefig(os.path.join(save_folder, 'seg_init.png'), dpi=500 )
106
- plt.close(fig)
107
  print("; ".join(label_list))
108
- return mask_np_list,label_list
109
 
110
 
111
- def run_segmentation(image, name="example_tmp", size = 512, noseg=False):
 
 
112
 
113
  base_folder_path = "."
114
 
115
- processor, model = get_segmentation_model()
 
116
 
117
 
118
  # input_folder = os.path.join(base_folder_path, name )
@@ -123,15 +105,15 @@ def run_segmentation(image, name="example_tmp", size = 512, noseg=False):
123
  image =Image.fromarray(image)
124
  image = image.resize((size, size))
125
  os.makedirs(name, exist_ok=True)
126
- #image.save(os.path.join(name,"img_{}.png".format(size)))
127
  inputs = processor(image, return_tensors="pt")
128
- with torch.inference_mode():
129
  outputs = model(**inputs)
130
 
131
  panoptic_segmentation = processor.post_process_panoptic_segmentation(outputs, target_sizes=[image.size[::-1]])[0]
132
  save_folder = os.path.join(base_folder_path, name)
133
  os.makedirs(save_folder, exist_ok=True)
134
- mask_list,label_list = draw_panoptic_segmentation(**panoptic_segmentation, save_folder = save_folder, noseg = noseg, model = model)
135
  print("Finish segment")
136
- #block_flag += 1
137
- return image,mask_list,label_list#, gr.Button.update("1.2 Load edited masks",visible = True), gr.Checkbox.update(label = "Show Segmentation",visible = True)
 
3
  from PIL import Image
4
  import torch
5
  from collections import defaultdict
 
6
  import matplotlib.pyplot as plt
7
  from matplotlib import cm
8
  import matplotlib.patches as mpatches
 
10
  import numpy as np
11
  import argparse
12
  import matplotlib
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  def load_image(image_path, left=0, right=0, top=0, bottom=0, size = 512):
15
  if type(image_path) is str:
 
44
  instances_counter = defaultdict(int)
45
  handles = []
46
  label_list = []
 
 
 
47
  if not noseg:
48
  if torch.min(segmentation) == 0:
49
  mask = segmentation==0
50
  mask = mask.cpu().detach().numpy() # [512,512] bool
 
51
  segment_label = "rest"
52
+ np.save( os.path.join(save_folder, "mask{}_{}.npy".format(0,"rest")) , mask)
53
  color = viridis(0)
54
  label = f"{segment_label}-{0}"
 
55
  handles.append(mpatches.Patch(color=color, label=label))
56
  label_list.append(label)
57
 
 
61
  if torch.min(segmentation) != 0:
62
  segment_id -= 1
63
  mask = mask.cpu().detach().numpy() # [512,512] bool
64
+
 
65
  segment_label = model.config.id2label[segment['label_id']]
66
  instances_counter[segment['label_id']] += 1
67
+ np.save( os.path.join(save_folder, "mask{}_{}.npy".format(segment_id,segment_label)) , mask)
68
  color = viridis(segment_id)
69
 
70
  label = f"{segment_label}-{segment_id}"
 
72
  label_list.append(label)
73
  else:
74
  mask = np.full(segmentation.shape, True)
 
 
75
  segment_label = "all"
76
+ np.save( os.path.join(save_folder, "mask{}_{}.npy".format(0,"all")) , mask)
77
  color = viridis(0)
78
  label = f"{segment_label}-{0}"
79
  handles.append(mpatches.Patch(color=color, label=label))
 
84
  # plt.savefig(os.path.join(save_folder, 'mask_clear.png'), dpi=500)
85
  ax.legend(handles=handles)
86
  plt.savefig(os.path.join(save_folder, 'seg_init.png'), dpi=500 )
 
87
  print("; ".join(label_list))
 
88
 
89
 
90
+
91
+
92
+ def run_segmentation(image, block_flag, name="example_tmp", size = 512, noseg=False):
93
 
94
  base_folder_path = "."
95
 
96
+ processor = AutoImageProcessor.from_pretrained("facebook/mask2former-swin-base-coco-panoptic")
97
+ model = Mask2FormerForUniversalSegmentation.from_pretrained("facebook/mask2former-swin-base-coco-panoptic")
98
 
99
 
100
  # input_folder = os.path.join(base_folder_path, name )
 
105
  image =Image.fromarray(image)
106
  image = image.resize((size, size))
107
  os.makedirs(name, exist_ok=True)
108
+ image.save(os.path.join(name,"img_{}.png".format(size)))
109
  inputs = processor(image, return_tensors="pt")
110
+ with torch.no_grad():
111
  outputs = model(**inputs)
112
 
113
  panoptic_segmentation = processor.post_process_panoptic_segmentation(outputs, target_sizes=[image.size[::-1]])[0]
114
  save_folder = os.path.join(base_folder_path, name)
115
  os.makedirs(save_folder, exist_ok=True)
116
+ draw_panoptic_segmentation(**panoptic_segmentation, save_folder = save_folder, noseg = noseg, model = model)
117
  print("Finish segment")
118
+ block_flag += 1
119
+ return block_flag
utils.py CHANGED
@@ -249,6 +249,7 @@ def load_mask (input_folder):
249
  except:
250
  print("please check mask")
251
  # plt.imsave( "out_mask.png", mask_list_edit[0])
 
252
  return mask_list, mask_label_list
253
 
254
  def load_image(image_path, left=0, right=0, top=0, bottom=0, size = 512):
 
249
  except:
250
  print("please check mask")
251
  # plt.imsave( "out_mask.png", mask_list_edit[0])
252
+ import pdb; pdb.set_trace()
253
  return mask_list, mask_label_list
254
 
255
  def load_image(image_path, left=0, right=0, top=0, bottom=0, size = 512):