Sm0kyWu commited on
Commit
c17faf0
ยท
verified ยท
1 Parent(s): 485f2ba

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -188
app.py CHANGED
@@ -69,9 +69,10 @@ def run_sam(predictor, selected_points):
69
  )
70
  best_mask = masks[0].astype(np.uint8)
71
  # dilate
72
- kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
73
- best_mask = cv2.dilate(best_mask, kernel, iterations=1)
74
- best_mask = cv2.erode(best_mask, kernel, iterations=1)
 
75
  return best_mask
76
 
77
  def apply_mask_overlay(image, mask, color=(255, 0, 0)):
@@ -105,9 +106,8 @@ def reset_points():
105
 
106
  @spaces.GPU
107
  def image_to_3d(
108
- image: Image.Image,
109
- multiimages: List[tuple],
110
- is_multiimage: bool,
111
  seed: int,
112
  ss_guidance_strength: float,
113
  ss_sampling_steps: int,
@@ -120,37 +120,22 @@ def image_to_3d(
120
  ๅฐ†ๅ›พๅƒ่ฝฌๆขไธบ 3D ๆจกๅž‹ใ€‚
121
  """
122
  user_dir = os.path.join(TMP_DIR, str(req.session_hash))
123
- if not is_multiimage:
124
- outputs = pipeline.run(
125
- image,
126
- seed=seed,
127
- formats=["gaussian", "mesh"],
128
- preprocess_image=False,
129
- sparse_structure_sampler_params={
130
- "steps": ss_sampling_steps,
131
- "cfg_strength": ss_guidance_strength,
132
- },
133
- slat_sampler_params={
134
- "steps": slat_sampling_steps,
135
- "cfg_strength": slat_guidance_strength,
136
- },
137
- )
138
- else:
139
- outputs = pipeline.run_multi_image(
140
- [img[0] for img in multiimages],
141
- seed=seed,
142
- formats=["gaussian", "mesh"],
143
- preprocess_image=False,
144
- sparse_structure_sampler_params={
145
- "steps": ss_sampling_steps,
146
- "cfg_strength": ss_guidance_strength,
147
- },
148
- slat_sampler_params={
149
- "steps": slat_sampling_steps,
150
- "cfg_strength": slat_guidance_strength,
151
- },
152
- mode=multiimage_algo,
153
- )
154
  video = render_utils.render_video(outputs['gaussian'][0], num_frames=120)['color']
155
  video_geo = render_utils.render_video(outputs['mesh'][0], num_frames=120)['normal']
156
  video = [np.concatenate([video[i], video_geo[i]], axis=1) for i in range(len(video))]
@@ -270,48 +255,40 @@ def get_sam_predictor():
270
  return sam_predictor
271
 
272
 
273
- def draw_points_on_image(image, point, point_type):
274
  """ๅœจๅ›พๅƒไธŠ็ป˜ๅˆถๆ‰€ๆœ‰็‚น๏ผŒpoints ไธบ [(x, y, point_type), ...]"""
275
  image_with_points = image.copy()
276
  x, y = point
277
- color = (255, 0, 0) if point_type == "vis" else (0, 255, 0)
278
  cv2.circle(image_with_points, (int(x), int(y)), radius=10, color=color, thickness=-1)
279
  return image_with_points
280
 
281
 
282
- def see_point(image, x, y, point_type):
283
  """
284
  seeๆ“ไฝœ๏ผšไธไฟฎๆ”น points ๅˆ—่กจ๏ผŒไป…ๅœจๅ›พๅƒไธŠไธดๆ—ถๆ˜พ็คบ่ฟ™ไธช็‚น๏ผŒ
285
  ๅนถ่ฟ”ๅ›žๆ›ดๆ–ฐๅŽ็š„ๅ›พๅƒๅ’Œๅฝ“ๅ‰ๅˆ—่กจ๏ผˆไธๆ›ดๆ–ฐ๏ผ‰ใ€‚
286
  """
287
  # ๅคๅˆถๅฝ“ๅ‰ๅˆ—่กจ๏ผŒๅนถๅœจๅ‰ฏๆœฌไธญๅŠ ไธŠๆ–ฐ็‚น๏ผˆไป…็”จไบŽๆ˜พ็คบ๏ผ‰
288
- updated_image = draw_points_on_image(image, [x,y], point_type)
289
  return updated_image
290
 
291
- def add_point(x, y, point_type, visible_points, occlusion_points):
292
  """
293
  addๆ“ไฝœ๏ผšๅฐ†ๆ–ฐ็‚นๆทปๅŠ ๅˆฐ points ๅˆ—่กจไธญ๏ผŒ
294
  ๅนถ่ฟ”ๅ›žๆ›ดๆ–ฐๅŽ็š„ๅ›พๅƒๅ’Œๆ–ฐ็š„็‚นๅˆ—่กจใ€‚
295
  """
296
- if point_type == "vis":
297
- # check duplicate
298
- if [x, y] not in visible_points:
299
- visible_points.append([x, y])
300
- else:
301
- if [x, y] not in occlusion_points:
302
- occlusion_points.append([x, y])
303
- return visible_points, occlusion_points
304
 
305
- def delete_point(point_type, visible_points, occlusion_points):
306
  """
307
  deleteๆ“ไฝœ๏ผšๅˆ ้™ค points ๅˆ—่กจไธญ็š„ๆœ€ๅŽไธ€ไธช็‚น๏ผŒ
308
  ๅนถ่ฟ”ๅ›žๆ›ดๆ–ฐๅŽ็š„ๅ›พๅƒๅ’Œๆ–ฐ็š„็‚นๅˆ—่กจใ€‚
309
  """
310
- if point_type == "vis":
311
- visible_points.pop()
312
- else:
313
- occlusion_points.pop()
314
- return visible_points, occlusion_points
315
 
316
 
317
  def clear_all_points(image):
@@ -331,23 +308,13 @@ def see_visible_points(image, visible_points):
331
  cv2.circle(updated_image, (int(p[0]), int(p[1])), radius=10, color=(255, 0, 0), thickness=-1)
332
  return updated_image
333
 
334
- def see_occlusion_points(image, occlusion_points):
335
- """
336
- ๅœจๅ›พๅƒไธŠ็ป˜ๅˆถๆ‰€ๆœ‰ occlusion ็‚น๏ผˆ็ปฟ่‰ฒ๏ผ‰ใ€‚
337
- """
338
- updated_image = image.copy()
339
- for p in occlusion_points:
340
- cv2.circle(updated_image, (int(p[0]), int(p[1])), radius=10, color=(0, 255, 0), thickness=-1)
341
- return updated_image
342
-
343
- def update_all_points(visible_points, occlusion_points):
344
- text = f"Visible Points: {visible_points}\nOcclusion Points: {occlusion_points}"
345
  visible_dropdown_choices = [f"({p[0]}, {p[1]})" for p in visible_points]
346
- occlusion_dropdown_choices = [f"({p[0]}, {p[1]})" for p in occlusion_points]
347
  # ่ฟ”ๅ›žๆ›ดๆ–ฐๅญ—ๅ…ธๆฅๆ˜Ž็กฎ่ฎพ็ฝฎ choices ๅ’Œ value
348
- return text, gr.Dropdown(label="Select Visible Point to Delete", choices=visible_dropdown_choices, value=None, interactive=True), gr.Dropdown(label="Select Occlusion Point to Delete", choices=occlusion_dropdown_choices, value=None, interactive=True)
349
 
350
- def delete_selected_visible(image, visible_points, occlusion_points, selected_value):
351
  # selected_value ๆ˜ฏ็ฑปไผผ "(x, y)" ็š„ๅญ—็ฌฆไธฒ
352
  try:
353
  selected_index = [f"({p[0]}, {p[1]})" for p in visible_points].index(selected_value)
@@ -359,22 +326,8 @@ def delete_selected_visible(image, visible_points, occlusion_points, selected_va
359
  # ้‡ๆ–ฐ็ป˜ๅˆถๆ‰€ๆœ‰ visible ็‚น๏ผˆ็บข่‰ฒ๏ผ‰
360
  for p in visible_points:
361
  cv2.circle(updated_image, (int(p[0]), int(p[1])), radius=10, color=(255, 0, 0), thickness=-1)
362
- updated_text, vis_dropdown, occ_dropdown = update_all_points(visible_points, occlusion_points)
363
- return updated_image, visible_points, occlusion_points, updated_text, vis_dropdown, occ_dropdown
364
-
365
- def delete_selected_occlusion(image, visible_points, occlusion_points, selected_value):
366
- try:
367
- selected_index = [f"({p[0]}, {p[1]})" for p in occlusion_points].index(selected_value)
368
- except ValueError:
369
- selected_index = None
370
- if selected_index is not None and 0 <= selected_index < len(occlusion_points):
371
- occlusion_points.pop(selected_index)
372
- updated_image = image.copy()
373
- # ้‡ๆ–ฐ็ป˜ๅˆถๆ‰€ๆœ‰ occlusion ็‚น๏ผˆ็ปฟ่‰ฒ๏ผ‰
374
- for p in occlusion_points:
375
- cv2.circle(updated_image, (int(p[0]), int(p[1])), radius=10, color=(0, 255, 0), thickness=-1)
376
- updated_text, vis_dropdown, occ_dropdown = update_all_points(visible_points, occlusion_points)
377
- return updated_image, visible_points, occlusion_points, updated_text, vis_dropdown, occ_dropdown
378
 
379
  def add_mask(mask, mask_list):
380
  # check if the mask if same as the last mask in the list
@@ -399,43 +352,25 @@ def delete_mask(mask_list):
399
  mask_list.pop()
400
  return mask_list
401
 
 
 
 
 
 
 
 
 
 
402
 
403
- def apply_combined_mask_overlay(image, vis_mask, occ_mask):
404
- """
405
- ๅœจๅŽŸๅ›พไธŠๅ ๅŠ  mask๏ผšไฝฟ็”จ็บข่‰ฒ็ป˜ๅˆถ mask ็š„่ฝฎๅป“๏ผŒ้ž mask ๅŒบๅŸŸๅ ๅŠ ๆต…็ฐ่‰ฒๅŠ้€ๆ˜Ž้ฎ็ฝฉใ€‚
406
- """
407
- img_arr = image
408
- overlay = img_arr.copy()
409
- gray_color = np.array([200, 200, 200], dtype=np.uint8)
410
- non_mask = (vis_mask == 0) & (occ_mask == 0)
411
- overlay[non_mask] = (0.5 * overlay[non_mask] + 0.5 * gray_color).astype(np.uint8)
412
- contours_occ, _ = cv2.findContours(occ_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
413
- cv2.drawContours(overlay, contours_occ, -1, (0,0,255), 2)
414
- contours_vis, _ = cv2.findContours(vis_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
415
- cv2.drawContours(overlay, contours_vis, -1, (255,0,0), 2)
416
- return overlay
417
 
418
 
419
- def combine_mask(image, visible_mask_list, occlusion_mask_list):
420
- combined_vis_mask = np.zeros_like(image[:, :, 0])
421
- combined_occ_mask = np.zeros_like(image[:, :, 0])
422
- combined_mask = np.zeros_like(image[:, :, 0])
423
- for mask in visible_mask_list:
424
- combined_vis_mask = cv2.bitwise_or(combined_mask, mask)
425
- for mask in occlusion_mask_list:
426
- combined_occ_mask = cv2.bitwise_or(combined_mask, mask)
427
- # ๆทปๅŠ  visible mask ่พน็ผ˜ไฝœไธบ occlusion mask ็š„ไธ€้ƒจๅˆ†
428
-
429
- overlay = apply_combined_mask_overlay(image, combined_vis_mask, combined_occ_mask)
430
- # 5*5 kernel dilate for occlusion mask
431
- kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
432
- combined_occ_mask = cv2.dilate(combined_occ_mask, kernel, iterations=1)
433
- combined_mask[combined_occ_mask > 0] = 128
434
- combined_mask[combined_vis_mask > 0] = 255
435
- # concat the mask and overlay to be a single image
436
- # print(overlay.shape, combined_mask.shape)
437
- result = cv2.hconcat([overlay, combined_mask[..., None].repeat(3, axis=-1)])
438
- return result
439
 
440
 
441
  with gr.Blocks(delete_cache=(600, 600)) as demo:
@@ -449,9 +384,9 @@ with gr.Blocks(delete_cache=(600, 600)) as demo:
449
  occlusion_points_state = gr.State(value=[])
450
  original_image = gr.State(value=None)
451
  visibility_mask = gr.State(value=None)
452
- occlusion_mask = gr.State(value=None)
453
  visibility_mask_list = gr.State(value=[])
454
- occlusion_mask_list = gr.State(value=[])
 
455
 
456
 
457
  with gr.Row():
@@ -471,25 +406,19 @@ with gr.Blocks(delete_cache=(600, 600)) as demo:
471
  with gr.Row():
472
  x_input = gr.Number(label="X Coordinate", value=0)
473
  y_input = gr.Number(label="Y Coordinate", value=0)
474
- point_type = gr.Radio(["vis", "occ"], label="Point Prompt Type", value="vis")
475
  with gr.Row():
476
  see_button = gr.Button("Render Point")
477
  add_button = gr.Button("Add Point")
478
  with gr.Row():
479
- # ๆ–ฐๅขžๆŒ‰้’ฎ๏ผšClearใ€ๅˆ†ๅˆซๆŸฅ็œ‹ visible/occlusion
480
  clear_button = gr.Button("Clear Points")
481
- see_visible_button = gr.Button("Visible Points")
482
- see_occlusion_button = gr.Button("Occluded Points")
483
  with gr.Row():
484
  # ๆ–ฐๅขžๆ–‡ๆœฌๆก†ๅฎžๆ—ถๆ˜พ็คบ็‚นๅˆ—่กจ
485
  points_text = gr.Textbox(label="Points List", interactive=False)
486
  with gr.Row():
487
  # ๆ–ฐๅขžไธ‹ๆ‹‰่œๅ•๏ผŒ็”จๆˆทๅฏ้€‰ๆ‹ฉ้œ€่ฆๅˆ ้™ค็š„็‚น
488
  visible_points_dropdown = gr.Dropdown(label="Select Visible Point to Delete", choices=[], value=None, interactive=True)
489
- occlusion_points_dropdown = gr.Dropdown(label="Select Occlusion Point to Delete", choices=[], value=None, interactive=True)
490
- with gr.Row():
491
  delete_visible_button = gr.Button("Delete Selected Visible")
492
- delete_occlusion_button = gr.Button("Delete Selected Occlusion")
493
  with gr.Column():
494
  # ็”จไบŽๆ˜พ็คบ SAM ๅˆ†ๅ‰ฒ็ป“ๆžœ
495
  visible_mask = gr.Image(label='Visible Mask', interactive=False, height=300)
@@ -499,25 +428,31 @@ with gr.Blocks(delete_cache=(600, 600)) as demo:
499
  with gr.Row():
500
  render_vis_mask = gr.Button("Render Mask")
501
  undo_vis_mask = gr.Button("Undo Last Mask")
502
- occluded_mask = gr.Image(label='Occlusion Mask', interactive=False, height=300)
503
  with gr.Row():
504
- gen_occ_mask = gr.Button("Generate Mask")
505
- add_occ_mask = gr.Button("Add Mask")
506
- with gr.Row():
507
- render_occ_mask = gr.Button("Render Mask")
508
- undo_occ_mask = gr.Button("Undo Last Mask")
509
- #
510
  with gr.Row():
511
  gr.Markdown("""* Step 2 - 3D Amodal Completion.
512
- * Please first check the obtained mask, and make sure there is no "GAP" between the visible area (white) and occluded area (gray).
513
  * Different random seeds can be tried in "Generation Settings", if you think the results are not ideal.
514
  * If the reconstruction 3D asset is satisfactory, you can extract the GLB file and download it.
515
  """)
516
  with gr.Row():
517
  with gr.Column():
518
- combined_mask = gr.Image(label='Combined Mask', interactive=False, height=300)
519
- with gr.Row():
520
- check_combine_button = gr.Button("Check Combined Mask")
 
 
 
 
 
 
 
 
 
 
 
 
521
 
522
  # ---------------------------
523
  # ๅŽŸๆœ‰ไบคไบ’้€ป่พ‘๏ผˆ็•ฅ๏ผ‰
@@ -529,13 +464,13 @@ with gr.Blocks(delete_cache=(600, 600)) as demo:
529
  )
530
  see_button.click(
531
  see_point,
532
- inputs=[original_image, x_input, y_input, point_type],
533
  outputs=[input_image]
534
  )
535
  add_button.click(
536
  add_point,
537
- inputs=[x_input, y_input, point_type, visible_points_state, occlusion_points_state],
538
- outputs=[visible_points_state, occlusion_points_state]
539
  )
540
 
541
  # ---------------------------
@@ -551,31 +486,16 @@ with gr.Blocks(delete_cache=(600, 600)) as demo:
551
  inputs=[input_image, visible_points_state],
552
  outputs=input_image
553
  )
554
- see_occlusion_button.click(
555
- see_occlusion_points,
556
- inputs=[input_image, occlusion_points_state],
557
- outputs=input_image
558
- )
559
  # ๅฝ“ visible_points_state ๆˆ– occlusion_points_state ๅ˜ๅŒ–ๆ—ถ๏ผŒๆ›ดๆ–ฐๆ–‡ๆœฌๆก†ๅ’Œไธ‹ๆ‹‰่œๅ•
560
  visible_points_state.change(
561
  update_all_points,
562
- inputs=[visible_points_state, occlusion_points_state],
563
- outputs=[points_text, visible_points_dropdown, occlusion_points_dropdown]
564
- )
565
- occlusion_points_state.change(
566
- update_all_points,
567
- inputs=[visible_points_state, occlusion_points_state],
568
- outputs=[points_text, visible_points_dropdown, occlusion_points_dropdown]
569
  )
570
  delete_visible_button.click(
571
  delete_selected_visible,
572
- inputs=[input_image, visible_points_state, occlusion_points_state, visible_points_dropdown],
573
- outputs=[input_image, visible_points_state, occlusion_points_state, points_text, visible_points_dropdown, occlusion_points_dropdown]
574
- )
575
- delete_occlusion_button.click(
576
- delete_selected_occlusion,
577
- inputs=[input_image, visible_points_state, occlusion_points_state, occlusion_points_dropdown],
578
- outputs=[input_image, visible_points_state, occlusion_points_state, points_text, visible_points_dropdown, occlusion_points_dropdown]
579
  )
580
 
581
  # ็”Ÿๆˆmask็š„้€ป่พ‘
@@ -599,33 +519,20 @@ with gr.Blocks(delete_cache=(600, 600)) as demo:
599
  inputs=[visibility_mask_list],
600
  outputs=[visibility_mask_list]
601
  )
602
- gen_occ_mask.click(
603
- segment_and_overlay,
604
- inputs=[original_image, occlusion_points_state, predictor],
605
- outputs=[occluded_mask, occlusion_mask]
606
- )
607
- add_occ_mask.click(
608
- add_mask,
609
- inputs=[occlusion_mask, occlusion_mask_list],
610
- outputs=[occlusion_mask_list]
611
- )
612
- render_occ_mask.click(
613
- vis_mask,
614
- inputs=[original_image, occlusion_mask_list],
615
- outputs=[occluded_mask]
616
- )
617
- undo_occ_mask.click(
618
- delete_mask,
619
- inputs=[occlusion_mask_list],
620
- outputs=[occlusion_mask_list]
621
- )
622
 
623
- # check combined mask
624
- check_combine_button.click(
625
- combine_mask,
626
- inputs=[original_image, visibility_mask_list, occlusion_mask_list],
627
- outputs=[combined_mask]
628
- )
 
 
 
 
 
 
 
629
 
630
 
631
  # ๅฏๅŠจ Gradio App
 
69
  )
70
  best_mask = masks[0].astype(np.uint8)
71
  # dilate
72
+ if len(selected_points) > 1:
73
+ kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
74
+ best_mask = cv2.dilate(best_mask, kernel, iterations=1)
75
+ best_mask = cv2.erode(best_mask, kernel, iterations=1)
76
  return best_mask
77
 
78
  def apply_mask_overlay(image, mask, color=(255, 0, 0)):
 
106
 
107
  @spaces.GPU
108
  def image_to_3d(
109
+ image: List[tuple],
110
+ masks: List[np.ndarray],
 
111
  seed: int,
112
  ss_guidance_strength: float,
113
  ss_sampling_steps: int,
 
120
  ๅฐ†ๅ›พๅƒ่ฝฌๆขไธบ 3D ๆจกๅž‹ใ€‚
121
  """
122
  user_dir = os.path.join(TMP_DIR, str(req.session_hash))
123
+ outputs = pipeline.run_multi_image(
124
+ [img[0] for img in image],
125
+ [mask[0] for mask in masks],
126
+ seed=seed,
127
+ formats=["gaussian", "mesh"],
128
+ preprocess_image=False,
129
+ sparse_structure_sampler_params={
130
+ "steps": ss_sampling_steps,
131
+ "cfg_strength": ss_guidance_strength,
132
+ },
133
+ slat_sampler_params={
134
+ "steps": slat_sampling_steps,
135
+ "cfg_strength": slat_guidance_strength,
136
+ },
137
+ mode=multiimage_algo,
138
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  video = render_utils.render_video(outputs['gaussian'][0], num_frames=120)['color']
140
  video_geo = render_utils.render_video(outputs['mesh'][0], num_frames=120)['normal']
141
  video = [np.concatenate([video[i], video_geo[i]], axis=1) for i in range(len(video))]
 
255
  return sam_predictor
256
 
257
 
258
+ def draw_points_on_image(image, point):
259
  """ๅœจๅ›พๅƒไธŠ็ป˜ๅˆถๆ‰€ๆœ‰็‚น๏ผŒpoints ไธบ [(x, y, point_type), ...]"""
260
  image_with_points = image.copy()
261
  x, y = point
262
+ color = (255, 0, 0)
263
  cv2.circle(image_with_points, (int(x), int(y)), radius=10, color=color, thickness=-1)
264
  return image_with_points
265
 
266
 
267
+ def see_point(image, x, y):
268
  """
269
  seeๆ“ไฝœ๏ผšไธไฟฎๆ”น points ๅˆ—่กจ๏ผŒไป…ๅœจๅ›พๅƒไธŠไธดๆ—ถๆ˜พ็คบ่ฟ™ไธช็‚น๏ผŒ
270
  ๅนถ่ฟ”ๅ›žๆ›ดๆ–ฐๅŽ็š„ๅ›พๅƒๅ’Œๅฝ“ๅ‰ๅˆ—่กจ๏ผˆไธๆ›ดๆ–ฐ๏ผ‰ใ€‚
271
  """
272
  # ๅคๅˆถๅฝ“ๅ‰ๅˆ—่กจ๏ผŒๅนถๅœจๅ‰ฏๆœฌไธญๅŠ ไธŠๆ–ฐ็‚น๏ผˆไป…็”จไบŽๆ˜พ็คบ๏ผ‰
273
+ updated_image = draw_points_on_image(image, [x,y])
274
  return updated_image
275
 
276
+ def add_point(x, y, visible_points):
277
  """
278
  addๆ“ไฝœ๏ผšๅฐ†ๆ–ฐ็‚นๆทปๅŠ ๅˆฐ points ๅˆ—่กจไธญ๏ผŒ
279
  ๅนถ่ฟ”ๅ›žๆ›ดๆ–ฐๅŽ็š„ๅ›พๅƒๅ’Œๆ–ฐ็š„็‚นๅˆ—่กจใ€‚
280
  """
281
+ if [x, y] not in visible_points:
282
+ visible_points.append([x, y])
283
+ return visible_points
 
 
 
 
 
284
 
285
+ def delete_point(visible_points):
286
  """
287
  deleteๆ“ไฝœ๏ผšๅˆ ้™ค points ๅˆ—่กจไธญ็š„ๆœ€ๅŽไธ€ไธช็‚น๏ผŒ
288
  ๅนถ่ฟ”ๅ›žๆ›ดๆ–ฐๅŽ็š„ๅ›พๅƒๅ’Œๆ–ฐ็š„็‚นๅˆ—่กจใ€‚
289
  """
290
+ visible_points.pop()
291
+ return visible_points
 
 
 
292
 
293
 
294
  def clear_all_points(image):
 
308
  cv2.circle(updated_image, (int(p[0]), int(p[1])), radius=10, color=(255, 0, 0), thickness=-1)
309
  return updated_image
310
 
311
+ def update_all_points(visible_points):
312
+ text = f"Points: {visible_points}"
 
 
 
 
 
 
 
 
 
313
  visible_dropdown_choices = [f"({p[0]}, {p[1]})" for p in visible_points]
 
314
  # ่ฟ”ๅ›žๆ›ดๆ–ฐๅญ—ๅ…ธๆฅๆ˜Ž็กฎ่ฎพ็ฝฎ choices ๅ’Œ value
315
+ return text, gr.Dropdown(label="Select Visible Point to Delete", choices=visible_dropdown_choices, value=None, interactive=True)
316
 
317
+ def delete_selected_visible(image, visible_points, selected_value):
318
  # selected_value ๆ˜ฏ็ฑปไผผ "(x, y)" ็š„ๅญ—็ฌฆไธฒ
319
  try:
320
  selected_index = [f"({p[0]}, {p[1]})" for p in visible_points].index(selected_value)
 
326
  # ้‡ๆ–ฐ็ป˜ๅˆถๆ‰€ๆœ‰ visible ็‚น๏ผˆ็บข่‰ฒ๏ผ‰
327
  for p in visible_points:
328
  cv2.circle(updated_image, (int(p[0]), int(p[1])), radius=10, color=(255, 0, 0), thickness=-1)
329
+ updated_text, vis_dropdown, occ_dropdown = update_all_points(visible_points)
330
+ return updated_image, visible_points, updated_text, vis_dropdown, occ_dropdown
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
 
332
  def add_mask(mask, mask_list):
333
  # check if the mask if same as the last mask in the list
 
352
  mask_list.pop()
353
  return mask_list
354
 
355
+ def check_combined_mask(image, mask_list, scale=1.7):
356
+ updated_image = image.copy()
357
+ # combine all the mask:
358
+ combined_mask = np.zeros_like(updated_image[:, :, 0])
359
+ occluded_mask = np.zeros_like(updated_image[:, :, 0])
360
+ for mask in mask_list:
361
+ combined_mask = cv2.bitwise_or(combined_mask, mask)
362
+ masked_image = updated_image * combined_mask[:, :, None]
363
+ occluded_mask[combined_mask == 1] = 127
364
 
365
+ return masked_image, occluded_mask
 
 
 
 
 
 
 
 
 
 
 
 
 
366
 
367
 
368
+
369
+ def get_seed(randomize_seed: bool, seed: int) -> int:
370
+ """
371
+ Get the random seed.
372
+ """
373
+ return np.random.randint(0, MAX_SEED) if randomize_seed else seed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
 
375
 
376
  with gr.Blocks(delete_cache=(600, 600)) as demo:
 
384
  occlusion_points_state = gr.State(value=[])
385
  original_image = gr.State(value=None)
386
  visibility_mask = gr.State(value=None)
 
387
  visibility_mask_list = gr.State(value=[])
388
+
389
+ combined_mask = gr.State(value=None)
390
 
391
 
392
  with gr.Row():
 
406
  with gr.Row():
407
  x_input = gr.Number(label="X Coordinate", value=0)
408
  y_input = gr.Number(label="Y Coordinate", value=0)
 
409
  with gr.Row():
410
  see_button = gr.Button("Render Point")
411
  add_button = gr.Button("Add Point")
412
  with gr.Row():
 
413
  clear_button = gr.Button("Clear Points")
414
+ see_visible_button = gr.Button("Render Added Points")
 
415
  with gr.Row():
416
  # ๆ–ฐๅขžๆ–‡ๆœฌๆก†ๅฎžๆ—ถๆ˜พ็คบ็‚นๅˆ—่กจ
417
  points_text = gr.Textbox(label="Points List", interactive=False)
418
  with gr.Row():
419
  # ๆ–ฐๅขžไธ‹ๆ‹‰่œๅ•๏ผŒ็”จๆˆทๅฏ้€‰ๆ‹ฉ้œ€่ฆๅˆ ้™ค็š„็‚น
420
  visible_points_dropdown = gr.Dropdown(label="Select Visible Point to Delete", choices=[], value=None, interactive=True)
 
 
421
  delete_visible_button = gr.Button("Delete Selected Visible")
 
422
  with gr.Column():
423
  # ็”จไบŽๆ˜พ็คบ SAM ๅˆ†ๅ‰ฒ็ป“ๆžœ
424
  visible_mask = gr.Image(label='Visible Mask', interactive=False, height=300)
 
428
  with gr.Row():
429
  render_vis_mask = gr.Button("Render Mask")
430
  undo_vis_mask = gr.Button("Undo Last Mask")
431
+ mask_check = gr.Image(label='Visible Input', interactive=False, height=300)
432
  with gr.Row():
433
+ check_visible_input = gr.Button("Check Combined Mask, make sure there is no GAP between the visible area (white) and occluded area (gray)")
 
 
 
 
 
434
  with gr.Row():
435
  gr.Markdown("""* Step 2 - 3D Amodal Completion.
 
436
  * Different random seeds can be tried in "Generation Settings", if you think the results are not ideal.
437
  * If the reconstruction 3D asset is satisfactory, you can extract the GLB file and download it.
438
  """)
439
  with gr.Row():
440
  with gr.Column():
441
+ with gr.Accordion(label="Generation Settings", open=True):
442
+ seed = gr.Slider(0, MAX_SEED, label="Seed", value=1, step=1)
443
+ randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
444
+ gr.Markdown("Stage 1: Sparse Structure Generation")
445
+ with gr.Row():
446
+ ss_guidance_strength = gr.Slider(0.0, 10.0, label="Guidance Strength", value=7.5, step=0.1)
447
+ ss_sampling_steps = gr.Slider(1, 50, label="Sampling Steps", value=12, step=1)
448
+ gr.Markdown("Stage 2: Structured Latent Generation")
449
+ with gr.Row():
450
+ slat_guidance_strength = gr.Slider(0.0, 10.0, label="Guidance Strength", value=3.0, step=0.1)
451
+ slat_sampling_steps = gr.Slider(1, 50, label="Sampling Steps", value=12, step=1)
452
+ generate_btn = gr.Button("Generate")
453
+ with gr.Column():
454
+ video_output = gr.Video(label="Generated 3D Asset", autoplay=True, loop=True, height=300)
455
+
456
 
457
  # ---------------------------
458
  # ๅŽŸๆœ‰ไบคไบ’้€ป่พ‘๏ผˆ็•ฅ๏ผ‰
 
464
  )
465
  see_button.click(
466
  see_point,
467
+ inputs=[original_image, x_input, y_input],
468
  outputs=[input_image]
469
  )
470
  add_button.click(
471
  add_point,
472
+ inputs=[x_input, y_input, visible_points_state],
473
+ outputs=[visible_points_state]
474
  )
475
 
476
  # ---------------------------
 
486
  inputs=[input_image, visible_points_state],
487
  outputs=input_image
488
  )
 
 
 
 
 
489
  # ๅฝ“ visible_points_state ๆˆ– occlusion_points_state ๅ˜ๅŒ–ๆ—ถ๏ผŒๆ›ดๆ–ฐๆ–‡ๆœฌๆก†ๅ’Œไธ‹ๆ‹‰่œๅ•
490
  visible_points_state.change(
491
  update_all_points,
492
+ inputs=[visible_points_state],
493
+ outputs=[points_text, visible_points_dropdown]
 
 
 
 
 
494
  )
495
  delete_visible_button.click(
496
  delete_selected_visible,
497
+ inputs=[input_image, visible_points_state, visible_points_dropdown],
498
+ outputs=[input_image, visible_points_state, points_text, visible_points_dropdown]
 
 
 
 
 
499
  )
500
 
501
  # ็”Ÿๆˆmask็š„้€ป่พ‘
 
519
  inputs=[visibility_mask_list],
520
  outputs=[visibility_mask_list]
521
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
522
 
523
+ check_visible_input.click(
524
+
525
+
526
+ # 3D Amodal Reconstruction
527
+ # generate_btn.click(
528
+ # get_seed,
529
+ # inputs=[randomize_seed, seed],
530
+ # outputs=[seed],
531
+ # ).then(
532
+ # image_to_3d,
533
+ # inputs=[original_image, [combined_mask], seed, ss_guidance_strength, ss_sampling_steps, slat_guidance_strength, slat_sampling_steps, "multiimage"],
534
+ # outputs=[visibility_mask]
535
+ # )
536
 
537
 
538
  # ๅฏๅŠจ Gradio App