Spaces:
Runtime error
Runtime error
artificialguybr
commited on
Commit
•
d58e89b
1
Parent(s):
07b8c5e
Upload 9 files
Browse files- scripts/__pycache__/pixelart.cpython-310.pyc +0 -0
- scripts/__pycache__/postprocessing_pixelart.cpython-310.pyc +0 -0
- scripts/__pycache__/utils.cpython-310.pyc +0 -0
- scripts/pixelart.py +148 -0
- scripts/postprocessing_pixelart.py +166 -0
- sd_webui_pixelart/__init__.py +0 -0
- sd_webui_pixelart/__pycache__/__init__.cpython-310.pyc +0 -0
- sd_webui_pixelart/__pycache__/utils.cpython-310.pyc +0 -0
- sd_webui_pixelart/utils.py +75 -0
scripts/__pycache__/pixelart.cpython-310.pyc
ADDED
Binary file (4.38 kB). View file
|
|
scripts/__pycache__/postprocessing_pixelart.cpython-310.pyc
ADDED
Binary file (4.33 kB). View file
|
|
scripts/__pycache__/utils.cpython-310.pyc
ADDED
Binary file (2.2 kB). View file
|
|
scripts/pixelart.py
ADDED
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
import modules.scripts as scripts
|
4 |
+
from modules import images
|
5 |
+
from modules.shared import opts
|
6 |
+
|
7 |
+
from sd_webui_pixelart.utils import DITHER_METHODS, QUANTIZATION_METHODS, downscale_image, limit_colors, resize_image, convert_to_black_and_white, convert_to_grayscale
|
8 |
+
|
9 |
+
class Script(scripts.Script):
|
10 |
+
def title(self):
|
11 |
+
return "Pixel art"
|
12 |
+
|
13 |
+
|
14 |
+
def show(self, is_img2img):
|
15 |
+
return scripts.AlwaysVisible
|
16 |
+
|
17 |
+
|
18 |
+
def ui(self, is_img2img):
|
19 |
+
quantization_methods = ['Median cut', 'Maximum coverage', 'Fast octree']
|
20 |
+
dither_methods = ['None', 'Floyd-Steinberg']
|
21 |
+
|
22 |
+
with gr.Accordion("Pixel art", open=False):
|
23 |
+
with gr.Row():
|
24 |
+
enabled = gr.Checkbox(label="Enable", value=False)
|
25 |
+
|
26 |
+
with gr.Column():
|
27 |
+
with gr.Row():
|
28 |
+
downscale = gr.Slider(label="Downscale", minimum=1, maximum=32, step=2, value=8)
|
29 |
+
need_rescale = gr.Checkbox(label="Rescale to original size", value=True)
|
30 |
+
with gr.Tabs():
|
31 |
+
with gr.TabItem("Color"):
|
32 |
+
enable_color_limit = gr.Checkbox(label="Enable", value=False)
|
33 |
+
number_of_colors = gr.Slider(label="Palette Size", minimum=1, maximum=256, step=1, value=16)
|
34 |
+
quantization_method = gr.Radio(choices=quantization_methods, value=quantization_methods[0], label='Colors quantization method')
|
35 |
+
dither_method = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
|
36 |
+
use_k_means = gr.Checkbox(label="Enable k-means for color quantization", value=True)
|
37 |
+
with gr.TabItem("Grayscale"):
|
38 |
+
is_grayscale = gr.Checkbox(label="Enable", value=False)
|
39 |
+
number_of_shades = gr.Slider(label="Palette Size", minimum=1, maximum=256, step=1, value=16)
|
40 |
+
quantization_method_grayscale = gr.Radio(choices=quantization_methods, value=quantization_methods[0], label='Colors quantization method')
|
41 |
+
dither_method_grayscale = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
|
42 |
+
use_k_means_grayscale = gr.Checkbox(label="Enable k-means for color quantization", value=True)
|
43 |
+
with gr.TabItem("Black and white"):
|
44 |
+
with gr.Row():
|
45 |
+
is_black_and_white = gr.Checkbox(label="Enable", value=False)
|
46 |
+
is_inversed_black_and_white = gr.Checkbox(label="Inverse", value=False)
|
47 |
+
with gr.Row():
|
48 |
+
black_and_white_threshold = gr.Slider(label="Threshold", minimum=1, maximum=256, step=1, value=128)
|
49 |
+
with gr.TabItem("Custom color palette"):
|
50 |
+
use_color_palette = gr.Checkbox(label="Enable", value=False)
|
51 |
+
palette_image=gr.Image(label="Color palette image", type="pil")
|
52 |
+
palette_colors = gr.Slider(label="Palette Size (only for complex images)", minimum=1, maximum=256, step=1, value=16)
|
53 |
+
dither_method_palette = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
|
54 |
+
|
55 |
+
return [enabled, downscale, need_rescale, enable_color_limit, number_of_colors, quantization_method, dither_method, use_k_means, is_grayscale, number_of_shades, quantization_method_grayscale, dither_method_grayscale, use_k_means_grayscale, is_black_and_white, is_inversed_black_and_white, black_and_white_threshold, use_color_palette, palette_image, palette_colors, dither_method_palette]
|
56 |
+
|
57 |
+
def postprocess(
|
58 |
+
self,
|
59 |
+
p,
|
60 |
+
processed,
|
61 |
+
enabled,
|
62 |
+
|
63 |
+
downscale,
|
64 |
+
need_rescale,
|
65 |
+
|
66 |
+
enable_color_limit,
|
67 |
+
number_of_colors,
|
68 |
+
quantization_method,
|
69 |
+
dither_method,
|
70 |
+
use_k_means,
|
71 |
+
|
72 |
+
is_grayscale,
|
73 |
+
number_of_shades,
|
74 |
+
quantization_method_grayscale,
|
75 |
+
dither_method_grayscale,
|
76 |
+
use_k_means_grayscale,
|
77 |
+
|
78 |
+
is_black_and_white,
|
79 |
+
is_inversed_black_and_white,
|
80 |
+
black_and_white_threshold,
|
81 |
+
|
82 |
+
use_color_palette,
|
83 |
+
palette_image,
|
84 |
+
palette_colors,
|
85 |
+
dither_method_palette
|
86 |
+
):
|
87 |
+
if not enabled:
|
88 |
+
return
|
89 |
+
|
90 |
+
dither = DITHER_METHODS[dither_method]
|
91 |
+
quantize = QUANTIZATION_METHODS[quantization_method]
|
92 |
+
dither_grayscale = DITHER_METHODS[dither_method_grayscale]
|
93 |
+
quantize_grayscale = QUANTIZATION_METHODS[quantization_method_grayscale]
|
94 |
+
dither_palette = DITHER_METHODS[dither_method_palette]
|
95 |
+
|
96 |
+
def process_image(original_image):
|
97 |
+
original_width, original_height = original_image.size
|
98 |
+
|
99 |
+
if original_image.mode != "RGB":
|
100 |
+
new_image = original_image.convert("RGB")
|
101 |
+
else:
|
102 |
+
new_image = original_image
|
103 |
+
|
104 |
+
new_image = downscale_image(new_image, downscale)
|
105 |
+
|
106 |
+
if use_color_palette:
|
107 |
+
new_image = limit_colors(
|
108 |
+
image=new_image,
|
109 |
+
palette=palette_image,
|
110 |
+
palette_colors=palette_colors,
|
111 |
+
dither=dither_palette
|
112 |
+
)
|
113 |
+
|
114 |
+
if is_black_and_white:
|
115 |
+
new_image = convert_to_black_and_white(new_image, black_and_white_threshold, is_inversed_black_and_white)
|
116 |
+
|
117 |
+
if is_grayscale:
|
118 |
+
new_image = convert_to_grayscale(new_image)
|
119 |
+
new_image = limit_colors(
|
120 |
+
image=new_image,
|
121 |
+
limit=int(number_of_shades),
|
122 |
+
quantize=quantize_grayscale,
|
123 |
+
dither=dither_grayscale,
|
124 |
+
use_k_means=use_k_means_grayscale
|
125 |
+
)
|
126 |
+
|
127 |
+
if enable_color_limit:
|
128 |
+
new_image = limit_colors(
|
129 |
+
image=new_image,
|
130 |
+
limit=int(number_of_colors),
|
131 |
+
quantize=quantize,
|
132 |
+
dither=dither,
|
133 |
+
use_k_means=use_k_means
|
134 |
+
)
|
135 |
+
|
136 |
+
if need_rescale:
|
137 |
+
new_image = resize_image(new_image, (original_width, original_height))
|
138 |
+
|
139 |
+
return new_image.convert('RGBA')
|
140 |
+
|
141 |
+
for i in range(len(processed.images)):
|
142 |
+
pixel_image = process_image(processed.images[i])
|
143 |
+
processed.images.append(pixel_image)
|
144 |
+
|
145 |
+
images.save_image(pixel_image, p.outpath_samples, "pixel",
|
146 |
+
processed.seed + i, processed.prompt, opts.samples_format, info= processed.info, p=p)
|
147 |
+
|
148 |
+
return processed
|
scripts/postprocessing_pixelart.py
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from PIL import features
|
3 |
+
|
4 |
+
from modules import scripts_postprocessing
|
5 |
+
from modules.shared import opts
|
6 |
+
|
7 |
+
from sd_webui_pixelart.utils import DITHER_METHODS, QUANTIZATION_METHODS, downscale_image, limit_colors, resize_image, convert_to_grayscale, convert_to_black_and_white
|
8 |
+
|
9 |
+
|
10 |
+
class ScriptPostprocessingUpscale(scripts_postprocessing.ScriptPostprocessing):
|
11 |
+
name = "Pixel art"
|
12 |
+
order = 20005
|
13 |
+
model = None
|
14 |
+
|
15 |
+
def ui(self):
|
16 |
+
quantization_methods = ['Median cut', 'Maximum coverage', 'Fast octree']
|
17 |
+
dither_methods = ['None', 'Floyd-Steinberg']
|
18 |
+
|
19 |
+
if features.check_feature("libimagequant"):
|
20 |
+
quantization_methods.insert(0, "libimagequant")
|
21 |
+
|
22 |
+
with gr.Blocks():
|
23 |
+
with gr.Accordion(label="Pixel art", open=False):
|
24 |
+
enabled = gr.Checkbox(label="Enable", value=False)
|
25 |
+
with gr.Row():
|
26 |
+
downscale = gr.Slider(label="Downscale", minimum=1, maximum=32, step=2, value=8)
|
27 |
+
need_rescale = gr.Checkbox(label="Rescale to original size", value=True)
|
28 |
+
with gr.Tabs():
|
29 |
+
with gr.TabItem("Color"):
|
30 |
+
enable_color_limit = gr.Checkbox(label="Enable", value=False)
|
31 |
+
number_of_colors = gr.Slider(label="Palette Size", minimum=1, maximum=256, step=1, value=16)
|
32 |
+
quantization_method = gr.Radio(choices=quantization_methods, value=quantization_methods[0], label='Colors quantization method')
|
33 |
+
dither_method = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
|
34 |
+
use_k_means = gr.Checkbox(label="Enable k-means for color quantization", value=True)
|
35 |
+
with gr.TabItem("Grayscale"):
|
36 |
+
is_grayscale = gr.Checkbox(label="Enable", value=False)
|
37 |
+
number_of_shades = gr.Slider(label="Palette Size", minimum=1, maximum=256, step=1, value=16)
|
38 |
+
quantization_method_grayscale = gr.Radio(choices=quantization_methods, value=quantization_methods[0], label='Colors quantization method')
|
39 |
+
dither_method_grayscale = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
|
40 |
+
use_k_means_grayscale = gr.Checkbox(label="Enable k-means for color quantization", value=True)
|
41 |
+
with gr.TabItem("Black and white"):
|
42 |
+
with gr.Row():
|
43 |
+
black_and_white = gr.Checkbox(label="Enable", value=False)
|
44 |
+
inversed_black_and_white = gr.Checkbox(label="Inverse", value=False)
|
45 |
+
with gr.Row():
|
46 |
+
black_and_white_threshold = gr.Slider(label="Threshold", minimum=1, maximum=256, step=1, value=128)
|
47 |
+
with gr.TabItem("Custom color palette"):
|
48 |
+
use_color_palette = gr.Checkbox(label="Enable", value=False)
|
49 |
+
palette_image=gr.Image(label="Color palette image", type="pil")
|
50 |
+
palette_colors = gr.Slider(label="Palette Size (only for complex images)", minimum=1, maximum=256, step=1, value=16)
|
51 |
+
dither_method_palette = gr.Radio(choices=dither_methods, value=dither_methods[0], label='Colors dither method')
|
52 |
+
|
53 |
+
return {
|
54 |
+
"enabled": enabled,
|
55 |
+
|
56 |
+
"downscale": downscale,
|
57 |
+
"need_rescale": need_rescale,
|
58 |
+
|
59 |
+
"enable_color_limit": enable_color_limit,
|
60 |
+
"number_of_colors": number_of_colors,
|
61 |
+
"quantization_method": quantization_method,
|
62 |
+
"dither_method": dither_method,
|
63 |
+
"use_k_means": use_k_means,
|
64 |
+
|
65 |
+
"is_grayscale": is_grayscale,
|
66 |
+
"number_of_shades": number_of_shades,
|
67 |
+
"quantization_method_grayscale": quantization_method_grayscale,
|
68 |
+
"dither_method_grayscale": dither_method_grayscale,
|
69 |
+
"use_k_means_grayscale": use_k_means_grayscale,
|
70 |
+
|
71 |
+
"use_color_palette": use_color_palette,
|
72 |
+
"palette_image": palette_image,
|
73 |
+
"palette_colors": palette_colors,
|
74 |
+
"dither_method_palette": dither_method_palette,
|
75 |
+
|
76 |
+
"black_and_white": black_and_white,
|
77 |
+
"inversed_black_and_white": inversed_black_and_white,
|
78 |
+
"black_and_white_threshold": black_and_white_threshold,
|
79 |
+
}
|
80 |
+
|
81 |
+
|
82 |
+
def process(
|
83 |
+
self,
|
84 |
+
pp: scripts_postprocessing.PostprocessedImage,
|
85 |
+
|
86 |
+
enabled,
|
87 |
+
|
88 |
+
downscale,
|
89 |
+
need_rescale,
|
90 |
+
|
91 |
+
enable_color_limit,
|
92 |
+
number_of_colors,
|
93 |
+
quantization_method,
|
94 |
+
dither_method,
|
95 |
+
use_k_means,
|
96 |
+
|
97 |
+
is_grayscale,
|
98 |
+
number_of_shades,
|
99 |
+
quantization_method_grayscale,
|
100 |
+
dither_method_grayscale,
|
101 |
+
use_k_means_grayscale,
|
102 |
+
|
103 |
+
use_color_palette,
|
104 |
+
palette_image,
|
105 |
+
palette_colors,
|
106 |
+
dither_method_palette,
|
107 |
+
|
108 |
+
black_and_white,
|
109 |
+
inversed_black_and_white,
|
110 |
+
black_and_white_threshold
|
111 |
+
):
|
112 |
+
dither = DITHER_METHODS[dither_method]
|
113 |
+
quantize = QUANTIZATION_METHODS[quantization_method]
|
114 |
+
dither_grayscale = DITHER_METHODS[dither_method_grayscale]
|
115 |
+
quantize_grayscale = QUANTIZATION_METHODS[quantization_method_grayscale]
|
116 |
+
dither_palette = DITHER_METHODS[dither_method_palette]
|
117 |
+
|
118 |
+
if not enabled:
|
119 |
+
return
|
120 |
+
|
121 |
+
def process_image(original_image):
|
122 |
+
original_width, original_height = original_image.size
|
123 |
+
|
124 |
+
if original_image.mode != "RGB":
|
125 |
+
new_image = original_image.convert("RGB")
|
126 |
+
else:
|
127 |
+
new_image = original_image
|
128 |
+
|
129 |
+
new_image = downscale_image(new_image, downscale)
|
130 |
+
|
131 |
+
if use_color_palette:
|
132 |
+
new_image = limit_colors(
|
133 |
+
image=new_image,
|
134 |
+
palette=palette_image,
|
135 |
+
palette_colors=palette_colors,
|
136 |
+
dither=dither_palette
|
137 |
+
)
|
138 |
+
|
139 |
+
if black_and_white:
|
140 |
+
new_image = convert_to_black_and_white(new_image, black_and_white_threshold, inversed_black_and_white)
|
141 |
+
|
142 |
+
if is_grayscale:
|
143 |
+
new_image = convert_to_grayscale(new_image)
|
144 |
+
new_image = limit_colors(
|
145 |
+
image=new_image,
|
146 |
+
limit=int(number_of_shades),
|
147 |
+
quantize=quantize_grayscale,
|
148 |
+
dither=dither_grayscale,
|
149 |
+
use_k_means=use_k_means_grayscale
|
150 |
+
)
|
151 |
+
|
152 |
+
if enable_color_limit:
|
153 |
+
new_image = limit_colors(
|
154 |
+
image=new_image,
|
155 |
+
limit=int(number_of_colors),
|
156 |
+
quantize=quantize,
|
157 |
+
dither=dither,
|
158 |
+
use_k_means=use_k_means
|
159 |
+
)
|
160 |
+
|
161 |
+
if need_rescale:
|
162 |
+
new_image = resize_image(new_image, (original_width, original_height))
|
163 |
+
|
164 |
+
return new_image.convert('RGBA')
|
165 |
+
|
166 |
+
pp.image = process_image(pp.image)
|
sd_webui_pixelart/__init__.py
ADDED
File without changes
|
sd_webui_pixelart/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (205 Bytes). View file
|
|
sd_webui_pixelart/__pycache__/utils.cpython-310.pyc
ADDED
Binary file (2.35 kB). View file
|
|
sd_webui_pixelart/utils.py
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from PIL import Image
|
2 |
+
|
3 |
+
# https://pillow.readthedocs.io/en/stable/reference/Image.html#dither-modes
|
4 |
+
DITHER_METHODS = {
|
5 |
+
"None": Image.Dither.NONE,
|
6 |
+
"Floyd-Steinberg": Image.Dither.FLOYDSTEINBERG
|
7 |
+
}
|
8 |
+
|
9 |
+
#https://pillow.readthedocs.io/en/stable/reference/Image.html#quantization-methods
|
10 |
+
QUANTIZATION_METHODS = {
|
11 |
+
"Median cut": Image.Quantize.MEDIANCUT,
|
12 |
+
"Maximum coverage": Image.Quantize.MAXCOVERAGE,
|
13 |
+
"Fast octree": Image.Quantize.FASTOCTREE,
|
14 |
+
"libimagequant": Image.Quantize.LIBIMAGEQUANT
|
15 |
+
}
|
16 |
+
|
17 |
+
|
18 |
+
def downscale_image(image: Image, scale: int) -> Image:
|
19 |
+
width, height = image.size
|
20 |
+
downscaled_image = image.resize((int(width / scale), int(height / scale)), Image.NEAREST)
|
21 |
+
return downscaled_image
|
22 |
+
|
23 |
+
|
24 |
+
def resize_image(image: Image, size) -> Image:
|
25 |
+
width, height = size
|
26 |
+
resized_image = image.resize((width, height), Image.NEAREST)
|
27 |
+
return resized_image
|
28 |
+
|
29 |
+
|
30 |
+
def limit_colors(
|
31 |
+
image,
|
32 |
+
limit: int=16,
|
33 |
+
palette=None,
|
34 |
+
palette_colors: int=256,
|
35 |
+
quantize: Image.Quantize=Image.Quantize.MEDIANCUT,
|
36 |
+
dither: Image.Dither=Image.Dither.NONE,
|
37 |
+
use_k_means: bool=False
|
38 |
+
):
|
39 |
+
if use_k_means:
|
40 |
+
k_means_value = limit
|
41 |
+
else:
|
42 |
+
k_means_value = 0
|
43 |
+
|
44 |
+
if palette:
|
45 |
+
palette_image = palette
|
46 |
+
ppalette = palette.getcolors()
|
47 |
+
if ppalette:
|
48 |
+
color_palette = palette.quantize(colors=len(list(set(ppalette))))
|
49 |
+
else:
|
50 |
+
colors = len(palette_image.getcolors()) if palette_image.getcolors() else palette_colors
|
51 |
+
color_palette = palette_image.quantize(colors, kmeans=colors)
|
52 |
+
else:
|
53 |
+
# we need to get palette from image, because
|
54 |
+
# dither in quantize doesn't work without it
|
55 |
+
# https://pillow.readthedocs.io/en/stable/_modules/PIL/Image.html#Image.quantize
|
56 |
+
color_palette = image.quantize(colors=limit, kmeans=k_means_value, method=quantize, dither=Image.Dither.NONE)
|
57 |
+
|
58 |
+
new_image = image.quantize(palette=color_palette, dither=dither)
|
59 |
+
|
60 |
+
return new_image
|
61 |
+
|
62 |
+
|
63 |
+
def convert_to_grayscale(image):
|
64 |
+
new_image = image.convert("L")
|
65 |
+
return new_image.convert("RGB")
|
66 |
+
|
67 |
+
|
68 |
+
def convert_to_black_and_white(image: Image, threshold: int=128, is_inversed: bool=False):
|
69 |
+
if is_inversed:
|
70 |
+
apply_threshold = lambda x : 255 if x < threshold else 0
|
71 |
+
else:
|
72 |
+
apply_threshold = lambda x : 255 if x > threshold else 0
|
73 |
+
|
74 |
+
black_and_white_image = image.convert('L', dither=Image.Dither.NONE).point(apply_threshold, mode='1')
|
75 |
+
return black_and_white_image.convert("RGB")
|