からあげ博士の日常と研究と

博士課程を満期退学した人が好きなことを好きなままに書くところ。

pythonを使って自分がよく使う焦点距離を可視化する方法

 こんにちは。からあげ博士(@phd_karaage)です。今回は自分がどんな焦点域で写真を撮影していることが多いのか、pythonを使って可視化してみたいと思います。Exifデータを使って可視化を行うので、マウントアダプタなどを使って焦点距離が記録されない方法で撮影を行っている方は今回の方法を使うことができないのでご容赦ください。また動作確認はソニーのα7R(初代)、α550、キヤノン EOS Kiss X8iでのみ行っています。他のカメラで試してみてうまくいかなかったら、Exifデータの中身を見てみてください。ちなみに以下に示しているのはソニー版の情報です。キヤノン版は最後の章をご覧ください。

 まずは簡単にコードを示しておきたいと思います。

import os
from PIL import Image
import matplotlib.pyplot as plt

path = "Please input your dir" ##写真の入ったディレクトリを入力する
imgs_list = os.listdir(path)

list_length = []

for i in imgs_list:
    img = Image.open(path + os.sep + i)
    exif = img._getexif()
    length = exif.get(41989) ## 35mm換算焦点距離を抽出する
    list_length.append(length)

plt.hist(list_length)

 これを実行することで、こんなヒストグラムが得られるはずです。

 このヒストグラムは参照したフォルダ内に存在する画像のうち、その焦点距離で撮影した枚数を示したものになります。このフォルダを見ると50mmで撮影した写真が多いようです。

今回使ったライブラリ

 今回はフォルダ内のリストを作成するために、osを、画像を読み込み、Exifデータを抽出するためにPIL、その中のImageを、ヒストグラムとして可視化するためにmatplotlibを使っています。それほど厄介なライブラリを使っている訳ではなく、Anacondaを入れている環境であれば普通に使えるライブラリを仕様しています。

 インポートはお決まりのやり方で。

import os
from PIL import Image
import matplotlib.pyplot as plt

まずは画像をリストにする

 たいていの人は1日ごとにフォルダ分けをしながら写真を管理しているのではないでしょうか?人それぞれなのでそんなことは知ったことではないのですが、そうではない人は、調べたい画像を1つのフォルダに入れてあげてください。

 調べてみたいフォルダが決まりましたか?それではその中身について、ファイル名のリストを作ってみましょう。

path = "E://Photo/20211002_jpg/" ##写真の入ったディレクトリを入力する
imgs_list = os.listdir(path)

 私のWindows環境では、このようなフォルダ構成になっているのでパスはこのように入力されました。ちなみにjpg以外にrawなどのデータが入っているとたぶんエラーになるのでそいつらは一時的にでも別の場所に居てもらってください。

 os.listdirで指定したpathの中にあるファイルをすべてリスト形式で取り出してくれます。もし気になる人が居たら、img_listの中身をprintしてみてください。きっとその中身はjpgファイルだけになっていることでしょう。

空のリストを作成して、その中に焦点距離を保存する

list_length = []

 やっていることとしては、題名の通りですね。この中に焦点距離を保存していきます。

Exif情報を取り出す

 フォルダ内にあるjpgについて、それぞれfor文を使ってExifを取り出していきましょう。

for i in imgs_list:
    img = Image.open(path + os.sep + i)
    exif = img._getexif()
    length = exif.get(41989)
    list_length.append(length)

 まずは画像を、Image.openで読み込んでいます。今回は、path+ os.sep + iという形にして、もともとのフォルダ内の、ファイルiを読み込めという形で指定しています。次に、Exif情報を取得しています。これには、._getexif()を使っています。これにより、exifには辞書形式でExif内の情報が保存されます。

 ここから焦点距離を抽出する訳ですが、Exif内のどこに保存されてんねん、という話になります。Spyderの変数エクスプローラでも見てみましょう。

 無茶苦茶ですね。だいたい写真をやっている人間は想像できそうなものですが、焦点距離なのかどうか真に怪しいなあというものがあったりするので根拠が欲しい訳です。今回はこちらを参照しました。 http://cachu.xrea.jp/perl/ExifTAG.htmlcachu.xrea.jp

 これによると、キーが41989のところに35mm換算の焦点距離が入っているようですから、これを抽出してきます。辞書形式からキーに基づいて抽出するときはdict.getでいけます。今回辞書の名前がexifなので、exif.get(41989)となる訳です。これをlenghtとして保存して、先ほど作った空のリストに次々appendしてあげればいい訳ですね。

 ちなみにキーが37386で撮影焦点距離が入っているようですが、ソニーの場合、(500, 10)というtupleが入力されているんですね。

最後はmatplotlibで可視化する

 matplotlibで可視化するとき、この手のデータを観察するにはヒストグラムが最適でしょう。特にオプションを指定することなくplt.hist(list_length)で表示することで、先ほどのヒストグラムが表示されます。やったね!

キヤノンはExifの格納状況が違うっぽい

 少なくともEOS Kiss X8iでは35mm換算焦点距離が保存されていないようなんですね。そこで本来の焦点距離を抽出しようと試みます。撮影焦点距離のキーは37386ですからここの中身を見てみましょう。

 どうやら単純に焦点距離を値として保存している訳ではなさそうですね。より具体的に中身を見てみましょう。

 このnumeratorが焦点距離のようです。なんでこんな格納しているんだろう。

 という訳でこの値を取ってくるパターンはこちら。

import os
from PIL import Image
import matplotlib.pyplot as plt

path = "Please input your dir"
imgs_list = os.listdir(path)

list_length = []

for i in imgs_list:
    img = Image.open(path + os.sep + i)
    exif = img._getexif()
    length = exif.get(37386).numerator ## キー37386のnumeratorに含まれている値を抽出する
    list_length.append(length)

plt.hist(list_length)

 これは本当に24mmでしか撮っていないのでこんな感じ。

 他のカメラで試してうまくいかなかったら情報くださいませ。