single.php

Pythonで菱形の画像から菱形を切り出す

Pythonで、菱形を描いた画像から菱形を切り出したい時に作った処理を備忘録的に投稿しておきます。

菱形から菱形を切り抜く

Unityで地形データを作るために、テストで作成したタイルマップのテンプレート画像。Rectangleグリッドの場合は正方形なので、気になりません。

しかし、Isometricグリッド(正方形を斜めから見たようなグリッド)にすると、タイルの形状が菱形になり、画像処理ソフトで切り分けるのに苦労します。

ウェブ用の画像を切り出す「スライス」機能が使えそうですが、色々調べてみましたが、菱形の形状にくり抜くのは、無理っぽいのでPythonのスクリプトの出番です。

入力した画像を小分けにするPythonスクリプトです。

変数は、固定値化しているので画像サイズとかを変更する場合には修正が必要です。

from PIL import Image, ImageDraw, ImageChops
from pathlib import Path
import sys

IMAGE_WIDTH = 256
IMAGE_HEIGHT = 128

TILE_WIDTH = 64
TILE_HEIGHT = 32

# 大きな菱形の中心
CENTER_X = 128
CENTER_Y = 64

# 保存するファイル名
filenames = [
    "mask_0_0_1_0",
    "mask_1_0_0_1",
    "mask_0_1_0_1",
    "mask_0_1_0_0",
    "mask_0_1_1_1",
    "mask_1_0_1_1",
    "mask_0_0_0_0",
    "mask_1_1_0_0",
    "mask_1_1_1_1",
    "mask_0_0_1_1",
    "mask_0_0_0_1",
    "mask_1_1_0_1",
    "mask_1_1_1_0",
    "mask_0_1_1_0",
    "mask_1_0_1_0",
    "mask_1_0_0_0",
]

def split_diamond_grid(input_path, output_dir="output"):
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)

    with Image.open(input_path) as src:
        image = src.convert("RGBA")

    if image.size != (IMAGE_WIDTH, IMAGE_HEIGHT):
        raise ValueError(
            f"画像サイズは256x128が必要です。現在: {image.size}"
        )

    # 小菱形のマスクを作成
    mask = Image.new("L", (TILE_WIDTH, TILE_HEIGHT), 0)
    draw = ImageDraw.Draw(mask)
    draw.polygon([
        (TILE_WIDTH // 2, 0),
        (TILE_WIDTH - 1, TILE_HEIGHT // 2),
        (TILE_WIDTH // 2, TILE_HEIGHT - 1),
        (0, TILE_HEIGHT // 2),
    ], fill=255)

    # 4×4の格子座標から16個の中心座標を算出
    centers = []

    for row in range(4):
        for col in range(4):
            x = CENTER_X + (col - row) * (TILE_WIDTH // 2)
            y = (row + col + 1) * (TILE_HEIGHT // 2)

            centers.append((x, y))

    # 上から下、同じ高さなら左から右の順に出力
    centers.sort(key=lambda p: (p[1], p[0]))

    for index, (cx, cy) in enumerate(centers, start=1):
        # 小菱形の外接矩形を元画像から切り出す
        left = cx - TILE_WIDTH // 2
        top = cy - TILE_HEIGHT // 2

        tile = image.crop((
            left,
            top,
            left + TILE_WIDTH,
            top + TILE_HEIGHT
        ))

        # 菱形の外側を透明化し、元の透明度も維持
        alpha = ImageChops.multiply(
            tile.getchannel("A"),
            mask
        )
        tile.putalpha(alpha)

        filename = f"{filenames[index - 1]}.png"
        tile.save(output_dir / filename)

    print(f"完了: {len(centers)}枚を {output_dir} に出力しました。")


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("使用方法: python split_diamond_grid.py input.png")
        sys.exit(1)

    split_diamond_grid(sys.argv[1], sys.argv[2])

コマンドの引数でで入力する画像の場所や出力先を指定するので、デバッグする環境用のファイルを追加します。

{
    "version": "0.2.0",
    "configurations": [

        {
            "name": "Python デバッガー: 引数を含む現在のファイル",
            "type": "debugpy",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "args": [
                "${input:_source}",
                "${input:_output}"
            ]
        }
    ],
    "inputs": [
        {
            "id": "_source",
            "type": "promptString",
            "description": "画像ファイルのパスを入力"
        },
        {
            "id": "_output",
            "type": "promptString",
            "description": "出力先フォルダーを入力"
        },
    ]    
}

実行すると、引数で指定した場所に切り抜いた菱形画像のファイルが保存されます。

まとめて修正した1つの画像を切り分けて、名前を付けて保存する作業が効率的になりました。

まとめ

今回は短い記事ですが、菱形を描いた画像から菱形を切り出したい時に作った処理について書きました。

Pythonの画像処理用のライブラリを使うことで、比較的簡単に菱形の画像から菱形を切り出す処理が作れました。

菱形を描いた画像から菱形の画像を切り出したい人の参考になれば幸いです。

スポンサーリンク

最後までご覧いただき、ありがとうございます。

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です