画像のアルファチャンネル(透明度情報)を利用して、背景の透明な部分で画像内の「非透明」な領域(つまり、表示されるオブジェクト)を自動的に検出し、それぞれを個別の画像として切り出す方法。Python

プログラム

from PIL import Image
import numpy as np
from scipy.ndimage import label, find_objects

def split_by_transparency(image_path, output_prefix="object"):
    # 画像をRGBAモードで読み込み(アルファチャンネルを有効にする)
    im = Image.open(image_path).convert("RGBA")
    data = np.array(im)
    
    # アルファチャンネルが0より大きい(=非透明)部分を True としたマスクを作成
    # ※ここでは、ピクセルの alpha 値が 0 より大きければ、それはオブジェクトの一部とみなします
    mask = data[:, :, 3] > 0
    
    # マスク上で連結成分(非透明領域ごと)を検出する
    labeled_array, num_features = label(mask)
    print(f"検出されたオブジェクト数: {num_features}")
    
    # それぞれのラベルのバウンディングボックス(範囲)を取得
    objects = find_objects(labeled_array)
    
    for i, obj_slice in enumerate(objects):
        # obj_slice は (slice_y, slice_x) 形式のタプル
        left   = obj_slice[1].start
        upper  = obj_slice[0].start
        right  = obj_slice[1].stop
        lower  = obj_slice[0].stop
        
        # バウンディングボックスに基づいて切り出し
        cropped = im.crop((left, upper, right, lower))
        output_name = f"{output_prefix}_{i}.png"
        cropped.save(output_name)
        print(f"{output_name} として保存しました。")

# 使用例:背景の透明部分を利用して input_image.png 内の各オブジェクトを分割
split_by_transparency("input_image.png")

フォルダーを指定して処理するプログラム

import os
import glob
import numpy as np
from PIL import Image
from scipy.ndimage import label, find_objects

def split_by_transparency(image_path, output_folder, output_prefix="object"):
    """
    指定した画像(image_path)をRGB(A)として読み込み、アルファチャンネルがある場合は
    背景(透明な部分)を除いた連結成分ごとに画像を切り出し、output_folderに保存します。
    
    保存ファイル名は、{output_prefix}_{元画像名}_{オブジェクト番号}.png の形式です。
    """
    # 画像をRGBAモードで読み込み(アルファチャンネル有効)
    im = Image.open(image_path).convert("RGBA")
    data = np.array(im)
    
    # アルファチャンネルが0より大きい=非透明なピクセルをTrueにするマスクを作成
    mask = data[:, :, 3] > 0
    
    # マスク上で連結する非透明領域(オブジェクト)を検出する
    labeled_array, num_features = label(mask)
    print(f"[{os.path.basename(image_path)}] 検出されたオブジェクト数: {num_features}")
    
    # 各オブジェクトのバウンディングボックスを取得し切り出す
    objects = find_objects(labeled_array)
    base_name = os.path.splitext(os.path.basename(image_path))[0]
    
    for i, obj_slice in enumerate(objects):
        left   = obj_slice[1].start
        upper  = obj_slice[0].start
        right  = obj_slice[1].stop
        lower  = obj_slice[0].stop

        # バウンディングボックス内を切り出し
        cropped = im.crop((left, upper, right, lower))
        output_filename = os.path.join(output_folder, f"{output_prefix}_{base_name}_{i}.png")
        cropped.save(output_filename)
        print(f"保存: {output_filename}")

def process_folder(input_folder, output_folder, output_prefix="object"):
    """
    インプットフォルダ内のすべてのPNG画像に対して split_by_transparency() を実行し、
    オブジェクトごとに画像をアウトプットフォルダに保存する関数です。
    """
    # 出力フォルダが存在しなければ作成
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)
        print(f"アウトプットフォルダ {output_folder} を作成しました。")
    
    # input_folder 内のPNGファイルを取得(他の形式も処理する場合は拡張子を変更してください)
    image_files = glob.glob(os.path.join(input_folder, "*.png"))
    if not image_files:
        print(f"対象ファイルが見つかりませんでした。入力フォルダ: {input_folder}")
    
    for image_path in image_files:
        split_by_transparency(image_path, output_folder, output_prefix)

# 使用例
if __name__ == "__main__":
    # インプットフォルダとアウトプットフォルダのパスを指定
    input_folder = "input_images"   # 例: 作業ディレクトリ内の入力用フォルダ
    output_folder = "output_images" # 例: 出力用フォルダ
    process_folder(input_folder, output_folder, output_prefix="object")

Python

Posted by eightban