
写真から主要色を抽出!Python画像解析で作るカラーパレット生成アプリ
「インスタの投稿に統一感を出したいけど、配色センスがない...」
「お気に入りの写真の色合いでWebサイトを作りたい!」
「プログラミング学習したけど、何か実用的なものを作ってみたい」
今回は、そんな悩みを解決する画像解析アプリをPythonで作ります!
完成すれば、こんなことができるようになります。
📷 写真をアップロードするだけで主要色を自動抽出
🎨 美しいカラーパレットを生成
💻 デザイン作業で実際に使えるHEXコード出力
📊 各色の占有率も分析可能
しかもGoogle Colabを使うので環境構築不要!今すぐ始められます。
🎯 今日作るもの
写真から主要な色を抽出して、デザイナーが使うようなカラーパレットを自動生成するアプリです。
例えば夕焼けの写真なら → オレンジ、ピンク、紫の美しいパレット
カフェの写真なら → ブラウン、ベージュ、グリーンの落ち着いたパレット
こんな風に、写真の「雰囲気」を色で表現できるツールを作ります。
🛠️ 環境セットアップ
まずはGoogle Colabを開いて、必要なライブラリをインストールしましょう。
Google Drive → 「新規」→ 「その他」→ 「Google Colaboratory」

以下のコードを順番にコードブロックにコピペするだけ!
(初めての人は下の画像を参照して真似する!)
# 必要なライブラリのインストール
!pip install pillow matplotlib numpy
# ライブラリのインポート
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
from collections import Counter
import io
import requests
# 日本語フォント設定(グラフの文字化け防止)
plt.rcParams['font.family'] = 'DejaVu Sans'
print("✅ セットアップ完了!")

📚 基礎知識:デジタル色彩の世界
プログラムで色を扱う前に、デジタル画像の色について理解しておきましょう。
RGB値って何?
デジタル画像の色はRGB(Red, Green, Blue)で表現されます。 各色は0〜255の値を持ち、組み合わせることで約1677万色を作れます。
# RGB値の例を視覚的に確認
colors_info = [
("赤色", (255, 0, 0)),
("緑色", (0, 255, 0)),
("青色", (0, 0, 255)),
("黄色", (255, 255, 0)),
("紫色", (128, 0, 128)),
("白色", (255, 255, 255)),
("黒色", (0, 0, 0))
]
fig, axes = plt.subplots(1, len(colors_info), figsize=(14, 2))
for i, (name, rgb) in enumerate(colors_info):
# 50x50の色見本を作成
color_square = np.full((50, 50, 3), rgb, dtype=np.uint8)
axes[i].imshow(color_square)
axes[i].set_title(f"{name}\nRGB{rgb}", fontsize=10)
axes[i].axis('off')
plt.tight_layout()
plt.suptitle("RGB色見本", fontsize=16, y=1.08)
plt.show()

🖼️ Step1:画像を読み込んでみよう
まずは画像の基本的な扱い方から学びましょう。
今回はサンプル画像を作って練習します。
# カラフルなサンプル画像を生成(実際の写真の代わり)
# 実際は自分の写真をアップロードして使います
np.random.seed(42) # 結果を再現可能にする
# 虹色のようなグラデーション画像を作成
width, height = 200, 200
sample_image = np.zeros((height, width, 3), dtype=np.uint8)
for y in range(height):
for x in range(width):
# 位置に応じて色を変化
r = int(255 * (x / width))
g = int(255 * (y / height))
b = int(255 * ((x + y) / (width + height)))
sample_image[y, x] = [r, g, b]
# NumPy配列からPIL画像に変換
sample_pil = Image.fromarray(sample_image)
# 画像情報を表示
print(f"📸 画像サイズ: {sample_pil.size} pixels") # (幅, 高さ)
print(f"🎨 画像モード: {sample_pil.mode}") # RGB, RGBA など
print(f"📊 合計ピクセル数: {sample_pil.size[0] * sample_pil.size[1]:,} pixels")

# 画像を表示
plt.figure(figsize=(8, 6))
plt.imshow(sample_pil)
plt.title("サンプル画像(虹色グラデーション)", fontsize=14)
plt.axis('off')
plt.show()
print("🌈 美しいグラデーション画像ができました!")

