NumPyでRGB画像処理:色チャンネル分離・単色化・白黒化・色交換の完全ガイド

 

NumPyを使用したRGB画像の色処理は、画像解析やコンピュータビジョンの基本技術です。本記事では、RGB画像の色チャンネル分離、単色化、白黒化、色交換の方法を、実践的なサンプルコードとともに詳しく解説します。

RGB画像とNumPy配列の基本

RGB画像は、赤(Red)、緑(Green)、青(Blue)の3つのチャンネルで構成されています。NumPyでは、これを3次元配列として扱います。

画像データの構造

import numpy as np
from PIL import Image

# サンプル画像の作成(100x100ピクセル)
height, width = 100, 100
rgb_image = np.random.randint(0, 256, (height, width, 3), dtype=np.uint8)

print(f"画像形状: {rgb_image.shape}")  # (100, 100, 3)
print(f"データ型: {rgb_image.dtype}")   # uint8

画像の読み込みと準備

import numpy as np
from PIL import Image

# 画像ファイルの読み込み例
# image = Image.open('sample.jpg')
# rgb_array = np.array(image)

# テスト用カラー画像の生成
test_image = np.zeros((200, 300, 3), dtype=np.uint8)
test_image[:, :100, 0] = 255  # 左側を赤
test_image[:, 100:200, 1] = 255  # 中央を緑
test_image[:, 200:, 2] = 255  # 右側を青

RGB色チャンネルの分離

基本的なチャンネル分離

各色チャンネルを個別に抽出する方法です。

import numpy as np

# RGB画像からチャンネル分離
def separate_rgb_channels(rgb_image):
    red_channel = rgb_image[:, :, 0]
    green_channel = rgb_image[:, :, 1]
    blue_channel = rgb_image[:, :, 2]
    return red_channel, green_channel, blue_channel

# 使用例
red, green, blue = separate_rgb_channels(test_image)
print(f"赤チャンネル形状: {red.shape}")  # (200, 300)

チャンネル別画像の可視化

分離したチャンネルを単色画像として表示する方法です。

import numpy as np

def create_single_color_images(rgb_image):
    h, w = rgb_image.shape[:2]
    
    # 赤色のみの画像
    red_only = np.zeros((h, w, 3), dtype=np.uint8)
    red_only[:, :, 0] = rgb_image[:, :, 0]
    
    # 緑色のみの画像
    green_only = np.zeros((h, w, 3), dtype=np.uint8)
    green_only[:, :, 1] = rgb_image[:, :, 1]
    
    # 青色のみの画像
    blue_only = np.zeros((h, w, 3), dtype=np.uint8)
    blue_only[:, :, 2] = rgb_image[:, :, 2]
    
    return red_only, green_only, blue_only

チャンネル統計情報の取得

import numpy as np

def analyze_channels(rgb_image):
    red, green, blue = separate_rgb_channels(rgb_image)
    
    stats = {
        'red': {'mean': np.mean(red), 'std': np.std(red)},
        'green': {'mean': np.mean(green), 'std': np.std(green)},
        'blue': {'mean': np.mean(blue), 'std': np.std(blue)}
    }
    
    return stats

# 統計情報の表示
channel_stats = analyze_channels(test_image)
print("チャンネル統計:", channel_stats)

画像の単色化

特定色のみを強調

指定した色チャンネルのみを残し、他を削除する処理です。

import numpy as np

def make_single_color(rgb_image, color='red'):
    result = rgb_image.copy()
    
    if color == 'red':
        result[:, :, 1] = 0  # 緑を削除
        result[:, :, 2] = 0  # 青を削除
    elif color == 'green':
        result[:, :, 0] = 0  # 赤を削除
        result[:, :, 2] = 0  # 青を削除
    elif color == 'blue':
        result[:, :, 0] = 0  # 赤を削除
        result[:, :, 1] = 0  # 緑を削除
    
    return result

# 使用例
red_image = make_single_color(test_image, 'red')

セピア調変換

セピア調の単色化処理です。

import numpy as np

def apply_sepia(rgb_image):
    # セピア変換行列
    sepia_matrix = np.array([
        [0.393, 0.769, 0.189],
        [0.349, 0.686, 0.168],
        [0.272, 0.534, 0.131]
    ])
    
    # 変換実行
    sepia = rgb_image.dot(sepia_matrix.T)
    sepia = np.clip(sepia, 0, 255).astype(np.uint8)
    
    return sepia

# セピア調変換
sepia_image = apply_sepia(test_image)

グレースケール・白黒化

基本的なグレースケール変換

RGB値を輝度値に変換してグレースケール画像を作成します。

import numpy as np

def rgb_to_grayscale(rgb_image):
    # 標準的な輝度計算式
    gray = 0.299 * rgb_image[:, :, 0] + \
           0.587 * rgb_image[:, :, 1] + \
           0.114 * rgb_image[:, :, 2]
    
    return gray.astype(np.uint8)

# グレースケール変換
gray_image = rgb_to_grayscale(test_image)
print(f"グレースケール形状: {gray_image.shape}")  # (200, 300)

異なる手法でのグレースケール変換

import numpy as np

def grayscale_methods(rgb_image):
    # 方法1: 平均値
    avg_gray = np.mean(rgb_image, axis=2).astype(np.uint8)
    
    # 方法2: 最大値
    max_gray = np.max(rgb_image, axis=2).astype(np.uint8)
    
    # 方法3: 最小値
    min_gray = np.min(rgb_image, axis=2).astype(np.uint8)
    
    return avg_gray, max_gray, min_gray

# 複数手法での変換
avg, max_g, min_g = grayscale_methods(test_image)

二値化(白黒化)

