shawnljw
add settings to app
5a41ea2
raw
history blame
4.02 kB
import gradio as gr
import numpy as np
import cv2
from tqdm import trange
from sklearn.cluster import KMeans
class KMeansClustering():
def __init__(self, n_clusters=8, max_iter=300):
self.n_clusters = n_clusters
self.max_iter = max_iter
def fit(self, X):
self.inertia_ = float('inf')
# random init of clusters
idx = np.random.choice(range(X.shape[0]), self.n_clusters, replace=False)
self.cluster_centers_ = X[idx]
print(f'Training for {self.max_iter} epochs')
epochs = trange(self.max_iter)
for i in epochs:
distances = X[:, np.newaxis, :] - self.cluster_centers_[np.newaxis, :, :]
distances = np.linalg.norm(distances, axis=2)
self.labels_ = np.argmin(distances, axis=1)
new_inertia = np.sum(np.min(distances, axis=1) ** 2)
epochs.set_description(f'Epoch-{i+1}, Inertia-{new_inertia}')
if new_inertia < self.inertia_:
self.inertia_ = new_inertia
else:
epochs.close()
print('Early Stopping. Inertia has converged.')
break
self.cluster_centers_ = np.empty_like(self.cluster_centers_)
for cluster in range(self.n_clusters):
in_cluster = (self.labels_ == cluster)
if np.any(in_cluster):
self.cluster_centers_[cluster] = np.mean(X[in_cluster], axis=0)
else:
# cluster is empty, pick random point as next centroid
self.cluster_centers_[cluster] = X[np.random.randint(0, X.shape[0])]
return self
def predict(self, X):
distances = X[:, np.newaxis, :] - self.cluster_centers_[np.newaxis, :, :]
distances = np.linalg.norm(distances, axis=2)
labels = np.argmin(distances, axis=1)
return labels
def fit_predict(self, X):
return self.fit(X).labels_
def segment_image(image, model: KMeansClustering):
w, b, c = image.shape
image = image.reshape(w*b, c) / 255
idx = np.random.choice(range(image.shape[0]), image.shape[0]//5, replace=False)
image_subset = image[idx]
model.fit(image_subset) # fit model on 20% sample of image
labels = model.predict(image)
return labels.reshape(w,b), model
def generate_outputs(image, implementation, num_colours):
if implementation == 'custom':
model = KMeansClustering(n_clusters=num_colours, max_iter=10)
elif implementation == 'sk-learn':
model = KMeans(n_clusters=num_colours, n_init='auto')
label_map, model = segment_image(image, model)
clustered_image = model.cluster_centers_[label_map]
clustered_image = (clustered_image * 255).astype('uint8')
clustered_image = cv2.medianBlur(clustered_image,5)
edges = 255 - cv2.Canny(clustered_image, 0, 1)
edges = cv2.cvtColor(edges, cv2.COLOR_GRAY2RGB)
return [(edges, 'Coloring Page'), (clustered_image, 'Filled Picture')]
with gr.Blocks() as demo:
gr.Markdown(
"""
# image2coloringbook
(image2coloringbook)[https://github.com/ShawnLJW/image2coloringbook] is a simple tool that converts an image into a coloring book.
""")
with gr.Row():
with gr.Column():
image = gr.Image()
submit = gr.Button('Generate')
with gr.Column():
num_colours = gr.Slider(
minimum=1,
maximum=40,
value=24,
step=1,
label='Number of colours'
)
implementation = gr.Dropdown(
choices=['sk-learn','custom'],
value='sk-learn',
label='Implementation'
)
with gr.Row():
output = gr.Gallery(preview=True)
submit.click(
generate_outputs,
inputs=[image, implementation, num_colours],
outputs=[output]
)
if __name__ == '__main__':
demo.launch()