見出し画像

撮影情報(Exif)をPythonで読み込む


はじめに

Exifは撮影に使用したカメラやレンズ、F値や露光時間、ISO感度などといった撮影情報を写真データに埋め込むための規格です。この規格により埋め込まれた撮影情報をExif情報と呼んだりします。

PythonのPillow(PIL)というライブラリを使用することで、写真データからこのExif情報を抽出することができます。

ちまたでは_getexifを使った抽出方法がよく紹介されていますが、今回はgetexifを使った抽出方法について紹介します。

PILのバージョンは9.1.1で検証しています。(バージョンによって挙動が違う場合あるので注意が必要です)

よく紹介される抽出方法(_getexif)

ググるとよく出てくるのは、以下のやり方です。

from PIL import Image
path = 'hoge.jpg'
im = Image.open(path)
im._getexif()

この_getexifメソッドを使ったやり方で何ら問題ないですが、
_(アンダースコア)から始まる名前のメソッドは、基本的に外部から使われることを想定していないプライベートなメソッドになります。

Pillowにはgetexifというパブリックなメソッドも用意されているので、
今回はこちらを使ったexif情報の抽出方法を紹介しようと思います。

getexifメソッド

getexifを使う場合コードはこちらになります。

from PIL import Image
with Image.open(path) as im:
    exif = im.getexif()
exif_dict = exif.get_ifd(0x8769)  # Exif情報の取得
gps_dict = exif.get_ifd(0x8825)  # GPS情報の取得
exif_dictの中身
キーが番号になっていて、どれが何を示しているかわかりませんが、
このあと意味の分かる名前に置換します

こちらの情報を参考にしました。

getexifでうまく情報が取れないという投稿者に対して、こうすれば取得できるという例を開発者が示しています。

exifの仕様について、私も詳細まで把握していないですが、
以下のサイト見ると上記のコードの意味がなんとなく分かるかと思います。

タグ番号を名前に置き換える

先ほどの処理だけだと、辞書のキーがタグ番号になっていて、ぱっと見何が何だかわかりません。
Pillowにはタグ番号とタグ名称の辞書(TAGS)がありますので、それを使って番号を名称に置換します。

PIL.ExifTags.TAGS

やり方はいろいろあると思いますが、pandasを使った置換が楽なので紹介します。

from PIL.ExifTags import TAGS,GPSTAGS
exif_sr = pd.Series(exif_dict).rename(TAGS)
gps_sr = pd.Series(gps_dict).rename(GPSTAGS)
exif_sr

pandas.Seriesに変換したのち、renameメソッドでindexを置換します。
また、to_dictメソッドを使って辞書に戻すこともできます。

まとめ

from PIL import Image
from PIL.ExifTags import TAGS,GPSTAGS

def load_exif(path):
    ifd_dict = {}
    with Image.open(path) as im:
        exif = im.getexif()
    ifd_dict["Exif"] = exif.get_ifd(0x8769)
    ifd_dict["GPSInfo"] = exif.get_ifd(0x8825)
    return ifd_dict

path = 'hoge.jpg'
ifd_dict = load_exif(path)
exif_sr = pd.Series(ifd_dict["Exif"]).rename(TAGS)
gps_sr = pd.Series(ifd_dict["GPSInfo"]).rename(GPSTAGS)

Pillowのgetexifメソッドを使って、写真の撮影情報を取得する方法を紹介しました。
今後は、複数の写真ファイルに対してPandas.DataFrameで扱いやすい形にする方法について紹介していきたいと思います。

追記(2023/10/14)

まとめに書いた方法だと、一部情報が取れないので、exifの情報をすべて取れるよう修正しました。

from PIL import Image
from PIL.ExifTags import TAGS,GPSTAGS


def load_exif(path):
    ifd_dict = {}
    with Image.open(path) as im:
        exif = im.getexif()
    # {タグID: 値}の辞書を{タグ名: 値}の辞書に変換
    ifd_dict["Zeroth"] =  {TAGS[tag_id]: value for tag_id, value in exif.items() }
    ifd_dict["Exif"] =    {TAGS[tag_id]: value for tag_id, value in exif.get_ifd(0x8769).items()}
    ifd_dict["GPSInfo"] = {GPSTAGS[tag_id]: value for tag_id, value in exif.get_ifd(0x8825).items()}
    return ifd_dict,exif

path = 'hoge.jpg'
ifd_dict = load_exif(path)

主な修正点としては、ifd_dict["Zeroth"]に0th IFDという種類の情報を追加したことです。これにはカメラのモデル名やメーカー名などが入っています。ついでにタグ番号・タグ名の置換方法もpandasを使わない方法にしました。

得られるifd_dictの中身は以下のような形です。

{'Exif': {'BrightnessValue': 8.571875,
          'ColorSpace': 1,
・・・・・・・・・・・・中略・・・・・・・・・・・・
          'Sharpness': 0,
          'WhiteBalance': 0},
 'GPSInfo': {'GPSDateStamp': '2023:02:25',
             'GPSDifferential': 0,
・・・・・・・・・・・・中略・・・・・・・・・・・・
             'GPSTimeStamp': (6.0, 15.0, 53.0),
             'GPSVersionID': b'\x02\x03\x00\x00'},
 'Zeroth': {'DateTime': '2023:02:25 15:15:52',
            'ExifOffset': 376,
・・・・・・・・・・・・中略・・・・・・・・・・・・
            'YCbCrPositioning': 2,
            'YResolution': 350.0}}

また、今回の修正内容に関することや、大量の画像のexifを読み込んで表形式にまとめる方法を以下の記事に書いたので、こちらも参照いただければと思います。


この記事が気に入ったらサポートをしてみませんか?