コードだけで画像を生成することができた!
🎨 Step2:最も多い色を見つけよう
まずは画像の中で「最も多く使われている色」を見つける方法を学びます。
# より色の領域がはっきりした画像を生成
def create_realistic_sample_image():
"""
色抽出に適したサンプル画像を作成
"""
width, height = 200, 200
sample_image = np.zeros((height, width, 3), dtype=np.uint8)
# 5つの色領域を作成(花や風景を想定)
regions = [
# (開始x, 終了x, 開始y, 終了y, RGB色)
(0, 100, 0, 100, [135, 206, 235]), # 空色(左上)
(100, 200, 0, 100, [34, 139, 34]), # 緑(右上)
(0, 80, 100, 200, [139, 69, 19]), # 茶色(左下)
(80, 150, 100, 200, [255, 192, 203]), # ピンク(中央下)
(150, 200, 100, 200, [255, 215, 0]) # 黄色(右下)
]
for x1, x2, y1, y2, color in regions:
sample_image[y1:y2, x1:x2] = color
# 各領域に少しノイズを追加(よりリアルに)
noise = np.random.randint(-10, 10, (y2-y1, x2-x1, 3))
sample_image[y1:y2, x1:x2] = np.clip(
sample_image[y1:y2, x1:x2].astype(int) + noise, 0, 255
).astype(np.uint8)
return Image.fromarray(sample_image)
# 新しいサンプル画像を生成
sample_pil = create_realistic_sample_image()
# 画像を確認
plt.figure(figsize=(8, 6))
plt.imshow(sample_pil)
plt.title("改良版サンプル画像(5色の領域)", fontsize=14)
plt.axis('off')
plt.show()
print("🎨 色の領域がはっきりした画像を生成しました!")
def quantize_colors(image, levels=16):
"""
色を量子化して似た色をまとめる
"""
rgb_array = np.array(image)
# 各色成分を指定したレベル数に量子化
quantized = np.floor(rgb_array / (256 / levels)) * (256 / levels)
quantized = np.clip(quantized, 0, 255).astype(np.uint8)
return Image.fromarray(quantized)
def get_dominant_color_quantized(image, quantize_levels=16):
"""
量子化を使った色抽出
"""
# 色を量子化
quantized_image = quantize_colors(image, quantize_levels)
print(f"🎨 色を{quantize_levels}レベルに量子化しました")
# 量子化した画像で色抽出
rgb_array = np.array(quantized_image)
pixels = rgb_array.reshape(-1, 3)
pixel_tuples = [tuple(map(int, pixel)) for pixel in pixels]
color_counter = Counter(pixel_tuples)
print(f"📊 量子化後の色の種類: {len(color_counter):,}")
most_common = color_counter.most_common(10)
dominant_color = most_common[0][0]
print(f"✨ 最頻値色: RGB{dominant_color}")
# 詳細情報
total_pixels = len(pixels)
print(f"🔍 Top 5色:")
for i, (color, count) in enumerate(most_common[:5]):
percentage = (count / total_pixels) * 100
print(f" 第{i+1}位: RGB{color} - {count:,}回 ({percentage:.1f}%)")
return dominant_color, most_common[:5], quantized_image
# 量子化版で実行
dominant_q, top_colors_q, quantized_img = get_dominant_color_quantized(sample_pil, quantize_levels=16)
# 結果比較表示
plt.figure(figsize=(16, 8))
# 元画像
plt.subplot(2, 3, 1)
plt.imshow(sample_pil)
plt.title("元画像(ノイズあり)", fontsize=12)
plt.axis('off')
# 量子化画像
plt.subplot(2, 3, 2)
plt.imshow(quantized_img)
plt.title("量子化画像", fontsize=12)
plt.axis('off')
# 量子化版の最頻値色
plt.subplot(2, 3, 3)
color_square_q = np.full((100, 100, 3), dominant_q, dtype=np.uint8)
plt.imshow(color_square_q)
plt.title(f"量子化版最頻値色\nRGB{dominant_q}", fontsize=12)
plt.axis('off')
# クリーン画像(比較用)
sample_pil_clean = create_clean_sample_image()
dominant_clean, top_colors_clean = get_dominant_color_simple(sample_pil_clean)
plt.subplot(2, 3, 4)
plt.imshow(sample_pil_clean)
plt.title("クリーン画像(ノイズなし)", fontsize=12)
plt.axis('off')
# クリーン版バーグラフ
plt.subplot(2, 3, 5)
colors_clean = [color[0] for color in top_colors_clean[:5]]
counts_clean = [color[1] for color in top_colors_clean[:5]]
colors_clean_norm = [[c/255.0 for c in color] for color in colors_clean]
bars_clean = plt.bar(range(len(colors_clean)), counts_clean, color=colors_clean_norm)
plt.title("クリーン画像 Top5", fontsize=12)
plt.xlabel("順位")
plt.ylabel("出現回数")
# 量子化版バーグラフ
plt.subplot(2, 3, 6)
colors_q = [color[0] for color in top_colors_q]
counts_q = [color[1] for color in top_colors_q]
colors_q_norm = [[c/255.0 for c in color] for color in colors_q]
bars_q = plt.bar(range(len(colors_q)), counts_q, color=colors_q_norm)
plt.title("量子化版 Top5", fontsize=12)
plt.xlabel("順位")
plt.ylabel("出現回数")
plt.tight_layout()
plt.show()
print("\n🎉 両方の手法で正常な結果が得られました!")
print("💡 実際の写真では量子化手法がより有効です。")
ノイズあり・ノイズなしで順位が変わっていることが見て取れます。
一見、、水色や緑色などが多いように見えますが、ピクセル単位で見ると実は黄色が一番多いということなんです。
📊 Step3:色の分布を詳しく調べよう
画像にはどんな色がどのくらい含まれているのか、もう少し詳しく調べてみましょう。
def analyze_color_distribution(image, top_n=10):
"""
画像の色分布を詳しく分析する関数
"""
rgb_array = np.array(image)
pixels = rgb_array.reshape(-1, 3)
# 各色要素の統計を計算
r_values = pixels[:, 0]
g_values = pixels[:, 1]
b_values = pixels[:, 2]
print("🔴 赤色成分の統計:")
print(f" 平均: {np.mean(r_values):.1f}")
print(f" 標準偏差: {np.std(r_values):.1f}")
print(f" 範囲: {np.min(r_values)} - {np.max(r_values)}")
print("\n🟢 緑色成分の統計:")
print(f" 平均: {np.mean(g_values):.1f}")
print(f" 標準偏差: {np.std(g_values):.1f}")
print(f" 範囲: {np.min(g_values)} - {np.max(g_values)}")
print("\n🔵 青色成分の統計:")
print(f" 平均: {np.mean(b_values):.1f}")
print(f" 標準偏差: {np.std(b_values):.1f}")
print(f" 範囲: {np.min(b_values)} - {np.max(b_values)}")
# 色分布のヒストグラム
plt.figure(figsize=(15, 4))
plt.subplot(1, 3, 1)
plt.hist(r_values, bins=50, alpha=0.7, color='red')
plt.title('赤色成分の分布')
plt.xlabel('RGB値')
plt.ylabel('頻度')
plt.subplot(1, 3, 2)
plt.hist(g_values, bins=50, alpha=0.7, color='green')
plt.title('緑色成分の分布')
plt.xlabel('RGB値')
plt.ylabel('頻度')
plt.subplot(1, 3, 3)
plt.hist(b_values, bins=50, alpha=0.7, color='blue')
plt.title('青色成分の分布')
plt.xlabel('RGB値')
plt.ylabel('頻度')
plt.tight_layout()
plt.show()
# 分析実行
analyze_color_distribution(sample_pil)

