Python PILを使用して写真コラージュを作成する方法

出版日: 2023年12月30日

Python PILを使用して写真コラージュを作成する方法

異なるサイズの多くの写真をコラージュに組み合わせたいと想像してください

たくさんの写真

この記事のタスクは、これらの写真を保持しながら、以下のようなコラージュに組み合わせることです。

写真コラージュ

以下のコードは、フォルダに含まれる画像ファイルをコラージュに変換します:

# 必要なライブラリをインポート
import os
from PIL import Image, ImageDraw

# 画像が含まれているフォルダを定義
directory = "./images"

# 画像のリストを取得
images = [i for i in os.listdir(directory) if i.endswith(".jpg") or i.endswith(".jpeg") or i.endswith(".png")]

# 出力コラージュのサイズとコラージュ内の1つの画像のサイズを (幅, 高さ) のタプルで定義
# 以下の値によって、横方向と縦方向にどれだけの画像が配置されるかが決まります
# 例: この場合 -  3600/600 = 6  および 1600/4 = 4 - コラージュは 6x4 になります
expected_size_collage = (3600, 1600)
expected_size_image = (600, 400)

# 画像を貼り付けるためのコラージュのキャンバスを作成
collage = Image.new("RGBA", expected_size_collage, color=(255,255,255,255))

# 画像ファイルをループする
file_count = 0
for h in range(0, expected_size_collage[1], expected_size_image[1]):
    for w in range(0, expected_size_collage[0], expected_size_image[0]):
        # 画像を読み込む
        file_name = images[file_count]
        path = directory + "/" + file_name
        image = Image.open(path).convert("RGBA")

        # 元の画像の幅と高さを取得
        image_width = image.size[0]
        image_height = image.size[1]

        # 画像の幅と高さの調整方法を取得
        width_factor = image_width / expected_size_image[0]
        height_factor = image_height / expected_size_image[1]

        # 幅と高さの調整係数が同じ場合、クロッピングは不要です
        # そうでない場合は、画像を expected_size_image と同じ比率にクロップする必要があります
        if width_factor != height_factor:
            # 制限係数を取得
            factor = min(width_factor, height_factor)

            # 結果画像の幅と高さを計算
            expected_width = round(factor * expected_size_image[0])
            expected_height = round(factor * expected_size_image[1])

            # 新しい画像の minx、miny、maxx、maxy 座標を取得
            start_width = round((image_width - expected_width) / 2)
            start_height = round((image_height - expected_height) / 2)
            end_width = expected_width + round((image_width - expected_width) / 2)
            end_height = expected_height + round((image_height - expected_height) / 2)

            # 画像をクロップ
            image = image.crop((start_width, start_height, end_width, end_height))

        # 画像をクロップしたら、画像をリサイズします
        # 画像は expected_size_image と同じアスペクト比を持っている必要があるため、リサイズは画像を妨げません
        image = image.resize(expected_size_image)

        # 画像をコラージュキャンバスに貼り付ける
        collage.paste(image, (w, h))
        file_count += 1

# コラージュを保存
collage.save("collage.png") 

では、次にコードをステップバイステップで見てみましょう。

1. ライブラリをインポートし、パラメータを定義する

# 必要なライブラリをインポート
import os
from PIL import Image, ImageDraw

# 画像が含まれているフォルダを定義
directory = "./images"

# 画像のリストを取得
images = [i for i in os.listdir(directory) if i.endswith(".jpg") or i.endswith(".jpeg") or i.endswith(".png")]

# 出力コラージュのサイズとコラージュ内の1つの画像のサイズを (幅, 高さ) のタプルで定義
# 以下の値によって、横方向と縦方向にどれだけの画像が配置されるかが決まります
# 例: この場合 -  3600/600 = 6  および 1600/4 = 4 - コラージュは 6x4 になります
expected_size_collage = (3600, 1600)
expected_size_image = (600, 400)

# 画像を貼り付けるためのコラージュのキャンバスを作成
collage = Image.new("RGBA", expected_size_collage, color=(255,255,255,255))

上記のコードでは、PIL を含む必要なライブラリをインポートします。これらのライブラリは、画像のクロッピングやリサイズに使用します。

指定されたフォルダ内で .png .jpg .jpeg で終わる画像を収集し、リストに入れます。

