Surn commited on
Commit
e34b08b
·
1 Parent(s): 375c110

Add Sketch to system

Browse files
Files changed (4) hide show
  1. app.py +96 -22
  2. style_20250128.css +15 -0
  3. utils/file_utils.py +22 -21
  4. utils/image_utils.py +3 -3
app.py CHANGED
@@ -102,8 +102,6 @@ from utils.version_info import (
102
  )
103
  #from utils.depth_estimation import (get_depth_map_from_state)
104
 
105
-
106
-
107
  input_image_palette = []
108
  current_prerendered_image = gr.State("./images/images/Beeuty-1.png")
109
  user_dir = constants.TMPDIR
@@ -619,7 +617,43 @@ def add_border(image, mask_width, mask_height, blank_color):
619
  print(f"Adding border to image with width: {mask_width}, height: {mask_height}, color: {margin_color}")
620
  return shrink_and_paste_on_blank(bordered_image_output, mask_width, mask_height, margin_color)
621
 
622
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
623
  ####################################### DEPTH ESTIMATION #######################################
624
 
625
 
@@ -634,7 +668,6 @@ def preprocess_image(image: Image.Image) -> Image.Image:
634
  processed_image = TRELLIS_PIPELINE.preprocess_image(image)
635
  return processed_image
636
 
637
-
638
  def pack_state(gs: Gaussian, mesh: MeshExtractResult, name: str) -> dict:
639
  return {
640
  'gaussian': {
@@ -651,8 +684,7 @@ def pack_state(gs: Gaussian, mesh: MeshExtractResult, name: str) -> dict:
651
  },
652
  'name': name
653
  }
654
-
655
-
656
  def unpack_state(state: dict) -> Tuple[Gaussian, edict, str]:
