Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,156 +1,61 @@
|
|
1 |
import gradio as gr
|
2 |
-
from PIL import Image,
|
3 |
-
import cv2
|
4 |
-
import numpy as np
|
5 |
import os
|
6 |
-
from collections import defaultdict
|
7 |
-
from skimage.color import deltaE_ciede2000, rgb2lab
|
8 |
import zipfile
|
9 |
|
10 |
-
def DoG_filter(image, kernel_size=0, sigma=1.0, k_sigma=2.0, gamma=1.5):
|
11 |
-
g1 = cv2.GaussianBlur(image, (kernel_size, kernel_size), sigma)
|
12 |
-
g2 = cv2.GaussianBlur(image, (kernel_size, kernel_size), sigma * k_sigma)
|
13 |
-
return g1 - gamma * g2
|
14 |
|
15 |
-
def
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
if not np.all(data[ni, :3] == color_1, axis=0):
|
68 |
-
valid_neighbors.append(data[ni, :3])
|
69 |
-
if valid_neighbors:
|
70 |
-
new_color = np.mean(valid_neighbors, axis=0).astype(np.uint8)
|
71 |
-
data[i, :3] = new_color
|
72 |
-
data[i, 3] = 255
|
73 |
-
mask[i] = True
|
74 |
-
else:
|
75 |
-
new_matches[i] = True
|
76 |
-
matches = new_matches
|
77 |
-
if match_num == np.sum(matches):
|
78 |
-
nochange_count += 1
|
79 |
-
if nochange_count > 5:
|
80 |
-
break
|
81 |
-
|
82 |
-
data = data.reshape(original_shape)
|
83 |
-
mask = mask.reshape(original_shape[:2])
|
84 |
-
|
85 |
-
result_image = Image.fromarray(data, 'RGBA')
|
86 |
-
blurred_image = result_image.filter(ImageFilter.GaussianBlur(radius=blur_radius))
|
87 |
-
blurred_data = np.array(blurred_image)
|
88 |
-
|
89 |
-
np.copyto(data, blurred_data, where=mask[..., None])
|
90 |
-
|
91 |
-
return Image.fromarray(data, 'RGBA')
|
92 |
-
|
93 |
-
def generate_distant_colors(consolidated_colors, distance_threshold):
|
94 |
-
consolidated_lab = [rgb2lab(np.array([color], dtype=np.float32) / 255.0).reshape(3) for color, _ in consolidated_colors]
|
95 |
-
max_attempts = 10000
|
96 |
-
for _ in range(max_attempts):
|
97 |
-
random_rgb = np.random.randint(0, 256, size=3)
|
98 |
-
random_lab = rgb2lab(np.array([random_rgb], dtype=np.float32) / 255.0).reshape(3)
|
99 |
-
if all(deltaE_ciede2000(base_color_lab, random_lab) > distance_threshold for base_color_lab in consolidated_lab):
|
100 |
-
return tuple(random_rgb)
|
101 |
-
return (128, 128, 128)
|
102 |
-
|
103 |
-
def consolidate_colors(major_colors, threshold):
|
104 |
-
colors_lab = [rgb2lab(np.array([[color]], dtype=np.float32)/255.0).reshape(3) for color, _ in major_colors]
|
105 |
-
i = 0
|
106 |
-
while i < len(colors_lab):
|
107 |
-
j = i + 1
|
108 |
-
while j < len(colors_lab):
|
109 |
-
if deltaE_ciede2000(colors_lab[i], colors_lab[j]) < threshold:
|
110 |
-
if major_colors[i][1] >= major_colors[j][1]:
|
111 |
-
major_colors[i] = (major_colors[i][0], major_colors[i][1] + major_colors[j][1])
|
112 |
-
major_colors.pop(j)
|
113 |
-
colors_lab.pop(j)
|
114 |
-
else:
|
115 |
-
major_colors[j] = (major_colors[j][0], major_colors[j][1] + major_colors[i][1])
|
116 |
-
major_colors.pop(i)
|
117 |
-
colors_lab.pop(i)
|
118 |
-
continue
|
119 |
-
j += 1
|
120 |
-
i += 1
|
121 |
-
return major_colors
|
122 |
-
|
123 |
-
def get_major_colors(image, threshold_percentage=0.01):
|
124 |
-
if image.mode != 'RGB':
|
125 |
-
image = image.convert('RGB')
|
126 |
-
color_count = defaultdict(int)
|
127 |
-
for pixel in image.getdata():
|
128 |
-
color_count[pixel] += 1
|
129 |
-
total_pixels = image.width * image.height
|
130 |
-
major_colors = [(color, count) for color, count in color_count.items() if (count / total_pixels) >= threshold_percentage]
|
131 |
-
return major_colors
|
132 |
-
|
133 |
-
def line_color(image, mask, new_color):
|
134 |
-
data = np.array(image)
|
135 |
-
data[mask, :3] = new_color
|
136 |
-
return Image.fromarray(data)
|
137 |
-
|
138 |
-
def process_image(image, lineart):
|
139 |
-
if image.mode != 'RGBA':
|
140 |
-
image = image.convert('RGBA')
|
141 |
-
|
142 |
-
lineart = lineart.point(lambda x: 0 if x < 200 else 255)
|
143 |
-
lineart = ImageOps.invert(lineart)
|
144 |
-
kernel = np.ones((3, 3), np.uint8)
|
145 |
-
lineart = cv2.dilate(np.array(lineart), kernel, iterations=1)
|
146 |
-
lineart = Image.fromarray(lineart)
|
147 |
-
mask = np.array(lineart) == 255
|
148 |
-
major_colors = get_major_colors(image, threshold_percentage=0.05)
|
149 |
-
major_colors = consolidate_colors(major_colors, 10)
|
150 |
-
new_color_1 = generate_distant_colors(major_colors, 100)
|
151 |
-
filled_image = line_color(image, mask, new_color_1)
|
152 |
-
replace_color_image = replace_color(filled_image, new_color_1, 2).convert('RGB')
|
153 |
-
return replace_color_image
|
154 |
|
155 |
def zip_files(zip_files, zip_path):
|
156 |
with zipfile.ZipFile(zip_path, 'w') as zipf:
|
@@ -163,32 +68,31 @@ class webui:
|
|
163 |
|
164 |
def main(self, image_path):
|
165 |
image = Image.open(image_path)
|
166 |
-
|
167 |
image_name = os.path.splitext(image_path)[0]
|
168 |
-
alpha = image.getchannel('A') if image.mode == 'RGBA' else None
|
169 |
-
image = Image.open(image_path).convert('RGBA')
|
170 |
-
rgb_image = image.convert('RGB')
|
171 |
-
lineart = process_XDoG(image_path).convert('L')
|
172 |
-
replace_color_image = process_image(rgb_image, lineart).convert('RGBA')
|
173 |
-
|
174 |
-
if alpha:
|
175 |
-
replace_color_image.putalpha(alpha)
|
176 |
-
|
177 |
-
replace_color_image_path = f"{image_name}_noline.png"
|
178 |
-
replace_color_image.save(replace_color_image_path)
|
179 |
-
|
180 |
-
lineart_image = lineart.convert('RGBA')
|
181 |
-
lineart_alpha = 255 - np.array(lineart)
|
182 |
-
lineart_image.putalpha(Image.fromarray(lineart_alpha))
|
183 |
-
|
184 |
-
lineart_image_path = f"{image_name}_lineart.png"
|
185 |
-
lineart_image.save(lineart_image_path)
|
186 |
|
187 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
188 |
zip_path = f"{image_name}.zip"
|
189 |
zip_files(zip_files_list, zip_path)
|
190 |
|
191 |
-
|
|
|
192 |
return outputs, zip_path
|
193 |
|
194 |
def launch(self, share):
|
@@ -213,4 +117,4 @@ class webui:
|
|
213 |
|
214 |
if __name__ == "__main__":
|
215 |
ui = webui()
|
216 |
-
ui.launch(share=True)
|
|
|
1 |
import gradio as gr
|
2 |
+
from PIL import Image, ImageOps
|
|
|
|
|
3 |
import os
|
|
|
|
|
4 |
import zipfile
|
5 |
|
|
|
|
|
|
|
|
|
6 |
|
7 |
+
def process_image(image):
|
8 |
+
# 元の画像のサイズ
|
9 |
+
original_width, original_height = image.size
|
10 |
+
|
11 |
+
# 新しいサイズ
|
12 |
+
target_width, target_height = 252, 144
|
13 |
+
|
14 |
+
# 分割後の画像を格納するリスト
|
15 |
+
outputs = []
|
16 |
+
|
17 |
+
# 画像を4つのセクションに分割するための新しいサイズ
|
18 |
+
new_width = original_width // 2
|
19 |
+
new_height = original_height // 2
|
20 |
+
|
21 |
+
# 画像を4つのセクションに分割
|
22 |
+
for i in range(2):
|
23 |
+
for j in range(2):
|
24 |
+
left = new_width * j
|
25 |
+
upper = new_height * i
|
26 |
+
right = new_width * (j + 1)
|
27 |
+
lower = new_height * (i + 1)
|
28 |
+
|
29 |
+
# 画像を切り取る
|
30 |
+
cropped_image = image.crop((left, upper, right, lower))
|
31 |
+
|
32 |
+
# アスペクト比を保ちながら、指定のサイズにリサイズ
|
33 |
+
cropped_image = cropped_image.resize((target_width, target_height), Image.ANTIALIAS)
|
34 |
+
|
35 |
+
# 新しい黒背景を作成
|
36 |
+
black_background = Image.new('RGBA', (target_width, target_height), (0, 0, 0, 255))
|
37 |
+
|
38 |
+
# 余白の追加を左上、左下、右上、右下に対応
|
39 |
+
if i == 0 and j == 0: # 左上
|
40 |
+
left_offset = 0
|
41 |
+
top_offset = 0
|
42 |
+
elif i == 1 and j == 0: # 左下
|
43 |
+
left_offset = 0
|
44 |
+
top_offset = target_height - cropped_image.height
|
45 |
+
elif i == 0 and j == 1: # 右上
|
46 |
+
left_offset = target_width - cropped_image.width
|
47 |
+
top_offset = 0
|
48 |
+
elif i == 1 and j == 1: # 右下
|
49 |
+
left_offset = target_width - cropped_image.width
|
50 |
+
top_offset = target_height - cropped_image.height
|
51 |
+
|
52 |
+
# 中心に元画像を貼り付け
|
53 |
+
black_background.paste(cropped_image, (left_offset, top_offset))
|
54 |
+
|
55 |
+
outputs.append(black_background)
|
56 |
+
|
57 |
+
# 出力される4つの画像を返す
|
58 |
+
return outputs[0], outputs[1], outputs[2], outputs[3]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
|
60 |
def zip_files(zip_files, zip_path):
|
61 |
with zipfile.ZipFile(zip_path, 'w') as zipf:
|
|
|
68 |
|
69 |
def main(self, image_path):
|
70 |
image = Image.open(image_path)
|
71 |
+
# 拡張子を取り除いたファイル名を取得
|
72 |
image_name = os.path.splitext(image_path)[0]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
|
74 |
+
# 画像を処理
|
75 |
+
output1, output2, output3, output4 = process_image(image)
|
76 |
+
|
77 |
+
# 保存先のパスを作成
|
78 |
+
output1_path = f"{image_name}_1.png"
|
79 |
+
output2_path = f"{image_name}_2.png"
|
80 |
+
output3_path = f"{image_name}_3.png"
|
81 |
+
output4_path = f"{image_name}_4.png"
|
82 |
+
|
83 |
+
# 画像を保存
|
84 |
+
output1.save(output1_path)
|
85 |
+
output2.save(output2_path)
|
86 |
+
output3.save(output3_path)
|
87 |
+
output4.save(output4_path)
|
88 |
+
|
89 |
+
# 保存したファイルをリストに追加
|
90 |
+
zip_files_list = [output1_path, output2_path, output3_path, output4_path]
|
91 |
zip_path = f"{image_name}.zip"
|
92 |
zip_files(zip_files_list, zip_path)
|
93 |
|
94 |
+
# 出力として画像とzipファイルを返す
|
95 |
+
outputs = [output1, output2, output3, output4]
|
96 |
return outputs, zip_path
|
97 |
|
98 |
def launch(self, share):
|
|
|
117 |
|
118 |
if __name__ == "__main__":
|
119 |
ui = webui()
|
120 |
+
ui.launch(share=True)
|