次に、希望のコラージュのサイズを定義します。ここではフォルダに24枚の画像があり、6x4の画像をコラージュにしたいとします。

タイル(画像)は 600x400 のサイズが割り当てられ、これによりコラージュのサイズが 3600x1600 になります。次のセクションでは、このブランクキャンバスに画像タイルを貼り付けます。

2. 画像タイルを処理し、コラージュを作成する

# 画像ファイルをループする
file_count = 0
for h in range(0, expected_size_collage[1], expected_size_image[1]):
    for w in range(0, expected_size_collage[0], expected_size_image[0]):
        # 画像を読み込む
        file_name = images[file_count]
        path = directory + "/" + file_name
        image = Image.open(path).convert("RGBA")

        # 元の画像の幅と高さを取得
        image_width = image.size[0]
        image_height = image.size[1]

        # 画像の幅と高さの調整方法を取得
        width_factor = image_width / expected_size_image[0]
        height_factor = image_height / expected_size_image[1]

        # 幅と高さの調整係数が同じ場合、クロッピングは不要です
        # そうでない場合は、画像を expected_size_image と同じ比率にクロップする必要があります
        if width_factor != height_factor:
            # 制限係数を取得
            factor = min(width_factor, height_factor)

            # 結果画像の幅と高さを計算
            expected_width = round(factor * expected_size_image[0])
            expected_height = round(factor * expected_size_image[1])

            # 新しい画像の minx、miny、maxx、maxy 座標を取得
            start_width = round((image_width - expected_width) / 2)
            start_height = round((image_height - expected_height) / 2)
            end_width = expected_width + round((image_width - expected_width) / 2)
            end_height = expected_height + round((image_height - expected_height) / 2)

            # 画像をクロップ
            image = image.crop((start_width, start_height, end_width, end_height))

        # 画像をクロップしたら、画像をリサイズします
        # 画像は expected_size_image と同じアスペクト比を持っている必要があるため、リサイズは画像を妨げません
        image = image.resize(expected_size_image)

        # 画像をコラージュキャンバスに貼り付ける
        collage.paste(image, (w, h))
        file_count += 1

ここでは、2つのループを作成します。1つ目のループは画像を横に並べ、2つ目のループは行を移動します。たとえば、1つ目のループの最後には、以下のような画像があります:

最初のループの最後の結果

ループ内では、以下の4つのアクションが実行されます:

  • 1. 画像の期待されるサイズを決定する
  • 2. 画像を期待されるサイズにクロップする
  • 3. 画像を以前のコードブロックで定義されたタイルサイズ(600, 400)にリサイズする
  • 4. タイル画像をコラージュに貼り付ける
アクション1、2、および4は直感的ですが、アクション3に焦点を当ててみたいと思います。これは、異なるサイズの画像を処理する際には簡単なタスクではありません。 例えば、以下のように異なるサイズの2つの画像がある場合、これらをどのように600x400 の画像に変換しますか?
風景 猿

ここで、画像を 600x400 のアスペクト比に変換する必要があります。これを達成するために、実際のサイズを期待されるサイズで割って、実際の側がどのくらい大きいかを特定します。結果は width_factorheight_factor 変数に格納されます。次に、これら2つの比率のうち小さい方を使用して、この画像に合わせることができる 600x400 の最小倍数を特定します。

例えば、サイズが 2400x3000 の画像は、2400x1600 のサイズとして 600x400 のアスペクト比に合わせることができます。これは、垂直方向に 3000 - 1600 = 1400 ピクセルを削除する必要があることを意味します。ピクセルを削除するときは、画像の中央部分を残します。

画像がクロップされたら、すでに同じアスペクト比を持っているため、安全に 600x400 にリサイズできます。その後、タイル画像がコラージュキャンバスに貼り付けられます。

3. 結果のコラージュを保存する

# コラージュを保存
collage.save("collage.png")

この最後のコードで、コラージュが指定された場所に保存されます。キャンバスが RGBA 画像として作成されたため、JPG として保存することはできません。

このアルゴリズムのさらなる改善点としては、次のようなものがあります:

  • 画像間に隙間を追加する
  • 常に画像の中央部分を残す代わりに、クロップエリアをスマートに選択する

質問はありますか?コメントセクションでお知らせください。

