Python の画像ライブラリ Pillow を使用すると、画像ファイルの Exif 情報を取得できます。
Exif 情報の中の撮影条件を取得するには一手間必要です。
その方法を解説します。
目次
◆画像ビューア アプリのサンプル画像
次の記事で紹介している画像ビューアで撮影条件を出力しています。
📔 画像ビューアの作り方(Treeviewに画像と疑似チェックボックス)【Python】 🔗
▽画像のサムネイルと画像情報(撮影条件を含む)を表示します
ここでの撮影条件とは、カメラで撮影する時の絞りやシャッタースピード、ISO感度などの Exif 情報として記録されているものを指します。
◆画像の Exif 情報の取得方法
前述のアプリは Python で書かれています。
Python には Pillow と呼ばれる画像を扱うライブラリがあります。
Pillow の open() メソッドで画像を読み込み Image オブジェクトを作成します。
Image オブジェクトには Exif 情報を取得するメソッド getexif()
があります。
実行すると Exif
オブジェクトを返します。
Exif オブジェクトは collections.abc.MutableMapping ( 辞書のようなもの ) を継承しています。
※_getexif()
メソッドは古いメソッド(戻り値は dict)
Exif オブジェクトはキー (TAGID) が数字なのでそのままでは読みずらく、理解しやすい文字に変換します。
変換には、Pillow パッケージの ExifTags モジュールにある TAGS を使用します。
▽タグの例
TAGID | 略称 | 日本語の説明 | 英語の説明 |
---|---|---|---|
256 | ImageWidth | 画像の幅 | Image width |
306 | ModifyDate | ファイル変更日時 | File change date and time |
34853 | GPSInfoIFDPointer | GPS タグ | GPS IFD pointer |
【処理】
- Exif のタグを取得
getexif()
- TAGS で読みやすい文に変換
- 改行でつないで表示用文字列を作成
【コード】
from PIL import Image, ImageTk # Pillow from PIL.ExifTags import TAGS, GPSTAGS # Exifタグ情報 # 画像の取得 image1 = Image.open(file_name) # Exif情報の取得 exif_dict = image1.getexif() exif = [TAGS.get(k, "Unknown")+ f": {str(v)}" for k, v in exif_dict.items()] exif_str = "\n".join(exif)
◆GPS情報の取得方法
GPS 情報は、Exif 情報のタグ ID 34853
が該当します。
その内容を取得するには、Exif オブジェクトの get_ifd()
メソッドを使用します。
GPS 情報もキーが数字なので Exif 情報と同様に変換して読みやすくします。
こちらは、Pillow パッケージの ExifTags モジュールにある GPSTAGS を使用します。
【処理】
- GPS 情報を取得
get_ifd(34853)
- GPSTAGS で読みやすい文に変換
- 改行でつないで表示用文字列を作成
【コード】
# GPS情報の取得 gps_dict = exif_dict.get_ifd(34853) gps = [GPSTAGS.get(k, "Unknown") + f": {str(v)}" for k, v in gps_dict.items()] gps_str = "\n".join(gps)
◆撮影条件の取得方法
撮影条件は、Exif 情報の Exif タグに保存されています。
Exif タグは、タグ ID 34665
が該当します。
その内容を取得するには、Exif オブジェクトの get_ifd()
メソッドを使用します。
Exif タグの情報も Exif 情報と同様に変換して読みやすくします。
こちらは、Pillow パッケージの ExifTags モジュールにある TAGS を使用しても可能なのですが、別途作成しました。
◇get_ifd()メソッドで取得できるタグ
GPS 情報や Exif タグ情報以外にも get_ifd()
メソッドで取得できるタグが全部で4種類あります。
タグの種類 | タグID(16進) | タグID(10進) | 内容 |
---|---|---|---|
Exifタグ | 0x8769 | 34665 | 撮影条件データなどの情報 |
GPSタグ | 0x8825 | 34853 | 撮影場所に関する GPS 情報 |
互換性IFD | 0xA005 | 40965 | 旧バージョンとの互換性のための情報 |
メーカーノート | 0x927C | 37500 | 機器メーカー毎の独自情報 |
◇Exifタグの中身
Exif タグの中には、絞りやシャッタースピード、ISO感度などの撮影条件があります。
【主な Exif タグの中身】
- 露出時間(33434):カメラのシャッタースピードで見られる値
- シャッタースピード(37377):露出時間の単位をAPEXにしたもの
露出時間と同じ意味のもの - Fナンバー(33437):カメラの絞りで見られる値
- 絞り値(37378):F ナンバーの単位を APEX にしたもの
F ナンバーと同じ意味のもの
◇撮影条件に関するタグ
撮影条件のタグの名称を画像ビューアに表示するため、タグ番号と名称の辞書を作成しました。
Pillow の ExifTags.TAGS にも名称はあるのですが、日本語にしたかったのと出力する項目を選択したかったので別途、作成しました。
▽タグ情報の定数
SHOOTING_CONDITIONS = { # 撮影条件に関するタグ from JEITA CP-3451C 表示したくないものはコメントにしてある 33434:"露出時間", # ExposureTime 33437:"F ナンバー", # FNumber 34850:"露出プログラム", # ExposureProgram 34852:"スペクトル感度", # SpectralSensitivity 34855:"撮影感度", # PhotographicSensitivity 34856:"光電変換関数", # OECF 34864:"感度種別", # SensitivityType 34865:"標準出力感度", # StandardOutputSensitivity 34866:"推奨露光指数", # RecommendedExposureIndex 34867:"ISO スピード", # ISOSpeed 34868:"ISO スピードラチチュード yyy", # ISOSpeedLatitudeyyy 34869:"ISO スピードラチチュード zzz", # ISOSpeedLatitudezzz # 37377:"シャッタースピード", # ShutterSpeedValue APEX値 # 37378:"絞り値", # ApertureValue APEX値 # 37379:"輝度値", # BrightnessValue APEX値 37380:"露光補正値", # ExposureBiasValue APEX値 # 37381:"レンズ最小F値", # MaxApertureValue APEX値 37382:"被写体距離", # SubjectDistance 37383:"測光方式", # MeteringMode 37384:"光源", # LightSource 37385:"フラッシュ", # Flash 37386:"レンズ焦点距離", # FocalLength 37396:"被写体領域", # SubjectArea 41483:"フラッシュ強度", # FlashEnergy 41484:"空間周波数応答", # SpatialFrequencyResponse # 41486:"焦点面の幅の解像度", # FocalPlaneXResolution # 41487:"焦点面の高さの解像度", # FocalPlaneYResolution # 41488:"焦点面解像度単位", # FocalPlaneResolutionUnit 41492:"被写体位置", # SubjectLocation 41493:"露出インデックス", # ExposureIndex 41495:"センサ方式", # SensingMethod # 41728:"ファイルソース", # FileSource 41729:"シーンタイプ", # SceneType 41730:"CFA パターン", # CFAPattern 41985:"個別画像処理", # CustomRendered 41986:"露出モード", # ExposureMode 41987:"ホワイトバランス", # WhiteBalance 41988:"デジタルズーム倍率", # DigitalZoomRatio 41989:"35mm 換算レンズ焦点距離", # FocalLengthIn35mmFilm 41990:"撮影シーンタイプ", # SceneCaptureType 41991:"ゲイン制御", # GainControl 41992:"撮影コントラスト", # Contrast 41993:"撮影彩度", # Saturation 41994:"撮影シャープネス", # Sharpness 41995:"撮影条件記述情報", # DeviceSettingDescription 41996:"被写体距離レンジ", # SubjectDistanceRange }
【処理】
- Exif タグを取得
get_ifd(34665)
- シャッタースピードだけ分数に変換(ただし0.3以下の時)
- キー(タグ ID)でソート
- 作成した SHOOTING_CONDITIONS で読みやすい文に変換(存在するものだけを出力)
- 改行でつないで表示用文字列を作成
【コード】
# exifタグ情報の取得 pvtag_dict = exif_dict.get_ifd(34665) if 33434 in pvtag_dict and pvtag_dict.get(33434) < 0.3: # シャッタースピードだけ分数に変換ただし0.3以下の時 pvtag_dict[33434] = str(Fraction(pvtag_dict.get(33434))) pvtag = sorted(pvtag_dict.items()) # キーでソート。結果はタプルのリスト pvtag = [ImageOp.SHOOTING_CONDITIONS.get(k) + f": {str(v)}" for k, v in pvtag if k in ImageOp.SHOOTING_CONDITIONS] # SHOOTING_CONDITIONSに存在するものだけ(撮影条件) pvtag_str = "\n".join(pvtag)
◎Pythonでの分数表示
標準ライブラリfractionsモジュールを使うことで分数を扱うことができます。
使用にはインポートが必要です。from fractions import Fraction
【コンストラクタの例】
- Fraction(1, 3)⇒1/3
- Fraction(0.25)⇒1/4
- Fraction('2/5')⇒2/5
文字列へ変換する場合は、str(a)
とすると 1/4
の形の文字列になります。
◆さいごに
最初に画像ビューアを作った時、Exif 情報を出力すればデジカメの撮影条件も出力されていると思っていました。
GPS 情報だけが特別と思い、そこだけ注意していました。
月の写真を撮った後、どういう設定で撮ったかを確認するために自分で作った画像ビューアを起動しました。
その時に撮影条件が出力されていないことに気が付きました。
Exif の規格も良く知らないし、Pillow の仕様も読み切れないし、撮影条件の取得方法を見つけるのに苦労しました。
この記事で、他の方が苦労せずに済むと幸いです。
画像ビューアの作り方も紹介しています。
📔 画像ビューアの作り方(Treeviewに画像と疑似チェックボックス)【Python】 🔗
◇ご注意
本記事は次のバージョンの下で動作した内容を基に記述しています。
- Python 3.8.5
- Pillow 8.3.0
◇免責事項
ご利用に際しては、『免責事項』をご確認ください。
お気づきの点がございましたら『お問い合わせ』からお問い合わせください。