グレースケール画像を完全な白黒画像に変換します。

import numpy as np

def binarize_image(gray_image, threshold=128):
    binary = np.where(gray_image > threshold, 255, 0).astype(np.uint8)
    return binary

def adaptive_binarize(gray_image):
    # 大津の手法による自動閾値設定
    threshold = np.mean(gray_image)
    return binarize_image(gray_image, threshold)

# 二値化実行
gray = rgb_to_grayscale(test_image)
binary = binarize_image(gray, 100)
adaptive_binary = adaptive_binarize(gray)

色チャンネルの交換

基本的な色交換

RGB チャンネルの順序を変更して色相を変化させます。

import numpy as np

def swap_channels(rgb_image, swap_type='rgb_to_bgr'):
    result = rgb_image.copy()
    
    if swap_type == 'rgb_to_bgr':
        # RGBをBGRに変換
        result = rgb_image[:, :, [2, 1, 0]]
    elif swap_type == 'rgb_to_gbr':
        # RGBをGBRに変換
        result = rgb_image[:, :, [1, 2, 0]]
    elif swap_type == 'rgb_to_brg':
        # RGBをBRGに変換
        result = rgb_image[:, :, [2, 0, 1]]
    
    return result

# 色交換実行
bgr_image = swap_channels(test_image, 'rgb_to_bgr')

カスタム色交換

import numpy as np

def custom_channel_swap(rgb_image, r_source=0, g_source=1, b_source=2):
    """
    カスタムチャンネル交換
    r_source, g_source, b_source: 0=R, 1=G, 2=B
    """
    result = np.zeros_like(rgb_image)
    result[:, :, 0] = rgb_image[:, :, r_source]  # R
    result[:, :, 1] = rgb_image[:, :, g_source]  # G
    result[:, :, 2] = rgb_image[:, :, b_source]  # B
    
    return result

# 赤と青を交換
red_blue_swap = custom_channel_swap(test_image, 2, 1, 0)

色調整と強調

import numpy as np

def adjust_color_channels(rgb_image, r_factor=1.0, g_factor=1.0, b_factor=1.0):
    result = rgb_image.astype(np.float32)
    
    result[:, :, 0] *= r_factor  # 赤の調整
    result[:, :, 1] *= g_factor  # 緑の調整
    result[:, :, 2] *= b_factor  # 青の調整
    
    # 値の範囲を0-255にクリップ
    result = np.clip(result, 0, 255).astype(np.uint8)
    return result

# 色調整例
enhanced = adjust_color_channels(test_image, 1.2, 0.8, 1.5)

実践的な応用例

画像フィルターの組み合わせ

複数の処理を組み合わせた高度な画像処理です。

import numpy as np

def create_artistic_effect(rgb_image):
    # 段階的な処理
    gray = rgb_to_grayscale(rgb_image)
    
    # エッジ強調
    edges = np.abs(np.gradient(gray.astype(float))[0])
    edges = (edges / np.max(edges) * 255).astype(np.uint8)
    
    # 色付きエッジ
    colored_edges = np.zeros_like(rgb_image)
    colored_edges[:, :, 0] = edges
    
    return colored_edges

# アーティスティック効果
artistic = create_artistic_effect(test_image)

チャンネル情報を使った画像解析

import numpy as np

def analyze_image_colors(rgb_image):
    red, green, blue = separate_rgb_channels(rgb_image)
    
    # 各チャンネルの支配的な領域を特定
    red_dominant = (red > green) & (red > blue)
    green_dominant = (green > red) & (green > blue)
    blue_dominant = (blue > red) & (blue > green)
    
    # 支配色の面積計算
    red_area = np.sum(red_dominant)
    green_area = np.sum(green_dominant)
    blue_area = np.sum(blue_dominant)
    
    return {
        'red_area': red_area,
        'green_area': green_area,
        'blue_area': blue_area
    }

# 色解析実行
color_analysis = analyze_image_colors(test_image)
print("色分析結果:", color_analysis)

性能最適化とベストプラクティス

効率的な処理方法

import numpy as np

def efficient_channel_processing(rgb_image):
    # インプレース操作でメモリ効率を向上
    result = rgb_image.copy()
    
    # ベクトル化操作を活用
    mask = np.sum(rgb_image, axis=2) > 400
    result[mask] = [255, 255, 255]  # 明るい部分を白に
    
    return result

# メモリ効率的な処理
optimized = efficient_channel_processing(test_image)

エラーハンドリング

import numpy as np

def safe_rgb_processing(rgb_image):
    # 入力検証
    if rgb_image.ndim != 3 or rgb_image.shape[2] != 3:
        raise ValueError("RGB画像(3チャンネル)が必要です")
    
    if rgb_image.dtype != np.uint8:
        print("警告: uint8以外のデータ型です")
    
    # 安全な処理実行
    try:
        result = rgb_to_grayscale(rgb_image)
        return result
    except Exception as e:
        print(f"処理エラー: {e}")
        return None

まとめ

NumPyを使用したRGB画像の色処理では、以下の技術が重要です:

基本技術:

  • チャンネル分離による個別色成分の抽出
  • グレースケール変換と二値化
  • 色チャンネルの交換と調整

応用技術:

  • セピア調変換などの芸術的効果
  • チャンネル統計による画像解析
  • 効率的なベクトル化処理

実装のポイント:

  • データ型(uint8)の適切な管理
  • 値の範囲(0-255)のクリッピング
  • メモリ効率を考慮した処理方法

これらの技術を組み合わせることで、高度な画像処理アプリケーションの開発が可能になります。画像解析、コンピュータビジョン、デジタル画像処理の分野で幅広く活用できる基礎技術です。