6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Python】写真の位置情報のタグ(JPGファイルのGPS Exif)の読み書き

Last updated at Posted at 2020-08-08

はじめに

これも自分用のメモです。python を使うと楽にできます。注意点として、

  • 緯度経度は度分秒なので60進数
  • 値は実数ではなく、分数で。(有理数、というのかな)

いくつか関係するライブラリがあります。どれか一つに統一したほうがよいのですが、とりあえず動いたものメモです。(おい)

仕様書?

下記の文献を見つけました。

これによるとGPS Info IFDは以下のように定義されているようです。

image.png

たくさんありますが、私が扱ったファイルでは0 - 6 までのタグのみでした。GPSの緯度、経度、高さが読み書きできたので、とりあえずは十分でした。ここでGPSLatitudeRefは一文字の'N'か'S'で北緯、南緯を表します。GPSLatitudeは分数で表します。

python で読み書きする

Pillow で緯度経度を読む

Pillow を使用しました。準備で苦労したかは覚えていません。

pip3 install pillow

下記で緯度経度を読めました。

read_gpsexif.py
from PIL import Image
infile = "test.JPG"
img = Image.open( infile )
exif = img._getexif()
for k, v in exif.items():
    if k==34853:
        print(v)

これで

{0: b'\x02\x00\x00\x00',
 1: 'N',
 2: (35.0, 20.0, 53.51123),
 3: 'E',
 4: (137.0, 9.0, 17.83123),
 5: b'\x00', 6: 256.123}

のような結果を得ます。先の仕様書のGPS INfo IFD の定義と見比べると意味が分かると思います。度分秒なので、10進法にするには変換が必要です。例えば


deg,minu,sec = 35.0, 20.0, 53.51366
deg + minu/60.0 + sec/3600.0

35.34819823888889 を得ます。

piexif でGPS Exif の緯度経度を書き換える

piexifを利用しました。
度分秒と分数への変換を関数にし、Gps exif を読んで書き換える作戦です。Fractionは実数を有理数に変換してくれる関数です。文字列だと3/4になるので、分子と分母をset にして返す処理を関数にしています。

def _to_deg(value:float, loc:list):
    """
    Convert degree in decimal to degree, minutes, and second. Note Degree and minute is integer and seconds is float.
    """
    if value < 0:
       loc_value = loc[0] # 'S' or 'E' 
    elif value > 0:
       loc_value = loc[1] # 'N' or 'W'
    else:
       loc_value = ""
    abs_value = abs(value)
    deg =  int(abs_value) # integer part
    t1 = (abs_value-deg)*60
    minu = int(t1) # minutes
    sec = round((t1 - minu)* 60, 5) # seconds
    return (deg, min, sec, loc_value)

from fractions import Fraction
def _change_to_rational(number):
    f = Fraction(str(number))
    return (f.numerator, f.denominator)

を用いて、以下を実行します。

write_gpsexif.py
import piexif
lat, lng, altitude = 39.123, 139.123, 50.123
jpg_filepath = "test.JPG"

# convert decimal to degree, minutes, seconds
lat_deg = to_deg(lat, ["S", "N"]) 
lng_deg = to_deg(lng, ["W", "E"])
exif_lat = (change_to_rational(lat_deg[0]),  change_to_rational(lat_deg[1]), change_to_rational(lat_deg[2]))
exif_lng = (change_to_rational(lng_deg[0]), change_to_rational(lng_deg[1]), change_to_rational(lng_deg[2]))
gps_ifd = {
    piexif.GPSIFD.GPSVersionID: (2, 0, 0, 0),
    piexif.GPSIFD.GPSAltitudeRef: 0,
    piexif.GPSIFD.GPSAltitude: change_to_rational(round(altitude, 3)),
    piexif.GPSIFD.GPSLatitudeRef: lat_deg[3],
    piexif.GPSIFD.GPSLatitude: exif_lat,
    piexif.GPSIFD.GPSLongitudeRef: lng_deg[3],
    piexif.GPSIFD.GPSLongitude: exif_lng,
}

gps_exif = {"GPS": gps_ifd}
exif_data = piexif.load(jpg_filepath)
exif_data.update(gps_exif)
exif_bytes = piexif.dump(exif_data)
piexif.insert(exif_bytes, file_name)

これは確かStackOverflow を参考にさせていただいたと思うのですが、linkを無くしてしまいました。見つけたら追加します。

まとめ・雑感

必要にせまらて写真のGPSExif の読み書きをした時のメモです。

  • Pillow, piexif を利用したが、何となくどちらかに統一して正しく使うのがよさそう。

えいやの作業メモなので、拡充させていきたい、、、という投稿でした。最近雑だな。。^^; (2020/08/08)

コードのタイポを修正しました。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?