Python | EXIFのカメラ機種・レンズ別に画像をまとめてHTMLギャラリーを作る

Python Python
スポンサーリンク

ここでは EXIFのカメラ機種・レンズ別に画像をまとめてHTMLギャラリーを作る 実践例を紹介します。これを使えば「Canonで撮った写真」「iPhoneで撮った写真」「50mmレンズで撮った写真」などを自動で分類できます。


1. EXIFから機種・レンズ情報を取得

EXIFには以下のタグが含まれます:

  • Make(メーカー名: Canon, Nikon, Apple など)
  • Model(カメラ機種: EOS 5D, iPhone 12 など)
  • LensModel(レンズ名: EF50mm f/1.8 など)
from pathlib import Path
from PIL import Image, ExifTags

# EXIFタグ辞書
EXIF_TAGS = {v: k for k, v in ExifTags.TAGS.items()}

def get_camera_info(img_path: Path):
    """カメラ機種とレンズ名を返す"""
    make, model, lens = None, None, None
    try:
        with Image.open(img_path) as img:
            exif = img._getexif()
            if not exif:
                return None, None
            make = exif.get(EXIF_TAGS.get("Make"))
            model = exif.get(EXIF_TAGS.get("Model"))
            lens = exif.get(EXIF_TAGS.get("LensModel"))
    except Exception:
        pass
    return (f"{make} {model}".strip() if model else make, lens)
Python

2. 分類の仕組み

  • camera_dict[機種名] = [画像リスト]
  • lens_dict[レンズ名] = [画像リスト]
  • HTMLで「機種別」「レンズ別」のページを生成

3. サンプル処理フロー

from collections import defaultdict
import shutil, html

src_dir = Path.home() / "Pictures" / "gallery_src"
out_dir = Path.home() / "Pictures" / "gallery_by_camera"
thumb_dir = out_dir / "thumbs"
img_copy_dir = out_dir / "images"

out_dir.mkdir(exist_ok=True)
thumb_dir.mkdir(exist_ok=True)
img_copy_dir.mkdir(exist_ok=True)

camera_dict = defaultdict(list)
lens_dict = defaultdict(list)

def make_thumbnail(src: Path, dst: Path, size=(240,240)):
    with Image.open(src) as img:
        img.thumbnail(size)
        if img.mode != "RGB":
            img = img.convert("RGB")
        dst.parent.mkdir(parents=True, exist_ok=True)
        img.save(dst, "JPEG", quality=85)

for img_path in src_dir.glob("*.jpg"):
    cam, lens = get_camera_info(img_path)
    cam = cam or "不明なカメラ"
    lens = lens or "不明なレンズ"

    thumb_path = thumb_dir / f"{img_path.stem}_thumb.jpg"
    make_thumbnail(img_path, thumb_path)

    copy_path = img_copy_dir / img_path.name
    if not copy_path.exists():
        shutil.copy(img_path, copy_path)

    item = {
        "full": f"images/{img_path.name}",
        "thumb": f"thumbs/{thumb_path.name}",
        "title": html.escape(img_path.stem),
    }
    camera_dict[cam].append(item)
    lens_dict[lens].append(item)
Python

4. HTML生成(例:カメラ機種別)

def render_gallery(title, groups, filename):
    html_content = f"""<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>{title}</title>
<style>
body {{ background:#111; color:#eee; font-family:sans-serif; }}
h2 {{ margin-top:24px; }}
.grid {{ display:grid; grid-template-columns:repeat(auto-fill,minmax(160px,1fr)); gap:12px; }}
.card {{ background:#1b1b1b; border:1px solid #333; border-radius:8px; overflow:hidden; }}
.thumb {{ width:100%; height:auto; object-fit:cover; aspect-ratio:1/1; }}
.meta {{ padding:8px; font-size:12px; color:#bbb; }}
</style>
</head>
<body>
<header><h1>{title}</h1></header>
"""
    for group, items in groups.items():
        html_content += f"<h2>{group}{len(items)}枚)</h2><div class='grid'>"
        for item in items:
            html_content += f"""
            <div class="card">
              <a href="{item['full']}" target="_blank">
                <img class="thumb" src="{item['thumb']}" alt="{item['title']}">
                <div class="meta">{item['title']}</div>
              </a>
            </div>
            """
        html_content += "</div>"
    html_content += "</body></html>"
    (out_dir / filename).write_text(html_content, encoding="utf-8")

# カメラ別ページ
render_gallery("カメラ機種別ギャラリー", camera_dict, "by_camera.html")
# レンズ別ページ
render_gallery("レンズ別ギャラリー", lens_dict, "by_lens.html")
Python

5. 出力イメージ

  • by_camera.html
    • Canon EOS 5D(20枚)
    • iPhone 12(15枚)
    • Sony α7 III(10枚)
  • by_lens.html
    • EF50mm f/1.8(12枚)
    • 24-70mm f/2.8(18枚)
    • 不明なレンズ(5枚)

✅ まとめ

  • EXIFのMake/Model/LensModel を使えば機種・レンズ別に分類可能
  • defaultdict(list) でグループ分けし、HTMLを自動生成
  • カメラやレンズごとの作風や傾向を振り返るのに便利

Python
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました