Spaces:
Sleeping
Sleeping
| 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() |