Application creation
Browse files
app.py
ADDED
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from diffusers import (
|
2 |
+
ControlNetModel,
|
3 |
+
DiffusionPipeline,
|
4 |
+
StableDiffusionControlNetPipeline,
|
5 |
+
)
|
6 |
+
import gradio as gr
|
7 |
+
import numpy as np
|
8 |
+
import os
|
9 |
+
import time
|
10 |
+
import math
|
11 |
+
import random
|
12 |
+
import imageio
|
13 |
+
from PIL import (Image, ImageFilter)
|
14 |
+
import torch
|
15 |
+
|
16 |
+
max_64_bit_int = 2**63 - 1
|
17 |
+
|
18 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
19 |
+
controlnet = ControlNetModel.from_pretrained("lllyasviel/control_v11e_sd15_ip2p", torch_dtype = torch.float32)
|
20 |
+
pipe = StableDiffusionControlNetPipeline.from_pretrained(
|
21 |
+
"runwayml/stable-diffusion-v1-5", safety_checker = None, controlnet = controlnet, torch_dtype = torch.float32
|
22 |
+
)
|
23 |
+
pipe = pipe.to(device)
|
24 |
+
|
25 |
+
def check(
|
26 |
+
source_img,
|
27 |
+
prompt,
|
28 |
+
negative_prompt,
|
29 |
+
denoising_steps,
|
30 |
+
num_inference_steps,
|
31 |
+
guidance_scale,
|
32 |
+
randomize_seed,
|
33 |
+
seed,
|
34 |
+
progress = gr.Progress()):
|
35 |
+
if source_img is None:
|
36 |
+
raise gr.Error("Please provide an image.")
|
37 |
+
|
38 |
+
if prompt is None or prompt == "":
|
39 |
+
raise gr.Error("Please provide a prompt input.")
|
40 |
+
|
41 |
+
def pix2pix(
|
42 |
+
source_img,
|
43 |
+
prompt,
|
44 |
+
negative_prompt,
|
45 |
+
denoising_steps,
|
46 |
+
num_inference_steps,
|
47 |
+
guidance_scale,
|
48 |
+
randomize_seed,
|
49 |
+
seed,
|
50 |
+
progress = gr.Progress()):
|
51 |
+
check(
|
52 |
+
source_img,
|
53 |
+
prompt,
|
54 |
+
negative_prompt,
|
55 |
+
denoising_steps,
|
56 |
+
num_inference_steps,
|
57 |
+
guidance_scale,
|
58 |
+
randomize_seed,
|
59 |
+
seed
|
60 |
+
)
|
61 |
+
start = time.time()
|
62 |
+
progress(0, desc = "Preparing data...")
|
63 |
+
|
64 |
+
if negative_prompt is None:
|
65 |
+
negative_prompt = ""
|
66 |
+
|
67 |
+
if denoising_steps is None:
|
68 |
+
denoising_steps = 0
|
69 |
+
|
70 |
+
if num_inference_steps is None:
|
71 |
+
num_inference_steps = 20
|
72 |
+
|
73 |
+
if guidance_scale is None:
|
74 |
+
guidance_scale = 5
|
75 |
+
|
76 |
+
if randomize_seed:
|
77 |
+
seed = random.randint(0, max_64_bit_int)
|
78 |
+
|
79 |
+
random.seed(seed)
|
80 |
+
#pipe = pipe.manual_seed(seed)
|
81 |
+
|
82 |
+
try:
|
83 |
+
imageio.imwrite("data.png", source_img)
|
84 |
+
except:
|
85 |
+
raise gr.Error("Can't read input image. You can try to first save your image in another format (.webp, .png, .jpeg, .bmp...).")
|
86 |
+
|
87 |
+
# Input image
|
88 |
+
try:
|
89 |
+
input_image = Image.open("data.png").convert("RGB")
|
90 |
+
except:
|
91 |
+
raise gr.Error("Can't open input image. You can try to first save your image in another format (.webp, .png, .jpeg, .bmp...).")
|
92 |
+
|
93 |
+
output_height, output_width, dummy_channel = np.array(input_image).shape
|
94 |
+
mask_image = Image.new(mode = input_image.mode, size = (output_width, output_height), color = "white")
|
95 |
+
|
96 |
+
limitation = "";
|
97 |
+
|
98 |
+
# Limited to 1 million pixels
|
99 |
+
if 1024 * 1024 < output_width * output_height:
|
100 |
+
factor = ((1024 * 1024) / (output_width * output_height))**0.5
|
101 |
+
output_width = math.floor(output_width * factor)
|
102 |
+
output_height = math.floor(output_height * factor)
|
103 |
+
|
104 |
+
limitation = " Due to technical limitation, the image have been downscaled.";
|
105 |
+
|
106 |
+
# Width and height must be multiple of 8
|
107 |
+
output_width = output_width - (output_width % 8)
|
108 |
+
output_height = output_height - (output_height % 8)
|
109 |
+
progress(None, desc = "Processing...")
|
110 |
+
|
111 |
+
output_image = pipe(
|
112 |
+
seeds=[seed],
|
113 |
+
width = output_width,
|
114 |
+
height = output_height,
|
115 |
+
prompt = prompt,
|
116 |
+
negative_prompt = negative_prompt,
|
117 |
+
image = input_image,
|
118 |
+
mask_image = mask_image,
|
119 |
+
num_inference_steps = num_inference_steps,
|
120 |
+
guidance_scale = guidance_scale,
|
121 |
+
denoising_steps = denoising_steps,
|
122 |
+
show_progress_bar = True
|
123 |
+
).images[0]
|
124 |
+
|
125 |
+
end = time.time()
|
126 |
+
secondes = int(end - start)
|
127 |
+
minutes = secondes // 60
|
128 |
+
secondes = secondes - (minutes * 60)
|
129 |
+
hours = minutes // 60
|
130 |
+
minutes = minutes - (hours * 60)
|
131 |
+
return [
|
132 |
+
output_image,
|
133 |
+
"Start again to get a different result. The new image is " + str(output_width) + " pixels large and " + str(output_height) + " pixels high, so an image of " + f'{output_width * output_height:,}' + " pixels. The image have been generated in " + str(hours) + " h, " + str(minutes) + " min, " + str(secondes) + " sec." + limitation
|
134 |
+
]
|
135 |
+
|
136 |
+
with gr.Blocks() as interface:
|
137 |
+
gr.Markdown(
|
138 |
+
"""
|
139 |
+
<p style="text-align: center;"><b><big><big><big>Instruct Pix2Pix demo</big></big></big></b></p>
|
140 |
+
<p style="text-align: center;">Modifies your image using a textual instruction, up to 1 million pixels, freely, without account, without watermark, without installation, which can be downloaded</p>
|
141 |
+
<br/>
|
142 |
+
<br/>
|
143 |
+
🚀 Powered by <i>SD 1.5</i> and <i>ControlNet</i>
|
144 |
+
<br/>
|
145 |
+
<ul>
|
146 |
+
<li>To change the <b>view angle</b> of your image, I recommend to use <i>Zero123</i>,</li>
|
147 |
+
<li>To <b>upscale</b> your image, I recommend to use <i>Ilaria Upscaler</i>,</li>
|
148 |
+
<li>To <b>slightly change</b> your image, I recommend to use <i>Image-to-Image SDXL</i>,</li>
|
149 |
+
<li>To change <b>one detail</b> on your image, I recommend to use <i>Inpaint SDXL</i>,</li>
|
150 |
+
<li>To remove the <b>background</b> of your image, I recommend to use <i>BRIA</i>,</li>
|
151 |
+
<li>To enlarge the <b>viewpoint</b> of your image, I recommend to use <i>Uncrop</i>,</li>
|
152 |
+
<li>To make a <b>tile</b> of your image, I recommend to use <i>Make My Image Tile</i>,</li>
|
153 |
+
</ul>
|
154 |
+
<br/>
|
155 |
+
🐌 Slow process... ~1 hour. If this space does not work or you want a faster run, use <i>Instruct Pix2Pix</i> available on terrapretapermaculture's <i>ControlNet-v1-1</i> space (last tab) or on <i>Dezgo</i> site.<br>You can duplicate this space on a free account, it works on CPU.<br/>
|
156 |
+
<a href='https://huggingface.co/spaces/Fabrice-TIERCELIN/Instruct-Pix2Pix?duplicate=true'><img src='https://img.shields.io/badge/-Duplicate%20Space-blue?labelColor=white&style=flat&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAP5JREFUOE+lk7FqAkEURY+ltunEgFXS2sZGIbXfEPdLlnxJyDdYB62sbbUKpLbVNhyYFzbrrA74YJlh9r079973psed0cvUD4A+4HoCjsA85X0Dfn/RBLBgBDxnQPfAEJgBY+A9gALA4tcbamSzS4xq4FOQAJgCDwV2CPKV8tZAJcAjMMkUe1vX+U+SMhfAJEHasQIWmXNN3abzDwHUrgcRGmYcgKe0bxrblHEB4E/pndMazNpSZGcsZdBlYJcEL9Afo75molJyM2FxmPgmgPqlWNLGfwZGG6UiyEvLzHYDmoPkDDiNm9JR9uboiONcBXrpY1qmgs21x1QwyZcpvxt9NS09PlsPAAAAAElFTkSuQmCC&logoWidth=14'></a>
|
157 |
+
<br/>
|
158 |
+
⚖️ You can use, modify and share the generated images but not for commercial uses.
|
159 |
+
"""
|
160 |
+
)
|
161 |
+
with gr.Column():
|
162 |
+
source_img = gr.Image(label = "Your image", sources = ["upload"], type = "numpy")
|
163 |
+
prompt = gr.Textbox(label = 'Prompt', info = "Instruct what to change in the image", placeholder = 'Order the AI what to change in the image')
|
164 |
+
with gr.Accordion("Advanced options", open = False):
|
165 |
+
negative_prompt = gr.Textbox(label = 'Negative prompt', placeholder = 'Describe what you do NOT want to see in the image', value = 'Watermark')
|
166 |
+
denoising_steps = gr.Slider(minimum = 0, maximum = 1000, value = 0, step = 1, label = "Denoising", info = "lower=irrelevant result, higher=relevant result")
|
167 |
+
num_inference_steps = gr.Slider(minimum = 10, maximum = 25, value = 20, step = 1, label = "Number of inference steps", info = "lower=faster, higher=image quality")
|
168 |
+
guidance_scale = gr.Slider(minimum = 1, maximum = 13, value = 5, step = 0.1, label = "Classifier-Free Guidance Scale", info = "lower=image quality, higher=follow the prompt")
|
169 |
+
randomize_seed = gr.Checkbox(label = "\U0001F3B2 Randomize seed (not working, always checked)", value = True, info = "If checked, result is always different")
|
170 |
+
seed = gr.Slider(minimum = 0, maximum = max_64_bit_int, step = 1, randomize = True, label = "Seed (if not randomized)")
|
171 |
+
|
172 |
+
submit = gr.Button("Modify", variant = "primary")
|
173 |
+
|
174 |
+
modified_image = gr.Image(label = "Modified image")
|
175 |
+
information = gr.Label(label = "Information")
|
176 |
+
|
177 |
+
submit.click(check, inputs = [
|
178 |
+
source_img,
|
179 |
+
prompt,
|
180 |
+
negative_prompt,
|
181 |
+
denoising_steps,
|
182 |
+
num_inference_steps,
|
183 |
+
guidance_scale,
|
184 |
+
randomize_seed,
|
185 |
+
seed
|
186 |
+
], outputs = [], queue = False, show_progress = False).success(pix2pix, inputs = [
|
187 |
+
source_img,
|
188 |
+
prompt,
|
189 |
+
negative_prompt,
|
190 |
+
denoising_steps,
|
191 |
+
num_inference_steps,
|
192 |
+
guidance_scale,
|
193 |
+
randomize_seed,
|
194 |
+
seed
|
195 |
+
], outputs = [
|
196 |
+
modified_image,
|
197 |
+
information
|
198 |
+
], scroll_to_output = True)
|
199 |
+
|
200 |
+
gr.Examples(
|
201 |
+
inputs = [
|
202 |
+
source_img,
|
203 |
+
prompt,
|
204 |
+
negative_prompt,
|
205 |
+
denoising_steps,
|
206 |
+
num_inference_steps,
|
207 |
+
guidance_scale,
|
208 |
+
randomize_seed,
|
209 |
+
seed
|
210 |
+
],
|
211 |
+
outputs = [
|
212 |
+
modified_image,
|
213 |
+
information
|
214 |
+
],
|
215 |
+
examples = [
|
216 |
+
[
|
217 |
+
"Example1.webp",
|
218 |
+
"What if it's snowing?",
|
219 |
+
"Watermark",
|
220 |
+
1,
|
221 |
+
20,
|
222 |
+
5,
|
223 |
+
True,
|
224 |
+
42
|
225 |
+
],
|
226 |
+
[
|
227 |
+
"Example2.png",
|
228 |
+
"What if this woman had brown hair?",
|
229 |
+
"Watermark",
|
230 |
+
1,
|
231 |
+
20,
|
232 |
+
5,
|
233 |
+
True,
|
234 |
+
42
|
235 |
+
],
|
236 |
+
[
|
237 |
+
"Example3.jpeg",
|
238 |
+
"Replace the house by a windmill",
|
239 |
+
"Watermark",
|
240 |
+
1,
|
241 |
+
20,
|
242 |
+
5,
|
243 |
+
True,
|
244 |
+
42
|
245 |
+
],
|
246 |
+
],
|
247 |
+
cache_examples = False,
|
248 |
+
)
|
249 |
+
|
250 |
+
interface.queue().launch()
|