Why compressed image size is greater than original one in kmeans algorithm? I have a png image as shown below.



And I use kmeans algorithm to compress the image by color quantization. I compressed the image to use 64 colours. The code is:

ncolor = 64
rimage = image.reshape(image.shape[0]*image.shape[1],3)
kmeans = KMeans(n_clusters = ncolor, n_init=10, max_iter=200)
kmeans.fit(rimage)
centers = kmeans.cluster_centers_

labels = np.asarray(kmeans.labels_).reshape(rows, cols)
compressed_image = np.zeros((rows, cols,3),dtype=np.uint8 )
for i in range(rows):
    for j in range(cols):
            compressed_image[i,j,:] = centers[labels[i,j],:]

fig, ax = plt.subplots(1, 2, figsize=(16, 6),
                       subplot_kw=dict(xticks=[], yticks=[]))
ax[0].imshow(image)
ax[0].set_title('Original Image', size=16)

ax[1].imshow(compressed_image)
ax[1].set_title(f'{ncolor}-color Image', size=16);

io.imsave('compressed_tiger.png',labels);


The image is the origin image. And the resulte shown on jupyter notebook is:



since I compressed the image to 64 colours but the size of the saved file compressed_tiger.png (588KB) is larger than the original one (435KB). I don't understand why it becomes larger.
Your are saving the same color format... if they are 24bits RGB you are currently saving also in 24 bits RGB. You should convert to RGB-8 that uses 8 bits per pixel.

I have used pypng and PIL to get the following result

from PIL import Image
import png

    s = []
    for i in range(rows):
        s.append(tuple(labels[i].astype(int)))

    palette = []
    for i in range(ncolor):
        c = (centers[i][0].astype(int), centers[i][1].astype(int), centers[i][2].astype(int))
        palette.append(c)

    w = png.Writer(width=cols, height=rows, palette=palette, bitdepth=8)
    f = open('tiger8bits3.png', 'wb')
    w.write(f, s)


Look at PNG formats: http://www.patrickhansen.com/2011/02/04/png-8-24-32-what/

The result is 269KB: