Pythonで画像をリサイズ・加工する方法

プログラミング

Pythonによる画像リサイズ・加工

Pythonは、その豊富なライブラリ群により、画像処理タスクを効率的に実行するための強力なツールとなります。特に、画像のサイズ変更(リサイズ)や様々な加工は、Web開発、データ分析、画像認識など、多岐にわたる分野で不可欠な操作です。本稿では、Pythonを用いた画像リサイズ・加工の主要な手法について、具体的なコード例と共に解説します。

Pillowライブラリを用いた画像リサイズ

Pythonで画像処理を行う際に最も一般的に使用されるライブラリの一つが、Pillow(PILのフォーク)です。Pillowは、画像の開く、保存する、サイズ変更、回転、色調補正など、幅広い機能を提供します。

Pillowのインストール

まず、Pillowライブラリをインストールします。ターミナルまたはコマンドプロンプトで以下のコマンドを実行します。

pip install Pillow

画像の読み込みとリサイズ

Pillowを使用して画像を読み込み、サイズを変更する基本的な手順は以下の通りです。

from PIL import Image

# 画像ファイルのパスを指定
image_path = 'sample.jpg'

try:
    # 画像を開く
    img = Image.open(image_path)

    # 現在の画像サイズを取得
    original_width, original_height = img.size
    print(f"元の画像サイズ: {original_width}x{original_height}")

    # 新しいサイズを指定 (例: 幅を半分、高さを半分)
    new_width = original_width // 2
    new_height = original_height // 2
    new_size = (new_width, new_height)

    # 画像をリサイズ (Image.LANCZOSは高品質な補間アルゴリズム)
    resized_img = img.resize(new_size, Image.LANCZOS)

    # リサイズ後の画像サイズを確認
    resized_width, resized_height = resized_img.size
    print(f"リサイズ後の画像サイズ: {resized_width}x{resized_height}")

    # リサイズした画像を保存
    resized_img.save('resized_sample.jpg')
    print("リサイズした画像を 'resized_sample.jpg' として保存しました。")

except FileNotFoundError:
    print(f"エラー: ファイル '{image_path}' が見つかりません。")
except Exception as e:
    print(f"画像処理中にエラーが発生しました: {e}")

このコードでは、Image.open()で画像を読み込み、img.sizeで現在のサイズを取得します。img.resize()メソッドに新しいサイズ(タプル形式)と補間アルゴリズムを指定することで、画像をリサイズします。Image.LANCZOSは、一般的に高品質な結果が得られる補間方法です。リサイズした画像はsave()メソッドで保存されます。

アスペクト比を維持したリサイズ

画像をリサイズする際に、アスペクト比を維持することは重要です。アスペクト比を維持しないと、画像が歪んでしまう可能性があります。以下のコードは、指定した最大幅または最大高さに合わせて、アスペクト比を維持しながらリサイズする方法です。

from PIL import Image

def resize_with_aspect_ratio(image_path, max_width=None, max_height=None, output_path='output.jpg'):
    try:
        img = Image.open(image_path)
        original_width, original_height = img.size

        if max_width is None and max_height is None:
            print("エラー: 最大幅または最大高さのどちらかを指定してください。")
            return

        ratio = 1.0
        if max_width is not None and original_width > max_width:
            ratio = min(ratio, max_width / original_width)
        if max_height is not None and original_height > max_height:
            ratio = min(ratio, max_height / original_height)

        new_width = int(original_width * ratio)
        new_height = int(original_height * ratio)
        new_size = (new_width, new_height)

        resized_img = img.resize(new_size, Image.LANCZOS)
        resized_img.save(output_path)
        print(f"アスペクト比を維持してリサイズした画像を '{output_path}' として保存しました。")

    except FileNotFoundError:
        print(f"エラー: ファイル '{image_path}' が見つかりません。")
    except Exception as e:
        print(f"画像処理中にエラーが発生しました: {e}")

# 使用例1: 最大幅を500pxに指定
resize_with_aspect_ratio('sample.jpg', max_width=500, output_path='resized_aspect_width.jpg')

# 使用例2: 最大高さを300pxに指定
resize_with_aspect_ratio('sample.jpg', max_height=300, output_path='resized_aspect_height.jpg')

# 使用例3: 最大幅と最大高さを指定 (小さい方の制限が適用される)
resize_with_aspect_ratio('sample.jpg', max_width=400, max_height=400, output_path='resized_aspect_both.jpg')

この関数では、指定された最大幅または最大高さに基づいて、適切なリサイズ比率を計算します。min()関数を使用して、幅と高さの両方の制限を考慮し、アスペクト比を壊さずに画像を縮小します。

Pillowライブラリを用いたその他の画像加工

Pillowはリサイズ以外にも、様々な画像加工機能を提供しています。

回転

画像を回転させるにはrotate()メソッドを使用します。

from PIL import Image

try:
    img = Image.open('sample.jpg')
    # 90度回転
    rotated_img_90 = img.rotate(90)
    rotated_img_90.save('rotated_90.jpg')

    # 45度回転 (expand=Trueで、画像全体を収めるようにキャンバスを拡張)
    rotated_img_45 = img.rotate(45, expand=True)
    rotated_img_45.save('rotated_45.jpg')

except FileNotFoundError:
    print("エラー: ファイルが見つかりません。")
except Exception as e:
    print(f"画像処理中にエラーが発生しました: {e}")

トリミング (切り抜き)

画像の特定の部分を切り抜くにはcrop()メソッドを使用します。引数には、切り抜きたい領域を左上隅の座標と右下隅の座標で指定するタプル (left, upper, right, lower) を渡します。

from PIL import Image

try:
    img = Image.open('sample.jpg')
    # 画像の一部を切り抜く (左から100px、上から50pxを始点とし、幅200px、高さ150pxの領域)
    # 座標は (left, upper, right, lower)
    box = (100, 50, 100 + 200, 50 + 150)
    cropped_img = img.crop(box)
    cropped_img.save('cropped_sample.jpg')
    print("画像を切り抜きました。")

except FileNotFoundError:
    print("エラー: ファイルが見つかりません。")
except Exception as e:
    print(f"画像処理中にエラーが発生しました: {e}")

画像モードの変換

RGB、グレースケール、CMYKなど、画像のカラーモードを変換できます。

from PIL import Image

try:
    img = Image.open('sample.jpg')
    # RGBからグレースケールに変換
    grayscale_img = img.convert('L')
    grayscale_img.save('grayscale_sample.jpg')
    print("画像をグレースケールに変換しました。")

    # RGBからCMYKに変換
    cmyk_img = img.convert('CMYK')
    cmyk_img.save('cmyk_sample.jpg')
    print("画像をCMYKに変換しました。")

except FileNotFoundError:
    print("エラー: ファイルが見つかりません。")
except Exception as e:
    print(f"画像処理中にエラーが発生しました: {e}")

フィルタの適用

PillowのImageFilterモジュールを使用すると、ぼかし、シャープ化などの様々なフィルタを適用できます。

from PIL import Image, ImageFilter

try:
    img = Image.open('sample.jpg')
    # 画像をぼかす (ガウシアンぼかし)
    blurred_img = img.filter(ImageFilter.BLUR)
    blurred_img.save('blurred_sample.jpg')

    # 画像をシャープにする
    sharpened_img = img.filter(ImageFilter.SHARPEN)
    sharpened_img.save('sharpened_sample.jpg')

    # エッジ検出
    edges_img = img.filter(ImageFilter.FIND_EDGES)
    edges_img.save('edges_sample.jpg')

    print("フィルタを適用した画像を保存しました。")

except FileNotFoundError:
    print("エラー: ファイルが見つかりません。")
except Exception as e:
    print(f"画像処理中にエラーが発生しました: {e}")

OpenCVライブラリを用いた画像リサイズ・加工

OpenCV(Open Source Computer Vision Library)は、コンピュータビジョンタスクに特化した強力なライブラリです。Pillowよりも高度な画像処理やリアルタイム処理に適していますが、インストールがPillowよりやや複雑な場合があります。

OpenCVのインストール

OpenCVをインストールするには、以下のコマンドを使用します。

pip install opencv-python

画像の読み込みとリサイズ

OpenCVでは、画像をNumPy配列として扱います。

import cv2
import numpy as np

# 画像ファイルのパスを指定
image_path = 'sample.jpg'

