Spaces:
Sleeping
Sleeping
File size: 2,584 Bytes
9ef7694 6b9ba41 9ef7694 1178f23 a1746b1 1178f23 9ef7694 6b9ba41 9ef7694 6b9ba41 9ef7694 a1746b1 e23c96e a1746b1 1178f23 a1746b1 1178f23 a1746b1 6b9ba41 1178f23 a1746b1 1178f23 a1746b1 9ef7694 a1746b1 9ef7694 a1746b1 9ef7694 a1746b1 9ef7694 a1746b1 9ef7694 a1746b1 9ef7694 a1746b1 9ef7694 a1746b1 9ef7694 a1746b1 9ef7694 a1746b1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | import gradio as gr
import numpy as np
from sklearn.cluster import MiniBatchKMeans
from sklearn.utils import shuffle
from PIL import Image
import os
import tempfile
from io import BytesIO
def compress_kmeans(image: np.ndarray, k: int, random_state: 42) -> np.ndarray:
"""
Faster K‑Means compression using a random pixel sample for centroid fitting.
"""
pixels = image.reshape(-1, 3).astype(np.float32)
sample_size = min(20000, len(pixels))
sample = shuffle(pixels, random_state=random_state)[:sample_size]
model = MiniBatchKMeans(
n_clusters=k,
batch_size=min(1024, sample_size),
n_init='auto',
max_iter=50,
random_state=random_state,
verbose=0,
)
model.fit(sample)
labels = model.predict(pixels)
centres = model.cluster_centers_.astype(np.uint8)
compressed_pixels = centres[labels]
return compressed_pixels.reshape(image.shape)
def process(filepath, k):
if filepath is None:
return None, "Please upload an image.", None
# Load original
orig = np.array(Image.open(filepath).convert('RGB'))
# Compress
comp = compress_kmeans(orig, k, random_state=42)
def get_size(img):
with BytesIO() as buf:
Image.fromarray(img).save(buf, format='PNG')
return len(buf.getvalue())
orig_size = get_size(orig)
comp_size = get_size(comp)
ratio = orig_size / comp_size
saved = (1 - comp_size/orig_size) * 100
# PSNR
mse = np.mean((orig.astype(float) - comp.astype(float)) ** 2)
psnr = 20 * np.log10(255.0 / np.sqrt(mse)) if mse > 0 else float('inf')
stats = (f"**Original:** {orig_size/1024:.1f} KB \n"
f"**Compressed:** {comp_size/1024:.1f} KB \n"
f"**Compression ratio:** {ratio:.1f}x \n"
f"**Space saved:** {saved:.1f}% \n"
f"**PSNR:** {psnr:.1f} dB")
temp = tempfile.mkdtemp()
out_path = os.path.join(temp, 'compressed.png')
Image.fromarray(comp).save(out_path)
return comp, stats, out_path
iface = gr.Interface(
fn=process,
inputs=[
gr.Image(type='filepath', label='Upload an Image'),
gr.Slider(minimum=2, maximum=64, step=2, value=16, label='Number of colours (k)')
],
outputs=[
gr.Image(label='Compressed Image'),
gr.Markdown(label='Compression Statistics'),
gr.File(label='Download Compressed Image')
],
title='Image Compression with K‑Means',
description='Reduce the number of colours in an image using K-Means clustering.'
)
iface.launch() |