Menu
CoddyTech

Image Colors

Part of the Unsupervised Learning section of Coddy's Machine Learning journey. Lesson 41 of 51.

A screen printer has a few inks, not millions of colors. k-means picks the best few for any picture:

Two pictures of a sunset side by side. Left, the original: a sky fading from purple to orange, a yellow sun, a dark sea with an orange reflection. Right, the same sunset in 4 flat colors

A color image has shape (rows, columns, 3): red, green and blue per pixel, each from 0 to 1. One reshape turns the pixels into data:

A 2 by 3 image of orange, yellow and dark blue pixels, with an arrow to a table of 6 rows, one per pixel, each holding its red, green and blue values

pixels = image.reshape(-1, 3)
km = KMeans(n_clusters=4, n_init=10, random_state=0).fit(pixels)
poster = km.cluster_centers_[km.labels_].reshape(image.shape)
ax.imshow(poster)

Each center is a color. Indexing the centers with the labels gives every pixel its center's color; the reshape folds the rows back into a picture.

challenge icon

Challenge

Medium

A poster studio screen-prints a mountain lake with k inks. The starter paints the 40 by 60 image, reads k and sets up a titled chart.

  1. Turn the image into one row per pixel and find k colors with k-means.
  2. Repaint every pixel with its center's color and fold the rows back into a picture.
  3. Draw it on ax and show it.

Like this sunset in 5 inks:

The sunset repainted with 5 flat colors and titled 5 inks: a plum and a rose sky band, an orange band, a yellow sun, a navy sea with orange stripes

Your program prints nothing: Coddy describes your picture and its inks. Then try other values of k: when does the red boat get its own ink?

Try it yourself

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans


# Paints a 40 by 60 mountain lake: a sky, a snowy peak, a forest, the water and a red boat
def paint_lake():
    image = np.zeros((40, 60, 3))
    for r in range(40):
        for c in range(60):
            if 30 <= r <= 31 and 10 <= c <= 17 - (r - 30) * 2:
                image[r, c] = [0.8, 0.15, 0.1]
            elif r >= 27:
                t = (r - 27) / 12
                image[r, c] = [0.1, 0.45 - 0.2 * t, 0.65 - 0.2 * t]
            elif r >= 21:
                image[r, c] = [0.1, 0.35 + 0.05 * (c % 3), 0.15]
            elif r >= abs(c - 34) + 4 and r < 10:
                image[r, c] = [0.95, 0.95, 0.97]
            elif r >= abs(c - 34) + 4:
                image[r, c] = [0.45, 0.42, 0.45]
            else:
                image[r, c] = [0.55 + r / 50, 0.75 + r / 120, 0.95]
    return np.round(image, 3)


# Don't change the lines below
image = paint_lake()
k = int(input())
fig, ax = plt.subplots()
ax.set_title(f"{k} inks")
ax.axis("off")

# Write your code below
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Unsupervised Learning

Practice on your own: Online Python compiler