657
  gs = Gaussian(
658
  aabb=state['gaussian']['aabb'],
@@ -954,22 +986,35 @@ with gr.Blocks(css_paths="style_20250128.css", title=title, theme='Surn/beeuty',
954
  elem_classes="centered solid imgcontainer",
955
  key="imgInput",
956
  image_mode=None,
957
- format="PNG"
 
958
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
959
 
960
- # New code to convert input image to RGBA PNG
961
- def on_input_image_change(image_path):
962
- if image_path is None:
963
- gr.Warning("Please upload an Input Image to get started.")
964
- return None
965
- img, img_path = convert_to_rgba_png(image_path)
966
- return img_path
967
-
968
- input_image.change(
969
- fn=on_input_image_change,
970
- inputs=[input_image],
971
- outputs=[input_image], scroll_to_output=True,
972
- )
973
  with gr.Column():
974
  with gr.Accordion("Hex Coloring and Exclusion", open = False):
975
  with gr.Row():
@@ -1032,7 +1077,7 @@ with gr.Blocks(css_paths="style_20250128.css", title=title, theme='Surn/beeuty',
1032
  outputs=[input_image],
1033
  scroll_to_output=True
1034
  )
1035
-
1036
  with gr.Row():
1037
  with gr.Accordion("Generate AI Image (click here for options)", open = False):
1038
  with gr.Row():
@@ -1267,8 +1312,29 @@ with gr.Blocks(css_paths="style_20250128.css", title=title, theme='Surn/beeuty',
1267
  fn=generate_input_image_click,
1268
  inputs=[input_image,map_options, prompt_textbox, negative_prompt_textbox, model_textbox, randomize_seed, seed_slider, gr.State(False), gr.State(0.5), image_size_ratio],
1269
  outputs=[input_image, seed_slider], scroll_to_output=True
 
 
 
 
1270
  )
1271
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1272
  model_textbox.change(
1273
  fn=update_prompt_notes,
1274
  inputs=model_textbox,
@@ -1295,6 +1361,10 @@ with gr.Blocks(css_paths="style_20250128.css", title=title, theme='Surn/beeuty',
1295
  fn=generate_input_image_click,
1296
  inputs=[input_image, map_options, prompt_textbox, negative_prompt_textbox, model_textbox,randomize_seed, seed_slider, gr.State(True), image_guidance_stength, image_size_ratio],
1297
  outputs=[input_image, seed_slider], scroll_to_output=True
 
 
 
 
1298
  )
1299
 
1300
  # Update the state variable with the prerendered image filepath when an image is selected
@@ -1309,6 +1379,10 @@ with gr.Blocks(css_paths="style_20250128.css", title=title, theme='Surn/beeuty',
1309
  lambda: current_prerendered_image.value,
1310
  inputs=None,
1311
  outputs=[input_image], scroll_to_output=True
 
 
 
 
1312
  )
1313
  output_overlay_composite.change(
1314
  fn=combine_images_with_lerp,
 
102
  )
103
  #from utils.depth_estimation import (get_depth_map_from_state)
104
 
 
 
105
  input_image_palette = []
106
  current_prerendered_image = gr.State("./images/images/Beeuty-1.png")
107
  user_dir = constants.TMPDIR
 
617
  print(f"Adding border to image with width: {mask_width}, height: {mask_height}, color: {margin_color}")
618
  return shrink_and_paste_on_blank(bordered_image_output, mask_width, mask_height, margin_color)
619
 
620
+ def on_input_image_change(image_path):
621
+ if image_path is None:
622
+ gr.Warning("Please upload an Input Image to get started.")
623
+ return None, gr.update()
624
+ img, img_path = convert_to_rgba_png(image_path)
625
+ with Image.open(img_path) as pil_img:
626
+ width, height = pil_img.size
627
+ return [img_path, gr.update(width=width, height=height)]
628
+
629
+ def update_sketch_dimensions(input_image, sketch_image):
630
+ # Load the images using open_image() if they are provided as file paths.
631
+ in_img = open_image(input_image) if isinstance(input_image, str) else input_image
632
+ sk_img_path, _ = get_image_from_dict(sketch_image)
633
+ sk_img = open_image(sk_img_path)
634
+ # Resize sketch image if dimensions don't match input image.
635
+ if in_img.size != sk_img.size:
636
+ sk_img = sk_img.resize(in_img.size, Image.LANCZOS)
637
+ return [sk_img, gr.update(width=in_img.width, height=in_img.height)]
638
+
639
+ def composite_with_control_sync(input_image, sketch_image, slider_value):
640
+ # Load the images using open_image() if they are provided as file paths.
641
+ in_img = open_image(input_image) if isinstance(input_image, str) else input_image
642
+ sk_img_path, _ = get_image_from_dict(sketch_image)
643
+ sk_img = open_image(sk_img_path)
644
+
645
+ # Resize sketch image if dimensions don't match input image.
646
+ if in_img.size != sk_img.size:
647
+ sk_img = sk_img.resize(in_img.size, Image.LANCZOS)
648
+
649
+ # Now composite using the original alpha_composite_with_control function.
650
+ result_img = alpha_composite_with_control(in_img, sk_img, slider_value)
651
+ return result_img
652
+
653
+ def replace_input_with_sketch_image(sketch_image):
654
+ print(f"Sketch Image: {sketch_image}\n")
655
+ sketch, is_dict = get_image_from_dict(sketch_image)
656
+ return sketch
657
  ####################################### DEPTH ESTIMATION #######################################
658
 
659
 
 
668
  processed_image = TRELLIS_PIPELINE.preprocess_image(image)
669
  return processed_image
670
 
 
671
  def pack_state(gs: Gaussian, mesh: MeshExtractResult, name: str) -> dict:
672
  return {
673
  'gaussian': {
 
684
  },
685
  'name': name
686
  }
687
+
 
688
  def unpack_state(state: dict) -> Tuple[Gaussian, edict, str]:
689
  gs = Gaussian(
690
  aabb=state['gaussian']['aabb'],
 
986
  elem_classes="centered solid imgcontainer",
987
  key="imgInput",
988
  image_mode=None,
989
+ format="PNG",
990
+ height=512
991
  )
992
+ with gr.Accordion("Sketch Pad", open = False, elem_id="sketchpd"):
993
+ with gr.Row():
994
+ sketch_image = gr.Sketchpad(
995
+ label="Sketch Image",
996
+ type="filepath",
997
+ #invert_colors=True,
998
+ #sources=['upload','canvas'],
999
+ #tool=['editor','select','color-sketch'],
1000
+ placeholder="Draw a sketch or upload an image. Currently broken in gradio 5.17.1",
1001
+ interactive=True,
1002
+ elem_classes="centered solid imgcontainer",
1003
+ key="imgSketch",
1004
+ image_mode="RGBA",
1005
+ format="PNG",
1006
+ brush=gr.Brush()
1007
+ )
1008
+ with gr.Row():
1009
+ with gr.Column(scale=1):
1010
+ sketch_replace_input_image_button = gr.Button(
1011
+ "Replace Input Image with sketch",
1012
+ elem_id="sketch_replace_input_image_button",
1013
+ elem_classes="solid"
1014
+ )
1015
+ sketch_alpha_composite_slider = gr.Slider(0,100,50,0.5, label="Sketch Transparancy", elem_id="alpha_composite_slider")
1016
+ btn_sketch_alpha_composite = gr.Button("Overlay Sketch on Input Image", elem_id="btn_sketchninput", elem_classes="solid")
1017
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1018
  with gr.Column():
1019
  with gr.Accordion("Hex Coloring and Exclusion", open = False):
1020
  with gr.Row():
 
1077
  outputs=[input_image],
1078
  scroll_to_output=True
1079
  )
1080
+
1081
  with gr.Row():
1082
  with gr.Accordion("Generate AI Image (click here for options)", open = False):
1083
  with gr.Row():
 
1312
  fn=generate_input_image_click,
1313
  inputs=[input_image,map_options, prompt_textbox, negative_prompt_textbox, model_textbox, randomize_seed, seed_slider, gr.State(False), gr.State(0.5), image_size_ratio],
1314
  outputs=[input_image, seed_slider], scroll_to_output=True
1315
+ ).then(
1316
+ fn=update_sketch_dimensions,
1317
+ inputs=[input_image, sketch_image],
1318
+ outputs=[sketch_image, sketch_image]
1319
  )
1320
+ input_image.input(
1321
+ fn=on_input_image_change,
1322
+ inputs=[input_image],
1323
+ outputs=[input_image,sketch_image], scroll_to_output=True,
1324
+ )
1325
+ ###################### sketchpad ############################
1326
+ btn_sketch_alpha_composite.click(
1327
+ fn=composite_with_control_sync,
1328
+ inputs=[input_image, sketch_image, sketch_alpha_composite_slider],
1329
+ outputs=[input_image],
1330
+ scroll_to_output=True
1331
+ )
1332
+ sketch_replace_input_image_button.click(
1333
+ lambda sketch_image: replace_input_with_sketch_image(sketch_image),
1334
+ inputs=[sketch_image],
1335
+ outputs=[input_image], scroll_to_output=True
1336
+ )
1337
+ ##################### model #######################################
1338
  model_textbox.change(
1339
  fn=update_prompt_notes,
1340
  inputs=model_textbox,
 
1361
  fn=generate_input_image_click,
1362
  inputs=[input_image, map_options, prompt_textbox, negative_prompt_textbox, model_textbox,randomize_seed, seed_slider, gr.State(True), image_guidance_stength, image_size_ratio],
1363
  outputs=[input_image, seed_slider], scroll_to_output=True
1364
+ ).then(
1365
+ fn=update_sketch_dimensions,
1366
+ inputs=[input_image, sketch_image],
1367
+ outputs=[sketch_image, sketch_image]
1368
  )
1369
 
1370
  # Update the state variable with the prerendered image filepath when an image is selected
 
1379
  lambda: current_prerendered_image.value,
1380
  inputs=None,
1381
  outputs=[input_image], scroll_to_output=True
1382
+ ).then(
1383
+ fn=update_sketch_dimensions,
1384
+ inputs=[input_image, sketch_image],
1385
+ outputs=[sketch_image, sketch_image]
1386
  )