🟢 緑色成分の統計: 平均: 160.0 標準偏差: 53.7 範囲: 59 - 224
🔵 青色成分の統計: 平均: 106.4 標準偏差: 99.9 範囲: 0 - 244
🎯 平均値(Average)から分かること
赤: 145.3 緑: 160.0 青: 106.4緑 > 赤 > 青の順 → 画像全体が緑がかった色調
0-255の中央は127.5なので、緑と赤がやや明るく、青が暗め
結論: 自然系(草原、森林)や暖かい色調の画像
📈 標準偏差(Standard Deviation)から分かること
青: 99.9 赤: 81.4 緑: 53.7青のばらつきが最大 → 濃い青から薄い青まで幅広く存在
緑のばらつきが最小 → 緑色が比較的均一
結論: 空(青の濃淡)と植物(安定した緑)が含まれる風景的画像
📏 範囲(Range)から分かること
赤: 24-255 (範囲231) 青: 0-244 (範囲244) 緑: 59-224 (範囲165)青と赤が全範囲近く → コントラストが強い
緑は中程度の範囲 → 極端に濃い/薄い緑は少ない
🌈 Step4:簡単なカラーパレット生成
ここまでで学んだ技術を使って、簡単なカラーパレットを作ってみましょう。
# カラーパレット表示
def display_correct_palette(colors_list, image_title="修正版"):
"""
カラーパレットを表示
"""
# パレット画像作成
palette_height = 100
palette_width = 500
n_colors = len(colors_list)
color_width = palette_width // n_colors
palette_img = np.zeros((palette_height, palette_width, 3), dtype=np.uint8)
print(f"🎨 {image_title}のカラーパレット作成:")
for i, (color, count) in enumerate(colors_list):
start_x = i * color_width
end_x = (i + 1) * color_width
if i == n_colors - 1:
end_x = palette_width
# 色を配置
palette_img[:, start_x:end_x, 0] = color[0] # R
palette_img[:, start_x:end_x, 1] = color[1] # G
palette_img[:, start_x:end_x, 2] = color[2] # B
print(f" 位置 {start_x:3d}-{end_x:3d}: RGB{color}")
# 表示
plt.figure(figsize=(12, 8))
plt.subplot(2, 1, 1)
plt.imshow(sample_new)
plt.title("元画像", fontsize=14)
plt.axis('off')
plt.subplot(2, 1, 2)
plt.imshow(palette_img)
plt.title(f"{image_title} - 5色カラーパレット", fontsize=14)
plt.axis('off')
# 境界線を追加
for i in range(1, n_colors):
plt.axvline(x=i * color_width, color='white', linewidth=3)
# 各色の名前を表示
for i, (color, count) in enumerate(colors_list):
x_pos = (i + 0.5) * color_width
plt.text(x_pos, palette_height//2, f'RGB\n{color}',
ha='center', va='center', fontweight='bold', fontsize=10,
bbox=dict(boxstyle="round,pad=0.3", facecolor='white', alpha=0.8))
plt.tight_layout()
plt.show()
return palette_img
# パレット表示
palette_correct = display_correct_palette(top_5_colors, "強力量子化版")
✨ ここまでのまとめ
お疲れ様でした!ここまでで以下のことができるようになりました:
✅ 画像の読み込みと基本情報取得
✅ RGB値の理解と色の可視化
✅ 最頻値色の抽出
✅ 色分布の統計的分析
✅ シンプルなカラーパレット生成
これだけでも、写真から主要な色を抽出する基本的な画像解析ツールが完成しました!
現在のアプリには以下の課題があります
❌ 単純な頻度カウントなので、似たような色が複数選ばれる
❌ ノイズや微細な色差に影響されやすい
❌ HEXコード出力がない(Web制作で使いづらい)
❌ 占有率の可視化ができない
❌ 実用的なファイル出力機能がない
これらを解決するには、機械学習の「K-meansクラスタリング」という手法を使います。
K-meansクラスタリングは、教師なし学習の代表的なクラスタリング手法です。データをあらかじめ指定した数 k 個のグループ(クラスタ)に分けるアルゴリズムです。
基本的な考え方
データの「近さ(距離)」に基づいて、似ているデータ同士を1つのクラスタにまとめます。
各クラスタの「中心(セントロイド)」を計算し、それを基準にデータを分類していきます。
アルゴリズムの流れ
クラスタ数 k を決める
例:3つのグループに分けたいなら k = 3。初期のクラスタ中心をランダムに選ぶ
データ空間からランダムに kk 個の点を選び、仮の中心とする。データをクラスタに割り当てる
各データ点を「一番近い中心」に属するクラスタへ分類する。中心を更新する
各クラスタに属する点の平均値を取り、それを新しい中心にする。収束判定
データの割り当てが変わらなくなるか、中心がほとんど動かなくなったら終了。
イメージ例
例えば「身長」と「体重」のデータをクラスタリングした場合:
k=2 に設定すると、「小柄で軽いグループ」と「大柄で重いグループ」に分けられる。
k = 3 にすると「小柄」「中くらい」「大柄」の3つに分かれることもある。
メリット
シンプルで実装しやすい。
計算が比較的速い。
デメリット
あらかじめ kk を決めなければならない。
クラスタの形が「球状(丸い形)」に近い場合にうまくいくが、複雑な形には弱い。
初期値の設定によって結果が変わることがある。
👉 まとめると、K-meansクラスタリングは
「データを似ているグループに分けるシンプルな方法」であり、マーケティングの顧客分類、画像圧縮、異常検知など幅広く使われています。
有料部分では、以下の内容をお届けします。
🧠 高度な技術を学べます
K-meansクラスタリングで高精度な色抽出
scikit-learnを使った機械学習入門
色空間変換(RGB ↔ HSV)の理解
🎨 実用的な機能が完成します
HEXコード自動生成(#FF5733形式)
占有率円グラフで視覚的分析
PNG形式でパレット保存
複数画像の一括処理
📚 応用・発展内容も充実
色の類似度判定機能
季節感推定アルゴリズム
動画ファイル対応
リアルタイム処理への拡張
画像解析はAI・データサイエンス分野への第一歩でもあります。この技術をマスターすれば、Instagram分析、商品画像の自動分類、Webデザイン支援ツールなど、様々な応用が可能になります。
ぜひチャレンジしてみてください! 🎉
【有料部分】プロ級カラーパレット生成アプリの完成版
🎯 機械学習で高精度な色抽出を実現しよう
無料部分では単純な頻度カウントで色抽出を行いましたが、これだけでは実用的ではありません。プロ級のツールにするため、K-meansクラスタリングという機械学習手法を導入します。
K-meansクラスタリングとは?
K-meansは「似た特徴を持つデータを自動的にグループ分けする」アルゴリズムです。色抽出では、似た色をまとめて代表色を決めることで、美しく実用的なカラーパレットを生成できます。
# 機械学習ライブラリの追加インストール
!pip install scikit-learn
from sklearn.cluster import KMeans
from sklearn.utils import shuffle
import webcolors
🧠 Step5:K-meansで高精度色抽出
def extract_colors_kmeans(image, n_colors=5, max_pixels=10000):
"""
K-meansクラスタリングを使った高精度な色抽出
Args:
image: PIL画像オブジェクト
n_colors: 抽出する色数
max_pixels: 処理速度向上のため、使用する最大ピクセル数
Returns:
colors: 抽出された色のリスト
percentages: 各色の占有率
"""
print(f"🧠 K-meansクラスタリングで{n_colors}色を抽出中...")
# 画像をNumPy配列に変換
rgb_array = np.array(image)
pixels = rgb_array.reshape(-1, 3)
# 大きな画像の場合、処理速度向上のためピクセルをサンプリング
if len(pixels) > max_pixels:
pixels = shuffle(pixels, random_state=42, n_samples=max_pixels)
print(f"⚡ 高速化のため{len(pixels):,}ピクセルをサンプリング")
# K-meansクラスタリング実行
kmeans = KMeans(n_clusters=n_colors, random_state=42, n_init=10)
kmeans.fit(pixels)
# クラスター中心(代表色)を取得
colors = kmeans.cluster_centers_.astype(int)
# 各ピクセルがどのクラスターに属するか予測
labels = kmeans.labels_
# 各色の占有率を計算
label_counts = np.bincount(labels)
percentages = (label_counts / len(labels)) * 100
print(f"✅ 抽出完了!各色の占有率:")
for i, (color, pct) in enumerate(zip(colors, percentages)):
print(f" 色{i+1}: RGB{tuple(color)} - {pct:.1f}%")
return colors, percentages
# サンプル画像で実行
extracted_colors, percentages = extract_colors_kmeans(sample_pil, n_colors=5)

⚡ 高速化のため10,000ピクセルをサンプリング
✅ 抽出完了!各色の占有率:
色1: RGB(np.int64(138), np.int64(68), np.int64(18)) - 20.0%
色2: RGB(np.int64(134), np.int64(205), np.int64(234)) - 24.9%
色3: RGB(np.int64(33), np.int64(138), np.int64(33)) - 25.3%
色4: RGB(np.int64(252), np.int64(214), np.int64(2)) - 12.4%
色5: RGB(np.int64(252), np.int64(191), np.int64(202)) - 17.4%
🎨 Step6:美しいカラーパレット表示とHEXコード生成
def rgb_to_hex(rgb_tuple):
"""
RGB値をHEXコード(#FF5733形式)に変換
"""
return "#{:02x}{:02x}{:02x}".format(int(rgb_tuple[0]), int(rgb_tuple[1]), int(rgb_tuple[2]))
def get_color_name(rgb_tuple):
"""
RGB値から近似色名を取得(可能な場合)
"""
try:
# webcolorsライブラリを使って色名を取得
color_name = webcolors.rgb_to_name(rgb_tuple)
return color_name
except ValueError:
# 完全一致しない場合は最近傍色を探す
min_colors = {}
for key, name in webcolors.CSS3_HEX_TO_NAMES.items():
r_c, g_c, b_c = webcolors.hex_to_rgb(key)
rd = (r_c - rgb_tuple[0]) ** 2
gd = (g_c - rgb_tuple[1]) ** 2
bd = (b_c - rgb_tuple[2]) ** 2
min_colors[(rd + gd + bd)] = name
return min_colors[min(min_colors.keys())]
def create_professional_palette(colors, percentages, palette_width=800, palette_height=150):
"""
プロフェッショナルなカラーパレット画像を生成
"""
n_colors = len(colors)
# パレット画像作成
palette_img = np.zeros((palette_height, palette_width, 3), dtype=np.uint8)
# 占有率に応じて幅を調整
current_x = 0
color_info = []
for i, (color, pct) in enumerate(zip(colors, percentages)):
# 占有率に応じた幅を計算
width = int((pct / 100) * palette_width)
if i == n_colors - 1: # 最後の色は残り全体を埋める
width = palette_width - current_x
# 色を配置
palette_img[:, current_x:current_x + width] = color
# 色情報を記録
hex_code = rgb_to_hex(color)
try:
color_name = get_color_name(tuple(color))
except:
color_name = "Unknown"
color_info.append({
'rgb': tuple(color),
'hex': hex_code,
'name': color_name,
'percentage': pct,
'position': current_x + width // 2
})
current_x += width
return palette_img, color_info
# プロフェッショナルパレット生成
palette_img, color_info = create_professional_palette(extracted_colors, percentages)
# 表示
plt.figure(figsize=(16, 10))
# 元画像
plt.subplot(3, 1, 1)
plt.imshow(sample_pil)
plt.title("元画像", fontsize=16)
plt.axis('off')
# カラーパレット(占有率反映)
plt.subplot(3, 1, 2)
plt.imshow(palette_img)
plt.title("カラーパレット(占有率反映)", fontsize=16)
plt.axis('off')
# HEXコードとパーセンテージを表示
for info in color_info:
plt.text(info['position'], palette_img.shape[0] // 2,
f"{info['hex']}\n{info['percentage']:.1f}%",
ha='center', va='center',
fontsize=10, fontweight='bold',
bbox=dict(boxstyle="round,pad=0.3", facecolor='white', alpha=0.8))
# 均等幅パレット(デザイン用)
plt.subplot(3, 1, 3)
equal_palette = np.zeros((100, 800, 3), dtype=np.uint8)
color_width = 800 // len(extracted_colors)
for i, color in enumerate(extracted_colors):
start_x = i * color_width
end_x = start_x + color_width
equal_palette[:, start_x:end_x] = color
plt.imshow(equal_palette)
plt.title("均等幅カラーパレット(デザイン用)", fontsize=16)
plt.axis('off')
# HEXコードを表示
for i, info in enumerate(color_info):
x_pos = (i + 0.5) * color_width
plt.text(x_pos, 50, info['hex'],
ha='center', va='center',
fontsize=12, fontweight='bold',
bbox=dict(boxstyle="round,pad=0.3", facecolor='white', alpha=0.9))
plt.tight_layout()
plt.show()
# 色情報を表形式で表示
print("🎨 抽出された色の詳細情報:")
print("-" * 80)
print(f"{'順位':<4} {'RGB値':<15} {'HEXコード':<10} {'色名':<15} {'占有率':<8}")
print("-" * 80)
for i, info in enumerate(color_info):
print(f"{i+1:<4} {str(info['rgb']):<15} {info['hex']:<10} {info['name']:<15} {info['percentage']:.1f}%")

🎨 抽出された色の詳細情報:
--------------------------------------------------------------------------------
順位 RGB値 HEXコード 色名 占有率
--------------------------------------------------------------------------------
1 (np.int64(138), np.int64(68), np.int64(18)) #8a4412 Unknown 20.0%
2 (np.int64(134), np.int64(205), np.int64(234)) #86cdea Unknown 24.9%
3 (np.int64(33), np.int64(138), np.int64(33)) #218a21 Unknown 25.3%
4 (np.int64(252), np.int64(214), np.int64(2)) #fcd602 Unknown 12.4%
5 (np.int64(252), np.int64(191), np.int64(202)) #fcbfca Unknown 17.4%
📊 Step7:占有率を円グラフで可視化
def create_color_pie_chart(colors, percentages, color_info):
"""
色の占有率を美しい円グラフで表示
"""
# 色を正規化(0-1の範囲に変換)
colors_normalized = [tuple(c/255 for c in color) for color in colors]
plt.figure(figsize=(12, 8))
# 円グラフ作成
plt.subplot(1, 2, 1)
wedges, texts, autotexts = plt.pie(
percentages,
colors=colors_normalized,
labels=[f"色{i+1}" for i in range(len(colors))],
autopct='%1.1f%%',
startangle=90,
textprops={'fontsize': 12}
)
# 円グラフを美しく装飾
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontweight('bold')
autotext.set_fontsize(10)
plt.title("色の占有率分析", fontsize=16, fontweight='bold')
# 凡例作成
plt.subplot(1, 2, 2)
plt.axis('off')
legend_y = 0.9
plt.text(0.1, 0.95, "📊 カラー分析レポート", fontsize=16, fontweight='bold')
for i, info in enumerate(color_info):
# 色見本
color_rect = plt.Rectangle((0.1, legend_y - 0.05), 0.08, 0.08,
facecolor=tuple(c/255 for c in info['rgb']))
plt.gca().add_patch(color_rect)
# 色情報テキスト
plt.text(0.25, legend_y, f"色{i+1}: {info['hex']}", fontsize=12, fontweight='bold')
plt.text(0.25, legend_y - 0.03, f"RGB{info['rgb']}", fontsize=10)
plt.text(0.25, legend_y - 0.06, f"{info['name']} ({info['percentage']:.1f}%)", fontsize=10)
legend_y -= 0.15
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.tight_layout()
plt.show()
# 円グラフ作成
create_color_pie_chart(extracted_colors, percentages, color_info)

🏗️ Step8:完成版クラス設計
実用的なアプリにするため、すべての機能をクラスにまとめましょう。
class ColorPaletteExtractor:
"""
プロフェッショナルなカラーパレット抽出クラス
"""
def __init__(self, n_colors=5, max_pixels=10000):
self.n_colors = n_colors
self.max_pixels = max_pixels
self.colors = None
self.percentages = None
self.color_info = None
def extract_palette(self, image):
"""
画像からカラーパレットを抽出
"""
print(f"🎨 カラーパレット抽出開始...")
# K-meansクラスタリング
rgb_array = np.array(image)
pixels = rgb_array.reshape(-1, 3)
if len(pixels) > self.max_pixels:
pixels = shuffle(pixels, random_state=42, n_samples=self.max_pixels)
kmeans = KMeans(n_clusters=self.n_colors, random_state=42, n_init=10)
kmeans.fit(pixels)
self.colors = kmeans.cluster_centers_.astype(int)
labels = kmeans.labels_
label_counts = np.bincount(labels)
self.percentages = (label_counts / len(labels)) * 100
# 占有率順にソート
sorted_indices = np.argsort(self.percentages)[::-1]
self.colors = self.colors[sorted_indices]
self.percentages = self.percentages[sorted_indices]
# 色情報を生成
self._generate_color_info()
print(f"✅ {self.n_colors}色のパレット抽出完了!")
return self
def _generate_color_info(self):
"""
色情報(HEXコード、色名など)を生成
"""
self.color_info = []
for color, pct in zip(self.colors, self.percentages):
rgb_tuple = tuple(color)
hex_code = "#{:02x}{:02x}{:02x}".format(int(color[0]), int(color[1]), int(color[2]))
try:
color_name = webcolors.rgb_to_name(rgb_tuple)
except ValueError:
color_name = self._get_closest_color_name(rgb_tuple)
self.color_info.append({
'rgb': rgb_tuple,
'hex': hex_code,
'name': color_name,
'percentage': pct
})
def _get_closest_color_name(self, rgb_tuple):
"""
最も近い色名を取得
"""
min_colors = {}
for key, name in webcolors.CSS3_HEX_TO_NAMES.items():
r_c, g_c, b_c = webcolors.hex_to_rgb(key)
rd = (r_c - rgb_tuple[0]) ** 2
gd = (g_c - rgb_tuple[1]) ** 2
bd = (b_c - rgb_tuple[2]) ** 2
min_colors[(rd + gd + bd)] = name
return min_colors[min(min_colors.keys())]
def visualize_palette(self, show_pie_chart=True):
"""
カラーパレットを可視化
"""
if self.colors is None:
print("❌ まずextract_palette()を実行してください")
return
fig_height = 12 if show_pie_chart else 8
plt.figure(figsize=(16, fig_height))
subplot_count = 3 if show_pie_chart else 2
# 占有率反映パレット
plt.subplot(subplot_count, 1, 1)
palette_img = self._create_proportional_palette()
plt.imshow(palette_img)
plt.title("カラーパレット(占有率反映)", fontsize=16)
plt.axis('off')
# 均等幅パレット
plt.subplot(subplot_count, 1, 2)
equal_palette = self._create_equal_palette()
plt.imshow(equal_palette)
plt.title("均等幅カラーパレット(デザイン用)", fontsize=16)
plt.axis('off')
# HEXコード表示
color_width = 800 // len(self.colors)
for i, info in enumerate(self.color_info):
x_pos = (i + 0.5) * color_width
plt.text(x_pos, 50, info['hex'],
ha='center', va='center',
fontsize=12, fontweight='bold',
bbox=dict(boxstyle="round,pad=0.3", facecolor='white', alpha=0.9))
# 円グラフ
if show_pie_chart:
plt.subplot(subplot_count, 1, 3)
colors_normalized = [tuple(c/255 for c in color) for color in self.colors]
plt.pie(self.percentages, colors=colors_normalized,
labels=[f"色{i+1}" for i in range(len(self.colors))],
autopct='%1.1f%%', startangle=90)
plt.title("色の占有率", fontsize=16)
plt.tight_layout()
plt.show()
def _create_proportional_palette(self, width=800, height=100):
"""
占有率に応じたパレット画像を作成
"""
palette_img = np.zeros((height, width, 3), dtype=np.uint8)
current_x = 0
for i, (color, pct) in enumerate(zip(self.colors, self.percentages)):
color_width = int((pct / 100) * width)
if i == len(self.colors) - 1:
color_width = width - current_x
palette_img[:, current_x:current_x + color_width] = color
current_x += color_width
return palette_img
def _create_equal_palette(self, width=800, height=100):
"""
均等幅のパレット画像を作成
"""
palette_img = np.zeros((height, width, 3), dtype=np.uint8)
color_width = width // len(self.colors)
for i, color in enumerate(self.colors):
start_x = i * color_width
end_x = start_x + color_width
palette_img[:, start_x:end_x] = color
return palette_img
def save_palette(self, filename="color_palette.png"):
"""
カラーパレットをPNG形式で保存
"""
if self.colors is None:
print("❌ まずextract_palette()を実行してください")
return
equal_palette = self._create_equal_palette(width=1000, height=200)
palette_pil = Image.fromarray(equal_palette)
palette_pil.save(filename)
print(f"💾 カラーパレットを{filename}として保存しました")
return filename
def get_color_codes(self):
"""
HEXコードのリストを取得
"""
if self.color_info is None:
return None
return [info['hex'] for info in self.color_info]
def get_css_variables(self):
"""
CSS変数形式で出力
"""
if self.color_info is None:
return None
css_vars = [
f"--color-{i+1}: {info['hex']};"
for i, info in enumerate(self.color_info)
]
return "\n".join(css_vars)
def print_report(self):
"""
詳細レポートを出力
"""
if self.color_info is None:
print("❌ まずextract_palette()を実行してください")
return
print("🎨 " + "="*60)
print(" カラーパレット分析レポート")
print("="*64)
print(f"抽出色数: {len(self.colors)}色")
print(f"解析手法: K-meansクラスタリング")
print("-" * 64)
print(f"{'順位':<4} {'RGB値':<15} {'HEXコード':<10} {'色名':<15} {'占有率':<8}")
print("-" * 64)
for i, info in enumerate(self.color_info):
print(f"{i+1:<4} {str(info['rgb']):<15} {info['hex']:<10} {info['name']:<15} {info['percentage']:.1f}%")
print("-" * 64)
print("💡 使用例:")
print(" • Webデザイン: CSS変数として活用")
print(" • グラフィック: Adobe製品のスウォッチにインポート")
print(" • 印刷物: CMYK変換してDTPに活用")
print("="*64)
# 使用例
extractor = ColorPaletteExtractor(n_colors=5)
extractor.extract_palette(sample_pil)
extractor.visualize_palette()
extractor.print_report()

🎨 =======================================================カラーパレット分析レポート =========================================================抽出色数: 5色 解析手法: K-meansクラスタリング
----------------------------------------------------------------
順位 RGB値 HEXコード 色名 占有率
----------------------------------------------------------------
1 (134, 206, 235) #86ceeb skyblue 25.4%
2 (33, 139, 33) #218b21 forestgreen 24.4%
3 (139, 69, 19) #8b4513 saddlebrown 17.3%
4 (254, 215, 0) #fed700 gold 16.8%
5 (254, 192, 202) #fec0ca pink 16.1%
----------------------------------------------------------------
💡 使用例:
• Webデザイン: CSS変数として活用
• グラフィック: Adobe製品のスウォッチにインポート
• 印刷物: CMYK変換してDTPに活用 =========================================================
💾 Step9:ファイル出力とバッチ処理
def process_multiple_images():
"""
複数画像の一括処理(修正版)
"""
# サンプル画像を複数作成(型を明示的に指定)
sample_images = []
print("🖼️ サンプル画像を生成中...")
# 異なるタイプの画像を生成
for i in range(3):
print(f" 画像{i+1}を作成中...")
if i == 0: # 暖色系画像
print(" -> 暖色系(夕焼け風)")
img = np.random.randint(150, 255, (150, 150, 3), dtype=np.uint8)
img[:, :, 2] = np.random.randint(50, 120, (150, 150), dtype=np.uint8) # 青を抑制
elif i == 1: # 寒色系画像
print(" -> 寒色系(海・空風)")
img = np.random.randint(50, 200, (150, 150, 3), dtype=np.uint8)
img[:, :, 0] = np.random.randint(30, 100, (150, 150), dtype=np.uint8) # 赤を抑制
img[:, :, 2] = np.random.randint(150, 255, (150, 150), dtype=np.uint8) # 青を強調
else: # モノクロ系画像
print(" -> モノクロ系(都市風)")
gray_values = np.random.randint(80, 180, (150, 150), dtype=np.uint8)
img = np.stack([gray_values, gray_values, gray_values], axis=2)
# 配列の型とshapeを確認
print(f" 配列shape: {img.shape}, dtype: {img.dtype}")
# PIL画像に変換(型チェック付き)
try:
pil_img = Image.fromarray(img)
sample_images.append(pil_img)
print(f" ✅ PIL変換成功")
except Exception as e:
print(f" ❌ PIL変換エラー: {e}")
# エラー時は安全な画像を作成
safe_img = np.full((150, 150, 3), [128, 128, 128], dtype=np.uint8)
sample_images.append(Image.fromarray(safe_img))
print(f"✅ {len(sample_images)}枚のサンプル画像生成完了")
# 一括処理実行
results = []
for i, img in enumerate(sample_images):
print(f"\n📸 画像 {i+1} を処理中...")
try:
extractor = ColorPaletteExtractor(n_colors=5)
extractor.extract_palette(img)
results.append(extractor)
# ファイル保存(エラーハンドリング付き)
filename = f"palette_{i+1}.png"
try:
extractor.save_palette(filename)
print(f" 💾 {filename} 保存成功")
except Exception as e:
print(f" ❌ ファイル保存エラー: {e}")
except Exception as e:
print(f" ❌ 色抽出エラー: {e}")
results.append(None)
# 結果をまとめて表示(成功したもののみ)
valid_results = [(img, res) for img, res in zip(sample_images, results) if res is not None]
if len(valid_results) > 0:
print(f"\n🎨 {len(valid_results)}枚の結果を表示中...")
plt.figure(figsize=(18, 6 * len(valid_results)))
for i, (img, extractor) in enumerate(valid_results):
row_base = i * 3
# 元画像
plt.subplot(len(valid_results), 3, row_base + 1)
plt.imshow(img)
plt.title(f"画像{i+1}", fontsize=12)
plt.axis('off')
# パレット
plt.subplot(len(valid_results), 3, row_base + 2)
try:
palette = extractor._create_equal_palette(width=400, height=100)
plt.imshow(palette)
plt.title(f"パレット{i+1}", fontsize=12)
plt.axis('off')
except Exception as e:
plt.text(0.5, 0.5, f"パレット表示エラー:\n{str(e)}",
ha='center', va='center', transform=plt.gca().transAxes)
plt.title(f"パレット{i+1} (エラー)", fontsize=12)
# 円グラフ
plt.subplot(len(valid_results), 3, row_base + 3)
try:
colors_norm = [tuple(c/255 for c in color) for color in extractor.colors]
plt.pie(extractor.percentages, colors=colors_norm,
startangle=90, textprops={'fontsize': 8})
plt.title(f"占有率{i+1}", fontsize=12)
except Exception as e:
plt.text(0.5, 0.5, f"円グラフエラー:\n{str(e)}",
ha='center', va='center', transform=plt.gca().transAxes)
plt.title(f"占有率{i+1} (エラー)", fontsize=12)
plt.tight_layout()
plt.show()
return results
# ColorPaletteExtractorにsave_paletteメソッドを追加
def save_palette_method(self, filename="color_palette.png"):
"""
カラーパレットをPNG形式で保存(修正版)
"""
if self.colors is None:
print("❌ まずextract_palette()を実行してください")
return None
try:
# パレット画像作成(型を明示的に指定)
equal_palette = self._create_equal_palette(width=1000, height=200)
# 型とshapeを確認
print(f"🔍 保存前チェック - shape: {equal_palette.shape}, dtype: {equal_palette.dtype}")
# uint8型であることを確認
if equal_palette.dtype != np.uint8:
equal_palette = equal_palette.astype(np.uint8)
print("🔧 uint8型に変換しました")
# PIL画像に変換
palette_pil = Image.fromarray(equal_palette)
# 保存
palette_pil.save(filename)
print(f"💾 カラーパレットを{filename}として保存しました")
return filename
except Exception as e:
print(f"❌ 保存中にエラーが発生: {e}")
return None
# メソッドを追加
ColorPaletteExtractor.save_palette = save_palette_method
# バッチ処理実行
print("🚀 バッチ処理を開始...")
batch_results = process_multiple_images()
# CSS出力例(成功したもののみ)
print("\n🎨 CSS変数出力例:")
for i, result in enumerate(batch_results):
if result is not None:
print(f"\n/* 画像{i+1}のカラーパレット */")
css_output = result.get_css_variables()
if css_output:
print(css_output)
else:
print("/* CSS変数生成エラー */")



🎨 CSS変数出力例:
画像1のカラーパレット
--color-1: #e3e554 ;
--color-2: #e7af54 ;
--color-3: #aee654 ;
--color-4: #b2b341 ;
--color-5: #b2b167 ;
画像2のカラーパレット
--color-1: #4057ad ;
--color-2: #40a3ad ;
--color-3: #3f7cdf ;
--color-4: #4049e2 ;
--color-5: #40afe2 ;
画像3のカラーパレット
--color-1: #828282 ;
--color-2: #969696 ;
--color-3: #595959 ;
--color-4: #aaaaaa ;
--color-5: #6d6d6d ;
🔍 Step10:色の類似度判定と高度な分析
def calculate_color_similarity(color1, color2):
"""
2つの色の類似度を計算(ユークリッド距離使用)
"""
r1, g1, b1 = color1
r2, g2, b2 = color2
return np.sqrt((r1-r2)**2 + (g1-g2)**2 + (b1-b2)**2)
def analyze_color_harmony(colors):
"""
色の調和性を分析
"""
harmonies = {
'complementary': [],
'analogous': [],
'triadic': [],
'split_complementary': []
}
# RGB to HSV変換で色相を分析
hsv_colors = []
for color in colors:
r, g, b = [x/255.0 for x in color]
h, s, v = colorsys.rgb_to_hsv(r, g, b)
hsv_colors.append((h*360, s, v)) # 色相を度数に変換
print("🎨 色彩調和分析:")
print("-" * 40)
for i, (rgb, hsv) in enumerate(zip(colors, hsv_colors)):
h, s, v = hsv
print(f"色{i+1}: H={h:.0f}° S={s:.2f} V={v:.2f}")
# 色相に基づく分類
if h < 30 or h >= 330:
color_family = "赤系"
elif h < 90:
color_family = "黄系"
elif h < 150:
color_family = "緑系"
elif h < 210:
color_family = "青系"
elif h < 270:
color_family = "紫系"
else:
color_family = "マゼンタ系"
print(f" 色系統: {color_family}")
# 色相の分布分析
hues = [hsv[0] for hsv in hsv_colors]
hue_range = max(hues) - min(hues)
print(f"\n📊 色相分析:")
print(f"色相の範囲: {hue_range:.1f}°")
if hue_range < 30:
harmony_type = "類似色調和(Analogous)"
elif hue_range < 60:
harmony_type = "近似類似色調和"
elif 150 < hue_range < 210:
harmony_type = "補色調和(Complementary)"
else:
harmony_type = "多色調和(Polychromatic)"
print(f"調和タイプ: {harmony_type}")
return harmony_type
def suggest_color_applications(extractor):
"""
色の特徴に基づいて用途を提案
"""
if extractor.color_info is None:
return
# 色の明度・彩度を分析
total_brightness = 0
total_saturation = 0
for info in extractor.color_info:
r, g, b = info['rgb']
brightness = (r + g + b) / 3
saturation = (max(r, g, b) - min(r, g, b)) / 255
total_brightness += brightness * (info['percentage'] / 100)
total_saturation += saturation * (info['percentage'] / 100)
print("\n💡 カラーパレット活用提案:")
print("=" * 50)
# 明度による提案
if total_brightness > 200:
print("🌟 明るい色調 → 春・夏向けデザイン、ポップなWebサイト")
elif total_brightness > 150:
print("☀️ 中明度 → オールシーズン対応、企業サイト")
else:
print("🌙 暗い色調 → 秋・冬向けデザイン、高級感のある表現")
# 彩度による提案
if total_saturation > 0.7:
print("🎨 高彩度 → エネルギッシュな表現、子供向けコンテンツ")
elif total_saturation > 0.4:
print("🎭 中彩度 → バランスの良い表現、一般的な用途")
else:
print("🏛️ 低彩度 → 落ち着いた表現、プロフェッショナル用途")
# 色数による提案
if len(extractor.colors) <= 3:
print("🎯 ミニマル → ロゴデザイン、シンプルなUI")
else:
print("🌈 リッチ → 複雑なデザイン、アート作品")
print("=" * 50)
import colorsys
# 高度な分析実行例
print("🔬 高度な色彩分析を実行中...")
extractor = ColorPaletteExtractor(n_colors=5)
extractor.extract_palette(sample_pil)
harmony_type = analyze_color_harmony(extractor.colors)
suggest_color_applications(extractor)

🔬 高度な色彩分析を実行中...
🎨 カラーパレット抽出開始...
✅ 5色のパレット抽出完了!
🎨 色彩調和分析:
----------------------------------------
色1: H=120° S=0.76 V=0.54 色系統: 緑系
色2: H=197° S=0.43 V=0.92 色系統: 青系
色3: H=25° S=0.87 V=0.54 色系統: 赤系
色4: H=349° S=0.24 V=0.99 色系統: 赤系
色5: H=51° S=0.99 V=0.99 色系統: 黄系
📊 色相分析:
色相の範囲: 324.2°
調和タイプ: 多色調和(Polychromatic)
💡 カラーパレット活用提案: ==================================================
🌙 暗い色調 → 秋・冬向けデザイン、高級感のある表現
🎭 中彩度 → バランスの良い表現、一般的な用途
🌈 リッチ → 複雑なデザイン、アート作品 ==================================================
🌍 Step11:実際の写真での応用例
# 実際の画像での応用を想定したサンプル
def create_realistic_sample_images():
"""
より現実的なサンプル画像を生成
"""
samples = {}
# 1. 自然風景風(空と草原)
landscape = np.zeros((200, 300, 3), dtype=np.uint8)
# 空部分(上半分)
landscape[:100, :, :] = [135, 206, 235] # スカイブルー
# 雲
for i in range(20):
x = np.random.randint(0, 280)
y = np.random.randint(10, 90)
cv2.circle(landscape, (x, y), np.random.randint(15, 25), (255, 255, 255), -1)
# 草原部分(下半分)
landscape[100:, :, :] = [34, 139, 34] # 森林緑
# 花を追加
for i in range(30):
x = np.random.randint(10, 290)
y = np.random.randint(120, 190)
cv2.circle(landscape, (x, y), 3, (255, 192, 203), -1) # ピンクの花
samples['landscape'] = Image.fromarray(landscape)
# 2. カフェ風(暖色系)
cafe = np.full((200, 300, 3), [139, 69, 19], dtype=np.uint8) # ブラウンベース
# テーブル
cafe[150:, :, :] = [160, 82, 45]
# コーヒーカップ
cv2.circle(cafe, (150, 170), 20, (255, 255, 255), -1)
cv2.circle(cafe, (150, 170), 15, (101, 67, 33), -1)
# 植物
cv2.circle(cafe, (250, 50), 30, (34, 139, 34), -1)
samples['cafe'] = Image.fromarray(cafe)
# 3. 夕焼け風
sunset = np.zeros((200, 300, 3), dtype=np.uint8)
for y in range(200):
ratio = y / 200
if y < 100: # 空部分
r = int(255 * (1 - ratio * 0.3))
g = int(165 * (1 - ratio * 0.8))
b = int(0 * (1 - ratio))
else: # 地面部分
r = int(139 * ratio)
g = int(69 * ratio)
b = int(19 * ratio)
sunset[y, :, :] = [r, g, b]
samples['sunset'] = Image.fromarray(sunset)
return samples
# OpenCVがない場合の代替実装
def create_simple_realistic_samples():
"""
OpenCVを使わないバージョン
"""
samples = {}
# 自然風景風
landscape = np.zeros((200, 300, 3), dtype=np.uint8)
landscape[:100, :, :] = [135, 206, 235] # 空
landscape[100:, :, :] = [34, 139, 34] # 草
samples['landscape'] = Image.fromarray(landscape)
# カフェ風
cafe = np.full((200, 300, 3), [139, 69, 19], dtype=np.uint8)
samples['cafe'] = Image.fromarray(cafe)
# 夕焼け風
sunset = np.zeros((200, 300, 3), dtype=np.uint8)
for y in range(200):
ratio = y / 200
r = int(255 - 100 * ratio)
g = int(165 - 100 * ratio)
b = int(50 * ratio)
sunset[y, :, :] = [max(0, r), max(0, g), max(0, b)]
samples['sunset'] = Image.fromarray(sunset)
return samples
# サンプル画像で分析実行
realistic_samples = create_simple_realistic_samples()
plt.figure(figsize=(18, 15))
for i, (name, image) in enumerate(realistic_samples.items()):
# 各画像の分析
extractor = ColorPaletteExtractor(n_colors=5)
extractor.extract_palette(image)
# 表示
row = i
# 元画像
plt.subplot(3, 3, row*3 + 1)
plt.imshow(image)
plt.title(f"{name.capitalize()} 画像", fontsize=12)
plt.axis('off')
# カラーパレット
plt.subplot(3, 3, row*3 + 2)
palette = extractor._create_equal_palette()
plt.imshow(palette)
plt.title(f"{name.capitalize()} パレット", fontsize=12)
plt.axis('off')
# HEXコード表示
hex_codes = extractor.get_color_codes()
y_pos = 0.8
for j, hex_code in enumerate(hex_codes):
plt.text(0.1, y_pos - j*0.15, hex_code, fontsize=10,
bbox=dict(boxstyle="round,pad=0.3", facecolor='lightgray'))
# 円グラフ
plt.subplot(3, 3, row*3 + 3)
colors_norm = [tuple(c/255 for c in color) for color in extractor.colors]
plt.pie(extractor.percentages, colors=colors_norm, startangle=90,
textprops={'fontsize': 8})
plt.title(f"{name.capitalize()} 分布", fontsize=12)
# コンソール出力
print(f"\n🎨 {name.upper()}の分析結果:")
extractor.print_report()
analyze_color_harmony(extractor.colors)
plt.tight_layout()
plt.show()




🚨 トラブルシューティング
よくあるエラーと対処法
# エラーハンドリングを含む堅牢なバージョン
class RobustColorExtractor(ColorPaletteExtractor):
"""
エラーハンドリングを強化したバージョン
"""
def extract_palette(self, image_input):
"""
様々な入力形式に対応
"""
try:
# 入力の型を判定
if isinstance(image_input, str):
# ファイルパスの場合
image = Image.open(image_input)
elif isinstance(image_input, Image.Image):
# PIL画像の場合
image = image_input
elif isinstance(image_input, np.ndarray):
# NumPy配列の場合
image = Image.fromarray(image_input)
else:
raise ValueError("サポートされていない画像形式です")
# RGBAからRGBに変換(透明度を除去)
if image.mode == 'RGBA':
background = Image.new('RGB', image.size, (255, 255, 255))
background.paste(image, mask=image.split()[-1])
image = background
elif image.mode != 'RGB':
image = image.convert('RGB')
# 画像サイズチェック
if image.size[0] * image.size[1] > 10000000: # 1000万ピクセル以上
print("⚠️ 画像が大きいため、リサイズします...")
image.thumbnail((2000, 2000), Image.Resampling.LANCZOS)
# 元の処理を実行
return super().extract_palette(image)
except FileNotFoundError:
print("❌ エラー: ファイルが見つかりません")
except PIL.UnidentifiedImageError:
print("❌ エラー: サポートされていない画像ファイル形式です")
except MemoryError:
print("❌ エラー: メモリ不足です。画像サイズを小さくしてください")
except Exception as e:
print(f"❌ 予期しないエラー: {str(e)}")
return None
# 使用例とテスト
def test_error_handling():
"""
エラーハンドリングのテスト
"""
extractor = RobustColorExtractor()
print("🔧 エラーハンドリングテスト:")
# 正常ケース
sample_img = np.random.randint(0, 255, (100, 100, 3), dtype=np.uint8)
result = extractor.extract_palette(sample_img)
if result:
print("✅ NumPy配列からの抽出: 成功")
# PIL画像
pil_img = Image.fromarray(sample_img)
result = extractor.extract_palette(pil_img)
if result:
print("✅ PIL画像からの抽出: 成功")
# 存在しないファイル
result = extractor.extract_palette("存在しないファイル.jpg")
print("🔧 テスト完了")
test_error_handling()
パフォーマンス最適化のコツ
def performance_tips():
"""
パフォーマンス向上のためのTips
"""
print("⚡ パフォーマンス最適化のコツ:")
print("-" * 50)
print("1. 大きな画像は事前にリサイズ")
print(" image.thumbnail((1000, 1000)) など")
print()
print("2. max_pixelsパラメータを調整")
print(" 精度 vs 速度のバランスを調整")
print()
print("3. 色数を適切に設定")
print(" 用途に応じて3-7色程度が最適")
print()
print("4. バッチ処理時はメモリ管理に注意")
print(" 大量の画像を処理する際は一定間隔でガベージコレクション")
print("-" * 50)
performance_tips()
# メモリ効率化例
import gc
def process_large_batch(image_list):
"""
大量画像の効率的な処理
"""
results = []
for i, img in enumerate(image_list):
extractor = ColorPaletteExtractor(max_pixels=5000) # ピクセル数制限
result = extractor.extract_palette(img)
results.append(result)
# 10枚ごとにメモリクリーンアップ
if (i + 1) % 10 == 0:
gc.collect()
print(f"✅ {i+1}枚処理完了")
return results
🔮 発展課題・応用アイデア
1. 動画ファイル対応
# 動画からキーフレームを抽出してカラーパレット生成
def extract_video_palette_concept():
"""
動画対応の概念実装
注意: 実際にはOpenCVやffmpegが必要
"""
print("🎬 動画対応の実装アイデア:")
print("-" * 40)
print("1. フレーム抽出:")
print(" import cv2")
print(" cap = cv2.VideoCapture('video.mp4')")
print(" # N秒間隔でフレームを取得")
print()
print("2. タイムラプス風パレット:")
print(" 時間経過と共に色が変化する様子を可視化")
print()
print("3. シーン検出:")
print(" 色の変化からシーンの切り替わりを検出")
print("-" * 40)
extract_video_palette_concept()
2. リアルタイム処理
def realtime_processing_concept():
"""
リアルタイム処理のアイデア
"""
print("📹 リアルタイム処理の実装アイデア:")
print("-" * 40)
print("1. Webカメラ連携:")
print(" カメラの映像からリアルタイムで色抽出")
print()
print("2. 配信アプリ連携:")
print(" OBS等の配信ソフトウェアと連携")
print()
print("3. IoT活用:")
print(" Raspberry Piでカメラ付きカラーセンサー")
print("-" * 40)
realtime_processing_concept()
3. Web API化
def web_api_concept():
"""
Web API化のアイデア
"""
print("🌐 Web API化のアイデア:")
print("-" * 40)
print("1. FastAPI/Flaskでの実装:")
print(" POST /extract_colors")
print(" 画像アップロード → JSON形式でパレット返却")
print()
print("2. 想定レスポンス:")
print(' {"colors": [{"hex": "#FF5733", "percentage": 25.5}]}')
print()
print("3. 料金設定例:")
print(" 個人利用: 無料(月100リクエスト)")
print(" 商用利用: 月額500円(月10,000リクエスト)")
print("-" * 40)
web_api_concept()
🎉 完成!全機能のデモ
# 完全版デモ: 全機能を統合したサンプル(修正版)
def final_demo():
"""
完成版アプリケーションの総合デモ
"""
print("🎉 カラーパレット抽出アプリ - 完成版デモ")
print("=" * 60)
# テスト用画像生成(カラフルなアート風)
demo_img = np.zeros((300, 400, 3), dtype=np.uint8)
# 複数の色領域を作成(より大きな領域で確実に色が抽出されるように)
regions = [
# (x1, y1, x2, y2, RGB色)
(0, 0, 200, 150, [255, 99, 71]), # トマト色(左上)
(200, 0, 400, 150, [60, 179, 113]), # ミディアムシーグリーン(右上)
(0, 150, 130, 300, [30, 144, 255]), # ドジャーブルー(左下)
(130, 150, 270, 300, [255, 215, 0]), # ゴールド(中央下)
(270, 150, 400, 300, [186, 85, 211]) # ミディアムオーキッド(右下)
]
print("🖼️ カラフルなデモ画像を作成中...")
for x1, y1, x2, y2, color in regions:
demo_img[y1:y2, x1:x2] = color
print(f" 領域 ({x1},{y1})-({x2},{y2}): RGB{color}")
demo_pil = Image.fromarray(demo_img)
# 作成された画像を表示
plt.figure(figsize=(10, 6))
plt.imshow(demo_pil)
plt.title("デモ用画像(5色の明確な領域)", fontsize=16)
plt.axis('off')
plt.show()
# 全機能実行(修正版ColorPaletteExtractorを使用)
print("🔍 Step 1: 高精度色抽出実行中...")
try:
extractor = ColorPaletteExtractor(n_colors=5)
result = extractor.extract_palette(demo_pil)
if result:
print("🎨 Step 2: パレット可視化...")
extractor.visualize_palette(show_pie_chart=True)
print("📊 Step 3: 詳細レポート出力...")
extractor.print_report()
print("🔬 Step 4: 色彩調和分析...")
if extractor.colors is not None:
try:
harmony_type = analyze_color_harmony(extractor.colors)
except Exception as e:
print(f"⚠️ 色彩調和分析でエラー: {e}")
print("💡 Step 5: 活用提案...")
try:
suggest_color_applications(extractor)
except Exception as e:
print(f"⚠️ 活用提案でエラー: {e}")
print("💾 Step 6: ファイル保存...")
try:
filename = extractor.save_palette("demo_palette.png")
if filename:
print(f"✅ {filename}に保存完了")
except Exception as e:
print(f"⚠️ ファイル保存でエラー: {e}")
print("🎯 Step 7: CSS出力...")
try:
css_vars = extractor.get_css_variables()
if css_vars:
print("\n/* 生成されたCSS変数 */")
print(css_vars)
else:
print("CSS変数の生成に失敗しました")
except Exception as e:
print(f"⚠️ CSS出力でエラー: {e}")
print("\n" + "=" * 60)
print("🎉 デモ完了!全機能が正常に動作しました。")
print("💰 このレベルのツールを500円で習得できるのはお得ですね!")
# 追加:実用性の確認
print("\n🔍 実用性チェック:")
if extractor.color_info:
unique_colors = set()
for info in extractor.color_info:
unique_colors.add(info['rgb'])
if len(unique_colors) >= 4:
print("✅ 4色以上の異なる色が抽出されました")
print("✅ 実用的なカラーパレットとして使用可能です")
else:
print("⚠️ 抽出された色の種類が少ないです")
print("=" * 60)
else:
print("❌ 色抽出に失敗しました")
except Exception as e:
print(f"❌ デモ実行中にエラーが発生: {e}")
import traceback
traceback.print_exc()
# 色彩調和分析とアプリケーション提案の簡易版(エラー対応)
def analyze_color_harmony_simple(colors):
"""
色彩調和分析(簡易版・エラー対応)
"""
try:
import colorsys
print("🎨 色彩調和分析:")
print("-" * 40)
hsv_colors = []
for i, color in enumerate(colors):
try:
r, g, b = [x/255.0 for x in color]
h, s, v = colorsys.rgb_to_hsv(r, g, b)
hsv_colors.append((h*360, s, v))
# 色相に基づく分類
hue = h * 360
if hue < 30 or hue >= 330:
color_family = "赤系"
elif hue < 90:
color_family = "黄系"
elif hue < 150:
color_family = "緑系"
elif hue < 210:
color_family = "青系"
elif hue < 270:
color_family = "紫系"
else:
color_family = "マゼンタ系"
print(f"色{i+1}: H={hue:.0f}° S={s:.2f} V={v:.2f} ({color_family})")
except Exception as e:
print(f"色{i+1}: 分析エラー - {e}")
# 色相の分布分析
if len(hsv_colors) > 0:
hues = [hsv[0] for hsv in hsv_colors]
hue_range = max(hues) - min(hues)
print(f"\n📊 色相分析:")
print(f"色相の範囲: {hue_range:.1f}°")
if hue_range < 30:
harmony_type = "類似色調和(Analogous)"
elif hue_range < 60:
harmony_type = "近似類似色調和"
elif 150 < hue_range < 210:
harmony_type = "補色調和(Complementary)"
else:
harmony_type = "多色調和(Polychromatic)"
print(f"調和タイプ: {harmony_type}")
return harmony_type
except ImportError:
print("⚠️ colorsysライブラリが利用できません")
except Exception as e:
print(f"⚠️ 色彩調和分析エラー: {e}")
return "分析不可"
def suggest_color_applications_simple(extractor):
"""
色の特徴に基づいて用途を提案(簡易版・エラー対応)
"""
try:
if extractor.color_info is None:
print("⚠️ 色情報が取得できていません")
return
print("\n💡 カラーパレット活用提案:")
print("=" * 50)
# 色数による提案
color_count = len(extractor.colors)
if color_count <= 3:
print("🎯 ミニマル → ロゴデザイン、シンプルなUI")
elif color_count <= 5:
print("🎨 バランス良好 → Webサイト、ポスターデザイン")
else:
print("🌈 リッチ → 複雑なデザイン、アート作品")
# 基本的な用途提案
print("🌟 基本的な活用例:")
print(" • Webサイトのカラースキーム")
print(" • SNS投稿の統一感演出")
print(" • プレゼン資料の配色")
print(" • イラスト・デザイン制作の参考")
print("=" * 50)
except Exception as e:
print(f"⚠️ 活用提案エラー: {e}")
# グローバル関数として定義
analyze_color_harmony = analyze_color_harmony_simple
suggest_color_applications = suggest_color_applications_simple
# 最終デモ実行
print("🚀 完全デモを開始します...")
final_demo()



この教材では以下を学習しました
✅ 基礎から応用まで体系的な画像解析技術
✅ 機械学習(K-means)の実践的な活用法
✅ 実用的なカラーパレット生成アプリ
✅ プロダクト品質のエラーハンドリング
✅ ビジネス活用までの具体的なロードマップ
🙏 最後に
画像解析はAI・データサイエンス分野の入り口でもあります。
画像認識システム
自動タグ付けツール
商品推薦システム
品質管理システム
など、様々な高度なアプリケーションへ発展させることができます。
今日学んだ技術が、あなたの未来を変える第一歩になることを願っています! 🌟
この教材が役に立ったら、ぜひレビューやシェアをお願いします。
質問があれば、コメント欄でお気軽にお聞きください!
Happy Coding! 🎨✨