Deadmon commited on
Commit
6a9250c
1 Parent(s): d86b8bd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +116 -82
app.py CHANGED
@@ -3,15 +3,23 @@ import random
3
 
4
  import gradio as gr
5
  import numpy as np
6
- from PIL import Image, ImageOps
7
  import torch
8
  import torchvision.transforms.functional as TF
 
9
  from diffusers import ControlNetModel, StableDiffusionXLControlNetPipeline, AutoencoderKL
10
  from diffusers import DDIMScheduler, EulerAncestralDiscreteScheduler
11
  from controlnet_aux import PidiNetDetector, HEDdetector
12
  from diffusers.utils import load_image
13
  from huggingface_hub import HfApi
14
  from pathlib import Path
 
 
 
 
 
 
 
15
  from gradio_imageslider import ImageSlider
16
 
17
  js_func = """
@@ -19,7 +27,6 @@ function refresh() {
19
  const url = new URL(window.location);
20
  }
21
  """
22
-
23
  def nms(x, t, s):
24
  x = cv2.GaussianBlur(x.astype(np.float32), (0, 0), s)
25
 
@@ -58,7 +65,7 @@ def HWC3(x):
58
  DESCRIPTION = ''''''
59
 
60
  if not torch.cuda.is_available():
61
- DESCRIPTION += "GPU not available. Using CPU."
62
 
63
  style_list = [
64
  {
@@ -117,17 +124,26 @@ styles = {k["name"]: (k["prompt"], k["negative_prompt"]) for k in style_list}
117
  STYLE_NAMES = list(styles.keys())
118
  DEFAULT_STYLE_NAME = "(No style)"
119
 
120
- def apply_style(style_name, positive, negative=""):
 
121
  p, n = styles.get(style_name, styles[DEFAULT_STYLE_NAME])
122
  return p.replace("{prompt}", positive), n + negative
123
 
 
124
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
125
 
126
  eulera_scheduler = EulerAncestralDiscreteScheduler.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0", subfolder="scheduler")
127
 
128
- controlnet = ControlNetModel.from_pretrained("xinsir/controlnet-scribble-sdxl-1.0", torch_dtype=torch.float16)
129
- controlnet_canny = ControlNetModel.from_pretrained("xinsir/controlnet-canny-sdxl-1.0", torch_dtype=torch.float16)
130
 
 
 
 
 
 
 
 
 
 
131
  vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16)
132
 
133
  pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
@@ -138,7 +154,7 @@ pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
138
  scheduler=eulera_scheduler,
139
  )
140
  pipe.to(device)