try:
    # 画像を読み込む (カラー画像として読み込む場合は cv2.IMREAD_COLOR)
    img = cv2.imread(image_path, cv2.IMREAD_COLOR)

    if img is None:
        print(f"エラー: ファイル '{image_path}' を読み込めませんでした。パスを確認してください。")
    else:
        # 現在の画像サイズを取得 (高さ, 幅, チャンネル数)
        original_height, original_width = img.shape[:2]
        print(f"元の画像サイズ: {original_width}x{original_height}")

        # 新しいサイズを指定 (幅, 高さ)
        new_width = original_width // 2
        new_height = original_height // 2
        new_size = (new_width, new_height)

        # 画像をリサイズ (補間方法を指定: cv2.INTER_AREAは縮小に適しています)
        resized_img = cv2.resize(img, new_size, interpolation=cv2.INTER_AREA)

        # リサイズ後の画像サイズを確認
        resized_height, resized_width = resized_img.shape[:2]
        print(f"リサイズ後の画像サイズ: {resized_width}x{resized_height}")

        # リサイズした画像を保存
        cv2.imwrite('resized_sample_cv2.jpg', resized_img)
        print("リサイズした画像を 'resized_sample_cv2.jpg' として保存しました。")

except Exception as e:
    print(f"画像処理中にエラーが発生しました: {e}")

OpenCVのcv2.resize()関数は、ターゲットサイズを(width, height)の順序で受け取ります。interpolation引数で補間方法を指定できます。cv2.INTER_AREAは画像を縮小する際に、cv2.INTER_CUBICcv2.INTER_LINEARは拡大する際に適しています。

アスペクト比を維持したリサイズ (OpenCV)

Pillowと同様に、OpenCVでもアスペクト比を維持しながらリサイズすることが可能です。

import cv2

def resize_with_aspect_ratio_cv2(image_path, target_width=None, target_height=None, output_path='output_cv2.jpg'):
    try:
        img = cv2.imread(image_path, cv2.IMREAD_COLOR)
        if img is None:
            print(f"エラー: ファイル '{image_path}' を読み込めませんでした。")
            return

        original_height, original_width = img.shape[:2]

        if target_width is None and target_height is None:
            print("エラー: target_width または target_height のどちらかを指定してください。")
            return

        ratio = 1.0
        if target_width is not None and original_width > target_width:
            ratio = min(ratio, target_width / original_width)
        if target_height is not None and original_height > target_height:
            ratio = min(ratio, target_height / original_height)

        new_width = int(original_width * ratio)
        new_height = int(original_height * ratio)
        new_size = (new_width, new_height)

        # 縮小に適した補間方法を選択
        resized_img = cv2.resize(img, new_size, interpolation=cv2.INTER_AREA)
        cv2.imwrite(output_path, resized_img)
        print(f"アスペクト比を維持してリサイズした画像を '{output_path}' として保存しました。")

    except Exception as e:
        print(f"画像処理中にエラーが発生しました: {e}")

# 使用例1: target_width を 500px に指定
resize_with_aspect_ratio_cv2('sample.jpg', target_width=500, output_path='resized_aspect_width_cv2.jpg')

# 使用例2: target_height を 300px に指定
resize_with_aspect_ratio_cv2('sample.jpg', target_height=300, output_path='resized_aspect_height_cv2.jpg')

その他のOpenCVによる加工

OpenCVは、フィルタリング、色空間変換、物体検出など、より高度な機能を提供します。例えば、グレースケール変換やぼかしは以下のように行えます。

import cv2

try:
    img = cv2.imread('sample.jpg', cv2.IMREAD_COLOR)
    if img is None:
        print("エラー: 画像を読み込めませんでした。")
    else:
        # グレースケール変換
        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        cv2.imwrite('grayscale_sample_cv2.jpg', gray_img)

        # ガウシアンぼかし
        blurred_img = cv2.GaussianBlur(img, (15, 15), 0) # (カーネルサイズ, シグマX)
        cv2.imwrite('blurred_sample_cv2.jpg', blurred_img)

        print("OpenCVで加工した画像を保存しました。")

except Exception as e:
    print(f"画像処理中にエラーが発生しました: {e}")

cv2.cvtColor()で色空間を変換し、cv2.GaussianBlur()でぼかしを適用できます。OpenCVは、これらの基本操作に加えて、特徴点検出、顔認識、物体追跡など、より複雑な画像解析タスクにも対応しています。

まとめ

Pythonを用いた画像リサイズ・加工は、PillowとOpenCVという強力なライブラリによって、非常に簡単かつ効率的に行うことができます。Pillowは、手軽に画像操作を行いたい場合に、OpenCVは、より高度な画像処理やコンピュータビジョンタスクに挑戦したい場合に適しています。どちらのライブラリも、豊富な機能と柔軟性を提供するため、目的に応じて適切なライブラリを選択し、活用することが重要です。