# 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.

• Did you check how many colors were used in the original image? Maybe it was already compressed.
– G5W
Oct 13, 2019 at 15:34

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:

• Thanks for your answer. How do you know it is 24bits? Oct 13, 2019 at 22:33
• I have just seen that image is 8bit depth (looking out the properties) but when you get image with PIL library and retrieve numpy array it gets a matrix of 1213 x 683 x 3, (24 bits) from the 256 palette default color. My code tries to store the PNG using again a 265 bit palette (using only 64 colors). Oct 14, 2019 at 9:47
• This is the way I obtained the image... I don't know if you did the same: img = Image.open("abaXL.png") im_rgb = img.convert("RGB") image = np.array(im_rgb) Oct 14, 2019 at 18:05