Spaces:
Runtime error
Runtime error
mattyamonaca
commited on
Commit
•
c3b62d3
1
Parent(s):
f483907
first commit
Browse files- app.py +80 -0
- bg_alpha.py +60 -0
- lineart.py +21 -0
- models/lora/_put_your_lora.txt +0 -0
- utils.py +33 -0
app.py
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import sys
|
3 |
+
from utils import load_lora_model
|
4 |
+
from bg_alpha import adjust_transparency
|
5 |
+
from lineart import get_pipe
|
6 |
+
import os
|
7 |
+
from PIL import Image
|
8 |
+
import spaces
|
9 |
+
|
10 |
+
path = os.getcwd()
|
11 |
+
output_dir = f"{path}/output"
|
12 |
+
lora_dir = f"{path}/models/lora"
|
13 |
+
|
14 |
+
load_lora_model(lora_dir)
|
15 |
+
|
16 |
+
pipe = get_pipe(lora_dir)
|
17 |
+
|
18 |
+
@spaces.GPU()
|
19 |
+
def generate(prompt, negative_prompt):
|
20 |
+
default_pos = "((white background)), lineart, <lora:sdxl_BWLine:1.0>, monochrome, "
|
21 |
+
default_neg = ""
|
22 |
+
prompt = default_pos + prompt
|
23 |
+
negative_prompt = default_neg + negative_prompt
|
24 |
+
|
25 |
+
width, height = 1024, 1024
|
26 |
+
color = (255, 255, 255)
|
27 |
+
white_bg = Image.new("RGB", (width, height), color)
|
28 |
+
|
29 |
+
image = pipe(
|
30 |
+
prompt=prompt,
|
31 |
+
negative_prompt = negative_prompt,
|
32 |
+
image=[white_bg],
|
33 |
+
num_inference_steps=50,
|
34 |
+
controlnet_conditioning_scale=[0.1]
|
35 |
+
).images[0]
|
36 |
+
|
37 |
+
return image
|
38 |
+
|
39 |
+
|
40 |
+
class webui:
|
41 |
+
def __init__(self):
|
42 |
+
self.demo = gr.Blocks()
|
43 |
+
|
44 |
+
def process(self, pos_prompt, neg_prompt):
|
45 |
+
image = generate(pos_prompt, neg_prompt)
|
46 |
+
image = adjust_transparency(image)
|
47 |
+
return [image]
|
48 |
+
|
49 |
+
def launch(self, share):
|
50 |
+
with self.demo:
|
51 |
+
with gr.Column():
|
52 |
+
with gr.Tab("output"):
|
53 |
+
output_0 = gr.Gallery(format="png")
|
54 |
+
#output_file = gr.File()
|
55 |
+
with gr.Column():
|
56 |
+
pos_prompt = gr.Textbox(value="1girl, cute, kawaii, medium breasts, medium hair, smile, mini skirt, best quality, very aesthetic," ,max_lines=1000, label="positive prompt")
|
57 |
+
neg_prompt = gr.Textbox(value="bold line, multiple people," ,max_lines=1000, label="negative prompt")
|
58 |
+
|
59 |
+
submit = gr.Button(value="Start")
|
60 |
+
|
61 |
+
|
62 |
+
submit.click(
|
63 |
+
self.process,
|
64 |
+
inputs=[pos_prompt, neg_prompt], #[input_image, pos_prompt, neg_prompt, alpha_th, thickness, reference_image],
|
65 |
+
outputs=[output_0]
|
66 |
+
)
|
67 |
+
|
68 |
+
self.demo.queue()
|
69 |
+
self.demo.launch(share=share)
|
70 |
+
|
71 |
+
|
72 |
+
if __name__ == "__main__":
|
73 |
+
ui = webui()
|
74 |
+
if len(sys.argv) > 1:
|
75 |
+
if sys.argv[1] == "share":
|
76 |
+
ui.launch(share=True)
|
77 |
+
else:
|
78 |
+
ui.launch(share=False)
|
79 |
+
else:
|
80 |
+
ui.launch(share=False)
|
bg_alpha.py
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from PIL import Image, ImageFilter
|
2 |
+
import numpy as np
|
3 |
+
|
4 |
+
def erode(image, iterations=1):
|
5 |
+
# モルフォロジー操作のためのカーネルを定義
|
6 |
+
kernel = np.array([[0, 1, 0],
|
7 |
+
[1, 1, 1],
|
8 |
+
[0, 1, 0]], dtype=np.uint8)
|
9 |
+
|
10 |
+
image_np = np.array(image)
|
11 |
+
for _ in range(iterations):
|
12 |
+
eroded_image = np.zeros_like(image_np)
|
13 |
+
for i in range(1, image_np.shape[0] - 1):
|
14 |
+
for j in range(1, image_np.shape[1] - 1):
|
15 |
+
region = image_np[i-1:i+2, j-1:j+2]
|
16 |
+
eroded_image[i, j] = np.min(region + (1 - kernel) * 255)
|
17 |
+
image_np = eroded_image
|
18 |
+
|
19 |
+
return Image.fromarray(image_np.astype(np.uint8))
|
20 |
+
|
21 |
+
def convert_non_white_to_black(image):
|
22 |
+
# 画像をNumPy配列に変換
|
23 |
+
image_np = np.array(image)
|
24 |
+
|
25 |
+
# 完全に白でないピクセルをすべて黒にする
|
26 |
+
#image_np[image_np < 250] = 0
|
27 |
+
image_np[image_np > 200] = 255
|
28 |
+
|
29 |
+
# NumPy配列を画像に変換
|
30 |
+
return Image.fromarray(image_np)
|
31 |
+
|
32 |
+
|
33 |
+
|
34 |
+
def adjust_transparency(image):
|
35 |
+
# 画像を読み込み、グレースケールに変換
|
36 |
+
image.save("tmp.png")
|
37 |
+
image = image.convert('L')
|
38 |
+
image = convert_non_white_to_black(image)
|
39 |
+
image = image.filter(ImageFilter.SMOOTH)
|
40 |
+
|
41 |
+
result = Image.new('RGBA', image.size)
|
42 |
+
for x in range(image.width):
|
43 |
+
for y in range(image.height):
|
44 |
+
# グレースケール値を取得
|
45 |
+
gray = image.getpixel((x, y))
|
46 |
+
|
47 |
+
alpha = 255
|
48 |
+
# 透明度の設定
|
49 |
+
if gray == 0:
|
50 |
+
alpha = 0 # 完全に透明
|
51 |
+
else:
|
52 |
+
alpha = 255-gray # 完全に不透明
|
53 |
+
|
54 |
+
# 新しい画像にピクセルを設定
|
55 |
+
result.putpixel((x, y), (0, 0, 0, alpha))
|
56 |
+
|
57 |
+
return result
|
58 |
+
|
59 |
+
def remove_bg(image):
|
60 |
+
image = adjust_transparency(image)
|
lineart.py
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from diffusers import AutoPipelineForText2Image
|
2 |
+
import torch
|
3 |
+
|
4 |
+
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel, UniPCMultistepScheduler
|
5 |
+
from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel, AutoencoderKL
|
6 |
+
import torch
|
7 |
+
|
8 |
+
from PIL import Image
|
9 |
+
|
10 |
+
|
11 |
+
def get_pipe(lora_dir):
|
12 |
+
controlnets = [ControlNetModel.from_pretrained("mattyamonaca/white2line", torch_dtype=torch.float16)]
|
13 |
+
|
14 |
+
vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16)
|
15 |
+
pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
|
16 |
+
"cagliostrolab/animagine-xl-3.1", controlnet=controlnets, vae=vae, torch_dtype=torch.float16
|
17 |
+
)
|
18 |
+
|
19 |
+
pipe.enable_model_cpu_offload()
|
20 |
+
pipe.load_lora_weights(lora_dir, weight_name="sdxl_BWLine.safetensors")
|
21 |
+
return pipe
|
models/lora/_put_your_lora.txt
ADDED
File without changes
|
utils.py
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import random
|
2 |
+
import string
|
3 |
+
import os
|
4 |
+
|
5 |
+
import requests
|
6 |
+
from tqdm import tqdm
|
7 |
+
|
8 |
+
|
9 |
+
def randomname(n):
|
10 |
+
randlst = [random.choice(string.ascii_letters + string.digits) for i in range(n)]
|
11 |
+
return ''.join(randlst)
|
12 |
+
|
13 |
+
def load_lora_model(model_dir):
|
14 |
+
folder = model_dir
|
15 |
+
file_name = 'sdxl_BWLine.safetensors'
|
16 |
+
url = "https://huggingface.co/tori29umai/lineart/resolve/main/sdxl_BWLine.safetensors"
|
17 |
+
|
18 |
+
|
19 |
+
file_path = os.path.join(folder, file_name)
|
20 |
+
if not os.path.exists(file_path):
|
21 |
+
response = requests.get(url, stream=True)
|
22 |
+
|
23 |
+
total_size = int(response.headers.get('content-length', 0))
|
24 |
+
with open(file_path, 'wb') as f, tqdm(
|
25 |
+
desc=file_name,
|
26 |
+
total=total_size,
|
27 |
+
unit='iB',
|
28 |
+
unit_scale=True,
|
29 |
+
unit_divisor=1024,
|
30 |
+
) as bar:
|
31 |
+
for data in response.iter_content(chunk_size=1024):
|
32 |
+
size = f.write(data)
|
33 |
+
bar.update(size)
|