I have a png image as shown below.

enter image description here

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)
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].set_title('Original Image', size=16)

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


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

enter image description here

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.

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

1 Answer 1


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):

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

    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:

enter image description here

  • $\begingroup$ Thanks for your answer. How do you know it is 24bits? $\endgroup$ Oct 13, 2019 at 22:33
  • $\begingroup$ 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). $\endgroup$ Oct 14, 2019 at 9:47
  • $\begingroup$ 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) $\endgroup$ Oct 14, 2019 at 18:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.