sdafd Fabrice-TIERCELIN commited on
Commit
bb0f88d
·
verified ·
1 Parent(s): c865610

This PR upgrades the space (model & parameters) (#1)

Browse files

- This PR upgrades the space (model & parameters) (dd2990fe38032ac0e4816d5dfd552756dc849ce4)


Co-authored-by: Fabrice TIERCELIN <[email protected]>

Files changed (3) hide show
  1. README.md +12 -1
  2. app.py +302 -51
  3. requirements.txt +1 -5
README.md CHANGED
@@ -3,10 +3,21 @@ title: Inpaint
3
  emoji: 🦀
4
  colorFrom: purple
5
  colorTo: gray
 
 
 
 
 
 
 
 
 
6
  sdk: gradio
7
  sdk_version: 4.41.0
8
  app_file: app.py
9
  pinned: false
 
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
3
  emoji: 🦀
4
  colorFrom: purple
5
  colorTo: gray
6
+ tags:
7
+ - Image-to-Image
8
+ - Image-2-Image
9
+ - Img-to-Img
10
+ - Img-2-Img
11
+ - SDXL
12
+ - Stable Diffusion
13
+ - language models
14
+ - LLMs
15
  sdk: gradio
16
  sdk_version: 4.41.0
17
  app_file: app.py
18
  pinned: false
19
+ license: mit
20
+ short_description: Modifies one detail of your image, at any resolution, freely
21
  ---
22
 
23
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -1,56 +1,307 @@
1
  import gradio as gr
2
- from PIL import Image
3
  import numpy as np
4
- from diffusers import StableDiffusionInpaintPipeline
 
 
5
  import torch
6
- from diffusers.utils import load_image
7
- from diffusers.pipelines.stable_diffusion import safety_checker
8
- # Bypass the safety checker
9
- def sc(self, clip_input, images):
10
- return images, [False for _ in images]
11
- safety_checker.StableDiffusionSafetyChecker.forward = sc
12
-
13
- # Initialize the inpainting pipeline
14
- pipe = StableDiffusionInpaintPipeline.from_pretrained(
15
- "stabilityai/stable-diffusion-2-inpainting",
16
- torch_dtype=torch.float32,
17
- )
18
- pipe.to('cpu')
19
-
20
- # Inpainting function
21
- def inpaint_image(image, mask, prompt, negative_prompt):
22
- n_image = pipe(prompt, image=image, mask_image=mask, guidance_scale=5,
23
- height=int(8*round(image.height/8)), width=int(8*round(image.width/8)),
24
- num_inference_steps=70, negative_prompt=negative_prompt).images[0]
25
- return n_image
26
-
27
- # Processing uploaded files
28
- def process_files(image_file, mask_file, prompt, negative_prompt):
29
- image = Image.open(image_file)
30
- mask = Image.open(mask_file)
31
- return inpaint_image(image, mask, prompt, negative_prompt)
32
-
33
- # Gradio UI
34
- with gr.Blocks() as demo:
35
- gr.Markdown("## Inpainting App")
36
-
37
- with gr.Row():
38
- with gr.Column():
39
- image_input = gr.File(label="Input Image", type="filepath")
40
- mask_input = gr.File(label="Mask Image", type="filepath")
41
- prompt_input = gr.Textbox(label="Prompt", placeholder="Enter your prompt here...")
42
- negative_prompt_input = gr.Textbox(label="Negative Prompt", placeholder="Enter your negative prompt here...")
43
-
44
- submit_button = gr.Button("Inpaint")
45
-
46
- with gr.Column():
47
- output_image = gr.Image(type="pil", label="Inpainted Image")
48
-
49
- submit_button.click(
50
- fn=process_files,
51
- inputs=[image_input, mask_input, prompt_input, negative_prompt_input],
52
- outputs=output_image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
- # Launch the interface
56
- demo.launch(show_error=True)
 
1
  import gradio as gr
 
2
  import numpy as np
3
+ import time
4
+ import math
5
+ import random
6
  import torch
7
+ import spaces
8
+
9
+ from diffusers import StableDiffusionXLInpaintPipeline
10
+ from PIL import Image, ImageFilter, ImageEnhance
11
+ import PIL.ImageOps
12
+
13
+ max_64_bit_int = 2**63 - 1
14
+
15
+ if torch.cuda.is_available():
16
+ device = "cuda"
17
+ floatType = torch.float16
18
+ variant = "fp16"
19
+ else:
20
+ device = "cpu"
21
+ floatType = torch.float32
22
+ variant = None
23
+
24
+ pipe = StableDiffusionXLInpaintPipeline.from_pretrained("diffusers/stable-diffusion-xl-1.0-inpainting-0.1", torch_dtype = floatType, variant = variant)
25
+ pipe = pipe.to(device)
26
+
27
+ def update_seed(is_randomize_seed, seed):
28
+ if is_randomize_seed:
29
+ return random.randint(0, max_64_bit_int)
30
+ return seed
31
+
32
+ def toggle_debug(is_debug_mode):
33
+ return [gr.update(visible = is_debug_mode)] * 2
34
+
35
+ def check(
36
+ source_img,
37
+ prompt,
38
+ uploaded_mask,
39
+ negative_prompt,
40
+ num_inference_steps,
41
+ guidance_scale,
42
+ image_guidance_scale,
43
+ strength,
44
+ denoising_steps,
45
+ is_randomize_seed,
46
+ seed,
47
+ debug_mode,
48
+ progress = gr.Progress()
49
+ ):
50
+ if source_img is None:
51
+ raise gr.Error("Please provide an image.")
52
+
53
+ if prompt is None or prompt == "":
54
+ raise gr.Error("Please provide a prompt input.")
55
+
56
+ def inpaint(
57
+ source_img,
58
+ prompt,
59
+ uploaded_mask,
60
+ negative_prompt,
61
+ num_inference_steps,
62
+ guidance_scale,
63
+ image_guidance_scale,
64
+ strength,
65
+ denoising_steps,
66
+ is_randomize_seed,
67
+ seed,
68
+ debug_mode,
69
+ progress = gr.Progress()
70
+ ):
71
+ check(
72
+ source_img,
73
+ prompt,
74
+ uploaded_mask,
75
+ negative_prompt,
76
+ num_inference_steps,
77
+ guidance_scale,
78
+ image_guidance_scale,
79
+ strength,
80
+ denoising_steps,
81
+ is_randomize_seed,
82
+ seed,
83
+ debug_mode
84
  )
85
+ start = time.time()
86
+ progress(0, desc = "Preparing data...")
87
+
88
+ if negative_prompt is None:
89
+ negative_prompt = ""
90
+
91
+ if num_inference_steps is None:
92
+ num_inference_steps = 25
93
+
94
+ if guidance_scale is None:
95
+ guidance_scale = 7
96
+
97
+ if image_guidance_scale is None:
98
+ image_guidance_scale = 1.1
99
+
100
+ if strength is None:
101
+ strength = 0.99
102
+
103
+ if denoising_steps is None:
104
+ denoising_steps = 1000
105
+
106
+ if seed is None:
107
+ seed = random.randint(0, max_64_bit_int)
108
+
109
+ random.seed(seed)
110
+ #pipe = pipe.manual_seed(seed)
111
+
112
+ input_image = source_img["background"].convert("RGB")
113
+
114
+ original_height, original_width, original_channel = np.array(input_image).shape
115
+ output_width = original_width
116
+ output_height = original_height
117
+
118
+ if uploaded_mask is None:
119
+ mask_image = source_img["layers"][0].convert("RGB")
120
+ else:
121
+ mask_image = uploaded_mask.convert("RGB")
122
+ mask_image = mask_image.resize((original_width, original_height))
123
+
124
+ # Limited to 1 million pixels
125
+ if 1024 * 1024 < output_width * output_height:
126
+ factor = ((1024 * 1024) / (output_width * output_height))**0.5
127
+ process_width = math.floor(output_width * factor)
128
+ process_height = math.floor(output_height * factor)
129
+
130
+ limitation = " Due to technical limitation, the image have been downscaled and then upscaled.";
131
+ else:
132
+ process_width = output_width
133
+ process_height = output_height
134
+
135
+ limitation = "";
136
+
137
+ # Width and height must be multiple of 8
138
+ if (process_width % 8) != 0 or (process_height % 8) != 0:
139
+ if ((process_width - (process_width % 8) + 8) * (process_height - (process_height % 8) + 8)) <= (1024 * 1024):
140
+ process_width = process_width - (process_width % 8) + 8
141
+ process_height = process_height - (process_height % 8) + 8
142
+ elif (process_height % 8) <= (process_width % 8) and ((process_width - (process_width % 8) + 8) * process_height) <= (1024 * 1024):
143
+ process_width = process_width - (process_width % 8) + 8
144
+ process_height = process_height - (process_height % 8)
145
+ elif (process_width % 8) <= (process_height % 8) and (process_width * (process_height - (process_height % 8) + 8)) <= (1024 * 1024):
146
+ process_width = process_width - (process_width % 8)
147
+ process_height = process_height - (process_height % 8) + 8
148
+ else:
149
+ process_width = process_width - (process_width % 8)
150
+ process_height = process_height - (process_height % 8)
151
+
152
+ progress(None, desc = "Processing...")
153
+ output_image = inpaint_on_gpu(
154
+ seed,
155
+ process_width,
156
+ process_height,
157
+ prompt,
158
+ negative_prompt,
159
+ input_image,
160
+ mask_image,
161
+ num_inference_steps,
162
+ guidance_scale,
163
+ image_guidance_scale,
164
+ strength,
165
+ denoising_steps
166
+ )
167
+
168
+ if limitation != "":
169
+ output_image = output_image.resize((output_width, output_height))
170
+
171
+ if debug_mode == False:
172
+ input_image = None
173
+ mask_image = None
174
+
175
+ end = time.time()
176
+ secondes = int(end - start)
177
+ minutes = math.floor(secondes / 60)
178
+ secondes = secondes - (minutes * 60)
179
+ hours = math.floor(minutes / 60)
180
+ minutes = minutes - (hours * 60)
181
+ return [
182
+ output_image,
183
+ ("Start again to get a different result. " if is_randomize_seed else "") + "The image has been generated in " + ((str(hours) + " h, ") if hours != 0 else "") + ((str(minutes) + " min, ") if hours != 0 or minutes != 0 else "") + str(secondes) + " sec." + limitation,
184
+ input_image,
185
+ mask_image
186
+ ]
187
+
188
+ def inpaint_on_gpu2(
189
+ seed,
190
+ process_width,
191
+ process_height,
192
+ prompt,
193
+ negative_prompt,
194
+ input_image,
195
+ mask_image,
196
+ num_inference_steps,
197
+ guidance_scale,
198
+ image_guidance_scale,
199
+ strength,
200
+ denoising_steps
201
+ ):
202
+ return input_image
203
+
204
+ @spaces.GPU(duration=420)
205
+ def inpaint_on_gpu(
206
+ seed,
207
+ process_width,
208
+ process_height,
209
+ prompt,
210
+ negative_prompt,
211
+ input_image,
212
+ mask_image,
213
+ num_inference_steps,
214
+ guidance_scale,
215
+ image_guidance_scale,
216
+ strength,
217
+ denoising_steps
218
+ ):
219
+ return pipe(
220
+ seeds = [seed],
221
+ width = process_width,
222
+ height = process_height,
223
+ prompt = prompt,
224
+ negative_prompt = negative_prompt,
225
+ image = input_image,
226
+ mask_image = mask_image,
227
+ num_inference_steps = num_inference_steps,
228
+ guidance_scale = guidance_scale,
229
+ image_guidance_scale = image_guidance_scale,
230
+ strength = strength,
231
+ denoising_steps = denoising_steps,
232
+ show_progress_bar = True
233
+ ).images[0]
234
+
235
+ with gr.Blocks() as interface:
236
+ gr.HTML(
237
+ """
238
+ <h1 style="text-align: center;">Inpaint</h1>
239
+ <p style="text-align: center;">Modifies one detail of your image, at any resolution, freely, without account, without watermark, without installation, which can be downloaded</p>
240
+ <br/>
241
+
242
+ """
243
+ )
244
+ with gr.Column():
245
+ source_img = gr.ImageMask(label = "Your image (click on the landscape 🌄 to upload your image; click on the pen 🖌️ to draw the mask)", type = "pil", brush=gr.Brush(colors=["white"], color_mode="fixed"))
246
+ prompt = gr.Textbox(label = "Prompt", info = "Describe the subject, the background and the style of image; 77 token limit", placeholder = "Describe what you want to see in the entire image", lines = 2)
247
+ with gr.Accordion("Upload a mask", open = False):
248
+ uploaded_mask = gr.Image(label = "Already made mask (black pixels will be preserved, white pixels will be redrawn)", sources = ["upload"], type = "pil")
249
+ with gr.Accordion("Advanced options", open = False):
250
+ negative_prompt = gr.Textbox(label = "Negative prompt", placeholder = "Describe what you do NOT want to see in the entire image", value = "Ugly, malformed, noise, blur, watermark")
251
+ num_inference_steps = gr.Slider(minimum = 10, maximum = 100, value = 25, step = 1, label = "Number of inference steps", info = "lower=faster, higher=image quality")
252
+ guidance_scale = gr.Slider(minimum = 1, maximum = 13, value = 7, step = 0.1, label = "Classifier-Free Guidance Scale", info = "lower=image quality, higher=follow the prompt")
253
+ image_guidance_scale = gr.Slider(minimum = 1, value = 1.1, step = 0.1, label = "Image Guidance Scale", info = "lower=image quality, higher=follow the image")
254
+ strength = gr.Slider(value = 0.99, minimum = 0.01, maximum = 1.0, step = 0.01, label = "Strength", info = "lower=follow the original area, higher=redraw from scratch")
255
+ denoising_steps = gr.Number(minimum = 0, value = 1000, step = 1, label = "Denoising", info = "lower=irrelevant result, higher=relevant result")
256
+ randomize_seed = gr.Checkbox(label = "\U0001F3B2 Randomize seed", value = True, info = "If checked, result is always different")
257
+ seed = gr.Slider(minimum = 0, maximum = max_64_bit_int, step = 1, randomize = True, label = "Seed")
258
+ debug_mode = gr.Checkbox(label = "Debug mode", value = False, info = "Show intermediate results")
259
+
260
+ submit = gr.Button("🚀 Inpaint", variant = "primary")
261
+
262
+ inpainted_image = gr.Image(label = "Inpainted image")
263
+ information = gr.HTML()
264
+ original_image = gr.Image(label = "Original image", visible = False)
265
+ mask_image = gr.Image(label = "Mask image", visible = False)
266
+
267
+ submit.click(update_seed, inputs = [
268
+ randomize_seed, seed
269
+ ], outputs = [
270
+ seed
271
+ ], queue = False, show_progress = False).then(toggle_debug, debug_mode, [
272
+ original_image,
273
+ mask_image
274
+ ], queue = False, show_progress = False).then(check, inputs = [
275
+ source_img,
276
+ prompt,
277
+ uploaded_mask,
278
+ negative_prompt,
279
+ num_inference_steps,
280
+ guidance_scale,
281
+ image_guidance_scale,
282
+ strength,
283
+ denoising_steps,
284
+ randomize_seed,
285
+ seed,
286
+ debug_mode
287
+ ], outputs = [], queue = False, show_progress = False).success(inpaint, inputs = [
288
+ source_img,
289
+ prompt,
290
+ uploaded_mask,
291
+ negative_prompt,
292
+ num_inference_steps,
293
+ guidance_scale,
294
+ image_guidance_scale,
295
+ strength,
296
+ denoising_steps,
297
+ randomize_seed,
298
+ seed,
299
+ debug_mode
300
+ ], outputs = [
301
+ inpainted_image,
302
+ information,
303
+ original_image,
304
+ mask_image
305
+ ], scroll_to_output = True)
306
 
307
+ interface.queue().launch()
 
requirements.txt CHANGED
@@ -1,7 +1,3 @@
1
- diffusers
2
  torch
3
- torchvision
4
- pillow
5
- numpy
6
  transformers
7
- accelerate
 
 
1
  torch
 
 
 
2
  transformers
3
+ diffusers