このブログは英語からChatGPTによって翻訳されました。不明な点がある場合は、お問い合わせページからご連絡ください。

コメントを残す

コメント

Kash

8ヶ月前

This is decent. But I want to go one step beyond this, and create a mixed collage with some landscape and some portrait images. To me, all landscape images look a bit bland. Mixed collage would be more dynamic. I've been trying to write code for this, but have been struggling for weeks. Dynamic image placement with some portraits and other landscape images is proving to be challenging. I'll get there.

その他のブログ

SvelteとJavaScriptを使用してシンプルで動的なツールチップを作成する

2024/06/19

SvelteとJavaScriptを使用してシンプルで動的なツールチップを作成する

JavaScriptSvelteTooltip動的シンプルツールチップフロントエンド
JavaScriptを用いて東京都のインタラクティブな地図を作成する

2024/06/17

JavaScriptを用いて東京都のインタラクティブな地図を作成する

SvelteSVGJavaScriptTailwindインタラクティブな地図東京市区町村23区地図
Matplotlibで日本語文字化けを解決できる簡単な方法

2024/06/14

Matplotlibで日本語文字化けを解決できる簡単な方法

MatplotlibグラフチャートPython日本語文字化け問題バグ
書評 | トーキング・トゥ・ストレンジャーズ 「よく知らない人」について私たちが知っておくべきこと by マルコム・グラッドウェル

2024/06/13

書評 | トーキング・トゥ・ストレンジャーズ 「よく知らない人」について私たちが知っておくべきこと by マルコム・グラッドウェル

書評トーキング・トゥ・ストレンジャーズ「よく知らない人」について私たちが知っておくべきことマルコム・グラッドウェル
日本語で最もよく使われる3000字の漢字

2024/06/07

日本語で最もよく使われる3000字の漢字

3000よく使う準漢字使用回数漢字日本語漢字リスト漢字普及率日本語能力試験独学勉強単語
VSCodeでRegexを使用してReplaceする方法

2024/06/07

VSCodeでRegexを使用してReplaceする方法

VSCodeRegex検索置き換える条件付き置換FindReplaceConditional Replace
SvelteではReadable Storeを使用するな

2024/06/06

SvelteではReadable Storeを使用するな

SvelteReadableWritableステート管理ストアStore速度メモリファイルサイズ
GzipとPakoでデータを圧縮してWebサイトのローディング速度を上げる方法

2024/06/05

GzipとPakoでデータを圧縮してWebサイトのローディング速度を上げる方法

Gzip圧縮PakoWebサイトローディング速度SvelteKit
JavaScriptを使用してWebページ上でマウスが指している単語を特定する

2024/05/31

JavaScriptを使用してWebページ上でマウスが指している単語を特定する

JavascriptマウスPointerHoverWeb開発
SvelteとSVGを用いてインタラクティブな地図を作成する

2024/05/29

SvelteとSVGを用いてインタラクティブな地図を作成する

SvelteSVGインタラクティブな地図フロントエンド
書評 | Originals 誰もが「人と違うこと」ができる時代 by アダム・グラント & シェリル・サンドバーグ

2024/05/28

書評 | Originals 誰もが「人と違うこと」ができる時代 by アダム・グラント & シェリル・サンドバーグ

書評Originals誰もが「人と違うこと」ができる時代アダム・グラント & シェリル・サンドバーグ
Javascriptを使用して数独を解く方法

2024/05/27

Javascriptを使用して数独を解く方法

数独を解くアルゴリズムJavaScriptコーディング
ウェブサイトへのトラフィックを1か月で10倍に増やした方法

2024/05/26

ウェブサイトへのトラフィックを1か月で10倍に増やした方法

ウェブサイトへのトラフィック増加クリックインプレッションGoogle Search Console
人生はサイクリングに似ている

2024/05/24

人生はサイクリングに似ている

サイクリング人生哲学成功
JavaScriptでバックトラッキング・アルゴリズムを用いて完全な数独グリッドを生成する

2024/05/19

JavaScriptでバックトラッキング・アルゴリズムを用いて完全な数独グリッドを生成する

数独バックトラッキング・アルゴリズム完全なグリッドJavaScript
Tailwindが素晴らしい理由とWeb開発をいかに楽にするか

2024/05/16

