0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SVDで「暗い顔した思想クン」を画像圧縮してみた

Last updated at Posted at 2025-07-08

はじめに

こんにちは。今回は、特異値分解(SVD: Singular Value Decomposition)を使って、
「暗い顔した思想クン」の顔画像を段階的に圧縮
していきます。

「暗い顔した思想クン」を太宰治と仮定し、その顔画像を特異値分解(SVD)で圧縮・復元。文学的な鬱を数式で可視化し、データサイエンスの力でポジティブに。

第1章:特異値分解(SVD)とは何か?

**特異値分解(SVD:Singular Value Decomposition)**とは、任意の行列 $A$ を3つの行列の積に分解する手法です:

$$
A = U \Sigma V^\top
$$

  • $A$:元の行列(たとえば画像のデータ)
  • $U$:左特異ベクトル(行方向の情報、縦軸の特徴)
  • $\Sigma$:特異値の対角行列(情報の重要度を表すスカラー)
  • $V^\top$:右特異ベクトルの転置(列方向の情報、横軸の特徴)

これによって、画像などのデータの中に含まれる「主要な構造」や「パターン」を抽出し、重要な情報だけを保持して圧縮することができます。


第2章:画像 = 数値の行列(ピクセル値)

画像というのは、実は「画素(ピクセル)の明るさを数値として並べた2次元の行列」にすぎません。

たとえば、グレースケール画像は以下のような数値で表されます:

[[  0  34  85 132 200 255]
 [  3  45  90 140 210 250]
 [ 10  50 100 150 220 240]
   ...(高さ × 幅の大きさ)...
]
  • 値の範囲は 0〜255(0:黒、255:白)
  • 各行列要素 $a_{ij}$ は、ピクセルの明るさ(輝度)
  • この2次元の数値配列をSVDで分解 → 圧縮 → 復元することで、画像の本質を保ったままデータ量を減らすことができます。

なぜ行列として扱うの?

SVDは数学的に「行列」を対象とするため、画像を数値の行列とみなすことで、

  • どのピクセルが重要か(特異値の大小で)
  • どんなパターンが繰り返されているか(特異ベクトルで)

顔の情報をベクトルで抽出する」という発想であり、SVDによる顔の本質情報抽出につながります。

Pythonコード

#  Step 1: 必要なライブラリのインポート
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
from google.colab import files  # Google Colab限定

#  Step 2: 画像のアップロード
uploaded = files.upload()  # 実行すると画像アップロードウィンドウが出ます

#  Step 3: アップロードされたファイル名を取得(1枚を想定)
filename = list(uploaded.keys())[0]

#  Step 4: グレースケールで画像読み込み & numpy配列に変換
img = Image.open(filename).convert('L')  # 'L' = grayscale
img_array = np.array(img)
print("画像サイズ:", img_array.shape)

#  Step 5: 特異値分解(SVD)
U, S, VT = np.linalg.svd(img_array, full_matrices=False)
print("分解完了:U, S, VT")

#  Step 6: 特異値k個だけ使って近似再構成
def svd_reconstruct(k):
    S_k = np.diag(S[:k])
    U_k = U[:, :k]
    VT_k = VT[:k, :]
    return np.dot(U_k, np.dot(S_k, VT_k))

# 📌 Step 7: 元画像と再構成画像を比較表示
k_values = [10, 30, 50, 100, 200]  # 使用する特異値の数

plt.figure(figsize=(15, 8))
plt.subplot(2, 3, 1)
plt.imshow(img_array, cmap='gray')
plt.title("Original")
plt.axis('off')

for i, k in enumerate(k_values):
    img_recon = svd_reconstruct(k)
    plt.subplot(2, 3, i+2)
    plt.imshow(img_recon, cmap='gray')
    plt.title(f"SVD k={k}")
    plt.axis('off')

plt.tight_layout()
plt.show()

結果

image.png

image.png

Original: オリジナルの未圧縮画像。詳細が最も鮮明で、ノイズや歪みがない。
SVD k=10: 特異値10個を使用した圧縮。画像が大きくぼやけ、細部の情報が失われている。
SVD k=30: 特異値30個を使用。k=10に比べて若干鮮明だが、まだ原画像と比べて劣化が顕著。
SVD k=50: 特異値50個を使用。顔の輪郭や特徴がより明確になり、劣化が軽減。
SVD k=100: 特異値100個を使用。原画像に近いクオリティで、細部の再現性が向上。
SVD k=200: 特異値200個を使用。原画像とほぼ同等の品質に近く、圧縮による影響が最小。

結論として、SVDのk値が大きいほど、画像の情報が保持され、品質が向上します。ただし、k値が増えるとデータ量も増えるため、圧縮率と画質のトレードオフが存在します

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?