1387
  output_overlay_composite.change(
1388
  fn=combine_images_with_lerp,
style_20250128.css CHANGED
@@ -125,4 +125,19 @@ a {
125
  .gradio-container, .gradio-container::before {
126
  max-width: 1920px !important;
127
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  }
 
125
  .gradio-container, .gradio-container::before {
126
  max-width: 1920px !important;
127
  }
128
+ }
129
+
130
+ .sidebar .toggle-button::before {
131
+ content: 'Sketch Pad';
132
+ font-weight: bold;
133
+ transform: rotate(180deg);
134
+ margin-right: -120px;
135
+ width: 120px;
136
+ background-color: rgba(242, 218, 163, 0.62);
137
+ }
138
+ .dark .sidebar .toggle-button::before {
139
+ background-color: rgba(41, 18, 5, 0.38) !important;
140
+ }
141
+ .sidebar.open .toggle-button::before {
142
+ content: '';
143
  }
utils/file_utils.py CHANGED
@@ -1,7 +1,7 @@
1
  # file_utils
2
  import os
3
  import utils.constants as constants
4
- import shutil
5
  from pathlib import Path
6
 
7
  def cleanup_temp_files():
@@ -11,32 +11,33 @@ def cleanup_temp_files():
11
  except Exception as e:
12
  print(f"Failed to delete temp file {file_path}: {e}")
13
 
14
- def rename_file_to_lowercase_extension(image_path: str) -> str:
15
  """
16
- Renames only the file extension to lowercase by copying it to the temporary folder.
17
 
18
  Parameters:
19
- image_path (str): The original file path.
20
 
21
  Returns:
22
- str: The new file path in the temporary folder with the lowercase extension.
23
 
24
  Raises:
25
- Exception: If there is an error copying the file.
26
  """
27
- path = Path(image_path)
28
- new_suffix = path.suffix.lower()
29
- new_path = path.with_suffix(new_suffix)
30
-
31
- # Make a copy in the temporary folder with the lowercase extension
32
- if path.suffix != new_suffix:
33
- try:
34
- shutil.copy(path, new_path)
35
- constants.temp_files.append(str(new_path))
36
- return str(new_path)
37
- except FileExistsError:
38
- raise Exception(f"Cannot copy {path} to {new_path}: target file already exists.")
39
- except Exception as e:
40
- raise Exception(f"Error copying file: {e}")
 
41
  else:
42
- return str(path)
 
1
  # file_utils
2
  import os
3
  import utils.constants as constants
4
+ #import shutil
5
  from pathlib import Path
6
 
7
  def cleanup_temp_files():
 
11
  except Exception as e:
12
  print(f"Failed to delete temp file {file_path}: {e}")
13
 
14
+ def rename_file_to_lowercase_extension(file_path: str) -> str:
15
  """
16
+ Renames a file's extension to lowercase in place.
17
 
18
  Parameters:
19
+ file_path (str): The original file path.
20
 
21
  Returns:
22
+ str: The new file path with the lowercase extension.
23
 
24
  Raises:
25
+ OSError: If there is an error renaming the file (e.g., file not found, permissions issue).
26
  """
27
+ # Split the path into directory and filename
28
+ directory, filename = os.path.split(file_path)
29
+
30
+ # Split the filename into name and extension
31
+ name, ext = os.path.splitext(filename)
32
+
33
+ # Convert the extension to lowercase
34
+ new_ext = ext.lower()
35
+
36
+ # If the extension changes, rename the file
37
+ if ext != new_ext:
38
+ new_filename = name + new_ext
39
+ new_file_path = os.path.join(directory, new_filename)
40
+ os.rename(file_path, new_file_path)
41
+ return new_file_path
42
  else:
43
+ return file_path
utils/image_utils.py CHANGED
@@ -19,10 +19,10 @@ from utils.file_utils import rename_file_to_lowercase_extension
19
 
20
  def get_image_from_dict(image_path):
21
  if isinstance(image_path, dict) :
22
- if 'image' in image_path:
23
- image_path = image_path.get('image')
24
- elif 'composite' in image_path:
25
  image_path = image_path.get('composite')
 
 
26
  else:
27
  print("\n Unknown image dictionary.\n")
28
  raise UserWarning("Unknown image dictionary.")
 
19
 
20
  def get_image_from_dict(image_path):
21
  if isinstance(image_path, dict) :
22
+ if 'composite' in image_path:
 
 
23
  image_path = image_path.get('composite')
24
+ elif 'image' in image_path:
25
+ image_path = image_path.get('image')
26
  else:
27
  print("\n Unknown image dictionary.\n")
28
  raise UserWarning("Unknown image dictionary.")