K-Means を用いた色量子化

Beginner

This tutorial is from open-source community. Access the source code

はじめに

カラー量子化は、画像全体の外観を維持しながら、画像で使用される異なる色の数を減らすプロセスです。これは、類似した色をグループ化し、単一の色値で表現することによって行われます。この実験では、中国の頤和園の画像に対して K-Means クラスタリングアルゴリズムを使用してカラー量子化を行います。

VM のヒント

VM の起動が完了したら、左上隅をクリックしてノートブックタブに切り替え、Jupyter Notebook を使って練習しましょう。

Jupyter Notebook が読み込み終わるまで数秒待つ必要がある場合があります。Jupyter Notebook の制限により、操作の検証は自動化できません。

学習中に問題が発生した場合は、Labby にお問い合わせください。セッション後にフィードバックを提供してください。すぐに問題を解決いたします。

元の画像を読み込んで表示する

まず、頤和園の元の画像を読み込んで表示します。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_sample_image

## 頤和園の写真を読み込む
china = load_sample_image("china.jpg")

## 元の画像を表示する
plt.figure()
plt.axis("off")
plt.title("Original Image")
plt.imshow(china)
plt.show()

画像を浮動小数点数に変換して形状を変更する

画像を浮動小数点数に変換し、2 次元の NumPy 配列に整形して、K-Means アルゴリズムで処理できるようにします。

## デフォルトの 8 ビット整数コーディングではなく、浮動小数点数に変換する。
china = np.array(china, dtype=np.float64) / 255

## 画像の寸法を取得する
w, h, d = original_shape = tuple(china.shape)
assert d == 3

## 画像を 2 次元の NumPy 配列に整形する
image_array = np.reshape(china, (w * h, d))

K-Means モデルをフィットさせる

画像データの小さなサブサンプルに K-Means モデルをフィットさせ、それを使って画像全体の色インデックスを予測します。

from sklearn.cluster import KMeans
from sklearn.utils import shuffle
from time import time

n_colors = 64

## データの小さなサブサンプルに K-Means モデルをフィットさせる
print("Fitting model on a small sub-sample of the data")
t0 = time()
image_array_sample = shuffle(image_array, random_state=0, n_samples=1000)
kmeans = KMeans(n_clusters=n_colors, n_init="auto", random_state=0).fit(
    image_array_sample
)
print(f"done in {time() - t0:0.3f}s.")

## すべての点に対するラベルを取得する
print("Predicting color indices on the full image (k-means)")
t0 = time()
labels = kmeans.predict(image_array)
print(f"done in {time() - t0:0.3f}s.")

ランダムなコードブックを使って色インデックスを予測する

ランダムなコードブックを使って画像全体の色インデックスを予測します。

## ランダムなコードブックを取得する
codebook_random = shuffle(image_array, random_state=0, n_samples=n_colors)

## ランダムなコードブックを使って画像全体の色インデックスを予測する
print("Predicting color indices on the full image (random)")
t0 = time()
labels_random = pairwise_distances_argmin(codebook_random, image_array, axis=0)
print(f"done in {time() - t0:0.3f}s.")

なお、pairwise_distances_argmin は既存の関数ですが、コード内に定義されていないため、そのまま残しておきます。もしこの関数が定義されていない場合、コードはエラーを起こします。

画像を再作成する

K-Means モデルとランダムなコードブックから得たコードブックとラベルを使って、圧縮された画像を再作成します。

def recreate_image(codebook, labels, w, h):
    """コードブックとラベルから(圧縮された)画像を再作成する"""
    return codebook[labels].reshape(w, h, -1)

## 量子化された画像とともに元の画像を表示する
plt.figure()
plt.clf()
plt.axis("off")
plt.title("Original image (96,615 colors)")
plt.imshow(china)

plt.figure()
plt.clf()
plt.axis("off")
plt.title(f"Quantized image ({n_colors} colors, K-Means)")
plt.imshow(recreate_image(kmeans.cluster_centers_, labels, w, h))

plt.figure()
plt.clf()
plt.axis("off")
plt.title(f"Quantized image ({n_colors} colors, Random)")
plt.imshow(recreate_image(codebook_random, labels_random, w, h))

plt.show()

まとめ

この実験では、画像に対して K-Means クラスタリングアルゴリズムを使って色量子化を行う方法を学びました。元の画像を読み込んで表示し、それを浮動小数点数に変換して 2 次元の NumPy 配列に整形しました。画像データのサブサンプルに K-Means モデルをフィットさせ、それを使って画像全体の色インデックスを予測しました。また、ランダムなコードブックを使って画像全体の色インデックスを予測しました。最後に、K-Means モデルとランダムなコードブックから得たコードブックとラベルを使って圧縮された画像を再作成し、量子化された画像とともに元の画像を表示しました。