Tailwindが素晴らしい理由とWeb開発をいかに楽にするか

Tailwind素晴らしいフロントエンドWeb開発
PythonとGitフックを使用してサイトマップを自動的に生成する

2024/05/15

PythonとGitフックを使用してサイトマップを自動的に生成する

GitフックPythonサイトマップSvelteKit
書評 | Range (レンジ) 知識の「幅」が最強の武器になる by デイビッド・エプスタイン

2024/05/14

書評 | Range (レンジ) 知識の「幅」が最強の武器になる by デイビッド・エプスタイン

書評Range (レンジ)David Epstein (デイビッド・エプスタイン)知識の「幅」が最強の武器になる
SvelteとSvelteKitはなんですか?

2024/05/13

SvelteとSvelteKitはなんですか?

SvelteSvelteKitFront-endVite
SvelteKitで国際化(多言語化)

2024/05/12

SvelteKitで国際化(多言語化)

国際化多言語SvelteKitI18N
SvelteでCachingを用いてDeploy時間を短縮する方法

2024/05/11

SvelteでCachingを用いてDeploy時間を短縮する方法

SvelteEnhanced ImageCachingDeploy Time
SvelteとIntersection Oberverによるレイジーローディング

2024/05/10

SvelteとIntersection Oberverによるレイジーローディング

レイジーローディングウェブサイト速度の最適化SvelteIntersection Observer
遺伝的アルゴリズムで最適な株式ポートフォリオを作る方法

2024/05/10

遺伝的アルゴリズムで最適な株式ポートフォリオを作る方法

株式書状ポートフォリ最適化遺伝的アルゴリズムPython
Pythonを用いてShapeFileをSVGに変換できる方法

2024/05/09

Pythonを用いてShapeFileをSVGに変換できる方法

ShapeFileSVGPythonGeoJSON
Svelteの反応性:変数、バインディング、およびキー関数

2024/05/08

Svelteの反応性:変数、バインディング、およびキー関数

Svelte反応性バインディングキー関数
書評 | 孫子の兵法

2024/05/07

書評 | 孫子の兵法

書評The Art Of War (兵法)Sun Tzu (孫子)Thomas Cleary
スペシャリストは終了。ゼネラリスト万歳!

2024/05/06

スペシャリストは終了。ゼネラリスト万歳!

専門家ジェネラリストパラダイムシフトソフトウエア・エンジニアリング
トルコ人の有権者の投票行動をPythonでの分析

2024/05/03

トルコ人の有権者の投票行動をPythonでの分析

トルコ投票者年齢分析国家投票有権者行動分析
Seleniumを用いてトルコ投票データベースを作る方法

2024/05/01

Seleniumを用いてトルコ投票データベースを作る方法

PythonSeleniumWeb Scrapingトルコ国家投票
SvelteとTailwindを使用してInfinite Scrollできる方法

2024/04/30

SvelteとTailwindを使用してInfinite Scrollできる方法

SvelteTailwindInfinite ScrollFront-end
1年間以内で日本語を駆使できるようになるための方法

2024/04/29

1年間以内で日本語を駆使できるようになるための方法

日本語短時間言語学習日本語能力試験ビジネス日本語
SvelteとTailwindを用いたWebサイトテンプレート

2024/04/25

SvelteとTailwindを用いたWebサイトテンプレート

Web開発フロントエンドSvelteTailwind
怠惰なエンジニアとひどいデザイン

2024/01/29

怠惰なエンジニアとひどいデザイン

怠け者エンジニア質の悪い製品StarbucksSBI証券
偉大さについて

2024/01/28

偉大さについて

雄大さ人生の意味満足できる人生目的
MacBook で PDF を PNG に変換する

2024/01/28

MacBook で PDF を PNG に変換する

PDFPNGMacBookAutomator
2023年振り返り:24冊の読んだ本のまとめ

2023/12/31

2023年振り返り:24冊の読んだ本のまとめ

読書 2023振り返り
ウェブサイトの訪問者のデバイスとブラウザを検出する方法

2024/01/09

ウェブサイトの訪問者のデバイスとブラウザを検出する方法

Javascript端末検知ブラウザ検知Website分析
ChatGPT回答の解析

2024/01/19

ChatGPT回答の解析

ChatGPT大規模言語モデル機械学習生成AI