141
-
142
  pipe_canny = StableDiffusionXLControlNetPipeline.from_pretrained(
143
  "stabilityai/stable-diffusion-xl-base-1.0",
144
  controlnet=controlnet_canny,
@@ -147,51 +163,60 @@ pipe_canny = StableDiffusionXLControlNetPipeline.from_pretrained(
147
  torch_dtype=torch.float16,
148
  scheduler=eulera_scheduler,
149
  )
 
150
  pipe_canny.to(device)
151
 
152
  MAX_SEED = np.iinfo(np.int32).max
153
  processor = HEDdetector.from_pretrained('lllyasviel/Annotators')
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
- def randomize_seed_fn(seed, randomize_seed):
 
 
 
 
156
  if randomize_seed:
157
  seed = random.randint(0, MAX_SEED)
158
  return seed
159
 
160
- @gr.annotations(
161
- image=dict,
162
- prompt=str,
163
- negative_prompt=str,
164
- style_name=str,
165
- num_steps=int,
166
- guidance_scale=float,
167
- controlnet_conditioning_scale=float,
168
- seed=int,
169
- use_hed=bool,
170
- use_canny=bool,
171
- controlnet_img=Image,
172
- out=Image,
173
- )
174
  def run(
175
- image,
176
- prompt,
177
- negative_prompt,
178
- style_name=DEFAULT_STYLE_NAME,
179
- num_steps=25,
180
- guidance_scale=5,
181
- controlnet_conditioning_scale=1.0,
182
- seed=0,
183
- use_hed=False,
184
- use_canny=False,
185
  progress=gr.Progress(track_tqdm=True),
186
- ):
 
187
  composite_image = image['composite']
188
  width, height = composite_image.size
 
 
189
  max_size = 1024
190
  ratio = min(max_size / width, max_size / height)
191
  new_width = int(width * ratio)
192
  new_height = int(height * ratio)
 
 
193
  resized_image = composite_image.resize((new_width, new_height), Image.LANCZOS)
194
-
195
  if use_canny:
196
  controlnet_img = np.array(resized_image)
197
  controlnet_img = cv2.Canny(controlnet_img, 100, 200)
@@ -209,11 +234,11 @@ def run(
209
  controlnet_img[controlnet_img > random_val] = 255
210
  controlnet_img[controlnet_img < 255] = 0
211
  image = Image.fromarray(controlnet_img)
212
-
213
  prompt, negative_prompt = apply_style(style_name, prompt, negative_prompt)
214
 
215
  generator = torch.Generator(device=device).manual_seed(seed)
216
-
217
  if use_canny:
218
  out = pipe_canny(
219
  prompt=prompt,
@@ -245,50 +270,58 @@ with gr.Blocks(css="style.css", js=js_func) as demo:
245
  gr.Markdown(DESCRIPTION, elem_id="description")
246
  gr.DuplicateButton(
247
  value="Duplicate Space for private use",
248
- elem_Multiplier: gr.ImageEditor(type="pil", label="Sketch your image or upload one", width=512, height=512)
249
- prompt: gr.Textbox(label="Prompt")
250
- style: gr.Dropdown(label="Style", choices=STYLE_NAMES, value=DEFAULT_STYLE_NAME)
251
- use_hed: gr.Checkbox(label="use HED detector", value=False, info="check this box if you upload an image and want to turn it to a sketch")
252
- use_canny: gr.Checkbox(label="use Canny", value=False, info="check this to use ControlNet canny instead of scribble")
253
- run_button: gr.Button("Run")
254
- gr.Accordion("Advanced options", open=False):
255
- negative_prompt: gr.Textbox(
256
- label="Negative prompt",
257
- value="longbody, lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality",
258
- )
259
- num_steps: gr.Slider(
260
- label="Number of steps",
261
- minimum=1,
262
- maximum=50,
263
- step=1,
264
- value=25,
265
- )
266
- guidance_scale: gr.Slider(
267
- label="Guidance scale",
268
- minimum=0.1,
269
- maximum=10.0,
270
- step=0.1,
271
- value=5,
272
- )
273
- controlnet_conditioning_scale: gr.Slider(
274
- label="controlnet conditioning scale",
275
- minimum=0.5,
276
- maximum=5.0,
277
- step=0.1,
278
- value=0.9,
279
- )
280
- seed: gr.Slider(
281
- label="Seed",
282
- minimum=0,
283
- maximum=MAX_SEED,
284
- step=1,
285
- value=0,
286
- )
287
- randomize_seed: gr.Checkbox(label="Randomize seed", value=True)
288
-
289
- with gr.Column():
290
- with gr.Group():
291
- image_slider: ImageSlider(position=0.5)
 
 
 
 
 
 
 
 
292
 
293
  inputs = [
294
  image,
@@ -303,7 +336,6 @@ with gr.Blocks(css="style.css", js=js_func) as demo:
303
  use_canny
304
  ]
305
  outputs = [image_slider]
306
-
307
  run_button.click(
308
  fn=randomize_seed_fn,
309
  inputs=[seed, randomize_seed],
@@ -313,5 +345,7 @@ with gr.Blocks(css="style.css", js=js_func) as demo:
313
  ).then(lambda x: None, inputs=None, outputs=image_slider).then(
314
  fn=run, inputs=inputs, outputs=outputs
315
  )
 
 
316
 
317
- demo.queue().launch(share=True, show_error=True)
 
3
 
4
  import gradio as gr
5
  import numpy as np
6
+ import PIL.Image
7
  import torch
8
  import torchvision.transforms.functional as TF
9
+
10
  from diffusers import ControlNetModel, StableDiffusionXLControlNetPipeline, AutoencoderKL
11
  from diffusers import DDIMScheduler, EulerAncestralDiscreteScheduler
12
  from controlnet_aux import PidiNetDetector, HEDdetector
13
  from diffusers.utils import load_image
14
  from huggingface_hub import HfApi
15
  from pathlib import Path
16
+ from PIL import Image, ImageOps
17
+ import torch
18
+ import numpy as np
19
+ import cv2
20
+ import os
21
+ import random
22
+ import spaces
23
  from gradio_imageslider import ImageSlider
24
 
25
  js_func = """
 
27
  const url = new URL(window.location);
28
  }
29
  """
 
30
  def nms(x, t, s):
31
  x = cv2.GaussianBlur(x.astype(np.float32), (0, 0), s)
32
 
 
65
  DESCRIPTION = ''''''
66
 
67
  if not torch.cuda.is_available():
68
+ DESCRIPTION += ""
69
 
70
  style_list = [
71
  {
 
124
  STYLE_NAMES = list(styles.keys())
125
  DEFAULT_STYLE_NAME = "(No style)"
126
 
127
+
128
+ def apply_style(style_name: str, positive: str, negative: str = "") -> tuple[str, str]:
129
  p, n = styles.get(style_name, styles[DEFAULT_STYLE_NAME])
130
  return p.replace("{prompt}", positive), n + negative
131
 
132
+
133
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
134
 
135
  eulera_scheduler = EulerAncestralDiscreteScheduler.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0", subfolder="scheduler")
136
 
 
 
137
 
138
+ controlnet = ControlNetModel.from_pretrained(
139
+ "xinsir/controlnet-scribble-sdxl-1.0",
140
+ torch_dtype=torch.float16
141
+ )
142
+ controlnet_canny = ControlNetModel.from_pretrained(
143
+ "xinsir/controlnet-canny-sdxl-1.0",
144
+ torch_dtype=torch.float16
145
+ )
146
+ # when test with other base model, you need to change the vae also.
147
  vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16)
148
 
149
  pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
 
154
  scheduler=eulera_scheduler,
155
  )
156
  pipe.to(device)
157
+ # Load model.
158
  pipe_canny = StableDiffusionXLControlNetPipeline.from_pretrained(
159
  "stabilityai/stable-diffusion-xl-base-1.0",
160
  controlnet=controlnet_canny,
 
163
  torch_dtype=torch.float16,
164
  scheduler=eulera_scheduler,
165
  )
166
+
167
  pipe_canny.to(device)
168
 
169
  MAX_SEED = np.iinfo(np.int32).max
170
  processor = HEDdetector.from_pretrained('lllyasviel/Annotators')
171
+ def nms(x, t, s):
172
+ x = cv2.GaussianBlur(x.astype(np.float32), (0, 0), s)
173
+
174
+ f1 = np.array([[0, 0, 0], [1, 1, 1], [0, 0, 0]], dtype=np.uint8)
175
+ f2 = np.array([[0, 1, 0], [0, 1, 0], [0, 1, 0]], dtype=np.uint8)
176
+ f3 = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype=np.uint8)
177
+ f4 = np.array([[0, 0, 1], [0, 1, 0], [1, 0, 0]], dtype=np.uint8)
178
+
179
+ y = np.zeros_like(x)
180
+
181
+ for f in [f1, f2, f3, f4]:
182
+ np.putmask(y, cv2.dilate(x, kernel=f) == x, x)
183
 
184
+ z = np.zeros_like(y, dtype=np.uint8)
185
+ z[y > t] = 255
186
+ return z
187
+
188
+ def randomize_seed_fn(seed: int, randomize_seed: bool) -> int:
189
  if randomize_seed:
190
  seed = random.randint(0, MAX_SEED)
191
  return seed
192
 
193
+ @spaces.GPU
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  def run(
195
+ image: dict,
196
+ prompt: str,
197
+ negative_prompt: str,
198
+ style_name: str = DEFAULT_STYLE_NAME,
199
+ num_steps: int = 25,
200
+ guidance_scale: float = 5,
201
+ controlnet_conditioning_scale: float = 1.0,
202
+ seed: int = 0,
203
+ use_hed: bool = False,
204
+ use_canny: bool = False,
205
  progress=gr.Progress(track_tqdm=True),
206
+ ) -> PIL.Image.Image:
207
+ # Get the composite image from the EditorValue dict
208
  composite_image = image['composite']
209
  width, height = composite_image.size
210
+
211
+ # Calculate new dimensions to fit within 1024x1024 while maintaining aspect ratio
212
  max_size = 1024
213
  ratio = min(max_size / width, max_size / height)
214
  new_width = int(width * ratio)
215
  new_height = int(height * ratio)
216
+
217
+ # Resize the image
218
  resized_image = composite_image.resize((new_width, new_height), Image.LANCZOS)
219
+
220
  if use_canny:
221
  controlnet_img = np.array(resized_image)
222
  controlnet_img = cv2.Canny(controlnet_img, 100, 200)
 
234
  controlnet_img[controlnet_img > random_val] = 255
235
  controlnet_img[controlnet_img < 255] = 0
236
  image = Image.fromarray(controlnet_img)
237
+
238
  prompt, negative_prompt = apply_style(style_name, prompt, negative_prompt)
239
 
240
  generator = torch.Generator(device=device).manual_seed(seed)
241
+
242
  if use_canny:
243
  out = pipe_canny(
244
  prompt=prompt,
 
270
  gr.Markdown(DESCRIPTION, elem_id="description")
271
  gr.DuplicateButton(
272
  value="Duplicate Space for private use",
273
+ elem_id="duplicate-button",
274
+ visible=os.getenv("SHOW_DUPLICATE_BUTTON") == "1",
275
+ )
276
+
277
+ with gr.Row():
278
+ with gr.Column():
279
+ with gr.Group():
280
+ image = gr.ImageEditor(type="pil", label="Sketch your image or upload one", width=512, height=512)
281
+ prompt = gr.Textbox(label="Prompt")
282
+ style = gr.Dropdown(label="Style", choices=STYLE_NAMES, value=DEFAULT_STYLE_NAME)
283
+ use_hed = gr.Checkbox(label="use HED detector", value=False, info="check this box if you upload an image and want to turn it to a sketch")
284
+ use_canny = gr.Checkbox(label="use Canny", value=False, info="check this to use ControlNet canny instead of scribble")
285
+ run_button = gr.Button("Run")
286
+ with gr.Accordion("Advanced options", open=False):
287
+ negative_prompt = gr.Textbox(
288
+ label="Negative prompt",
289
+ value="longbody, lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality",
290
+ )
291
+ num_steps = gr.Slider(
292
+ label="Number of steps",
293
+ minimum=1,
294
+ maximum=50,
295
+ step=1,
296
+ value=25,
297
+ )
298
+ guidance_scale = gr.Slider(
299
+ label="Guidance scale",
300
+ minimum=0.1,
301
+ maximum=10.0,
302
+ step=0.1,
303
+ value=5,
304
+ )
305
+ controlnet_conditioning_scale = gr.Slider(
306
+ label="controlnet conditioning scale",
307
+ minimum=0.5,
308
+ maximum=5.0,
309
+ step=0.1,
310
+ value=0.9,
311
+ )
312
+ seed = gr.Slider(
313
+ label="Seed",
314
+ minimum=0,
315
+ maximum=MAX_SEED,
316
+ step=1,
317
+ value=0,
318
+ )
319
+ randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
320
+
321
+ with gr.Column():
322
+ with gr.Group():
323
+ image_slider = ImageSlider(position=0.5)
324
+
325
 
326
  inputs = [
327
  image,
 
336
  use_canny
337
  ]
338
  outputs = [image_slider]
 
339
  run_button.click(
340
  fn=randomize_seed_fn,
341
  inputs=[seed, randomize_seed],
 
345
  ).then(lambda x: None, inputs=None, outputs=image_slider).then(
346
  fn=run, inputs=inputs, outputs=outputs
347
  )
348
+
349
+
350
 
351
+ demo.queue().launch(show_error=True)